delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / kdedglobalaccel / kglobalaccel_x11.cpp
blob448cd18eadc433eff49fdfaecbfce1a1a129b013
1 /* This file is part of the KDE libraries
2 Copyright (C) 2001,2002 Ellis Whitehead <ellis@kde.org>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library 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 GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include "kglobalaccel_x11.h"
22 #include <QtGui/QWidgetList>
24 #include "kaction.h"
25 #include "globalshortcutsregistry.h"
26 #include "kkeyserver_x11.h"
28 #include <kapplication.h>
29 #include <kdebug.h>
31 #include <QtCore/QRegExp>
32 #include <QtGui/QWidget>
33 #include <QtCore/QMetaClassInfo>
34 #include <QtGui/QMenu>
36 #include <kxerrorhandler.h>
38 #include <X11/X.h>
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/keysym.h>
42 #include <fixx11h.h>
44 extern "C" {
45 static int XGrabErrorHandler( Display *, XErrorEvent *e ) {
46 if ( e->error_code != BadAccess ) {
47 kWarning() << "grabKey: got X error " << e->type << " instead of BadAccess\n";
49 return 1;
53 // g_keyModMaskXAccel
54 // mask of modifiers which can be used in shortcuts
55 // (meta, alt, ctrl, shift)
56 // g_keyModMaskXOnOrOff
57 // mask of modifiers where we don't care whether they are on or off
58 // (caps lock, num lock, scroll lock)
59 static uint g_keyModMaskXAccel = 0;
60 static uint g_keyModMaskXOnOrOff = 0;
62 static void calculateGrabMasks()
64 g_keyModMaskXAccel = KKeyServer::accelModMaskX();
65 g_keyModMaskXOnOrOff =
66 KKeyServer::modXLock() |
67 KKeyServer::modXNumLock() |
68 KKeyServer::modXScrollLock() |
69 KKeyServer::modXModeSwitch();
70 //kDebug() << "g_keyModMaskXAccel = " << g_keyModMaskXAccel
71 // << "g_keyModMaskXOnOrOff = " << g_keyModMaskXOnOrOff << endl;
74 //----------------------------------------------------
76 KGlobalAccelImpl::KGlobalAccelImpl(GlobalShortcutsRegistry *owner)
77 : m_owner(owner)
79 calculateGrabMasks();
82 bool KGlobalAccelImpl::grabKey( int keyQt, bool grab )
84 if( !keyQt ) {
85 kDebug() << "Tried to grab key with null code.";
86 return false;
89 int keyCodeX;
90 uint keyModX;
91 KKeyServer::keyQtToCodeX(keyQt, &keyCodeX);
92 KKeyServer::keyQtToModX(keyQt, &keyModX);
94 keyModX &= g_keyModMaskXAccel; // Get rid of any non-relevant bits in mod
96 // HACK: make Alt+Print work
97 // only do this for the Xorg default keyboard keycodes,
98 // other mappings (e.g. evdev) don't need or want it
99 if( keyCodeX == XK_Sys_Req && XKeycodeToKeysym( QX11Info::display(), 111, 0 ) == XK_Print ) {
100 keyModX |= KKeyServer::modXAlt();
101 keyCodeX = 111;
104 if( !keyCodeX )
105 return false;
107 // kDebug() << "grabKey keyQt " << (keyQt & ~Qt::KeyboardModifierMask)
108 // << " mod " << (keyQt & Qt::KeyboardModifierMask) << " ( key: '" << QKeySequence(keyQt).toString()
109 // << "', grab: " << grab << " ): keyCodeX: " << keyCodeX << " keyModX: " << keyModX << endl;
111 KXErrorHandler handler( XGrabErrorHandler );
113 // We'll have to grab 8 key modifier combinations in order to cover all
114 // combinations of CapsLock, NumLock, ScrollLock.
115 // Does anyone with more X-savvy know how to set a mask on QX11Info::appRootWindow so that
116 // the irrelevant bits are always ignored and we can just make one XGrabKey
117 // call per accelerator? -- ellis
118 #ifndef NDEBUG
119 QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
120 #endif
121 uint keyModMaskX = ~g_keyModMaskXOnOrOff;
122 for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
123 if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
124 #ifndef NDEBUG
125 sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
126 #endif
127 if( grab )
128 XGrabKey( QX11Info::display(), keyCodeX, keyModX | irrelevantBitsMask,
129 QX11Info::appRootWindow(), True, GrabModeAsync, GrabModeSync );
130 else
131 XUngrabKey( QX11Info::display(), keyCodeX, keyModX | irrelevantBitsMask, QX11Info::appRootWindow() );
135 bool failed = false;
136 if( grab ) {
137 failed = handler.error( true ); // sync now
138 if( failed ) {
139 kDebug() << "grab failed!\n";
140 for( uint m = 0; m <= 0xff; m++ ) {
141 if(( m & keyModMaskX ) == 0 )
142 XUngrabKey( QX11Info::display(), keyCodeX, keyModX | m, QX11Info::appRootWindow() );
147 return !failed;
150 bool KGlobalAccelImpl::x11Event( XEvent* event )
152 switch( event->type ) {
153 case MappingNotify:
154 XRefreshKeyboardMapping(&event->xmapping);
155 x11MappingNotify();
156 return true;
158 case XKeyPress:
159 if( x11KeyPress( event ) )
160 return true;
161 break;
163 return false;
166 void KGlobalAccelImpl::x11MappingNotify()
168 // Maybe the X modifier map has been changed.
169 // uint oldKeyModMaskXAccel = g_keyModMaskXAccel;
170 // uint oldKeyModMaskXOnOrOff = g_keyModMaskXOnOrOff;
172 KKeyServer::initializeMods();
173 calculateGrabMasks();
175 #if 0 //### investigate!
176 if (oldKeyModMaskXAccel != g_keyModMaskXAccel || oldKeyModMaskXOnOrOff != g_keyModMaskXOnOrOff)
177 // Do new XGrabKey()s.
178 m_owner->regrabKeys();
179 #endif
182 bool KGlobalAccelImpl::x11KeyPress( const XEvent *pEvent )
184 // ATTENTION: SECURITY
186 // This method should NEVER EVER print out the key it received as debug
187 // output. kpwasswdserver is a kded module too. So we get key events from
188 // it too. Which means we would print out all passwords.
190 // We are only allowed to print out the key received AFTER we made sure
191 // it is a global shortcut. KGlobalAccelImpl cannot check this.
192 // GlobalShortcutsRegistry will do that.
194 // Keyboard needs to be ungrabed after XGrabKey() activates the grab, otherwise
195 // it becomes frozen. There is a chance this will ungrab even when it should
196 // not, if some code calls XGrabKeyboard() directly, but doing so in kded
197 // should be very unlikely, and probably stupid.
198 // If this code is again moved out of kded for some reason, this needs
199 // to be revisited (I'm pretty sure this used to break KWin).
200 if( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget()) {
201 XUngrabKeyboard( QX11Info::display(), pEvent->xkey.time );
202 XFlush( QX11Info::display()); // avoid X(?) bug
205 uchar keyCodeX = pEvent->xkey.keycode;
206 uint keyModX = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
208 KeySym keySym;
209 XLookupString( (XKeyEvent*) pEvent, 0, 0, &keySym, 0 );
210 uint keySymX = (uint)keySym;
212 // If numlock is active and a keypad key is pressed, XOR the SHIFT state.
213 // e.g., KP_4 => Shift+KP_Left, and Shift+KP_4 => KP_Left.
214 if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
215 uint sym = XKeycodeToKeysym( QX11Info::display(), keyCodeX, 0 );
216 // If this is a keypad key,
217 if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
218 switch( sym ) {
219 // Leave the following keys unaltered
220 // FIXME: The proper solution is to see which keysyms don't change when shifted.
221 case XK_KP_Multiply:
222 case XK_KP_Add:
223 case XK_KP_Subtract:
224 case XK_KP_Divide:
225 break;
226 default:
227 keyModX ^= KKeyServer::modXShift();
232 int keyCodeQt;
233 int keyModQt;
234 KKeyServer::symXToKeyQt(keySymX, &keyCodeQt);
235 KKeyServer::modXToQt(keyModX, &keyModQt);
237 int keyQt = keyCodeQt | keyModQt;
239 // All that work for this hey... argh...
240 if (m_owner->keyPressed(keyQt))
241 return true;
243 return false;
246 void KGlobalAccelImpl::setEnabled( bool enable )
248 if (enable) {
249 kapp->installX11EventFilter( this );
250 } else
251 kapp->removeX11EventFilter( this );
255 #include "kglobalaccel_x11.moc"