Launch my script
[kdeaccessibility.git] / kbstateapplet / kbstate.cpp
blob6d7f97f195179b60e3ac8d76c994248139dd8a8d
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.h>
19 #include <qtooltip.h>
20 #include <qdrawutil.h>
21 #include <qcursor.h>
22 #include <qimage.h>
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 <kkeynative.h>
41 #include <kdemacros.h>
42 #include <kprocess.h>
43 #include "kdeexportfix.h"
44 #include "kbstate.h"
45 #include "kbstate.moc"
46 #include <QX11Info>
48 extern "C"
50 #include <X11/Xlib.h>
51 #include <X11/Xutil.h>
52 #include <X11/XKBlib.h>
53 #define XK_MISCELLANY
54 #define XK_XKB_KEYS
55 #include <X11/keysymdef.h>
56 #include <X11/extensions/XKB.h>
57 #include <ktoolinvocation.h>
59 KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile)
61 KGlobal::locale()->insertCatalog("kbstateapplet");
62 KbStateApplet *applet = new KbStateApplet(configFile, Plasma::Normal, Plasma::About, parent, "kbstateapplet");
63 return applet;
67 struct ModifierKey {
68 const unsigned int mask;
69 const KeySym keysym;
70 const char *name;
71 const char *icon;
72 const char *text;
73 const bool isModifier;
76 static ModifierKey modifierKeys[] = {
77 { ShiftMask, 0, I18N_NOOP("Shift"), "shiftkey", "", true },
78 { ControlMask, 0, I18N_NOOP("Control"), "controlkey", "", true },
79 { 0, XK_Alt_L, I18N_NOOP("Alt"), "altkey", "", true },
80 { 0, 0, I18N_NOOP("Win"), "superkey", "", true },
81 { 0, XK_Meta_L, I18N_NOOP("Meta"), "metakey", "", true },
82 { 0, XK_Super_L, I18N_NOOP("Super"), "superkey", "", true },
83 { 0, XK_Hyper_L, I18N_NOOP("Hyper"), "hyperkey", "", true },
84 { 0, 0, I18N_NOOP("Alt Graph"), "", I18N_NOOP("æ"), true },
85 { 0, XK_Num_Lock, I18N_NOOP("Num Lock"), "lockkey", I18N_NOOP("Num"), false },
86 { LockMask, 0, I18N_NOOP("Caps Lock"), "capskey", "", false },
87 { 0, XK_Scroll_Lock, I18N_NOOP("Scroll Lock"), "lockkey", I18N_NOOP("Scroll"), false },
88 { 0, 0, "", "", "", false }
92 /********************************************************************/
94 KbStateApplet::KbStateApplet(const QString& configFile, Plasma::Type t, int actions,
95 QWidget *parent, const char *name)
96 : KPanelApplet( configFile, t, actions, parent, name )
98 for (int i = 0; i < 8; i++) {
99 icons[i] = 0;
101 instance = new KInstance ("kbstateapplet");
102 loadConfig();
103 initMasks();
104 mouse = new MouseIcon (instance, this, "mouse");
105 sticky = new TimeoutIcon (instance, "", "kbstate_stickykeys", this, "sticky");
106 slow = new TimeoutIcon (instance, "", "kbstate_slowkeys", this, "slow");
107 bounce = new TimeoutIcon (instance, "", "", this, "bounce");
109 xkb = XkbGetMap(QX11Info::display(), 0, XkbUseCoreKbd);
111 if (xkb != 0) {
112 XkbGetControls (QX11Info::display(), XkbAllControlsMask, xkb);
113 if (xkb->ctrls != 0)
114 accessxFeatures = xkb->ctrls->enabled_ctrls;
115 else
116 accessxFeatures = 0;
118 else
119 accessxFeatures = 0;
121 //startTimer(100); // ten times a second
122 connect(kapp, SIGNAL(kdisplayPaletteChanged()), SLOT(paletteChanged()));
124 kapp->installX11EventFilter (this);
125 int opcode_rtn, error_rtn;
126 XkbQueryExtension (QX11Info::display(), &opcode_rtn, &xkb_base_event_type, &error_rtn, NULL, NULL);
127 XkbSelectEvents (QX11Info::display(), XkbUseCoreKbd, XkbAllEventsMask,
128 XkbAllEventsMask);
130 buildPopupMenu();
133 KbStateApplet::~KbStateApplet() {
134 kapp->removeX11EventFilter (this);
135 setCustomMenu(0);
136 delete instance;
137 delete popup;
138 delete sizePopup;
140 // Builds, connects _popup menu
141 void KbStateApplet::buildPopupMenu()
143 sizePopup=new KMenu(this);
144 sizePopup->setCheckable( true );
145 sizePopup->insertItem(i18n("Small"), 13);
146 sizePopup->insertItem(i18n("Medium"), 20);
147 sizePopup->insertItem(i18n("Large"), 26);
148 connect(sizePopup,SIGNAL(activated(int)), this, SLOT(setIconDim(int)));
150 showPopup=new KMenu(this);
151 showPopup->setCheckable( true );
152 modifierItem=showPopup->insertItem(i18n("Modifier Keys"), this, SLOT(toggleModifier()));
153 lockkeysItem=showPopup->insertItem(i18n("Lock Keys"), this, SLOT(toggleLockkeys()));
154 mouseItem=showPopup->insertItem(i18n("Mouse Status"), this, SLOT(toggleMouse()));
155 accessxItem=showPopup->insertItem(i18n("AccessX Status"), this, SLOT(toggleAccessX()));
157 popup = new KMenu(this);
158 popup->setCheckable( true );
159 popup->insertTitle(0, i18n("Keyboard Status Applet"));
160 popup->insertItem(i18n("Set Icon Size"),sizePopup);
161 fillSpaceItem = popup->insertItem(i18n("Fill Available Space"),
162 this, SLOT(toggleFillSpace()));
163 popup->insertItem(i18n("Show"),showPopup);
164 popup->insertItem(i18n("Configure AccessX Features..."), this, SLOT(configureAccessX()));
165 popup->insertItem(i18n("Configure Keyboard..."), this, SLOT(configureKeyboard()));
166 popup->insertItem(i18n("Configure Mouse..."), this, SLOT(configureMouse()));
167 popup->insertSeparator();
168 popup->insertItem(i18n("About"), this, SLOT(about()));
169 setCustomMenu(popup);
170 updateMenu();
173 void KbStateApplet::updateMenu()
174 { if (popup) {
175 showPopup->setItemChecked (modifierItem, showModifiers);
176 showPopup->setItemChecked (lockkeysItem, showLockkeys);
177 showPopup->setItemChecked (mouseItem, showMouse);
178 showPopup->setItemChecked (accessxItem, showAccessX);
179 popup->setItemChecked (fillSpaceItem, fillSpace);
180 sizePopup->setItemChecked(13, size == 13);
181 sizePopup->setItemChecked(20, size == 20);
182 sizePopup->setItemChecked(26, size == 26);
186 void calculateSizes (int space, int modifiers, int lockkeys, int accessx,
187 bool showMouse, int &lines, int &length, int &size)
188 // Calculates the layout based on a given number of modifiers, lockkeys and
189 // accessx features.
190 // Output:
191 // lines: number of lines
192 // length: number of icons per line
193 // size: size of the icons
195 // Calculate lines and length
196 if (showMouse)
197 ++accessx;
199 lines = space>=size ? space/size : 1;
200 length = modifiers + lockkeys + accessx;
202 if (length > 0 && lines >= 2) {
203 length = (length + lines-1)/lines;
205 // As we want to have some line breaks, we need to do some corrections:
206 // Calculate the number of lines that are really needed:
207 int linesNeeded = (modifiers+length-1)/length + (lockkeys+length-1)/length;
208 int tmp1 = modifiers%length == 0 ? 0 : length - modifiers%length;
209 int tmp2 = lockkeys%length == 0 ? 0 : length - lockkeys%length;
210 if ((tmp1 + tmp2) < accessx)
211 linesNeeded = (modifiers+lockkeys+accessx + length-1)/length;
213 // If we need more lines than we have, try with more icons per line:
214 while (linesNeeded > lines) {
215 length++;
216 linesNeeded = (modifiers+length-1)/length + (lockkeys+length-1)/length;
217 int tmp1 = modifiers%length == 0 ? 0 : length - modifiers%length;
218 int tmp2 = lockkeys%length == 0 ? 0 : length - lockkeys%length;
219 if ((tmp1 + tmp2) < accessx)
220 linesNeeded = (modifiers+lockkeys+accessx + length-1)/length;
222 lines = linesNeeded;
226 int KbStateApplet::widthForHeight(int h) const {
227 int lines, length;
228 int size = this->size;
230 int accessx = 0;
231 if ((accessxFeatures & XkbStickyKeysMask) != 0)
232 accessx++;
233 if ((accessxFeatures & XkbSlowKeysMask) != 0)
234 accessx++;
235 if ((accessxFeatures & XkbBounceKeysMask) != 0)
236 accessx++;
238 calculateSizes (h, showModifiers?modifiers.count():0,
239 showLockkeys?lockkeys.count():0,
240 showAccessX?accessx:0,
241 showMouse, lines, length, size);
243 if (fillSpace)
244 size = h/lines;
246 return length*size;
249 int KbStateApplet::heightForWidth(int w) const {
250 int lines, length;
251 int size = this->size;
253 int accessx = 0;
254 if ((accessxFeatures & XkbStickyKeysMask) != 0)
255 accessx++;
256 if ((accessxFeatures & XkbSlowKeysMask) != 0)
257 accessx++;
258 if ((accessxFeatures & XkbBounceKeysMask) != 0)
259 accessx++;
261 calculateSizes (w, showModifiers?modifiers.count():0,
262 showLockkeys?lockkeys.count():0,
263 showAccessX?accessx:0,
264 showMouse, lines, length, size);
266 if (fillSpace)
267 size = w/lines;
269 return length*size;
272 void KbStateApplet::mousePressEvent(QMouseEvent *e) {
273 if (e->button() == Qt::RightButton)
274 popup->popup(e->globalPos());
277 void KbStateApplet::setIconDim (int size) {
278 this->size = size;
279 saveConfig();
280 updateMenu();
281 update();
282 updateGeometry();
283 emit updateLayout();
286 void KbStateApplet::resizeEvent( QResizeEvent*e ) {
287 QWidget::resizeEvent(e);
288 layout();
291 void KbStateApplet::toggleFillSpace() {
292 fillSpace = !fillSpace;
293 saveConfig();
294 updateMenu();
295 layout();
296 updateGeometry();
297 emit updateLayout();
300 void KbStateApplet::layout() {
301 int size = this->size;
303 int lines, length, x,y,dx,dy, ldx,ldy;
304 int modifierCount = showModifiers?modifiers.count():0;
305 int lockkeyCount = showLockkeys?lockkeys.count():0;
306 int accessxCount = 0;
308 if (showAccessX) {
309 if ((accessxFeatures & XkbStickyKeysMask) != 0)
310 accessxCount++;
311 if ((accessxFeatures & XkbSlowKeysMask) != 0)
312 accessxCount++;
313 if ((accessxFeatures & XkbBounceKeysMask) != 0)
314 accessxCount++;
317 if (orientation() == Qt::Vertical) {
318 calculateSizes (width(), modifierCount, lockkeyCount, accessxCount,
319 showMouse, lines, length, size);
321 if (fillSpace)
322 size = width()/lines;
324 x = (width()-lines*size)/2;
325 y = 0;
326 dx = 0;
327 dy = size;
328 ldx= size;
329 ldy= 0;
331 else {
332 calculateSizes (height(), modifierCount, lockkeyCount, accessxCount,
333 showMouse, lines, length, size);
335 if (fillSpace)
336 size = height()/lines;
338 x = 0;
339 y = (height()-lines*size)/2;
340 dx = size;
341 dy = 0;
342 ldx= 0;
343 ldy= size;
346 StatusIcon *icon;
347 int item = 1;
348 for (icon = modifiers.first(); icon; icon = modifiers.next()) {
349 if (showModifiers) {
350 icon->setGeometry (x, y, size, size);
351 icon->show();
352 icon->update();
353 item++; x+=dx; y+=dy;
354 if (item > length) {
355 x = x - length*dx + ldx;
356 y = y - length*dy + ldy;
357 item = 1;
360 else
361 icon->hide();
364 int lockkeyLines = (lockkeyCount+length-1)/length;
365 int accessxLines = lines - (modifierCount+length-1)/length - lockkeyLines;
367 if (showMouse)
368 ++accessxCount;
370 if (lockkeyLines*length + accessxLines*length
371 >= lockkeyCount + accessxCount)
373 if (lines > 1 && item > 1) {
374 x = x - (item-1)*dx + ldx;
375 y = y - (item-1)*dy + ldy;
376 item = 1;
379 else {
380 accessxLines++;
383 if (showMouse && showAccessX && accessxLines > 0) {
384 mouse->setGeometry (x, y, size, size);
385 mouse->show();
386 mouse->update();
387 accessxCount--;
388 item++; x+=dx; y+=dy;
389 if (item > length) {
390 x = x - length*dx + ldx;
391 y = y - length*dy + ldy;
392 item = 1;
393 accessxLines--;
396 else
397 mouse->hide();
399 if ((accessxFeatures & XkbStickyKeysMask) != 0
400 && showAccessX && accessxLines > 0)
402 sticky->setGeometry (x, y, size, size);
403 sticky->show();
404 sticky->update();
405 accessxCount--;
406 item++; x+=dx; y+=dy;
407 if (item > length) {
408 x = x - length*dx + ldx;
409 y = y - length*dy + ldy;
410 item = 1;
411 accessxLines--;
414 else
415 sticky->hide();
417 if ((accessxFeatures & XkbSlowKeysMask) != 0
418 && showAccessX && accessxLines > 0)
420 slow->setGeometry (x, y, size, size);
421 slow->show();
422 slow->update();
423 accessxCount--;
424 item++; x+=dx; y+=dy;
425 if (item > length) {
426 x = x - length*dx + ldx;
427 y = y - length*dy + ldy;
428 item = 1;
429 accessxLines--;
432 else
433 slow->hide();
435 if ((accessxFeatures & XkbBounceKeysMask) != 0
436 && showAccessX && accessxLines > 0)
438 bounce->setGeometry (x, y, size, size);
439 bounce->show();
440 bounce->update();
441 accessxCount--;
442 item++; x+=dx; y+=dy;
443 if (item > length) {
444 x = x - length*dx + ldx;
445 y = y - length*dy + ldy;
446 item = 1;
447 accessxLines--;
450 else
451 bounce->hide();
453 if (lines > 1) {
454 if (item != 1) {
455 x = x - (item-1)*dx + ldx;
456 y = y - (item-1)*dy + ldy;
458 item = 1;
460 for (icon = lockkeys.first(); icon; icon = lockkeys.next()) {
461 if (showLockkeys) {
462 icon->setGeometry (x, y, size, size);
463 icon->show();
464 icon->update();
465 item++; x+=dx; y+=dy;
466 if (item > length) {
467 x = x - length*dx + ldx;
468 y = y - length*dy + ldy;
469 item = 1;
472 else
473 icon->hide();
476 if ((accessxFeatures & XkbBounceKeysMask) != 0
477 && showAccessX && accessxCount > 0)
479 bounce->setGeometry (x, y, size, size);
480 bounce->show();
481 bounce->update();
482 item++; x+=dx; y+=dy;
483 accessxCount--;
486 if ((accessxFeatures & XkbSlowKeysMask) != 0
487 && showAccessX && accessxCount > 0)
489 slow->setGeometry (x, y, size, size);
490 slow->show();
491 slow->update();
492 item++; x+=dx; y+=dy;
493 accessxCount--;
496 if ((accessxFeatures & XkbStickyKeysMask) != 0
497 && showAccessX && accessxCount > 0)
499 sticky->setGeometry (x, y, size, size);
500 sticky->show();
501 sticky->update();
502 item++; x+=dx; y+=dy;
503 accessxCount--;
506 if (showMouse && accessxCount > 0)
508 mouse->setGeometry (x, y, size, size);
509 mouse->show();
510 mouse->update();
511 item++; x+=dx; y+=dy;
512 accessxCount--;
516 void KbStateApplet::paletteChanged() {
517 for (int i = 0; i < 8; i++) {
518 if (icons[i])
519 icons[i]->updateImages();
521 mouse->update();
522 sticky->update();
523 slow->update();
524 bounce->update();
527 void KbStateApplet::initMasks() {
528 for (int i = 0; i < 8; i++) {
529 if (icons[i])
530 delete icons[i];
531 icons[i] = 0;
533 state = 0;
535 for (int i = 0; modifierKeys[i].name != ""; i++) {
536 int mask = modifierKeys[i].mask;
537 if (mask == 0)
538 if (modifierKeys[i].keysym != 0)
539 mask = XkbKeysymToModifiers (this->x11Display(), modifierKeys[i].keysym);
540 else if (modifierKeys[i].name == "Win")
541 mask = KKeyNative::modX(KKey::WIN);
542 else
543 mask = XkbKeysymToModifiers (this->x11Display(), XK_Mode_switch)
544 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Shift)
545 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Latch)
546 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Lock);
548 int map = 0;
549 for (map = 0; map < 8; map++) {
550 if ((mask & (1 << map)) != 0)
551 break;
553 if ((map <= 7) && !(icons[map])) {
554 icons[map] = new KeyIcon (i, instance, this, modifierKeys[i].name);
555 icons[map]->setToolTip( i18n (modifierKeys[i].name));
556 connect (icons[map], SIGNAL(stateChangeRequest (KeyIcon*,bool,bool)),
557 SLOT(stateChangeRequest (KeyIcon*,bool,bool)));
558 if (modifierKeys[i].isModifier)
559 modifiers.append(icons[map]);
560 else
561 lockkeys.append(icons[map]);
566 bool KbStateApplet::x11Event (XEvent *evt) {
567 if (evt->type == xkb_base_event_type + XkbEventCode) {
568 XkbEvent *kbevt = (XkbEvent *)evt;
569 switch (kbevt->any.xkb_type) {
570 case XkbStateNotify:
571 timerEvent (0);
573 mouse->setState (kbevt->state.ptr_buttons);
574 break;
575 case XkbAccessXNotify:
576 switch (kbevt->accessx.detail) {
577 case XkbAXN_SKPress:
578 slow->setGlyth(i18n("a (the first letter in the alphabet)", "a"));
579 slow->setImage("unlatched");
580 break;
581 case XkbAXN_SKAccept:
582 slow->setImage("keypressok");
583 break;
584 case XkbAXN_SKRelease:
585 slow->setGlyth(" ");
586 slow->setImage("kbstate_slowkeys");
587 break;
588 case XkbAXN_SKReject:
589 slow->setImage("keypressno", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
590 break;
591 case XkbAXN_BKAccept:
592 slow->setGlyth(i18n("a (the first letter in the alphabet)", "a"));
593 bounce->setImage("keypressok", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
594 break;
595 case XkbAXN_BKReject:
596 slow->setGlyth(i18n("a (the first letter in the alphabet)", "a"));
597 bounce->setImage("keypressno", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
598 break;
600 break;
601 case XkbControlsNotify: {
602 XkbControlsNotifyEvent* event = (XkbControlsNotifyEvent*)evt;
603 accessxFeatures = event->enabled_ctrls;
605 if ((accessxFeatures & XkbMouseKeysMask) != 0) {
606 XkbGetControls (QX11Info::display(), XkbMouseKeysMask, xkb);
607 if (xkb->ctrls->mk_dflt_btn < 1)
608 mouse->setActiveKey (1);
609 else if (xkb->ctrls->mk_dflt_btn > 3)
610 mouse->setActiveKey (1);
611 else
612 mouse->setActiveKey (xkb->ctrls->mk_dflt_btn);
614 else
615 mouse->setActiveKey (0);
617 layout();
618 updateGeometry();
619 emit updateLayout();
620 break;
622 case XkbExtensionDeviceNotify:
623 /* This is a hack around the fact that XFree86's XKB doesn't give AltGr notifications */
624 break;
625 default:
626 break;
629 return false;
632 void KbStateApplet::timerEvent(QTimerEvent*) {
633 XkbStateRec state_return;
634 XkbGetState (this->x11Display(), XkbUseCoreKbd, &state_return);
635 unsigned char latched = XkbStateMods (&state_return);
636 unsigned char locked = XkbModLocks (&state_return);
637 int mods = ((int)latched)<<8 | locked;
639 if (state != mods) {
640 state = mods;
641 for (int i = 0; i < 8; i++) {
642 if (icons[i])
643 icons[i]->setState ((latched&(1<<i)) != 0, (locked&(1<<i)) != 0);
648 void KbStateApplet::stateChangeRequest (KeyIcon *source, bool latched, bool locked) {
649 for (int i = 0; i < 8; i++) {
650 if (icons[i] == source) {
651 if (locked)
652 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 1<<i);
653 else if (latched) {
654 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
655 XkbLatchModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 1<<i);
657 else {
658 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
659 XkbLatchModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
666 void KbStateApplet::toggleModifier() {
667 showModifiers = !showModifiers;
668 updateMenu();
669 layout();
670 updateGeometry();
671 emit updateLayout();
674 void KbStateApplet::toggleLockkeys() {
675 showLockkeys = !showLockkeys;
676 updateMenu();
677 layout();
678 updateGeometry();
679 emit updateLayout();
682 void KbStateApplet::toggleMouse() {
683 showMouse = !showMouse;
684 updateMenu();
685 layout();
686 updateGeometry();
687 emit updateLayout();
690 void KbStateApplet::toggleAccessX() {
691 showAccessX = !showAccessX;
692 updateMenu();
693 layout();
694 updateGeometry();
695 emit updateLayout();
698 void KbStateApplet::configureAccessX() {
699 KToolInvocation::startServiceByDesktopName("kcmaccess");
702 void KbStateApplet::configureKeyboard() {
703 // The modulename "keyboard" is ambiguous on SuSE systems
704 // as there is also a YaST-module called "keyboard".
705 KProcess proc;
706 proc << "kcmshell";
707 proc << "kde/keyboard";
708 proc.start(KProcess::DontCare);
709 proc.detach();
712 void KbStateApplet::configureMouse() {
713 KToolInvocation::startServiceByDesktopName("mouse");
716 void KbStateApplet::about() {
717 KAboutData about("kbstateapplet", I18N_NOOP("Keyboard Status Applet"), "0.2",
718 I18N_NOOP("Panel applet that shows the state of the modifier keys"), KAboutData::License_GPL_V2, "(C) 2004 Gunnar Schmi Dt");
719 KAboutApplication a(&about, this);
720 a.exec();
723 void KbStateApplet::loadConfig()
725 KConfig *c = config();
726 c->setGroup("General");
727 size = c->readNumEntry("IconDim", 20);
728 fillSpace = c->readBoolEntry("fill space", true);
729 showModifiers = c->readBoolEntry("Modifierkeys visible",true);
730 showLockkeys = c->readBoolEntry("Lockkeys visible",true);
731 showMouse = c->readBoolEntry("Mouse status visible",true);
732 showAccessX = c->readBoolEntry("Slowkeys status visible",true);
733 showAccessX = c->readBoolEntry("AccessX status visible",showAccessX);
736 void KbStateApplet::saveConfig()
738 KConfig *c = config();
739 c->setGroup("General");
740 c->writeEntry("IconDim", size);
741 c->writeEntry("fill space", fillSpace);
742 c->writeEntry("Modifierkeys visible", showModifiers);
743 c->writeEntry("Lockkeys visible", showLockkeys);
744 c->writeEntry("Mouse status visible", showMouse);
745 c->writeEntry("AccessX status visible", showAccessX);
746 c->sync();
749 /********************************************************************/
751 KeyIcon::KeyIcon (int keyId, KInstance *instance,
752 QWidget *parent, const char *name)
753 : StatusIcon (modifierKeys[keyId].name, parent, name) {
754 this->instance = instance;
755 this->keyId = keyId;
756 this->tristate = (modifierKeys[keyId].isModifier);
757 isLocked = false;
758 isLatched = false;
759 updateImages ();
760 connect (this, SIGNAL(clicked()), SLOT(clickedSlot()));
763 KeyIcon::~KeyIcon () {
766 void KeyIcon::setState (bool latched, bool locked) {
767 latched = latched | locked;
769 isLatched = latched;
770 isLocked = locked;
771 update();
774 void KeyIcon::clickedSlot () {
775 if (tristate)
776 emit stateChangeRequest (this, !isLocked, isLatched&!isLocked);
777 else
778 emit stateChangeRequest (this, false, !isLocked);
782 void KeyIcon::resizeEvent( QResizeEvent*e )
784 QWidget::resizeEvent(e);
785 updateImages();
788 void KeyIcon::updateImages () {
789 int size = width()<height() ? width() : height();
791 locked = instance->iconLoader()->loadIcon("lock_overlay", KIcon::Panel, size-4);
792 if (modifierKeys[keyId].icon != "") {
793 latched = instance->iconLoader()->loadIcon(modifierKeys[keyId].icon, KIcon::NoGroup, size-4);
794 unlatched = instance->iconLoader()->loadIcon(modifierKeys[keyId].icon, KIcon::NoGroup, size-4);
796 QImage img = latched.convertToImage();
797 KIconEffect::colorize(img, KGlobalSettings::highlightedTextColor(), 1.0);
798 latched.convertFromImage (img);
800 img = unlatched.convertToImage();
801 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
802 unlatched.convertFromImage (img);
805 update();
808 void KeyIcon::drawButton (QPainter *p) {
809 QColor black;
811 int x = (width()-locked.width())/2;
812 int y = (height()-locked.height())/2;
813 int o = 0;
814 if (isLocked || isLatched) {
815 qDrawShadePanel (p, 0, 0, width(), height(), colorGroup(), true, 1, NULL);
816 p->fillRect (1,1,width()-2,height()-2, KGlobalSettings::highlightColor());
817 if (modifierKeys[keyId].icon != "")
818 p->drawPixmap (x+1,y+1, latched);
819 black = KGlobalSettings::highlightedTextColor();
820 o = 1;
822 else {
823 qDrawShadePanel (p, 0, 0, width(), height(), colorGroup(), false, 1, NULL);
824 if (modifierKeys[keyId].icon != "")
825 p->drawPixmap (x,y, unlatched);
826 black = KGlobalSettings::textColor();
829 QString text = i18n(modifierKeys[keyId].text);
830 if (!text.isEmpty() && !text.isNull()) {
831 QFont font = KGlobalSettings::generalFont();
832 font.setWeight(QFont::Black);
833 QFontMetrics metrics(font);
834 QRect rect = metrics.boundingRect (text);
835 int size;
836 if (modifierKeys[keyId].name == "Alt Graph")
837 size = rect.width()>rect.height()?rect.width():rect.height();
838 else
839 size = rect.width()>12*rect.height()/5?rect.width():12*rect.height()/5;
841 if (font.pixelSize() != -1)
842 font.setPixelSize (font.pixelSize()*width()*19/size/32);
843 else
844 font.setPointSizeFloat (font.pointSizeFloat()*width()*19/size/32);
846 p->setPen (black);
847 p->setFont (font);
848 if (modifierKeys[keyId].name == "Alt Graph")
849 p->drawText (o,o, width(), height(), Qt::AlignCenter, text);
850 else
851 p->drawText (o,o, width(), height()*(251)/384, Qt::AlignCenter, text);
853 if (tristate && isLocked) {
854 p->drawPixmap(x+o,y+o, locked);
858 /********************************************************************/
860 MouseIcon::MouseIcon (KInstance *instance, QWidget *parent, const char *name)
861 : StatusIcon ("", parent, name)
863 this->instance = instance;
864 state = 0;
865 activekey = 0;
866 updateImages ();
867 connect (this, SIGNAL(clicked()), SLOT(clickedSlot()));
870 MouseIcon::~MouseIcon () {
873 void MouseIcon::setState (int state) {
874 this->state = state;
876 update();
879 void MouseIcon::setActiveKey (int activekey) {
880 this->activekey = activekey;
882 update();
885 void MouseIcon::resizeEvent( QResizeEvent*e )
887 QWidget::resizeEvent(e);
888 updateImages();
891 QPixmap loadIcon(KInstance *instance, int size, QColor color, QString name) {
892 KIconLoader *loader = instance->iconLoader();
893 QPixmap result = loader->loadIcon(name, KIcon::NoGroup, size);
895 QImage img = result.convertToImage();
896 KIconEffect::colorize(img, color, 1.0);
897 result.convertFromImage (img);
899 return result;
902 void MouseIcon::updateImages () {
903 int size = width()<height() ? width() : height();
905 QColor textcolor = KGlobalSettings::textColor();
906 QColor basecolor = KGlobalSettings::baseColor();
907 mouse = loadIcon (instance, size, textcolor, "kbstate_mouse");
908 leftSelected = loadIcon (instance, size, textcolor,
909 "kbstate_mouse_left_selected");
910 middleSelected = loadIcon (instance, size, textcolor,
911 "kbstate_mouse_mid_selected");
912 rightSelected = loadIcon (instance, size, textcolor,
913 "kbstate_mouse_right_selected");
914 leftDot = loadIcon (instance, size, textcolor, "kbstate_mouse_left");
915 middleDot = loadIcon (instance, size, textcolor, "kbstate_mouse_mid");
916 rightDot = loadIcon (instance, size, textcolor, "kbstate_mouse_right");
917 leftDotSelected = loadIcon (instance, size, basecolor,
918 "kbstate_mouse_left");
919 middleDotSelected = loadIcon (instance, size, basecolor,
920 "kbstate_mouse_mid");
921 rightDotSelected = loadIcon (instance, size, basecolor,
922 "kbstate_mouse_right");
924 update();
927 void MouseIcon::drawButton (QPainter *p) {
928 p->drawPixmap(0,0, mouse);
929 if ((state & Button1Mask) != 0)
930 p->drawPixmap(0,0, leftSelected);
931 if ((state & Button2Mask) != 0)
932 p->drawPixmap(0,0, middleSelected);
933 if ((state & Button3Mask) != 0)
934 p->drawPixmap(0,0, rightSelected);
935 switch (activekey) {
936 case 0:
937 break;
938 case 1:
939 if ((state & Button1Mask) != 0)
940 p->drawPixmap(0,0, leftDotSelected);
941 else
942 p->drawPixmap(0,0, leftDot);
943 break;
944 case 2:
945 if ((state & Button2Mask) != 0)
946 p->drawPixmap(0,0, middleDotSelected);
947 else
948 p->drawPixmap(0,0, middleDot);
949 break;
950 case 3:
951 if ((state & Button3Mask) != 0)
952 p->drawPixmap(0,0, rightDotSelected);
953 else
954 p->drawPixmap(0,0, rightDot);
955 break;
959 /********************************************************************/
961 TimeoutIcon::TimeoutIcon (KInstance *instance, const QString &text,
962 const QString &featurename,
963 QWidget *parent, const char *name)
964 : StatusIcon (text, parent, name) {
965 this->instance = instance;
966 this->featurename = featurename;
967 glyth = " ";
968 setImage (featurename);
969 connect (&timer, SIGNAL(timeout()), this, SLOT(timeout()));
972 TimeoutIcon::~TimeoutIcon () {
975 void TimeoutIcon::update () {
976 int size = width()<height() ? width() : height();
977 if (pixmap.width() != size)
978 pixmap = instance->iconLoader()->loadIcon(iconname, KIcon::NoGroup, size);
980 QImage img = pixmap.convertToImage();
981 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
982 pixmap.convertFromImage (img);
984 image = pixmap;
985 QWidget::update();
988 void TimeoutIcon::setGlyth (const QString &glyth) {
989 timer.stop();
990 this->glyth = glyth;
992 QImage img = pixmap.convertToImage();
993 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
994 pixmap.convertFromImage (img);
996 image = pixmap;
997 update();
1000 void TimeoutIcon::setImage (const QString &name, int timeout) {
1001 timer.stop();
1002 iconname = name;
1003 if (!name.isNull() && !name.isEmpty()) {
1004 int size = width()<height() ? width() : height();
1005 pixmap = instance->iconLoader()->loadIcon(iconname, KIcon::NoGroup, size);
1007 QImage img = pixmap.convertToImage();
1008 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
1009 pixmap.convertFromImage (img);
1011 image = pixmap;
1013 update();
1014 if (timeout > 0)
1015 timer.start (timeout, true);
1018 void TimeoutIcon::timeout () {
1019 setGlyth (" ");
1020 setImage(featurename);
1024 void TimeoutIcon::drawButton (QPainter *p) {
1025 QString text = glyth;
1026 int count = 1;
1027 int factor = 19;
1029 if (!iconname.isNull() && !iconname.isEmpty())
1030 p->drawPixmap(0,0, image);
1031 else if (glyth == " ") {
1032 text = i18n("a (the first letter in the alphabet)", "a");
1033 count = 3;
1034 factor = 64;
1037 QFont font = KGlobalSettings::generalFont();
1038 font.setWeight(QFont::Black);
1039 QFontMetrics metrics(font);
1040 QRect rect = metrics.boundingRect (text);
1041 int size = count*rect.width() > rect.height()
1042 ? count*rect.width() : rect.height();
1043 if (font.pixelSize() != -1)
1044 font.setPixelSize (font.pixelSize()*width()*factor/size/64);
1045 else
1046 font.setPointSizeFloat (font.pointSizeFloat()*width()*factor/size/64);
1048 p->setFont (font);
1049 if (count == 1) {
1050 p->setPen (KGlobalSettings::textColor());
1051 p->drawText (0,0, width()/2, height()/2, Qt::AlignCenter, text);
1053 else {
1054 QColor t = KGlobalSettings::textColor();
1055 QColor b = KGlobalSettings::baseColor();
1056 p->setPen (QColor ((2*t.red()+3*b.red())/5,
1057 (2*t.green()+3*b.green())/5,
1058 (2*t.blue()+3*b.blue())/5));
1059 p->drawText (width()/2,0, width()/2, height(), Qt::AlignCenter, text);
1060 p->setPen (QColor ((2*t.red()+b.red())/3,
1061 (2*t.green()+b.green())/3,
1062 (2*t.blue()+b.blue())/3));
1063 p->drawText (0,0, width(), height(), Qt::AlignCenter, text);
1064 p->setPen (KGlobalSettings::textColor());
1065 p->drawText (0,0, width()/2, height(), Qt::AlignCenter, text);
1069 /********************************************************************/
1071 StatusIcon::StatusIcon (const QString &text, QWidget *parent, const char *name)
1072 : QPushButton (text, parent, name) {
1073 setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
1076 StatusIcon::~StatusIcon () {
1079 QSize StatusIcon::minimumSizeHint () const {
1080 return QSize (0,0);