Fix header
[kdeaccessibility.git] / kbstateapplet / kbstate.cpp
blob9333f7c71fa783de387cd55a6606d16bf24c8e57
1 /*
2 * Copyright (c) 2004 Gunnar Schmi Dt <gunnar@schmi-dt.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
18 #include <QPainter>
19 #include <QToolTip>
20 #include <qdrawutil.h>
21 #include <QCursor>
22 #include <QImage>
23 #include <q3popupmenu.h>
24 //Added by qt3to4:
25 #include <QMouseEvent>
26 #include <QTimerEvent>
27 #include <QResizeEvent>
29 #include <kaboutapplication.h>
30 #include <kmenu.h>
31 #include <kaboutdata.h>
32 #include <klocale.h>
33 #include <kglobal.h>
34 #include <kglobalsettings.h>
35 #include <kapplication.h>
36 #include <kiconloader.h>
37 #include <kiconeffect.h>
38 #include <knotifyclient.h>
39 #include <kshortcut.h>
40 #include <kdemacros.h>
41 #include <kprocess.h>
42 #include "kdeexportfix.h"
43 #include "kbstate.h"
44 #include "kbstate.moc"
45 #include <QX11Info>
47 extern "C"
49 #include <X11/Xlib.h>
50 #include <X11/Xutil.h>
51 #include <X11/XKBlib.h>
52 #define XK_MISCELLANY
53 #define XK_XKB_KEYS
54 #include <X11/keysymdef.h>
55 #include <X11/extensions/XKB.h>
56 #include <ktoolinvocation.h>
58 KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile)
60 KGlobal::locale()->insertCatalog("kbstateapplet");
61 KbStateApplet *applet = new KbStateApplet(configFile, Plasma::Normal, Plasma::About, parent, "kbstateapplet");
62 return applet;
66 struct ModifierKey {
67 const unsigned int mask;
68 const KeySym keysym;
69 const char *name;
70 const char *icon;
71 const char *text;
72 const bool isModifier;
75 static ModifierKey modifierKeys[] = {
76 { ShiftMask, 0, I18N_NOOP("Shift"), "shiftkey", "", true },
77 { ControlMask, 0, I18N_NOOP("Control"), "controlkey", "", true },
78 { 0, XK_Alt_L, I18N_NOOP("Alt"), "altkey", "", true },
79 { 0, 0, I18N_NOOP("Win"), "superkey", "", true },
80 { 0, XK_Meta_L, I18N_NOOP("Meta"), "metakey", "", true },
81 { 0, XK_Super_L, I18N_NOOP("Super"), "superkey", "", true },
82 { 0, XK_Hyper_L, I18N_NOOP("Hyper"), "hyperkey", "", true },
83 { 0, 0, I18N_NOOP("Alt Graph"), "", I18N_NOOP("æ"), true },
84 { 0, XK_Num_Lock, I18N_NOOP("Num Lock"), "lockkey", I18N_NOOP("Num"), false },
85 { LockMask, 0, I18N_NOOP("Caps Lock"), "capskey", "", false },
86 { 0, XK_Scroll_Lock, I18N_NOOP("Scroll Lock"), "lockkey", I18N_NOOP("Scroll"), false },
87 { 0, 0, "", "", "", false }
91 /********************************************************************/
93 KbStateApplet::KbStateApplet(const QString& configFile, Plasma::Type t, int actions,
94 QWidget *parent, const char *name)
95 : KPanelApplet( configFile, t, actions, parent )
97 for (int i = 0; i < 8; i++) {
98 icons[i] = 0;
100 instance = new KInstance ("kbstateapplet");
101 loadConfig();
102 initMasks();
103 mouse = new MouseIcon (instance, this, "mouse");
104 sticky = new TimeoutIcon (instance, "", "kbstate_stickykeys", this, "sticky");
105 slow = new TimeoutIcon (instance, "", "kbstate_slowkeys", this, "slow");
106 bounce = new TimeoutIcon (instance, "", "", this, "bounce");
108 xkb = XkbGetMap(QX11Info::display(), 0, XkbUseCoreKbd);
110 if (xkb != 0) {
111 XkbGetControls (QX11Info::display(), XkbAllControlsMask, xkb);
112 if (xkb->ctrls != 0)
113 accessxFeatures = xkb->ctrls->enabled_ctrls;
114 else
115 accessxFeatures = 0;
117 else
118 accessxFeatures = 0;
120 //startTimer(100); // ten times a second
121 connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), SLOT(paletteChanged()));
123 kapp->installX11EventFilter (this);
124 int opcode_rtn, error_rtn;
125 XkbQueryExtension (QX11Info::display(), &opcode_rtn, &xkb_base_event_type, &error_rtn, NULL, NULL);
126 XkbSelectEvents (QX11Info::display(), XkbUseCoreKbd, XkbAllEventsMask,
127 XkbAllEventsMask);
129 buildPopupMenu();
132 KbStateApplet::~KbStateApplet() {
133 kapp->removeX11EventFilter (this);
134 setCustomMenu(0);
135 delete instance;
136 delete popup;
137 delete sizePopup;
139 // Builds, connects _popup menu
140 void KbStateApplet::buildPopupMenu()
142 sizePopup=new KMenu(this);
143 sizePopup->setCheckable( true );
144 sizePopup->insertItem(i18n("Small"), 13);
145 sizePopup->insertItem(i18n("Medium"), 20);
146 sizePopup->insertItem(i18n("Large"), 26);
147 connect(sizePopup,SIGNAL(activated(int)), this, SLOT(setIconDim(int)));
149 showPopup=new KMenu(this);
150 showPopup->setCheckable( true );
151 modifierItem=showPopup->insertItem(i18n("Modifier Keys"), this, SLOT(toggleModifier()));
152 lockkeysItem=showPopup->insertItem(i18n("Lock Keys"), this, SLOT(toggleLockkeys()));
153 mouseItem=showPopup->insertItem(i18n("Mouse Status"), this, SLOT(toggleMouse()));
154 accessxItem=showPopup->insertItem(i18n("AccessX Status"), this, SLOT(toggleAccessX()));
156 popup = new KMenu(this);
157 popup->setCheckable( true );
158 popup->addTitle(i18n("Keyboard Status Applet"));
159 popup->insertItem(i18n("Set Icon Size"),sizePopup);
160 fillSpaceItem = popup->insertItem(i18n("Fill Available Space"),
161 this, SLOT(toggleFillSpace()));
162 popup->insertItem(i18n("Show"),showPopup);
163 popup->insertItem(i18n("Configure AccessX Features..."), this, SLOT(configureAccessX()));
164 popup->insertItem(i18n("Configure Keyboard..."), this, SLOT(configureKeyboard()));
165 popup->insertItem(i18n("Configure Mouse..."), this, SLOT(configureMouse()));
166 popup->insertSeparator();
167 popup->insertItem(i18n("About"), this, SLOT(about()));
168 setCustomMenu(popup);
169 updateMenu();
172 void KbStateApplet::updateMenu()
173 { if (popup) {
174 showPopup->setItemChecked (modifierItem, showModifiers);
175 showPopup->setItemChecked (lockkeysItem, showLockkeys);
176 showPopup->setItemChecked (mouseItem, showMouse);
177 showPopup->setItemChecked (accessxItem, showAccessX);
178 popup->setItemChecked (fillSpaceItem, fillSpace);
179 sizePopup->setItemChecked(13, size == 13);
180 sizePopup->setItemChecked(20, size == 20);
181 sizePopup->setItemChecked(26, size == 26);
185 void calculateSizes (int space, int modifiers, int lockkeys, int accessx,
186 bool showMouse, int &lines, int &length, int &size)
187 // Calculates the layout based on a given number of modifiers, lockkeys and
188 // accessx features.
189 // Output:
190 // lines: number of lines
191 // length: number of icons per line
192 // size: size of the icons
194 // Calculate lines and length
195 if (showMouse)
196 ++accessx;
198 lines = space>=size ? space/size : 1;
199 length = modifiers + lockkeys + accessx;
201 if (length > 0 && lines >= 2) {
202 length = (length + lines-1)/lines;
204 // As we want to have some line breaks, we need to do some corrections:
205 // Calculate the number of lines that are really needed:
206 int linesNeeded = (modifiers+length-1)/length + (lockkeys+length-1)/length;
207 int tmp1 = modifiers%length == 0 ? 0 : length - modifiers%length;
208 int tmp2 = lockkeys%length == 0 ? 0 : length - lockkeys%length;
209 if ((tmp1 + tmp2) < accessx)
210 linesNeeded = (modifiers+lockkeys+accessx + length-1)/length;
212 // If we need more lines than we have, try with more icons per line:
213 while (linesNeeded > lines) {
214 length++;
215 linesNeeded = (modifiers+length-1)/length + (lockkeys+length-1)/length;
216 int tmp1 = modifiers%length == 0 ? 0 : length - modifiers%length;
217 int tmp2 = lockkeys%length == 0 ? 0 : length - lockkeys%length;
218 if ((tmp1 + tmp2) < accessx)
219 linesNeeded = (modifiers+lockkeys+accessx + length-1)/length;
221 lines = linesNeeded;
225 int KbStateApplet::widthForHeight(int h) const {
226 int lines, length;
227 int size = this->size;
229 int accessx = 0;
230 if ((accessxFeatures & XkbStickyKeysMask) != 0)
231 accessx++;
232 if ((accessxFeatures & XkbSlowKeysMask) != 0)
233 accessx++;
234 if ((accessxFeatures & XkbBounceKeysMask) != 0)
235 accessx++;
237 calculateSizes (h, showModifiers?modifiers.count():0,
238 showLockkeys?lockkeys.count():0,
239 showAccessX?accessx:0,
240 showMouse, lines, length, size);
242 if (fillSpace)
243 size = h/lines;
245 return length*size;
248 int KbStateApplet::heightForWidth(int w) const {
249 int lines, length;
250 int size = this->size;
252 int accessx = 0;
253 if ((accessxFeatures & XkbStickyKeysMask) != 0)
254 accessx++;
255 if ((accessxFeatures & XkbSlowKeysMask) != 0)
256 accessx++;
257 if ((accessxFeatures & XkbBounceKeysMask) != 0)
258 accessx++;
260 calculateSizes (w, showModifiers?modifiers.count():0,
261 showLockkeys?lockkeys.count():0,
262 showAccessX?accessx:0,
263 showMouse, lines, length, size);
265 if (fillSpace)
266 size = w/lines;
268 return length*size;
271 void KbStateApplet::mousePressEvent(QMouseEvent *e) {
272 if (e->button() == Qt::RightButton)
273 popup->popup(e->globalPos());
276 void KbStateApplet::setIconDim (int size) {
277 this->size = size;
278 saveConfig();
279 updateMenu();
280 update();
281 updateGeometry();
282 emit updateLayout();
285 void KbStateApplet::resizeEvent( QResizeEvent*e ) {
286 QWidget::resizeEvent(e);
287 layout();
290 void KbStateApplet::toggleFillSpace() {
291 fillSpace = !fillSpace;
292 saveConfig();
293 updateMenu();
294 layout();
295 updateGeometry();
296 emit updateLayout();
299 void KbStateApplet::layout() {
300 int size = this->size;
302 int lines, length, x,y,dx,dy, ldx,ldy;
303 int modifierCount = showModifiers?modifiers.count():0;
304 int lockkeyCount = showLockkeys?lockkeys.count():0;
305 int accessxCount = 0;
307 if (showAccessX) {
308 if ((accessxFeatures & XkbStickyKeysMask) != 0)
309 accessxCount++;
310 if ((accessxFeatures & XkbSlowKeysMask) != 0)
311 accessxCount++;
312 if ((accessxFeatures & XkbBounceKeysMask) != 0)
313 accessxCount++;
316 if (orientation() == Qt::Vertical) {
317 calculateSizes (width(), modifierCount, lockkeyCount, accessxCount,
318 showMouse, lines, length, size);
320 if (fillSpace)
321 size = width()/lines;
323 x = (width()-lines*size)/2;
324 y = 0;
325 dx = 0;
326 dy = size;
327 ldx= size;
328 ldy= 0;
330 else {
331 calculateSizes (height(), modifierCount, lockkeyCount, accessxCount,
332 showMouse, lines, length, size);
334 if (fillSpace)
335 size = height()/lines;
337 x = 0;
338 y = (height()-lines*size)/2;
339 dx = size;
340 dy = 0;
341 ldx= 0;
342 ldy= size;
345 StatusIcon *icon;
346 int item = 1;
347 for (icon = modifiers.first(); icon; icon = modifiers.next()) {
348 if (showModifiers) {
349 icon->setGeometry (x, y, size, size);
350 icon->show();
351 icon->update();
352 item++; x+=dx; y+=dy;
353 if (item > length) {
354 x = x - length*dx + ldx;
355 y = y - length*dy + ldy;
356 item = 1;
359 else
360 icon->hide();
363 int lockkeyLines = (lockkeyCount+length-1)/length;
364 int accessxLines = lines - (modifierCount+length-1)/length - lockkeyLines;
366 if (showMouse)
367 ++accessxCount;
369 if (lockkeyLines*length + accessxLines*length
370 >= lockkeyCount + accessxCount)
372 if (lines > 1 && item > 1) {
373 x = x - (item-1)*dx + ldx;
374 y = y - (item-1)*dy + ldy;
375 item = 1;
378 else {
379 accessxLines++;
382 if (showMouse && showAccessX && accessxLines > 0) {
383 mouse->setGeometry (x, y, size, size);
384 mouse->show();
385 mouse->update();
386 accessxCount--;
387 item++; x+=dx; y+=dy;
388 if (item > length) {
389 x = x - length*dx + ldx;
390 y = y - length*dy + ldy;
391 item = 1;
392 accessxLines--;
395 else
396 mouse->hide();
398 if ((accessxFeatures & XkbStickyKeysMask) != 0
399 && showAccessX && accessxLines > 0)
401 sticky->setGeometry (x, y, size, size);
402 sticky->show();
403 sticky->update();
404 accessxCount--;
405 item++; x+=dx; y+=dy;
406 if (item > length) {
407 x = x - length*dx + ldx;
408 y = y - length*dy + ldy;
409 item = 1;
410 accessxLines--;
413 else
414 sticky->hide();
416 if ((accessxFeatures & XkbSlowKeysMask) != 0
417 && showAccessX && accessxLines > 0)
419 slow->setGeometry (x, y, size, size);
420 slow->show();
421 slow->update();
422 accessxCount--;
423 item++; x+=dx; y+=dy;
424 if (item > length) {
425 x = x - length*dx + ldx;
426 y = y - length*dy + ldy;
427 item = 1;
428 accessxLines--;
431 else
432 slow->hide();
434 if ((accessxFeatures & XkbBounceKeysMask) != 0
435 && showAccessX && accessxLines > 0)
437 bounce->setGeometry (x, y, size, size);
438 bounce->show();
439 bounce->update();
440 accessxCount--;
441 item++; x+=dx; y+=dy;
442 if (item > length) {
443 x = x - length*dx + ldx;
444 y = y - length*dy + ldy;
445 item = 1;
446 accessxLines--;
449 else
450 bounce->hide();
452 if (lines > 1) {
453 if (item != 1) {
454 x = x - (item-1)*dx + ldx;
455 y = y - (item-1)*dy + ldy;
457 item = 1;
459 for (icon = lockkeys.first(); icon; icon = lockkeys.next()) {
460 if (showLockkeys) {
461 icon->setGeometry (x, y, size, size);
462 icon->show();
463 icon->update();
464 item++; x+=dx; y+=dy;
465 if (item > length) {
466 x = x - length*dx + ldx;
467 y = y - length*dy + ldy;
468 item = 1;
471 else
472 icon->hide();
475 if ((accessxFeatures & XkbBounceKeysMask) != 0
476 && showAccessX && accessxCount > 0)
478 bounce->setGeometry (x, y, size, size);
479 bounce->show();
480 bounce->update();
481 item++; x+=dx; y+=dy;
482 accessxCount--;
485 if ((accessxFeatures & XkbSlowKeysMask) != 0
486 && showAccessX && accessxCount > 0)
488 slow->setGeometry (x, y, size, size);
489 slow->show();
490 slow->update();
491 item++; x+=dx; y+=dy;
492 accessxCount--;
495 if ((accessxFeatures & XkbStickyKeysMask) != 0
496 && showAccessX && accessxCount > 0)
498 sticky->setGeometry (x, y, size, size);
499 sticky->show();
500 sticky->update();
501 item++; x+=dx; y+=dy;
502 accessxCount--;
505 if (showMouse && accessxCount > 0)
507 mouse->setGeometry (x, y, size, size);
508 mouse->show();
509 mouse->update();
510 item++; x+=dx; y+=dy;
511 accessxCount--;
515 void KbStateApplet::paletteChanged() {
516 for (int i = 0; i < 8; i++) {
517 if (icons[i])
518 icons[i]->updateImages();
520 mouse->update();
521 sticky->update();
522 slow->update();
523 bounce->update();
526 void KbStateApplet::initMasks() {
527 for (int i = 0; i < 8; i++) {
528 if (icons[i])
529 delete icons[i];
530 icons[i] = 0;
532 state = 0;
534 for (int i = 0; strcmp(modifierKeys[i].name, "") != 0; i++) {
535 int mask = modifierKeys[i].mask;
536 if (mask == 0)
537 if (modifierKeys[i].keysym != 0)
538 mask = XkbKeysymToModifiers (this->x11Display(), modifierKeys[i].keysym);
539 #warning "kde4: how to port it ?"
540 #if 0
541 else if (strcmp(modifierKeys[i].name, "Win") == 0)
542 mask = KKeyNative::modXWin();
543 #endif
544 else
545 mask = XkbKeysymToModifiers (this->x11Display(), XK_Mode_switch)
546 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Shift)
547 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Latch)
548 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Lock);
550 int map = 0;
551 for (map = 0; map < 8; map++) {
552 if ((mask & (1 << map)) != 0)
553 break;
555 if ((map <= 7) && !(icons[map])) {
556 icons[map] = new KeyIcon (i, instance, this, modifierKeys[i].name);
557 icons[map]->setToolTip( i18n (modifierKeys[i].name));
558 connect (icons[map], SIGNAL(stateChangeRequest (KeyIcon*,bool,bool)),
559 SLOT(stateChangeRequest (KeyIcon*,bool,bool)));
560 if (modifierKeys[i].isModifier)
561 modifiers.append(icons[map]);
562 else
563 lockkeys.append(icons[map]);
568 bool KbStateApplet::x11Event (XEvent *evt) {
569 if (evt->type == xkb_base_event_type + XkbEventCode) {
570 XkbEvent *kbevt = (XkbEvent *)evt;
571 switch (kbevt->any.xkb_type) {
572 case XkbStateNotify:
573 timerEvent (0);
575 mouse->setState (kbevt->state.ptr_buttons);
576 break;
577 case XkbAccessXNotify:
578 switch (kbevt->accessx.detail) {
579 case XkbAXN_SKPress:
580 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
581 slow->setImage("unlatched");
582 break;
583 case XkbAXN_SKAccept:
584 slow->setImage("keypressok");
585 break;
586 case XkbAXN_SKRelease:
587 slow->setGlyth(" ");
588 slow->setImage("kbstate_slowkeys");
589 break;
590 case XkbAXN_SKReject:
591 slow->setImage("keypressno", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
592 break;
593 case XkbAXN_BKAccept:
594 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
595 bounce->setImage("keypressok", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
596 break;
597 case XkbAXN_BKReject:
598 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
599 bounce->setImage("keypressno", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
600 break;
602 break;
603 case XkbControlsNotify: {
604 XkbControlsNotifyEvent* event = (XkbControlsNotifyEvent*)evt;
605 accessxFeatures = event->enabled_ctrls;
607 if ((accessxFeatures & XkbMouseKeysMask) != 0) {
608 XkbGetControls (QX11Info::display(), XkbMouseKeysMask, xkb);
609 if (xkb->ctrls->mk_dflt_btn < 1)
610 mouse->setActiveKey (1);
611 else if (xkb->ctrls->mk_dflt_btn > 3)
612 mouse->setActiveKey (1);
613 else
614 mouse->setActiveKey (xkb->ctrls->mk_dflt_btn);
616 else
617 mouse->setActiveKey (0);
619 layout();
620 updateGeometry();
621 emit updateLayout();
622 break;
624 case XkbExtensionDeviceNotify:
625 /* This is a hack around the fact that XFree86's XKB doesn't give AltGr notifications */
626 break;
627 default:
628 break;
631 return false;
634 void KbStateApplet::timerEvent(QTimerEvent*) {
635 XkbStateRec state_return;
636 XkbGetState (this->x11Display(), XkbUseCoreKbd, &state_return);
637 unsigned char latched = XkbStateMods (&state_return);
638 unsigned char locked = XkbModLocks (&state_return);
639 int mods = ((int)latched)<<8 | locked;
641 if (state != mods) {
642 state = mods;
643 for (int i = 0; i < 8; i++) {
644 if (icons[i])
645 icons[i]->setState ((latched&(1<<i)) != 0, (locked&(1<<i)) != 0);
650 void KbStateApplet::stateChangeRequest (KeyIcon *source, bool latched, bool locked) {
651 for (int i = 0; i < 8; i++) {
652 if (icons[i] == source) {
653 if (locked)
654 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 1<<i);
655 else if (latched) {
656 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
657 XkbLatchModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 1<<i);
659 else {
660 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
661 XkbLatchModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
668 void KbStateApplet::toggleModifier() {
669 showModifiers = !showModifiers;
670 updateMenu();
671 layout();
672 updateGeometry();
673 emit updateLayout();
676 void KbStateApplet::toggleLockkeys() {
677 showLockkeys = !showLockkeys;
678 updateMenu();
679 layout();
680 updateGeometry();
681 emit updateLayout();
684 void KbStateApplet::toggleMouse() {
685 showMouse = !showMouse;
686 updateMenu();
687 layout();
688 updateGeometry();
689 emit updateLayout();
692 void KbStateApplet::toggleAccessX() {
693 showAccessX = !showAccessX;
694 updateMenu();
695 layout();
696 updateGeometry();
697 emit updateLayout();
700 void KbStateApplet::configureAccessX() {
701 KToolInvocation::startServiceByDesktopName("kcmaccess");
704 void KbStateApplet::configureKeyboard() {
705 // The modulename "keyboard" is ambiguous on SuSE systems
706 // as there is also a YaST-module called "keyboard".
707 KProcess proc;
708 proc << "kcmshell";
709 proc << "kde/keyboard";
710 proc.start(KProcess::DontCare);
711 proc.detach();
714 void KbStateApplet::configureMouse() {
715 KToolInvocation::startServiceByDesktopName("mouse");
718 void KbStateApplet::about() {
719 KAboutData about("kbstateapplet", I18N_NOOP("Keyboard Status Applet"), "0.2",
720 I18N_NOOP("Panel applet that shows the state of the modifier keys"), KAboutData::License_GPL_V2, "(C) 2004 Gunnar Schmi Dt");
721 KAboutApplication a(&about, this);
722 a.exec();
725 void KbStateApplet::loadConfig()
727 KConfig *c = config();
728 c->setGroup("General");
729 size = c->readEntry("IconDim", 20);
730 fillSpace = c->readEntry("fill space", true);
731 showModifiers = c->readEntry("Modifierkeys visible", true);
732 showLockkeys = c->readEntry("Lockkeys visible", true);
733 showMouse = c->readEntry("Mouse status visible", true);
734 showAccessX = c->readEntry("Slowkeys status visible", true);
735 showAccessX = c->readEntry("AccessX status visible", showAccessX);
738 void KbStateApplet::saveConfig()
740 KConfig *c = config();
741 c->setGroup("General");
742 c->writeEntry("IconDim", size);
743 c->writeEntry("fill space", fillSpace);
744 c->writeEntry("Modifierkeys visible", showModifiers);
745 c->writeEntry("Lockkeys visible", showLockkeys);
746 c->writeEntry("Mouse status visible", showMouse);
747 c->writeEntry("AccessX status visible", showAccessX);
748 c->sync();
751 /********************************************************************/
753 KeyIcon::KeyIcon (int keyId, KInstance *instance,
754 QWidget *parent, const char *name)
755 : StatusIcon (modifierKeys[keyId].name, parent, name) {
756 this->instance = instance;
757 this->keyId = keyId;
758 this->tristate = (modifierKeys[keyId].isModifier);
759 isLocked = false;
760 isLatched = false;
761 updateImages ();
762 connect (this, SIGNAL(clicked()), SLOT(clickedSlot()));
765 KeyIcon::~KeyIcon () {
768 void KeyIcon::setState (bool latched, bool locked) {
769 latched = latched | locked;
771 isLatched = latched;
772 isLocked = locked;
773 update();
776 void KeyIcon::clickedSlot () {
777 if (tristate)
778 emit stateChangeRequest (this, !isLocked, isLatched&!isLocked);
779 else
780 emit stateChangeRequest (this, false, !isLocked);
784 void KeyIcon::resizeEvent( QResizeEvent*e )
786 QWidget::resizeEvent(e);
787 updateImages();
790 void KeyIcon::updateImages () {
791 int size = width()<height() ? width() : height();
793 locked = instance->iconLoader()->loadIcon("lock_overlay", K3Icon::Panel, size-4);
794 if (strcmp(modifierKeys[keyId].icon, "")) {
795 latched = instance->iconLoader()->loadIcon(modifierKeys[keyId].icon, K3Icon::NoGroup, size-4);
796 unlatched = instance->iconLoader()->loadIcon(modifierKeys[keyId].icon, K3Icon::NoGroup, size-4);
798 QImage img = latched.convertToImage();
799 KIconEffect::colorize(img, KGlobalSettings::highlightedTextColor(), 1.0);
800 latched.convertFromImage (img);
802 img = unlatched.convertToImage();
803 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
804 unlatched.convertFromImage (img);
807 update();
810 void KeyIcon::drawButton (QPainter *p) {
811 QColor black;
813 int x = (width()-locked.width())/2;
814 int y = (height()-locked.height())/2;
815 int o = 0;
816 if (isLocked || isLatched) {
817 qDrawShadePanel (p, 0, 0, width(), height(), colorGroup(), true, 1, NULL);
818 p->fillRect (1,1,width()-2,height()-2, KGlobalSettings::highlightColor());
819 if (strcmp(modifierKeys[keyId].icon, ""))
820 p->drawPixmap (x+1,y+1, latched);
821 black = KGlobalSettings::highlightedTextColor();
822 o = 1;
824 else {
825 qDrawShadePanel (p, 0, 0, width(), height(), colorGroup(), false, 1, NULL);
826 if (strcmp(modifierKeys[keyId].icon, ""))
827 p->drawPixmap (x,y, unlatched);
828 black = KGlobalSettings::textColor();
831 QString text = i18n(modifierKeys[keyId].text);
832 if (!text.isEmpty() && !text.isNull()) {
833 QFont font = KGlobalSettings::generalFont();
834 font.setWeight(QFont::Black);
835 QFontMetrics metrics(font);
836 QRect rect = metrics.boundingRect (text);
837 int size;
838 if (!strcmp(modifierKeys[keyId].name, "Alt Graph"))
839 size = rect.width()>rect.height()?rect.width():rect.height();
840 else
841 size = rect.width()>12*rect.height()/5?rect.width():12*rect.height()/5;
843 if (font.pixelSize() != -1)
844 font.setPixelSize (font.pixelSize()*width()*19/size/32);
845 else
846 font.setPointSizeFloat (font.pointSizeFloat()*width()*19/size/32);
848 p->setPen (black);
849 p->setFont (font);
850 if (!strcmp(modifierKeys[keyId].name, "Alt Graph"))
851 p->drawText (o,o, width(), height(), Qt::AlignCenter, text);
852 else
853 p->drawText (o,o, width(), height()*(251)/384, Qt::AlignCenter, text);
855 if (tristate && isLocked) {
856 p->drawPixmap(x+o,y+o, locked);
860 /********************************************************************/
862 MouseIcon::MouseIcon (KInstance *instance, QWidget *parent, const char *name)
863 : StatusIcon ("", parent, name)
865 this->instance = instance;
866 state = 0;
867 activekey = 0;
868 updateImages ();
869 connect (this, SIGNAL(clicked()), SLOT(clickedSlot()));
872 MouseIcon::~MouseIcon () {
875 void MouseIcon::setState (int state) {
876 this->state = state;
878 update();
881 void MouseIcon::setActiveKey (int activekey) {
882 this->activekey = activekey;
884 update();
887 void MouseIcon::resizeEvent( QResizeEvent*e )
889 QWidget::resizeEvent(e);
890 updateImages();
893 QPixmap loadIcon(KInstance *instance, int size, QColor color, QString name) {
894 KIconLoader *loader = instance->iconLoader();
895 QPixmap result = loader->loadIcon(name, K3Icon::NoGroup, size);
897 QImage img = result.convertToImage();
898 KIconEffect::colorize(img, color, 1.0);
899 result.convertFromImage (img);
901 return result;
904 void MouseIcon::updateImages () {
905 int size = width()<height() ? width() : height();
907 QColor textcolor = KGlobalSettings::textColor();
908 QColor basecolor = KGlobalSettings::baseColor();
909 mouse = loadIcon (instance, size, textcolor, "kbstate_mouse");
910 leftSelected = loadIcon (instance, size, textcolor,
911 "kbstate_mouse_left_selected");
912 middleSelected = loadIcon (instance, size, textcolor,
913 "kbstate_mouse_mid_selected");
914 rightSelected = loadIcon (instance, size, textcolor,
915 "kbstate_mouse_right_selected");
916 leftDot = loadIcon (instance, size, textcolor, "kbstate_mouse_left");
917 middleDot = loadIcon (instance, size, textcolor, "kbstate_mouse_mid");
918 rightDot = loadIcon (instance, size, textcolor, "kbstate_mouse_right");
919 leftDotSelected = loadIcon (instance, size, basecolor,
920 "kbstate_mouse_left");
921 middleDotSelected = loadIcon (instance, size, basecolor,
922 "kbstate_mouse_mid");
923 rightDotSelected = loadIcon (instance, size, basecolor,
924 "kbstate_mouse_right");
926 update();
929 void MouseIcon::drawButton (QPainter *p) {
930 p->drawPixmap(0,0, mouse);
931 if ((state & Button1Mask) != 0)
932 p->drawPixmap(0,0, leftSelected);
933 if ((state & Button2Mask) != 0)
934 p->drawPixmap(0,0, middleSelected);
935 if ((state & Button3Mask) != 0)
936 p->drawPixmap(0,0, rightSelected);
937 switch (activekey) {
938 case 0:
939 break;
940 case 1:
941 if ((state & Button1Mask) != 0)
942 p->drawPixmap(0,0, leftDotSelected);
943 else
944 p->drawPixmap(0,0, leftDot);
945 break;
946 case 2:
947 if ((state & Button2Mask) != 0)
948 p->drawPixmap(0,0, middleDotSelected);
949 else
950 p->drawPixmap(0,0, middleDot);
951 break;
952 case 3:
953 if ((state & Button3Mask) != 0)
954 p->drawPixmap(0,0, rightDotSelected);
955 else
956 p->drawPixmap(0,0, rightDot);
957 break;
961 /********************************************************************/
963 TimeoutIcon::TimeoutIcon (KInstance *instance, const QString &text,
964 const QString &featurename,
965 QWidget *parent, const char *name)
966 : StatusIcon (text, parent, name) {
967 this->instance = instance;
968 this->featurename = featurename;
969 glyth = " ";
970 setImage (featurename);
971 connect (&timer, SIGNAL(timeout()), this, SLOT(timeout()));
974 TimeoutIcon::~TimeoutIcon () {
977 void TimeoutIcon::update () {
978 int size = width()<height() ? width() : height();
979 if (pixmap.width() != size)
980 pixmap = instance->iconLoader()->loadIcon(iconname, K3Icon::NoGroup, size);
982 QImage img = pixmap.convertToImage();
983 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
984 pixmap.convertFromImage (img);
986 image = pixmap;
987 QWidget::update();
990 void TimeoutIcon::setGlyth (const QString &glyth) {
991 timer.stop();
992 this->glyth = glyth;
994 QImage img = pixmap.convertToImage();
995 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
996 pixmap.convertFromImage (img);
998 image = pixmap;
999 update();
1002 void TimeoutIcon::setImage (const QString &name, int timeout) {
1003 timer.stop();
1004 iconname = name;
1005 if (!name.isNull() && !name.isEmpty()) {
1006 int size = width()<height() ? width() : height();
1007 pixmap = instance->iconLoader()->loadIcon(iconname, K3Icon::NoGroup, size);
1009 QImage img = pixmap.convertToImage();
1010 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
1011 pixmap.convertFromImage (img);
1013 image = pixmap;
1015 update();
1016 if (timeout > 0)
1017 timer.start (timeout, true);
1020 void TimeoutIcon::timeout () {
1021 setGlyth (" ");
1022 setImage(featurename);
1026 void TimeoutIcon::drawButton (QPainter *p) {
1027 QString text = glyth;
1028 int count = 1;
1029 int factor = 19;
1031 if (!iconname.isNull() && !iconname.isEmpty())
1032 p->drawPixmap(0,0, image);
1033 else if (glyth == " ") {
1034 text = i18nc("a (the first letter in the alphabet)", "a");
1035 count = 3;
1036 factor = 64;
1039 QFont font = KGlobalSettings::generalFont();
1040 font.setWeight(QFont::Black);
1041 QFontMetrics metrics(font);
1042 QRect rect = metrics.boundingRect (text);
1043 int size = count*rect.width() > rect.height()
1044 ? count*rect.width() : rect.height();
1045 if (font.pixelSize() != -1)
1046 font.setPixelSize (font.pixelSize()*width()*factor/size/64);
1047 else
1048 font.setPointSizeFloat (font.pointSizeFloat()*width()*factor/size/64);
1050 p->setFont (font);
1051 if (count == 1) {
1052 p->setPen (KGlobalSettings::textColor());
1053 p->drawText (0,0, width()/2, height()/2, Qt::AlignCenter, text);
1055 else {
1056 QColor t = KGlobalSettings::textColor();
1057 QColor b = KGlobalSettings::baseColor();
1058 p->setPen (QColor ((2*t.red()+3*b.red())/5,
1059 (2*t.green()+3*b.green())/5,
1060 (2*t.blue()+3*b.blue())/5));
1061 p->drawText (width()/2,0, width()/2, height(), Qt::AlignCenter, text);
1062 p->setPen (QColor ((2*t.red()+b.red())/3,
1063 (2*t.green()+b.green())/3,
1064 (2*t.blue()+b.blue())/3));
1065 p->drawText (0,0, width(), height(), Qt::AlignCenter, text);
1066 p->setPen (KGlobalSettings::textColor());
1067 p->drawText (0,0, width()/2, height(), Qt::AlignCenter, text);
1071 /********************************************************************/
1073 StatusIcon::StatusIcon (const QString &text, QWidget *parent, const char *name)
1074 : QPushButton (text, parent, name) {
1075 setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
1078 StatusIcon::~StatusIcon () {
1081 QSize StatusIcon::minimumSizeHint () const {
1082 return QSize (0,0);