Remove header (need to port it)
[kdeaccessibility.git] / kbstateapplet / kbstate.cpp
blob2561ade725722a3396ace6d95d7767207daf7a16
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 <kshortcut.h>
39 #include <kdemacros.h>
40 #include <kprocess.h>
41 #include "kdeexportfix.h"
42 #include "kbstate.h"
43 #include "kbstate.moc"
44 #include <QX11Info>
46 extern "C"
48 #include <X11/Xlib.h>
49 #include <X11/Xutil.h>
50 #include <X11/XKBlib.h>
51 #define XK_MISCELLANY
52 #define XK_XKB_KEYS
53 #include <X11/keysymdef.h>
54 #include <X11/extensions/XKB.h>
55 #include <ktoolinvocation.h>
57 KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile)
59 KGlobal::locale()->insertCatalog("kbstateapplet");
60 KbStateApplet *applet = new KbStateApplet(configFile, Plasma::Normal, Plasma::About, parent, "kbstateapplet");
61 return applet;
65 struct ModifierKey {
66 const unsigned int mask;
67 const KeySym keysym;
68 const char *name;
69 const char *icon;
70 const char *text;
71 const bool isModifier;
74 static ModifierKey modifierKeys[] = {
75 { ShiftMask, 0, I18N_NOOP("Shift"), "shiftkey", "", true },
76 { ControlMask, 0, I18N_NOOP("Control"), "controlkey", "", true },
77 { 0, XK_Alt_L, I18N_NOOP("Alt"), "altkey", "", true },
78 { 0, 0, I18N_NOOP("Win"), "superkey", "", true },
79 { 0, XK_Meta_L, I18N_NOOP("Meta"), "metakey", "", true },
80 { 0, XK_Super_L, I18N_NOOP("Super"), "superkey", "", true },
81 { 0, XK_Hyper_L, I18N_NOOP("Hyper"), "hyperkey", "", true },
82 { 0, 0, I18N_NOOP("Alt Graph"), "", I18N_NOOP("æ"), true },
83 { 0, XK_Num_Lock, I18N_NOOP("Num Lock"), "lockkey", I18N_NOOP("Num"), false },
84 { LockMask, 0, I18N_NOOP("Caps Lock"), "capskey", "", false },
85 { 0, XK_Scroll_Lock, I18N_NOOP("Scroll Lock"), "lockkey", I18N_NOOP("Scroll"), false },
86 { 0, 0, "", "", "", false }
90 /********************************************************************/
92 KbStateApplet::KbStateApplet(const QString& configFile, Plasma::Type t, int actions,
93 QWidget *parent, const char *name)
94 : KPanelApplet( configFile, t, actions, parent )
96 for (int i = 0; i < 8; i++) {
97 icons[i] = 0;
99 instance = new KInstance ("kbstateapplet");
100 loadConfig();
101 initMasks();
102 mouse = new MouseIcon (instance, this, "mouse");
103 sticky = new TimeoutIcon (instance, "", "kbstate_stickykeys", this, "sticky");
104 slow = new TimeoutIcon (instance, "", "kbstate_slowkeys", this, "slow");
105 bounce = new TimeoutIcon (instance, "", "", this, "bounce");
107 xkb = XkbGetMap(QX11Info::display(), 0, XkbUseCoreKbd);
109 if (xkb != 0) {
110 XkbGetControls (QX11Info::display(), XkbAllControlsMask, xkb);
111 if (xkb->ctrls != 0)
112 accessxFeatures = xkb->ctrls->enabled_ctrls;
113 else
114 accessxFeatures = 0;
116 else
117 accessxFeatures = 0;
119 //startTimer(100); // ten times a second
120 connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), SLOT(paletteChanged()));
122 kapp->installX11EventFilter (this);
123 int opcode_rtn, error_rtn;
124 XkbQueryExtension (QX11Info::display(), &opcode_rtn, &xkb_base_event_type, &error_rtn, NULL, NULL);
125 XkbSelectEvents (QX11Info::display(), XkbUseCoreKbd, XkbAllEventsMask,
126 XkbAllEventsMask);
128 buildPopupMenu();
131 KbStateApplet::~KbStateApplet() {
132 kapp->removeX11EventFilter (this);
133 setCustomMenu(0);
134 delete instance;
135 delete popup;
136 delete sizePopup;
138 // Builds, connects _popup menu
139 void KbStateApplet::buildPopupMenu()
141 sizePopup=new KMenu(this);
142 sizePopup->setCheckable( true );
143 sizePopup->insertItem(i18n("Small"), 13);
144 sizePopup->insertItem(i18n("Medium"), 20);
145 sizePopup->insertItem(i18n("Large"), 26);
146 connect(sizePopup,SIGNAL(activated(int)), this, SLOT(setIconDim(int)));
148 showPopup=new KMenu(this);
149 showPopup->setCheckable( true );
150 modifierItem=showPopup->insertItem(i18n("Modifier Keys"), this, SLOT(toggleModifier()));
151 lockkeysItem=showPopup->insertItem(i18n("Lock Keys"), this, SLOT(toggleLockkeys()));
152 mouseItem=showPopup->insertItem(i18n("Mouse Status"), this, SLOT(toggleMouse()));
153 accessxItem=showPopup->insertItem(i18n("AccessX Status"), this, SLOT(toggleAccessX()));
155 popup = new KMenu(this);
156 popup->setCheckable( true );
157 popup->addTitle(i18n("Keyboard Status Applet"));
158 popup->insertItem(i18n("Set Icon Size"),sizePopup);
159 fillSpaceItem = popup->insertItem(i18n("Fill Available Space"),
160 this, SLOT(toggleFillSpace()));
161 popup->insertItem(i18n("Show"),showPopup);
162 popup->insertItem(i18n("Configure AccessX Features..."), this, SLOT(configureAccessX()));
163 popup->insertItem(i18n("Configure Keyboard..."), this, SLOT(configureKeyboard()));
164 popup->insertItem(i18n("Configure Mouse..."), this, SLOT(configureMouse()));
165 popup->insertSeparator();
166 popup->insertItem(i18n("About"), this, SLOT(about()));
167 setCustomMenu(popup);
168 updateMenu();
171 void KbStateApplet::updateMenu()
172 { if (popup) {
173 showPopup->setItemChecked (modifierItem, showModifiers);
174 showPopup->setItemChecked (lockkeysItem, showLockkeys);
175 showPopup->setItemChecked (mouseItem, showMouse);
176 showPopup->setItemChecked (accessxItem, showAccessX);
177 popup->setItemChecked (fillSpaceItem, fillSpace);
178 sizePopup->setItemChecked(13, size == 13);
179 sizePopup->setItemChecked(20, size == 20);
180 sizePopup->setItemChecked(26, size == 26);
184 void calculateSizes (int space, int modifiers, int lockkeys, int accessx,
185 bool showMouse, int &lines, int &length, int &size)
186 // Calculates the layout based on a given number of modifiers, lockkeys and
187 // accessx features.
188 // Output:
189 // lines: number of lines
190 // length: number of icons per line
191 // size: size of the icons
193 // Calculate lines and length
194 if (showMouse)
195 ++accessx;
197 lines = space>=size ? space/size : 1;
198 length = modifiers + lockkeys + accessx;
200 if (length > 0 && lines >= 2) {
201 length = (length + lines-1)/lines;
203 // As we want to have some line breaks, we need to do some corrections:
204 // Calculate the number of lines that are really needed:
205 int linesNeeded = (modifiers+length-1)/length + (lockkeys+length-1)/length;
206 int tmp1 = modifiers%length == 0 ? 0 : length - modifiers%length;
207 int tmp2 = lockkeys%length == 0 ? 0 : length - lockkeys%length;
208 if ((tmp1 + tmp2) < accessx)
209 linesNeeded = (modifiers+lockkeys+accessx + length-1)/length;
211 // If we need more lines than we have, try with more icons per line:
212 while (linesNeeded > lines) {
213 length++;
214 linesNeeded = (modifiers+length-1)/length + (lockkeys+length-1)/length;
215 int tmp1 = modifiers%length == 0 ? 0 : length - modifiers%length;
216 int tmp2 = lockkeys%length == 0 ? 0 : length - lockkeys%length;
217 if ((tmp1 + tmp2) < accessx)
218 linesNeeded = (modifiers+lockkeys+accessx + length-1)/length;
220 lines = linesNeeded;
224 int KbStateApplet::widthForHeight(int h) const {
225 int lines, length;
226 int size = this->size;
228 int accessx = 0;
229 if ((accessxFeatures & XkbStickyKeysMask) != 0)
230 accessx++;
231 if ((accessxFeatures & XkbSlowKeysMask) != 0)
232 accessx++;
233 if ((accessxFeatures & XkbBounceKeysMask) != 0)
234 accessx++;
236 calculateSizes (h, showModifiers?modifiers.count():0,
237 showLockkeys?lockkeys.count():0,
238 showAccessX?accessx:0,
239 showMouse, lines, length, size);
241 if (fillSpace)
242 size = h/lines;
244 return length*size;
247 int KbStateApplet::heightForWidth(int w) const {
248 int lines, length;
249 int size = this->size;
251 int accessx = 0;
252 if ((accessxFeatures & XkbStickyKeysMask) != 0)
253 accessx++;
254 if ((accessxFeatures & XkbSlowKeysMask) != 0)
255 accessx++;
256 if ((accessxFeatures & XkbBounceKeysMask) != 0)
257 accessx++;
259 calculateSizes (w, showModifiers?modifiers.count():0,
260 showLockkeys?lockkeys.count():0,
261 showAccessX?accessx:0,
262 showMouse, lines, length, size);
264 if (fillSpace)
265 size = w/lines;
267 return length*size;
270 void KbStateApplet::mousePressEvent(QMouseEvent *e) {
271 if (e->button() == Qt::RightButton)
272 popup->popup(e->globalPos());
275 void KbStateApplet::setIconDim (int size) {
276 this->size = size;
277 saveConfig();
278 updateMenu();
279 update();
280 updateGeometry();
281 emit updateLayout();
284 void KbStateApplet::resizeEvent( QResizeEvent*e ) {
285 QWidget::resizeEvent(e);
286 layout();
289 void KbStateApplet::toggleFillSpace() {
290 fillSpace = !fillSpace;
291 saveConfig();
292 updateMenu();
293 layout();
294 updateGeometry();
295 emit updateLayout();
298 void KbStateApplet::layout() {
299 int size = this->size;
301 int lines, length, x,y,dx,dy, ldx,ldy;
302 int modifierCount = showModifiers?modifiers.count():0;
303 int lockkeyCount = showLockkeys?lockkeys.count():0;
304 int accessxCount = 0;
306 if (showAccessX) {
307 if ((accessxFeatures & XkbStickyKeysMask) != 0)
308 accessxCount++;
309 if ((accessxFeatures & XkbSlowKeysMask) != 0)
310 accessxCount++;
311 if ((accessxFeatures & XkbBounceKeysMask) != 0)
312 accessxCount++;
315 if (orientation() == Qt::Vertical) {
316 calculateSizes (width(), modifierCount, lockkeyCount, accessxCount,
317 showMouse, lines, length, size);
319 if (fillSpace)
320 size = width()/lines;
322 x = (width()-lines*size)/2;
323 y = 0;
324 dx = 0;
325 dy = size;
326 ldx= size;
327 ldy= 0;
329 else {
330 calculateSizes (height(), modifierCount, lockkeyCount, accessxCount,
331 showMouse, lines, length, size);
333 if (fillSpace)
334 size = height()/lines;
336 x = 0;
337 y = (height()-lines*size)/2;
338 dx = size;
339 dy = 0;
340 ldx= 0;
341 ldy= size;
344 StatusIcon *icon;
345 int item = 1;
346 for (icon = modifiers.first(); icon; icon = modifiers.next()) {
347 if (showModifiers) {
348 icon->setGeometry (x, y, size, size);
349 icon->show();
350 icon->update();
351 item++; x+=dx; y+=dy;
352 if (item > length) {
353 x = x - length*dx + ldx;
354 y = y - length*dy + ldy;
355 item = 1;
358 else
359 icon->hide();
362 int lockkeyLines = (lockkeyCount+length-1)/length;
363 int accessxLines = lines - (modifierCount+length-1)/length - lockkeyLines;
365 if (showMouse)
366 ++accessxCount;
368 if (lockkeyLines*length + accessxLines*length
369 >= lockkeyCount + accessxCount)
371 if (lines > 1 && item > 1) {
372 x = x - (item-1)*dx + ldx;
373 y = y - (item-1)*dy + ldy;
374 item = 1;
377 else {
378 accessxLines++;
381 if (showMouse && showAccessX && accessxLines > 0) {
382 mouse->setGeometry (x, y, size, size);
383 mouse->show();
384 mouse->update();
385 accessxCount--;
386 item++; x+=dx; y+=dy;
387 if (item > length) {
388 x = x - length*dx + ldx;
389 y = y - length*dy + ldy;
390 item = 1;
391 accessxLines--;
394 else
395 mouse->hide();
397 if ((accessxFeatures & XkbStickyKeysMask) != 0
398 && showAccessX && accessxLines > 0)
400 sticky->setGeometry (x, y, size, size);
401 sticky->show();
402 sticky->update();
403 accessxCount--;
404 item++; x+=dx; y+=dy;
405 if (item > length) {
406 x = x - length*dx + ldx;
407 y = y - length*dy + ldy;
408 item = 1;
409 accessxLines--;
412 else
413 sticky->hide();
415 if ((accessxFeatures & XkbSlowKeysMask) != 0
416 && showAccessX && accessxLines > 0)
418 slow->setGeometry (x, y, size, size);
419 slow->show();
420 slow->update();
421 accessxCount--;
422 item++; x+=dx; y+=dy;
423 if (item > length) {
424 x = x - length*dx + ldx;
425 y = y - length*dy + ldy;
426 item = 1;
427 accessxLines--;
430 else
431 slow->hide();
433 if ((accessxFeatures & XkbBounceKeysMask) != 0
434 && showAccessX && accessxLines > 0)
436 bounce->setGeometry (x, y, size, size);
437 bounce->show();
438 bounce->update();
439 accessxCount--;
440 item++; x+=dx; y+=dy;
441 if (item > length) {
442 x = x - length*dx + ldx;
443 y = y - length*dy + ldy;
444 item = 1;
445 accessxLines--;
448 else
449 bounce->hide();
451 if (lines > 1) {
452 if (item != 1) {
453 x = x - (item-1)*dx + ldx;
454 y = y - (item-1)*dy + ldy;
456 item = 1;
458 for (icon = lockkeys.first(); icon; icon = lockkeys.next()) {
459 if (showLockkeys) {
460 icon->setGeometry (x, y, size, size);
461 icon->show();
462 icon->update();
463 item++; x+=dx; y+=dy;
464 if (item > length) {
465 x = x - length*dx + ldx;
466 y = y - length*dy + ldy;
467 item = 1;
470 else
471 icon->hide();
474 if ((accessxFeatures & XkbBounceKeysMask) != 0
475 && showAccessX && accessxCount > 0)
477 bounce->setGeometry (x, y, size, size);
478 bounce->show();
479 bounce->update();
480 item++; x+=dx; y+=dy;
481 accessxCount--;
484 if ((accessxFeatures & XkbSlowKeysMask) != 0
485 && showAccessX && accessxCount > 0)
487 slow->setGeometry (x, y, size, size);
488 slow->show();
489 slow->update();
490 item++; x+=dx; y+=dy;
491 accessxCount--;
494 if ((accessxFeatures & XkbStickyKeysMask) != 0
495 && showAccessX && accessxCount > 0)
497 sticky->setGeometry (x, y, size, size);
498 sticky->show();
499 sticky->update();
500 item++; x+=dx; y+=dy;
501 accessxCount--;
504 if (showMouse && accessxCount > 0)
506 mouse->setGeometry (x, y, size, size);
507 mouse->show();
508 mouse->update();
509 item++; x+=dx; y+=dy;
510 accessxCount--;
514 void KbStateApplet::paletteChanged() {
515 for (int i = 0; i < 8; i++) {
516 if (icons[i])
517 icons[i]->updateImages();
519 mouse->update();
520 sticky->update();
521 slow->update();
522 bounce->update();
525 void KbStateApplet::initMasks() {
526 for (int i = 0; i < 8; i++) {
527 if (icons[i])
528 delete icons[i];
529 icons[i] = 0;
531 state = 0;
533 for (int i = 0; strcmp(modifierKeys[i].name, "") != 0; i++) {
534 int mask = modifierKeys[i].mask;
535 if (mask == 0)
536 if (modifierKeys[i].keysym != 0)
537 mask = XkbKeysymToModifiers (this->x11Display(), modifierKeys[i].keysym);
538 #ifdef __GNUC__
539 #warning "kde4: how to port it ?"
540 #endif
541 #if 0
542 else if (strcmp(modifierKeys[i].name, "Win") == 0)
543 mask = KKeyNative::modXWin();
544 #endif
545 else
546 mask = XkbKeysymToModifiers (this->x11Display(), XK_Mode_switch)
547 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Shift)
548 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Latch)
549 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Lock);
551 int map = 0;
552 for (map = 0; map < 8; map++) {
553 if ((mask & (1 << map)) != 0)
554 break;
556 if ((map <= 7) && !(icons[map])) {
557 icons[map] = new KeyIcon (i, instance, this, modifierKeys[i].name);
558 icons[map]->setToolTip( i18n (modifierKeys[i].name));
559 connect (icons[map], SIGNAL(stateChangeRequest (KeyIcon*,bool,bool)),
560 SLOT(stateChangeRequest (KeyIcon*,bool,bool)));
561 if (modifierKeys[i].isModifier)
562 modifiers.append(icons[map]);
563 else
564 lockkeys.append(icons[map]);
569 bool KbStateApplet::x11Event (XEvent *evt) {
570 if (evt->type == xkb_base_event_type + XkbEventCode) {
571 XkbEvent *kbevt = (XkbEvent *)evt;
572 switch (kbevt->any.xkb_type) {
573 case XkbStateNotify:
574 timerEvent (0);
576 mouse->setState (kbevt->state.ptr_buttons);
577 break;
578 case XkbAccessXNotify:
579 switch (kbevt->accessx.detail) {
580 case XkbAXN_SKPress:
581 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
582 slow->setImage("unlatched");
583 break;
584 case XkbAXN_SKAccept:
585 slow->setImage("keypressok");
586 break;
587 case XkbAXN_SKRelease:
588 slow->setGlyth(" ");
589 slow->setImage("kbstate_slowkeys");
590 break;
591 case XkbAXN_SKReject:
592 slow->setImage("keypressno", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
593 break;
594 case XkbAXN_BKAccept:
595 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
596 bounce->setImage("keypressok", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
597 break;
598 case XkbAXN_BKReject:
599 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
600 bounce->setImage("keypressno", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
601 break;
603 break;
604 case XkbControlsNotify: {
605 XkbControlsNotifyEvent* event = (XkbControlsNotifyEvent*)evt;
606 accessxFeatures = event->enabled_ctrls;
608 if ((accessxFeatures & XkbMouseKeysMask) != 0) {
609 XkbGetControls (QX11Info::display(), XkbMouseKeysMask, xkb);
610 if (xkb->ctrls->mk_dflt_btn < 1)
611 mouse->setActiveKey (1);
612 else if (xkb->ctrls->mk_dflt_btn > 3)
613 mouse->setActiveKey (1);
614 else
615 mouse->setActiveKey (xkb->ctrls->mk_dflt_btn);
617 else
618 mouse->setActiveKey (0);
620 layout();
621 updateGeometry();
622 emit updateLayout();
623 break;
625 case XkbExtensionDeviceNotify:
626 /* This is a hack around the fact that XFree86's XKB doesn't give AltGr notifications */
627 break;
628 default:
629 break;
632 return false;
635 void KbStateApplet::timerEvent(QTimerEvent*) {
636 XkbStateRec state_return;
637 XkbGetState (this->x11Display(), XkbUseCoreKbd, &state_return);
638 unsigned char latched = XkbStateMods (&state_return);
639 unsigned char locked = XkbModLocks (&state_return);
640 int mods = ((int)latched)<<8 | locked;
642 if (state != mods) {
643 state = mods;
644 for (int i = 0; i < 8; i++) {
645 if (icons[i])
646 icons[i]->setState ((latched&(1<<i)) != 0, (locked&(1<<i)) != 0);
651 void KbStateApplet::stateChangeRequest (KeyIcon *source, bool latched, bool locked) {
652 for (int i = 0; i < 8; i++) {
653 if (icons[i] == source) {
654 if (locked)
655 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 1<<i);
656 else if (latched) {
657 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
658 XkbLatchModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 1<<i);
660 else {
661 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
662 XkbLatchModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
669 void KbStateApplet::toggleModifier() {
670 showModifiers = !showModifiers;
671 updateMenu();
672 layout();
673 updateGeometry();
674 emit updateLayout();
677 void KbStateApplet::toggleLockkeys() {
678 showLockkeys = !showLockkeys;
679 updateMenu();
680 layout();
681 updateGeometry();
682 emit updateLayout();
685 void KbStateApplet::toggleMouse() {
686 showMouse = !showMouse;
687 updateMenu();
688 layout();
689 updateGeometry();
690 emit updateLayout();
693 void KbStateApplet::toggleAccessX() {
694 showAccessX = !showAccessX;
695 updateMenu();
696 layout();
697 updateGeometry();
698 emit updateLayout();
701 void KbStateApplet::configureAccessX() {
702 KToolInvocation::startServiceByDesktopName("kcmaccess");
705 void KbStateApplet::configureKeyboard() {
706 // The modulename "keyboard" is ambiguous on SuSE systems
707 // as there is also a YaST-module called "keyboard".
708 KProcess proc;
709 proc << "kcmshell";
710 proc << "kde/keyboard";
711 proc.start(KProcess::DontCare);
712 proc.detach();
715 void KbStateApplet::configureMouse() {
716 KToolInvocation::startServiceByDesktopName("mouse");
719 void KbStateApplet::about() {
720 KAboutData about("kbstateapplet", I18N_NOOP("Keyboard Status Applet"), "0.2",
721 I18N_NOOP("Panel applet that shows the state of the modifier keys"), KAboutData::License_GPL_V2, "(C) 2004 Gunnar Schmi Dt");
722 KAboutApplication a(&about, this);
723 a.exec();
726 void KbStateApplet::loadConfig()
728 KConfig *c = config();
729 c->setGroup("General");
730 size = c->readEntry("IconDim", 20);
731 fillSpace = c->readEntry("fill space", true);
732 showModifiers = c->readEntry("Modifierkeys visible", true);
733 showLockkeys = c->readEntry("Lockkeys visible", true);
734 showMouse = c->readEntry("Mouse status visible", true);
735 showAccessX = c->readEntry("Slowkeys status visible", true);
736 showAccessX = c->readEntry("AccessX status visible", showAccessX);
739 void KbStateApplet::saveConfig()
741 KConfig *c = config();
742 c->setGroup("General");
743 c->writeEntry("IconDim", size);
744 c->writeEntry("fill space", fillSpace);
745 c->writeEntry("Modifierkeys visible", showModifiers);
746 c->writeEntry("Lockkeys visible", showLockkeys);
747 c->writeEntry("Mouse status visible", showMouse);
748 c->writeEntry("AccessX status visible", showAccessX);
749 c->sync();
752 /********************************************************************/
754 KeyIcon::KeyIcon (int keyId, KInstance *instance,
755 QWidget *parent, const char *name)
756 : StatusIcon (modifierKeys[keyId].name, parent, name) {
757 this->instance = instance;
758 this->keyId = keyId;
759 this->tristate = (modifierKeys[keyId].isModifier);
760 isLocked = false;
761 isLatched = false;
762 updateImages ();
763 connect (this, SIGNAL(clicked()), SLOT(clickedSlot()));
766 KeyIcon::~KeyIcon () {
769 void KeyIcon::setState (bool latched, bool locked) {
770 latched = latched | locked;
772 isLatched = latched;
773 isLocked = locked;
774 update();
777 void KeyIcon::clickedSlot () {
778 if (tristate)
779 emit stateChangeRequest (this, !isLocked, isLatched&!isLocked);
780 else
781 emit stateChangeRequest (this, false, !isLocked);
785 void KeyIcon::resizeEvent( QResizeEvent*e )
787 QWidget::resizeEvent(e);
788 updateImages();
791 void KeyIcon::updateImages () {
792 int size = width()<height() ? width() : height();
794 locked = instance->iconLoader()->loadIcon("lock_overlay", K3Icon::Panel, size-4);
795 if (strcmp(modifierKeys[keyId].icon, "")) {
796 latched = instance->iconLoader()->loadIcon(modifierKeys[keyId].icon, K3Icon::NoGroup, size-4);
797 unlatched = instance->iconLoader()->loadIcon(modifierKeys[keyId].icon, K3Icon::NoGroup, size-4);
799 QImage img = latched.convertToImage();
800 KIconEffect::colorize(img, KGlobalSettings::highlightedTextColor(), 1.0);
801 latched.convertFromImage (img);
803 img = unlatched.convertToImage();
804 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
805 unlatched.convertFromImage (img);
808 update();
811 void KeyIcon::drawButton (QPainter *p) {
812 QColor black;
814 int x = (width()-locked.width())/2;
815 int y = (height()-locked.height())/2;
816 int o = 0;
817 if (isLocked || isLatched) {
818 qDrawShadePanel (p, 0, 0, width(), height(), colorGroup(), true, 1, NULL);
819 p->fillRect (1,1,width()-2,height()-2, KGlobalSettings::highlightColor());
820 if (strcmp(modifierKeys[keyId].icon, ""))
821 p->drawPixmap (x+1,y+1, latched);
822 black = KGlobalSettings::highlightedTextColor();
823 o = 1;
825 else {
826 qDrawShadePanel (p, 0, 0, width(), height(), colorGroup(), false, 1, NULL);
827 if (strcmp(modifierKeys[keyId].icon, ""))
828 p->drawPixmap (x,y, unlatched);
829 black = KGlobalSettings::textColor();
832 QString text = i18n(modifierKeys[keyId].text);
833 if (!text.isEmpty() && !text.isNull()) {
834 QFont font = KGlobalSettings::generalFont();
835 font.setWeight(QFont::Black);
836 QFontMetrics metrics(font);
837 QRect rect = metrics.boundingRect (text);
838 int size;
839 if (!strcmp(modifierKeys[keyId].name, "Alt Graph"))
840 size = rect.width()>rect.height()?rect.width():rect.height();
841 else
842 size = rect.width()>12*rect.height()/5?rect.width():12*rect.height()/5;
844 if (font.pixelSize() != -1)
845 font.setPixelSize (font.pixelSize()*width()*19/size/32);
846 else
847 font.setPointSizeFloat (font.pointSizeFloat()*width()*19/size/32);
849 p->setPen (black);
850 p->setFont (font);
851 if (!strcmp(modifierKeys[keyId].name, "Alt Graph"))
852 p->drawText (o,o, width(), height(), Qt::AlignCenter, text);
853 else
854 p->drawText (o,o, width(), height()*(251)/384, Qt::AlignCenter, text);
856 if (tristate && isLocked) {
857 p->drawPixmap(x+o,y+o, locked);
861 /********************************************************************/
863 MouseIcon::MouseIcon (KInstance *instance, QWidget *parent, const char *name)
864 : StatusIcon ("", parent, name)
866 this->instance = instance;
867 state = 0;
868 activekey = 0;
869 updateImages ();
870 connect (this, SIGNAL(clicked()), SLOT(clickedSlot()));
873 MouseIcon::~MouseIcon () {
876 void MouseIcon::setState (int state) {
877 this->state = state;
879 update();
882 void MouseIcon::setActiveKey (int activekey) {
883 this->activekey = activekey;
885 update();
888 void MouseIcon::resizeEvent( QResizeEvent*e )
890 QWidget::resizeEvent(e);
891 updateImages();
894 QPixmap loadIcon(KInstance *instance, int size, QColor color, QString name) {
895 KIconLoader *loader = instance->iconLoader();
896 QPixmap result = loader->loadIcon(name, K3Icon::NoGroup, size);
898 QImage img = result.convertToImage();
899 KIconEffect::colorize(img, color, 1.0);
900 result.convertFromImage (img);
902 return result;
905 void MouseIcon::updateImages () {
906 int size = width()<height() ? width() : height();
908 QColor textcolor = KGlobalSettings::textColor();
909 QColor basecolor = KGlobalSettings::baseColor();
910 mouse = loadIcon (instance, size, textcolor, "kbstate_mouse");
911 leftSelected = loadIcon (instance, size, textcolor,
912 "kbstate_mouse_left_selected");
913 middleSelected = loadIcon (instance, size, textcolor,
914 "kbstate_mouse_mid_selected");
915 rightSelected = loadIcon (instance, size, textcolor,
916 "kbstate_mouse_right_selected");
917 leftDot = loadIcon (instance, size, textcolor, "kbstate_mouse_left");
918 middleDot = loadIcon (instance, size, textcolor, "kbstate_mouse_mid");
919 rightDot = loadIcon (instance, size, textcolor, "kbstate_mouse_right");
920 leftDotSelected = loadIcon (instance, size, basecolor,
921 "kbstate_mouse_left");
922 middleDotSelected = loadIcon (instance, size, basecolor,
923 "kbstate_mouse_mid");
924 rightDotSelected = loadIcon (instance, size, basecolor,
925 "kbstate_mouse_right");
927 update();
930 void MouseIcon::drawButton (QPainter *p) {
931 p->drawPixmap(0,0, mouse);
932 if ((state & Button1Mask) != 0)
933 p->drawPixmap(0,0, leftSelected);
934 if ((state & Button2Mask) != 0)
935 p->drawPixmap(0,0, middleSelected);
936 if ((state & Button3Mask) != 0)
937 p->drawPixmap(0,0, rightSelected);
938 switch (activekey) {
939 case 0:
940 break;
941 case 1:
942 if ((state & Button1Mask) != 0)
943 p->drawPixmap(0,0, leftDotSelected);
944 else
945 p->drawPixmap(0,0, leftDot);
946 break;
947 case 2:
948 if ((state & Button2Mask) != 0)
949 p->drawPixmap(0,0, middleDotSelected);
950 else
951 p->drawPixmap(0,0, middleDot);
952 break;
953 case 3:
954 if ((state & Button3Mask) != 0)
955 p->drawPixmap(0,0, rightDotSelected);
956 else
957 p->drawPixmap(0,0, rightDot);
958 break;
962 /********************************************************************/
964 TimeoutIcon::TimeoutIcon (KInstance *instance, const QString &text,
965 const QString &featurename,
966 QWidget *parent, const char *name)
967 : StatusIcon (text, parent, name) {
968 this->instance = instance;
969 this->featurename = featurename;
970 glyth = " ";
971 setImage (featurename);
972 connect (&timer, SIGNAL(timeout()), this, SLOT(timeout()));
975 TimeoutIcon::~TimeoutIcon () {
978 void TimeoutIcon::update () {
979 int size = width()<height() ? width() : height();
980 if (pixmap.width() != size)
981 pixmap = instance->iconLoader()->loadIcon(iconname, K3Icon::NoGroup, size);
983 QImage img = pixmap.convertToImage();
984 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
985 pixmap.convertFromImage (img);
987 image = pixmap;
988 QWidget::update();
991 void TimeoutIcon::setGlyth (const QString &glyth) {
992 timer.stop();
993 this->glyth = glyth;
995 QImage img = pixmap.convertToImage();
996 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
997 pixmap.convertFromImage (img);
999 image = pixmap;
1000 update();
1003 void TimeoutIcon::setImage (const QString &name, int timeout) {
1004 timer.stop();
1005 iconname = name;
1006 if (!name.isNull() && !name.isEmpty()) {
1007 int size = width()<height() ? width() : height();
1008 pixmap = instance->iconLoader()->loadIcon(iconname, K3Icon::NoGroup, size);
1010 QImage img = pixmap.convertToImage();
1011 KIconEffect::colorize(img, KGlobalSettings::textColor(), 1.0);
1012 pixmap.convertFromImage (img);
1014 image = pixmap;
1016 update();
1017 if (timeout > 0)
1018 timer.start (timeout, true);
1021 void TimeoutIcon::timeout () {
1022 setGlyth (" ");
1023 setImage(featurename);
1027 void TimeoutIcon::drawButton (QPainter *p) {
1028 QString text = glyth;
1029 int count = 1;
1030 int factor = 19;
1032 if (!iconname.isNull() && !iconname.isEmpty())
1033 p->drawPixmap(0,0, image);
1034 else if (glyth == " ") {
1035 text = i18nc("a (the first letter in the alphabet)", "a");
1036 count = 3;
1037 factor = 64;
1040 QFont font = KGlobalSettings::generalFont();
1041 font.setWeight(QFont::Black);
1042 QFontMetrics metrics(font);
1043 QRect rect = metrics.boundingRect (text);
1044 int size = count*rect.width() > rect.height()
1045 ? count*rect.width() : rect.height();
1046 if (font.pixelSize() != -1)
1047 font.setPixelSize (font.pixelSize()*width()*factor/size/64);
1048 else
1049 font.setPointSizeFloat (font.pointSizeFloat()*width()*factor/size/64);
1051 p->setFont (font);
1052 if (count == 1) {
1053 p->setPen (KGlobalSettings::textColor());
1054 p->drawText (0,0, width()/2, height()/2, Qt::AlignCenter, text);
1056 else {
1057 QColor t = KGlobalSettings::textColor();
1058 QColor b = KGlobalSettings::baseColor();
1059 p->setPen (QColor ((2*t.red()+3*b.red())/5,
1060 (2*t.green()+3*b.green())/5,
1061 (2*t.blue()+3*b.blue())/5));
1062 p->drawText (width()/2,0, width()/2, height(), Qt::AlignCenter, text);
1063 p->setPen (QColor ((2*t.red()+b.red())/3,
1064 (2*t.green()+b.green())/3,
1065 (2*t.blue()+b.blue())/3));
1066 p->drawText (0,0, width(), height(), Qt::AlignCenter, text);
1067 p->setPen (KGlobalSettings::textColor());
1068 p->drawText (0,0, width()/2, height(), Qt::AlignCenter, text);
1072 /********************************************************************/
1074 StatusIcon::StatusIcon (const QString &text, QWidget *parent, const char *name)
1075 : QPushButton (text, parent, name) {
1076 setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
1079 StatusIcon::~StatusIcon () {
1082 QSize StatusIcon::minimumSizeHint () const {
1083 return QSize (0,0);