#
# Machekku Blink Keyboard LED
#
# Version: 0.1
# Date: 2005-05-18
#
# http://machekku.uaznia.net/jabber/psi/patches/
#
# psics.pri                                   |    6 +
# src/common.h                                |    2
# src/mainwin.cpp                             |   22 +++
# src/mainwin.h                               |    1
# src/options/opt_events-ui.ui                |    8 +
# src/options/opt_events.cpp                  |    8 +
# src/psi_profiles.cpp                        |    6 +
# src/tools/keyboardled/keyboardled.cpp       |  165 ++++++++++++++++++++++++++++
# src/tools/keyboardled/keyboardled.h         |   67 +++++++++++
# src/tools/keyboardled/keyboardled.pri       |   14 ++
# src/tools/keyboardled/keyboardled_dummy.cpp |   45 +++++++
# src/tools/keyboardled/keyboardled_win.cpp   |  129 +++++++++++++++++++++
# 12 files changed, 473 insertions(+)
#
diff -X exclude -Naru psi_cvs-2005.05.17/psi/psics.pri psi/psi/psics.pri
--- psi_cvs-2005.05.17/psi/psics.pri	Tue Apr 12 17:51:40 2005
+++ psi/psi/psics.pri	Tue May 17 13:48:16 2005
@@ -56,6 +56,12 @@
 		}
 	}
 
+	# keyboardled
+	CONFIG += keyboardled
+	KEYBOARDLED_CPP = $$PSICS_CPP/keyboardled
+	INCLUDEPATH += $$KEYBOARDLED_CPP
+	include($$KEYBOARDLED_CPP/keyboardled.pri)
+
 	# zip
 	CONFIG += zip
 	ZIP_CPP = $$PSICS_CPP/zip
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/common.h psi/psi/src/common.h
--- psi_cvs-2005.05.17/psi/src/common.h	Wed May  4 18:18:20 2005
+++ psi/psi/src/common.h	Tue May 17 13:48:16 2005
@@ -93,6 +93,8 @@
 	bool smallChats, chatLineEdit, showJoins, useTabs, putTabsAtBottom, autoRosterSize, autoResolveNicksOnAdd;
 	bool autoCopy; // although this setting is ignored under linux,
 					// it is preserved in case user uses the same config file on different platforms
+	bool blinkLED;
+	int blinkLEDTime;
 
   bool oldSmallChats; //Filthy hack, see chat code.
 	int delChats, browser;
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/mainwin.cpp psi/psi/src/mainwin.cpp
--- psi_cvs-2005.05.17/psi/src/mainwin.cpp	Tue Feb 22 17:57:42 2005
+++ psi/psi/src/mainwin.cpp	Wed May 18 20:53:02 2005
@@ -43,6 +43,7 @@
 #include"fancylabel.h"
 #include"psitoolbar.h"
 #include"psipopup.h"
+#include"keyboardled.h"
 
 #include"mainwin_p.h"
 
@@ -100,6 +101,8 @@
 
 	void registerActions();
 	IconAction *getAction( QString name );
+
+	KeyboardLED *ledScrollLock;
 };
 
 MainWin::Private::Private(PsiCon *_psi, MainWin *_mainWin)
@@ -115,6 +118,8 @@
 
 	statusMapper = new QSignalMapper(mainWin, "statusMapper");
 	mainWin->connect(statusMapper, SIGNAL(mapped(int)), mainWin, SLOT(activatedStatusAction(int)));
+
+	ledScrollLock = KeyboardLED::getInstance(KeyboardLED::ledScroll);
 }
 
 MainWin::Private::~Private()
@@ -793,6 +798,7 @@
 	}
 
 	updateTray();
+	updateLED();
 }
 
 bool MainWin::askQuit()
@@ -886,6 +892,7 @@
 		d->gm->show();
 
 	updateTray();
+	updateLED();
 }
 
 void MainWin::toggleVisible()
@@ -980,6 +987,7 @@
 
 	updateTray();
 	updateCaption();
+	updateLED();
 }
 
 QString MainWin::numEventsString(int x) const
@@ -1006,6 +1014,20 @@
 		d->tray->setAlert(IconsetFactory::iconPtr("psi/connect"));
 	else
 		d->tray->setIcon(is->statusPtr(d->lastStatus));
+}
+
+/*!
+	Updates keyboard LED blinking.
+	LED will be blinking if there are events waiting in event queue
+	and blinking is enabled.
+*/
+
+void MainWin::updateLED()
+{
+	if ( d->nextAmount > 0 && option.blinkLED)
+		d->ledScrollLock->blink(option.blinkLEDTime);
+	else
+		d->ledScrollLock->stop();
 }
 
 void MainWin::doRecvNextEvent()
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/mainwin.h psi/psi/src/mainwin.h
--- psi_cvs-2005.05.17/psi/src/mainwin.h	Sun Feb 13 17:53:48 2005
+++ psi/psi/src/mainwin.h	Tue May 17 13:48:16 2005
@@ -139,6 +139,7 @@
 
 	void updateCaption();
 	void updateTray();
+	void updateLED();
 
 private:
 	class Private;
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/options/opt_events-ui.ui psi/psi/src/options/opt_events-ui.ui
--- psi_cvs-2005.05.17/psi/src/options/opt_events-ui.ui	Wed May  4 18:18:20 2005
+++ psi/psi/src/options/opt_events-ui.ui	Tue May 17 13:48:16 2005
@@ -94,6 +94,14 @@
                 <string>Notify when authorization was received</string>
             </property>
         </widget>
+        <widget class="QCheckBox">
+            <property name="name">
+                <cstring>ck_blinkLED</cstring>
+            </property>
+            <property name="text">
+                <string>Blink ScrollLock LED on incoming events</string>
+            </property>
+        </widget>
         <widget class="QButtonGroup">
             <property name="name">
                 <cstring>bg_alerts</cstring>
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/options/opt_events.cpp psi/psi/src/options/opt_events.cpp
--- psi_cvs-2005.05.17/psi/src/options/opt_events.cpp	Wed May  4 18:18:20 2005
+++ psi/psi/src/options/opt_events.cpp	Tue May 17 13:48:16 2005
@@ -30,6 +30,10 @@
 	OptEventsUI *d = (OptEventsUI *)w;
 	connect(d->bg_alerts, SIGNAL(clicked(int)), SLOT(selectAlertStyle(int)));
 
+#ifndef Q_OS_WIN
+	d->ck_blinkLED->hide();
+#endif
+
 	QWhatsThis::add(d->ck_popupMsgs,
 		tr("Makes new incoming message windows pop up automatically when received."));
 	QWhatsThis::add(d->ck_popupHeadlines,
@@ -57,6 +61,8 @@
 		tr("Makes Psi automatically accept all authorization requests from <b>anyone</b>."));
 	QWhatsThis::add(d->ck_notifyAuth,
 		tr("Makes Psi notify you when your authorization request was approved."));
+	QWhatsThis::add(d->ck_blinkLED,
+		tr("Makes Psi blink ScrollLock LED when new event arrives."));
 
 	return w;
 }
@@ -78,6 +84,7 @@
 	opt->alertStyle = alertStyle;
 	opt->autoAuth = d->ck_autoAuth->isChecked();
 	opt->notifyAuth = d->ck_notifyAuth->isChecked();
+	opt->blinkLED = d->ck_blinkLED->isChecked();
 
 	opt->ppIsOn = d->ck_popupOn->isChecked();
 	opt->ppMessage = d->ck_popupOnMessage->isChecked();
@@ -106,6 +113,7 @@
 	d->bg_alerts->setButton( alertStyle );
 	d->ck_autoAuth->setChecked( opt->autoAuth );
 	d->ck_notifyAuth->setChecked( opt->notifyAuth );
+	d->ck_blinkLED->setChecked( opt->blinkLED );
 
 	d->ck_popupOn->setChecked( true );
 	d->ck_popupOn->setChecked( opt->ppIsOn );
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/psi_profiles.cpp psi/psi/src/psi_profiles.cpp
--- psi_cvs-2005.05.17/psi/src/psi_profiles.cpp	Sun May 15 22:26:44 2005
+++ psi/psi/src/psi_profiles.cpp	Wed May 18 20:59:02 2005
@@ -388,6 +388,8 @@
 	prefs.chatBgImage = "";
 	prefs.rosterBgImage = "";
 	prefs.autoCopy = false;
+	prefs.blinkLED = false;
+	prefs.blinkLEDTime = 500;
 
 	prefs.sp.clear();
 	prefs.sp.set(QObject::tr("Away from desk"), QObject::tr("I am away from my desk.  Leave a message."));
@@ -836,6 +838,8 @@
 			p_receive.appendChild(textTag(doc, "noUnlistedPopup", prefs.noUnlistedPopup));
 			p_receive.appendChild(textTag(doc, "raise", prefs.raise));
 			p_receive.appendChild(textTag(doc, "incomingAs", prefs.incomingAs));
+			p_receive.appendChild(textTag(doc, "blinkLED", prefs.blinkLED));
+			p_receive.appendChild(textTag(doc, "blinkLEDTime", prefs.blinkLEDTime));
 		}
 
 		{
@@ -1379,6 +1383,8 @@
 				readBoolEntry(tag, "noUnlistedPopup", &prefs.noUnlistedPopup);
 				readBoolEntry(tag, "raise", &prefs.raise);
 				readNumEntry(tag, "incomingAs", &prefs.incomingAs);
+				readBoolEntry(tag, "blinkLED", &prefs.blinkLED);
+				readNumEntry(tag, "blinkLEDTime", &prefs.blinkLEDTime);
 			}
 
 			tag = findSubTag(p_events, "priority", &found);
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled.cpp psi/psi/src/tools/keyboardled/keyboardled.cpp
--- psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled.cpp	Thu Jan  1 01:00:00 1970
+++ psi/psi/src/tools/keyboardled/keyboardled.cpp	Wed May 18 20:57:10 2005
@@ -0,0 +1,165 @@
+/*
+ * keyboardled.cpp - Class used to blink keyboard LED
+ * Copyright (C) 2005  Maciej Niedzielski
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#include "keyboardled.h"
+
+#include <qmutex.h>
+
+
+//----------------------------------------------------------------------------
+// KeyboardLED::Instances
+//----------------------------------------------------------------------------
+
+
+class KeyboardLED::Instances
+{
+public:
+
+	Instances()
+	{
+		instance[0] = instance[1] = instance[2] = 0;
+	}
+	~Instances()
+	{
+		delete instance[0];
+		delete instance[1];
+		delete instance[2];
+	}
+
+
+	KeyboardLED* getInstance(KeyboardLED::LedType led)
+	{
+		if ( !instance[led] ) {
+				instanceMutex[led].lock();
+				if ( !instance[led] )
+					instance[led] =  new KeyboardLED(led);
+				instanceMutex[led].unlock();
+		}
+
+		return instance[led];
+	}
+
+private:
+	KeyboardLED *instance[3];
+	QMutex instanceMutex[3];
+};
+
+KeyboardLED::Instances KeyboardLED::instances;
+
+
+//----------------------------------------------------------------------------
+// KeyboardLED
+//----------------------------------------------------------------------------
+
+
+/*!
+    \class KeyboardLED keyboardled.h
+    \brief The KeyboardLED class provides a simple way to blink keyboard LED.
+
+    \mainclass
+
+	KeyboardLED is a simple class controlling keyboard LED blinking.
+	One instance of this class controlls one LED.
+
+	\code
+
+	KeyboardLED *ledScrollLock = KeyboardLED::getInstance(KeyboardLED::ledScroll);
+
+	ledScrollLock->blink(option.blinkLEDTime);
+
+	// ...
+
+	ledScrollLock->stop();
+
+	\endcode
+
+	Stopping blinking before exiting application is not necessary - it will be stopped in class' destructor.
+
+	Note: Windows implementation will really emulate ...Key pressing to blink corresponding LED.
+	For example, if you try typing while blinking CapsLock LED, some characters will be written in capitals.
+*/
+
+/*!
+    \enum KeyboardLED::LedType
+
+    This enum represents keyboard LED type:
+
+    \value ledNum - NumLock LED
+    \value ledCaps - CapsLock LED
+    \value ledScroll - ScrollLock LED
+*/
+
+/*!
+	Constructs a class instance controlling led \a led blinking.
+	Just after creating, it is in non-blinking state.
+*/
+
+KeyboardLED::KeyboardLED(KeyboardLED::LedType led)
+{
+	d = new KeyboardLEDPlatform(led);
+}
+
+/*!
+	Stops blinking and destroys the controller.
+*/
+
+KeyboardLED::~KeyboardLED()
+{
+	d->stop();
+	delete d;
+	d = 0;
+}
+
+/*!
+	Returns a poitner to a class instance controlling led \a led blinking.
+	Just after creating, it is in non-blinking state.
+*/
+
+KeyboardLED* KeyboardLED::getInstance(KeyboardLED::LedType led)
+{
+	return instances.getInstance(led);
+}
+
+/*!
+	Starts blinking. LED state will change every \msec miliseconds.
+	If the LED was already blinking, blink time will be changed.
+	If \msec is zero, this function works exactly like stop().
+
+	\sa stop()
+*/
+
+void KeyboardLED::blink(int msec)
+{
+	if ( !msec )
+		stop();
+	else
+		d->blink(msec);
+}
+
+/*!
+	Stops blinking.
+*/
+
+void KeyboardLED::stop()
+{
+	d->stop();
+}
+
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled.h psi/psi/src/tools/keyboardled/keyboardled.h
--- psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled.h	Thu Jan  1 01:00:00 1970
+++ psi/psi/src/tools/keyboardled/keyboardled.h	Tue May 17 14:56:28 2005
@@ -0,0 +1,67 @@
+/*
+ * keyboardled.h - Class used to blink keyboard LED
+ * Copyright (C) 2005  Maciej Niedzielski
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef KEYBOARDLED_H
+
+class KeyboardLED
+{
+public:
+	enum LedType { ledNum = 0, ledCaps, ledScroll };
+
+	static KeyboardLED* getInstance(LedType led);
+
+
+
+	void blink(int msec);
+	void stop();
+
+	class KeyboardLEDPlatform;
+
+private:
+
+	KeyboardLED(LedType led);
+	~KeyboardLED();
+
+
+	KeyboardLEDPlatform *d;
+
+	class Instances;
+	static Instances instances;
+	
+friend
+	class Instances;
+};
+
+// platform-specific implementation class
+class KeyboardLED::KeyboardLEDPlatform
+{
+public:
+	KeyboardLEDPlatform(KeyboardLED::LedType led);
+	~KeyboardLEDPlatform();
+
+	void blink(int msec);	// msec != 0 is quaranteed by KeyboardLED
+	void stop(); 
+	
+	class Private;
+private:          
+	Private *d;
+};
+
+#endif
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled.pri psi/psi/src/tools/keyboardled/keyboardled.pri
--- psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled.pri	Thu Jan  1 01:00:00 1970
+++ psi/psi/src/tools/keyboardled/keyboardled.pri	Tue May 17 13:48:16 2005
@@ -0,0 +1,14 @@
+keyboardled {
+	HEADERS += $$KEYBOARDLED_CPP/keyboardled.h
+	SOURCES += $$KEYBOARDLED_CPP/keyboardled.cpp
+
+	unix:!mac {
+		SOURCES += $$KEYBOARDLED_CPP/keyboardled_dummy.cpp
+	}
+	win32: {
+		SOURCES += $$KEYBOARDLED_CPP/keyboardled_win.cpp
+	}
+	mac: {
+		SOURCES += $$KEYBOARDLED_CPP/keyboardled_dummy.cpp
+	}
+}
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled_dummy.cpp psi/psi/src/tools/keyboardled/keyboardled_dummy.cpp
--- psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled_dummy.cpp	Thu Jan  1 01:00:00 1970
+++ psi/psi/src/tools/keyboardled/keyboardled_dummy.cpp	Tue May 17 13:48:16 2005
@@ -0,0 +1,45 @@
+/*
+ * keyboardled_dummy.cpp - Class used to blink keyboard LED - dummy impl
+ * Copyright (C) 2005  Maciej Niedzielski
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * dummy implementation used when there is... no implementation ;)
+ */
+
+#include "keyboardled.h"
+
+class KeyboardLED::KeyboardLEDPlatform::Private
+{
+};
+
+KeyboardLED::KeyboardLEDPlatform::KeyboardLEDPlatform(KeyboardLED::LedType led)
+{
+}
+
+KeyboardLED::KeyboardLEDPlatform::~KeyboardLEDPlatform()
+{
+}
+
+void KeyboardLED::KeyboardLEDPlatform::blink(int msec)
+{
+}
+
+void KeyboardLED::KeyboardLEDPlatform::stop()
+{
+}             
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled_win.cpp psi/psi/src/tools/keyboardled/keyboardled_win.cpp
--- psi_cvs-2005.05.17/psi/src/tools/keyboardled/keyboardled_win.cpp	Thu Jan  1 01:00:00 1970
+++ psi/psi/src/tools/keyboardled/keyboardled_win.cpp	Tue May 17 13:48:16 2005
@@ -0,0 +1,129 @@
+/*
+ * keyboardled_win.cpp - Class used to blink keyboard LED - Windows impl
+ * Copyright (C) 2005  Maciej Niedzielski
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <qtimer.h>
+#include <qt_windows.h>
+
+#include "keyboardled.h"
+
+//----------------------------------------------------------------------------
+// KeyboardLED::KeyboardLEDPlatform::Private
+//----------------------------------------------------------------------------
+
+class KeyboardLED::KeyboardLEDPlatform::Private : public QObject
+{
+	Q_OBJECT;
+public:	
+	Private(KeyboardLED::LedType led)
+	{   		
+		if ( led == KeyboardLED::ledNum )
+			vk = VK_NUMLOCK;
+		else if ( led == KeyboardLED::ledCaps )
+			vk = VK_CAPITAL;
+		else
+			vk = VK_SCROLL;
+
+		timer = new QTimer(this);
+		connect(timer, SIGNAL(timeout()), this, SLOT(change()) );
+
+		inverted = false;
+	};
+
+	~Private()
+	{
+		delete timer;
+		timer = 0;
+		reset();
+	}
+
+	// start blinking or just change blink time
+	void blink(int msec)
+	{
+		timer->changeInterval(msec);
+
+		if ( !timer->isActive() ) {
+			inverted = false;
+			timer->start(msec);
+		}                     
+	}
+
+	// stop blinking and restore LED to its proper state
+	void stop()
+	{
+		if ( timer->isActive() ) {
+			timer->stop();
+			reset();
+		}                		
+	}
+
+	// restore LED to its proper state
+	void reset()
+	{
+		if ( inverted ) {
+			change();
+			inverted = false;
+		}
+	}
+
+public slots:
+
+	// change LED state
+	void change() {
+		keybd_event( vk, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0 );
+		keybd_event( vk, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+		inverted = !inverted;
+	}        
+
+private:
+	QTimer *timer;
+	BYTE vk;
+	bool inverted;	// true when you need to inverse led state
+					// to make it the same as at the beginning
+
+					// inverting led even number of times is better than remembering
+					// its initial state because it will work fine also when ...Lock key
+					// was pressed while blinking
+};
+
+//----------------------------------------------------------------------------
+// KeyboardLED::KeyboardLEDPlatform
+//----------------------------------------------------------------------------
+
+KeyboardLED::KeyboardLEDPlatform::KeyboardLEDPlatform(KeyboardLED::LedType led)
+{
+	d = new Private(led);
+}
+
+KeyboardLED::KeyboardLEDPlatform::~KeyboardLEDPlatform()
+{
+	delete d;
+}
+
+void KeyboardLED::KeyboardLEDPlatform::blink(int msec)
+{
+	d->blink(msec);
+}
+
+void KeyboardLED::KeyboardLEDPlatform::stop()
+{
+	d->stop();
+}             
+
+#include "keyboardled_win.moc"
