SVN_SILENT made messages (.desktop file)
[kdeaccessibility.git] / kbstateapplet / kbstate.cpp
blobf9c890cacc6277d2f8c47cd960256a59d4b14f50
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 <QtGui/QPainter>
19 #include <QtGui/qdrawutil.h>
20 #include <QtGui/QCursor>
21 #include <QtGui/QImage>
22 #include <QtGui/QMouseEvent>
23 #include <QtCore/QTimerEvent>
24 #include <QtGui/QResizeEvent>
25 #include <QtCore/QProcess>
26 #include <QtGui/QX11Info>
28 #include <KMenu>
29 #include <kaboutapplicationdialog.h>
30 #include <kaboutdata.h>
31 #include <klocale.h>
32 #include <kglobal.h>
33 #include <kglobalsettings.h>
34 #include <kcolorscheme.h>
35 #include <kapplication.h>
36 #include <kiconloader.h>
37 #include <kiconeffect.h>
38 #include <kshortcut.h>
39 #include <kdemacros.h>
40 #include <ktoolinvocation.h>
41 #include "kdeexportfix.h"
42 #include "kbstate.h"
43 #include "kbstate.moc"
45 extern "C"
47 #include <X11/Xlib.h>
48 #include <X11/Xutil.h>
49 #include <X11/XKBlib.h>
50 #define XK_MISCELLANY
51 #define XK_XKB_KEYS
52 #include <X11/keysymdef.h>
53 #include <X11/extensions/XKB.h>
55 KDE_EXPORT K3PanelApplet* init(QWidget *parent, const QString& configFile)
57 KGlobal::locale()->insertCatalog("kbstateapplet");
58 KbStateApplet *applet = new KbStateApplet(configFile, K3PanelApplet::Normal, K3PanelApplet::About, parent, "kbstateapplet");
59 return applet;
63 struct ModifierKey {
64 const unsigned int mask;
65 const KeySym keysym;
66 const char *name;
67 const char *icon;
68 const char *text;
69 const bool isModifier;
72 static ModifierKey modifierKeys[] = {
73 { ShiftMask, 0, I18N_NOOP("Shift"), "shiftkey", "", true },
74 { ControlMask, 0, I18N_NOOP("Control"), "controlkey", "", true },
75 { 0, XK_Alt_L, I18N_NOOP("Alt"), "altkey", "", true },
76 { 0, 0, I18N_NOOP("Win"), "superkey", "", true },
77 { 0, XK_Meta_L, I18N_NOOP("Meta"), "metakey", "", true },
78 { 0, XK_Super_L, I18N_NOOP("Super"), "superkey", "", true },
79 { 0, XK_Hyper_L, I18N_NOOP("Hyper"), "hyperkey", "", true },
80 { 0, 0, I18N_NOOP("Alt Graph"), "", I18N_NOOP("æ"), true },
81 { 0, XK_Num_Lock, I18N_NOOP("Num Lock"), "lockkey", I18N_NOOP("Num"), false },
82 { LockMask, 0, I18N_NOOP("Caps Lock"), "capskey", "", false },
83 { 0, XK_Scroll_Lock, I18N_NOOP("Scroll Lock"), "lockkey", I18N_NOOP("Scroll"), false },
84 { 0, 0, "", "", "", false }
88 /********************************************************************/
90 KbStateApplet::KbStateApplet(const QString& configFile, K3PanelApplet::Type t, int actions,
91 QWidget *parent, const char *name)
92 : K3PanelApplet( configFile, t, actions, parent ),
93 componentData("kbstateapplet")
95 Q_UNUSED(name)
97 for (int i = 0; i < 8; i++) {
98 icons[i] = 0;
100 m_iconLoader = new KIconLoader(componentData.componentName(), componentData.dirs());
102 loadConfig();
103 initMasks();
104 mouse = new MouseIcon (m_iconLoader, this, "mouse");
105 sticky = new TimeoutIcon (m_iconLoader, "", "kbstate_stickykeys", this, "sticky");
106 slow = new TimeoutIcon (m_iconLoader, "", "kbstate_slowkeys", this, "slow");
107 bounce = new TimeoutIcon (m_iconLoader, "", "", 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(KGlobalSettings::self(), 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 m_iconLoader;
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->addTitle(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->addAction(i18n("Configure AccessX Features..."), this, SLOT(configureAccessX()));
165 popup->addAction(i18n("Configure Keyboard..."), this, SLOT(configureKeyboard()));
166 popup->addAction(i18n("Configure Mouse..."), this, SLOT(configureMouse()));
167 popup->addSeparator();
168 popup->addAction(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; strcmp(modifierKeys[i].name, "") != 0; 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 #ifdef __GNUC__
541 #warning "kde4: how to port it ?"
542 #endif
543 #if 0
544 else if (strcmp(modifierKeys[i].name, "Win") == 0)
545 mask = KKeyNative::modXWin();
546 #endif
547 else
548 mask = XkbKeysymToModifiers (this->x11Display(), XK_Mode_switch)
549 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Shift)
550 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Latch)
551 | XkbKeysymToModifiers (this->x11Display(), XK_ISO_Level3_Lock);
553 int map = 0;
554 for (map = 0; map < 8; map++) {
555 if ((mask & (1 << map)) != 0)
556 break;
558 if ((map <= 7) && !(icons[map])) {
559 icons[map] = new KeyIcon (i, m_iconLoader, this, modifierKeys[i].name);
560 icons[map]->setToolTip( i18n (modifierKeys[i].name));
561 connect (icons[map], SIGNAL(stateChangeRequest (KeyIcon*,bool,bool)),
562 SLOT(stateChangeRequest (KeyIcon*,bool,bool)));
563 if (modifierKeys[i].isModifier)
564 modifiers.append(icons[map]);
565 else
566 lockkeys.append(icons[map]);
571 bool KbStateApplet::x11Event (XEvent *evt) {
572 if (evt->type == xkb_base_event_type + XkbEventCode) {
573 XkbEvent *kbevt = (XkbEvent *)evt;
574 switch (kbevt->any.xkb_type) {
575 case XkbStateNotify:
576 timerEvent (0);
578 mouse->setState (kbevt->state.ptr_buttons);
579 break;
580 case XkbAccessXNotify:
581 switch (kbevt->accessx.detail) {
582 case XkbAXN_SKPress:
583 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
584 slow->setImage("unlatched");
585 break;
586 case XkbAXN_SKAccept:
587 slow->setImage("keypressok");
588 break;
589 case XkbAXN_SKRelease:
590 slow->setGlyth(" ");
591 slow->setImage("kbstate_slowkeys");
592 break;
593 case XkbAXN_SKReject:
594 slow->setImage("keypressno", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
595 break;
596 case XkbAXN_BKAccept:
597 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
598 bounce->setImage("keypressok", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
599 break;
600 case XkbAXN_BKReject:
601 slow->setGlyth(i18nc("a (the first letter in the alphabet)", "a"));
602 bounce->setImage("keypressno", kbevt->accessx.sk_delay>150?kbevt->accessx.sk_delay:150);
603 break;
605 break;
606 case XkbControlsNotify: {
607 XkbControlsNotifyEvent* event = (XkbControlsNotifyEvent*)evt;
608 accessxFeatures = event->enabled_ctrls;
610 if ((accessxFeatures & XkbMouseKeysMask) != 0) {
611 XkbGetControls (QX11Info::display(), XkbMouseKeysMask, xkb);
612 if (xkb->ctrls->mk_dflt_btn < 1)
613 mouse->setActiveKey (1);
614 else if (xkb->ctrls->mk_dflt_btn > 3)
615 mouse->setActiveKey (1);
616 else
617 mouse->setActiveKey (xkb->ctrls->mk_dflt_btn);
619 else
620 mouse->setActiveKey (0);
622 layout();
623 updateGeometry();
624 emit updateLayout();
625 break;
627 case XkbExtensionDeviceNotify:
628 /* This is a hack around the fact that XFree86's XKB doesn't give AltGr notifications */
629 break;
630 default:
631 break;
634 return false;
637 void KbStateApplet::timerEvent(QTimerEvent*) {
638 XkbStateRec state_return;
639 XkbGetState (this->x11Display(), XkbUseCoreKbd, &state_return);
640 unsigned char latched = XkbStateMods (&state_return);
641 unsigned char locked = XkbModLocks (&state_return);
642 int mods = ((int)latched)<<8 | locked;
644 if (state != mods) {
645 state = mods;
646 for (int i = 0; i < 8; i++) {
647 if (icons[i])
648 icons[i]->setState ((latched&(1<<i)) != 0, (locked&(1<<i)) != 0);
653 void KbStateApplet::stateChangeRequest (KeyIcon *source, bool latched, bool locked) {
654 for (int i = 0; i < 8; i++) {
655 if (icons[i] == source) {
656 if (locked)
657 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 1<<i);
658 else if (latched) {
659 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
660 XkbLatchModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 1<<i);
662 else {
663 XkbLockModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
664 XkbLatchModifiers (this->x11Display(), XkbUseCoreKbd, 1<<i, 0);
671 void KbStateApplet::toggleModifier() {
672 showModifiers = !showModifiers;
673 updateMenu();
674 layout();
675 updateGeometry();
676 emit updateLayout();
679 void KbStateApplet::toggleLockkeys() {
680 showLockkeys = !showLockkeys;
681 updateMenu();
682 layout();
683 updateGeometry();
684 emit updateLayout();
687 void KbStateApplet::toggleMouse() {
688 showMouse = !showMouse;
689 updateMenu();
690 layout();
691 updateGeometry();
692 emit updateLayout();
695 void KbStateApplet::toggleAccessX() {
696 showAccessX = !showAccessX;
697 updateMenu();
698 layout();
699 updateGeometry();
700 emit updateLayout();
703 void KbStateApplet::configureAccessX() {
704 KToolInvocation::startServiceByDesktopName("kcmaccess");
707 void KbStateApplet::configureKeyboard() {
708 // The modulename "keyboard" is ambiguous on SuSE systems
709 // as there is also a YaST-module called "keyboard".
710 QStringList arg;
711 arg<<"kde/keyboard";
712 QProcess::startDetached("kcmshell4",arg);
715 void KbStateApplet::configureMouse() {
716 KToolInvocation::startServiceByDesktopName("mouse");
719 void KbStateApplet::about() {
720 KAboutData about("kbstateapplet", 0, ki18n("Keyboard Status Applet"), "0.2",
721 ki18n("Panel applet that shows the state of the modifier keys"), KAboutData::License_GPL_V2, ki18n("(C) 2004 Gunnar Schmi Dt"));
722 KAboutApplicationDialog a(&about, this);
723 a.exec();
726 void KbStateApplet::loadConfig()
728 KConfigGroup c(config(), "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 KConfigGroup c(config(), "General");
741 c.writeEntry("IconDim", size);
742 c.writeEntry("fill space", fillSpace);
743 c.writeEntry("Modifierkeys visible", showModifiers);
744 c.writeEntry("Lockkeys visible", showLockkeys);
745 c.writeEntry("Mouse status visible", showMouse);
746 c.writeEntry("AccessX status visible", showAccessX);
747 c.sync();
750 /********************************************************************/
752 KeyIcon::KeyIcon (int keyId, KIconLoader *iconLoader,
753 QWidget *parent, const char *name)
754 : StatusIcon (modifierKeys[keyId].name, parent, name) {
755 this->iconLoader = iconLoader;
756 this->keyId = keyId;
757 this->tristate = (modifierKeys[keyId].isModifier);
758 isLocked = false;
759 isLatched = false;
760 updateImages ();
761 connect (this, SIGNAL(clicked()), SLOT(clickedSlot()));
764 KeyIcon::~KeyIcon () {
767 void KeyIcon::setState (bool latched, bool locked) {
768 latched = latched | locked;
770 isLatched = latched;
771 isLocked = locked;
772 update();
775 void KeyIcon::clickedSlot () {
776 if (tristate)
777 emit stateChangeRequest (this, !isLocked, isLatched&!isLocked);
778 else
779 emit stateChangeRequest (this, false, !isLocked);
783 void KeyIcon::resizeEvent( QResizeEvent*e )
785 QWidget::resizeEvent(e);
786 updateImages();
789 void KeyIcon::updateImages () {
790 int size = width()<height() ? width() : height();
792 locked = iconLoader->loadIcon("lock_overlay", KIconLoader::Panel, size-4);
793 if (strcmp(modifierKeys[keyId].icon, "")) {
794 latched = iconLoader->loadIcon(modifierKeys[keyId].icon, KIconLoader::NoGroup, size-4);
795 unlatched = iconLoader->loadIcon(modifierKeys[keyId].icon, KIconLoader::NoGroup, size-4);
797 QImage img = latched.convertToImage();
798 KIconEffect::colorize(img, KColorScheme(QPalette::Active, KColorScheme::Selection).foreground().color(), 1.0);
799 latched.convertFromImage (img);
801 img = unlatched.convertToImage();
802 KIconEffect::colorize(img, KColorScheme(QPalette::Active, KColorScheme::View).foreground().color(), 1.0);
803 unlatched.convertFromImage (img);
806 update();
809 void KeyIcon::drawButton (QPainter *p) {
810 QColor black;
812 int x = (width()-locked.width())/2;
813 int y = (height()-locked.height())/2;
814 int o = 0;
815 if (isLocked || isLatched) {
816 qDrawShadePanel (p, 0, 0, width(), height(), colorGroup(), true, 1, NULL);
817 p->fillRect (1,1,width()-2,height()-2, KColorScheme(QPalette::Active, KColorScheme::Selection).background().color());
818 if (strcmp(modifierKeys[keyId].icon, ""))
819 p->drawPixmap (x+1,y+1, latched);
820 black = KColorScheme(QPalette::Active, KColorScheme::Selection).foreground().color();
821 o = 1;
823 else {
824 qDrawShadePanel (p, 0, 0, width(), height(), colorGroup(), false, 1, NULL);
825 if (strcmp(modifierKeys[keyId].icon, ""))
826 p->drawPixmap (x,y, unlatched);
827 black = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
830 QString text = i18n(modifierKeys[keyId].text);
831 if (!text.isEmpty() && !text.isNull()) {
832 QFont font = KGlobalSettings::generalFont();
833 font.setWeight(QFont::Black);
834 QFontMetrics metrics(font);
835 QRect rect = metrics.boundingRect (text);
836 int size;
837 if (!strcmp(modifierKeys[keyId].name, "Alt Graph"))
838 size = rect.width()>rect.height()?rect.width():rect.height();
839 else
840 size = rect.width()>12*rect.height()/5?rect.width():12*rect.height()/5;
842 if (font.pixelSize() != -1)
843 font.setPixelSize (font.pixelSize()*width()*19/size/32);
844 else
845 font.setPointSizeFloat (font.pointSizeFloat()*width()*19/size/32);
847 p->setPen (black);
848 p->setFont (font);
849 if (!strcmp(modifierKeys[keyId].name, "Alt Graph"))
850 p->drawText (o,o, width(), height(), Qt::AlignCenter, text);
851 else
852 p->drawText (o,o, width(), height()*(251)/384, Qt::AlignCenter, text);
854 if (tristate && isLocked) {
855 p->drawPixmap(x+o,y+o, locked);
859 /********************************************************************/
861 MouseIcon::MouseIcon (KIconLoader *iconLoader, QWidget *parent, const char *name)
862 : StatusIcon ("", parent, name)
864 this->iconLoader = iconLoader;
865 state = 0;
866 activekey = 0;
867 updateImages ();
868 connect (this, SIGNAL(clicked()), SLOT(clickedSlot()));
871 MouseIcon::~MouseIcon () {
874 void MouseIcon::setState (int state) {
875 this->state = state;
877 update();
880 void MouseIcon::setActiveKey (int activekey) {
881 this->activekey = activekey;
883 update();
886 void MouseIcon::resizeEvent( QResizeEvent*e )
888 QWidget::resizeEvent(e);
889 updateImages();
892 QPixmap loadIcon(KIconLoader *iconLoader, int size, const QColor &color, const QString &name) {
893 QPixmap result = iconLoader->loadIcon(name, KIconLoader::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 = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
906 QColor basecolor = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
907 mouse = loadIcon (iconLoader, size, textcolor, "kbstate_mouse");
908 leftSelected = loadIcon (iconLoader, size, textcolor,
909 "kbstate_mouse_left_selected");
910 middleSelected = loadIcon (iconLoader, size, textcolor,
911 "kbstate_mouse_mid_selected");
912 rightSelected = loadIcon (iconLoader, size, textcolor,
913 "kbstate_mouse_right_selected");
914 leftDot = loadIcon (iconLoader, size, textcolor, "kbstate_mouse_left");
915 middleDot = loadIcon (iconLoader, size, textcolor, "kbstate_mouse_mid");
916 rightDot = loadIcon (iconLoader, size, textcolor, "kbstate_mouse_right");
917 leftDotSelected = loadIcon (iconLoader, size, basecolor,
918 "kbstate_mouse_left");
919 middleDotSelected = loadIcon (iconLoader, size, basecolor,
920 "kbstate_mouse_mid");
921 rightDotSelected = loadIcon (iconLoader, 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 (KIconLoader *iconLoader, const QString &text,
962 const QString &featurename,
963 QWidget *parent, const char *name)
964 : StatusIcon (text, parent, name) {
965 this->iconLoader = iconLoader;
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 = iconLoader->loadIcon(iconname, KIconLoader::NoGroup, size);
980 QImage img = pixmap.convertToImage();
981 KIconEffect::colorize(img, KColorScheme(QPalette::Active, KColorScheme::View).foreground().color(), 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, KColorScheme(QPalette::Active, KColorScheme::View).foreground().color(), 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 = iconLoader->loadIcon(iconname, KIconLoader::NoGroup, size);
1007 QImage img = pixmap.convertToImage();
1008 KIconEffect::colorize(img, KColorScheme(QPalette::Active, KColorScheme::View).foreground().color(), 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 = i18nc("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 (KColorScheme(QPalette::Active, KColorScheme::View).foreground().color());
1051 p->drawText (0,0, width()/2, height()/2, Qt::AlignCenter, text);
1053 else {
1054 QColor t = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
1055 QColor b = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
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 (KColorScheme(QPalette::Active, KColorScheme::View).foreground().color());
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) {
1073 setObjectName(name);
1074 setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
1077 StatusIcon::~StatusIcon () {
1080 QSize StatusIcon::minimumSizeHint () const {
1081 return QSize (0,0);