~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to src/tools/globalaccel/globalaccelman_x11.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * globalaccelman_x11.cpp - manager for global hotkeys
3
 
 * Copyright (C) 2003  Justin Karneges
4
 
 *
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2.1 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 * Lesser General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Lesser General Public
16
 
 * License along with this library; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 *
19
 
 */
20
 
 
21
 
#include"globalaccelman.h"
22
 
 
23
 
#include<qkeysequence.h>
24
 
#include<qwidget.h>
25
 
#include<qapplication.h>
26
 
 
27
 
#include<X11/X.h>
28
 
#include<X11/Xlib.h>
29
 
#include<X11/keysym.h>
30
 
 
31
 
#ifdef KeyPress
32
 
// defined by X11 headers
33
 
const int XKeyPress = KeyPress;
34
 
const int XKeyRelease = KeyRelease;
35
 
#undef KeyPress
36
 
#endif
37
 
 
38
 
struct QT_XK_KEYGROUP
39
 
{
40
 
        char num;
41
 
        int sym[3];
42
 
};
43
 
 
44
 
struct QT_XK_KEYMAP
45
 
{
46
 
        int key;
47
 
        QT_XK_KEYGROUP xk;
48
 
} qt_xk_table[] = {
49
 
        { Qt::Key_Escape,     {1, { XK_Escape }}},
50
 
        { Qt::Key_Tab,        {2, { XK_Tab, XK_KP_Tab }}},
51
 
        { Qt::Key_Backtab,    {1, { XK_ISO_Left_Tab }}},
52
 
        { Qt::Key_Backspace,  {1, { XK_BackSpace }}},
53
 
        { Qt::Key_Return,     {1, { XK_Return }}},
54
 
        { Qt::Key_Enter,      {1, { XK_KP_Enter }}},
55
 
        { Qt::Key_Insert,     {2, { XK_Insert, XK_KP_Insert }}},
56
 
        { Qt::Key_Delete,     {3, { XK_Delete, XK_KP_Delete, XK_Clear }}},
57
 
        { Qt::Key_Pause,      {1, { XK_Pause }}},
58
 
        { Qt::Key_Print,      {1, { XK_Print }}},
59
 
        { Qt::Key_SysReq,     {1, { XK_Sys_Req }}},
60
 
        { Qt::Key_Clear,      {1, { XK_KP_Begin }}},
61
 
        { Qt::Key_Home,       {2, { XK_Home, XK_KP_Home }}},
62
 
        { Qt::Key_End,        {2, { XK_End, XK_KP_End }}},
63
 
        { Qt::Key_Left,       {2, { XK_Left, XK_KP_Left }}},
64
 
        { Qt::Key_Up,         {2, { XK_Up, XK_KP_Up }}},
65
 
        { Qt::Key_Right,      {2, { XK_Right, XK_KP_Right }}},
66
 
        { Qt::Key_Down,       {2, { XK_Down, XK_KP_Down }}},
67
 
        { Qt::Key_Prior,      {2, { XK_Prior, XK_KP_Prior }}},
68
 
        { Qt::Key_Next,       {2, { XK_Next, XK_KP_Next }}},
69
 
        { Qt::Key_Shift,      {3, { XK_Shift_L, XK_Shift_R, XK_Shift_Lock  }}},
70
 
        { Qt::Key_Control,    {2, { XK_Control_L, XK_Control_R }}},
71
 
        { Qt::Key_Meta,       {2, { XK_Meta_L, XK_Meta_R }}},
72
 
        { Qt::Key_Alt,        {2, { XK_Alt_L, XK_Alt_R }}},
73
 
        { Qt::Key_CapsLock,   {1, { XK_Caps_Lock }}},
74
 
        { Qt::Key_NumLock,    {1, { XK_Num_Lock }}},
75
 
        { Qt::Key_ScrollLock, {1, { XK_Scroll_Lock }}},
76
 
        { Qt::Key_Space,      {2, { XK_space, XK_KP_Space }}},
77
 
        { Qt::Key_Equal,      {2, { XK_equal, XK_KP_Equal }}},
78
 
        { Qt::Key_Asterisk,   {2, { XK_asterisk, XK_KP_Multiply }}},
79
 
        { Qt::Key_Plus,       {2, { XK_plus, XK_KP_Add }}},
80
 
        { Qt::Key_Comma,      {2, { XK_comma, XK_KP_Separator }}},
81
 
        { Qt::Key_Minus,      {2, { XK_minus, XK_KP_Subtract }}},
82
 
        { Qt::Key_Period,     {2, { XK_period, XK_KP_Decimal }}},
83
 
        { Qt::Key_Slash,      {2, { XK_slash, XK_KP_Divide }}},
84
 
        { Qt::Key_F1,         {1, { XK_F1 }}},
85
 
        { Qt::Key_F2,         {1, { XK_F2 }}},
86
 
        { Qt::Key_F3,         {1, { XK_F3 }}},
87
 
        { Qt::Key_F4,         {1, { XK_F4 }}},
88
 
        { Qt::Key_F5,         {1, { XK_F5 }}},
89
 
        { Qt::Key_F6,         {1, { XK_F6 }}},
90
 
        { Qt::Key_F7,         {1, { XK_F7 }}},
91
 
        { Qt::Key_F8,         {1, { XK_F8 }}},
92
 
        { Qt::Key_F9,         {1, { XK_F9 }}},
93
 
        { Qt::Key_F10,        {1, { XK_F10 }}},
94
 
        { Qt::Key_F11,        {1, { XK_F11 }}},
95
 
        { Qt::Key_F12,        {1, { XK_F12 }}},
96
 
        { Qt::Key_F13,        {1, { XK_F13 }}},
97
 
        { Qt::Key_F14,        {1, { XK_F14 }}},
98
 
        { Qt::Key_F15,        {1, { XK_F15 }}},
99
 
        { Qt::Key_F16,        {1, { XK_F16 }}},
100
 
        { Qt::Key_F17,        {1, { XK_F17 }}},
101
 
        { Qt::Key_F18,        {1, { XK_F18 }}},
102
 
        { Qt::Key_F19,        {1, { XK_F19 }}},
103
 
        { Qt::Key_F20,        {1, { XK_F20 }}},
104
 
        { Qt::Key_F21,        {1, { XK_F21 }}},
105
 
        { Qt::Key_F22,        {1, { XK_F22 }}},
106
 
        { Qt::Key_F23,        {1, { XK_F23 }}},
107
 
        { Qt::Key_F24,        {1, { XK_F24 }}},
108
 
        { Qt::Key_F25,        {1, { XK_F25 }}},
109
 
        { Qt::Key_F26,        {1, { XK_F26 }}},
110
 
        { Qt::Key_F27,        {1, { XK_F27 }}},
111
 
        { Qt::Key_F28,        {1, { XK_F28 }}},
112
 
        { Qt::Key_F29,        {1, { XK_F29 }}},
113
 
        { Qt::Key_F30,        {1, { XK_F30 }}},
114
 
        { Qt::Key_F31,        {1, { XK_F31 }}},
115
 
        { Qt::Key_F32,        {1, { XK_F32 }}},
116
 
        { Qt::Key_F33,        {1, { XK_F33 }}},
117
 
        { Qt::Key_F34,        {1, { XK_F34 }}},
118
 
        { Qt::Key_F35,        {1, { XK_F35 }}},
119
 
        { Qt::Key_Super_L,    {1, { XK_Super_L }}},
120
 
        { Qt::Key_Super_R,    {1, { XK_Super_R }}},
121
 
        { Qt::Key_Menu,       {1, { XK_Menu }}},
122
 
        { Qt::Key_Hyper_L,    {1, { XK_Hyper_L }}},
123
 
        { Qt::Key_Hyper_R,    {1, { XK_Hyper_R }}},
124
 
        { Qt::Key_Help,       {1, { XK_Help }}},
125
 
        { Qt::Key_Direction_L,{0, { 0 }}},
126
 
        { Qt::Key_Direction_R,{0, { 0 }}},
127
 
 
128
 
        { Qt::Key_unknown,    {0, { 0 }}},
129
 
};
130
 
 
131
 
static long alt_mask = 0;
132
 
static long meta_mask = 0;
133
 
static bool haveMods = false;
134
 
 
135
 
// adapted from qapplication_x11.cpp
136
 
static void ensureModifiers()
137
 
{
138
 
        if(haveMods)
139
 
                return;
140
 
 
141
 
        Display *appDpy = qt_xdisplay();
142
 
        XModifierKeymap *map = XGetModifierMapping(appDpy);
143
 
        if(map) {
144
 
                int i, maskIndex = 0, mapIndex = 0;
145
 
                for (maskIndex = 0; maskIndex < 8; maskIndex++) {
146
 
                        for (i = 0; i < map->max_keypermod; i++) {
147
 
                                if (map->modifiermap[mapIndex]) {
148
 
                                        KeySym sym = XKeycodeToKeysym(appDpy, map->modifiermap[mapIndex], 0);
149
 
                                        if ( alt_mask == 0 && ( sym == XK_Alt_L || sym == XK_Alt_R ) ) {
150
 
                                                alt_mask = 1 << maskIndex;
151
 
                                        }
152
 
                                        if ( meta_mask == 0 && (sym == XK_Meta_L || sym == XK_Meta_R ) ) {
153
 
                                                meta_mask = 1 << maskIndex;
154
 
                                        }
155
 
                                }
156
 
                                mapIndex++;
157
 
                        }
158
 
                }
159
 
 
160
 
                XFreeModifiermap(map);
161
 
        }
162
 
        else {
163
 
                // assume defaults
164
 
                alt_mask = Mod1Mask;
165
 
                meta_mask = Mod4Mask;
166
 
        }
167
 
 
168
 
        haveMods = true;
169
 
}
170
 
 
171
 
static bool convertKeySequence(const QKeySequence &ks, unsigned int *_mod, QT_XK_KEYGROUP *_kg)
172
 
{
173
 
        int code = ks;
174
 
        ensureModifiers();
175
 
 
176
 
        unsigned int mod = 0;
177
 
        if(code & Qt::META)
178
 
                mod |= meta_mask;
179
 
        if(code & Qt::SHIFT)
180
 
                mod |= ShiftMask;
181
 
        if(code & Qt::CTRL)
182
 
                mod |= ControlMask;
183
 
        if(code & Qt::ALT)
184
 
                mod |= alt_mask;
185
 
 
186
 
        QT_XK_KEYGROUP kg;
187
 
        kg.num = 0;
188
 
        code &= 0xffff;
189
 
        // see if it is in our table
190
 
        bool found = false;
191
 
        for(int n = 0; qt_xk_table[n].key != Qt::Key_unknown; ++n) {
192
 
                if(qt_xk_table[n].key == code) {
193
 
                        kg = qt_xk_table[n].xk;
194
 
                        found = true;
195
 
                        break;
196
 
                }
197
 
        }
198
 
        // not found?
199
 
        if(!found) {
200
 
                // try latin1
201
 
                if(code >= 0x20 && code <= 0x7f) {
202
 
                        kg.num = 1;
203
 
                        kg.sym[0] = code;
204
 
                }
205
 
        }
206
 
        if(!kg.num)
207
 
                return false;
208
 
 
209
 
        if(_mod)
210
 
                *_mod = mod;
211
 
        if(_kg)
212
 
                *_kg = kg;
213
 
 
214
 
        return true;
215
 
}
216
 
 
217
 
class X11HotKey
218
 
{
219
 
public:
220
 
        X11HotKey() {}
221
 
        ~X11HotKey()
222
 
        {
223
 
                XUngrabKey(dsp, code, mod, grab);
224
 
        }
225
 
 
226
 
        static bool failed;
227
 
        static int XGrabErrorHandler(Display *, XErrorEvent *)
228
 
        {
229
 
                failed = true;
230
 
                return 0;
231
 
        }
232
 
 
233
 
        static X11HotKey * bind(int keysym, unsigned int mod)
234
 
        {
235
 
                Display *dsp = qt_xdisplay();
236
 
                Window grab = qt_xrootwin();
237
 
                int code = XKeysymToKeycode(dsp, keysym);
238
 
 
239
 
                // don't grab keys with empty code (because it means just the modifier key)
240
 
                if ( keysym && !code )
241
 
                        return 0;
242
 
 
243
 
                failed = false;
244
 
                XErrorHandler savedErrorHandler = XSetErrorHandler(XGrabErrorHandler);
245
 
                XGrabKey(dsp, code, mod, grab, False, GrabModeAsync, GrabModeAsync);
246
 
                XSync(dsp, False);
247
 
                XSetErrorHandler(savedErrorHandler);
248
 
                if(failed)
249
 
                        return 0;
250
 
                X11HotKey *k = new X11HotKey;
251
 
                k->dsp = dsp;
252
 
                k->grab = grab;
253
 
                k->code = code;
254
 
                k->mod = mod;
255
 
                return k;
256
 
        }
257
 
 
258
 
        Display *dsp;     // X11 display
259
 
        Window grab;      // Window (root window, in our case)
260
 
        int code;         // Keycode
261
 
        unsigned int mod; // modifiers (shift/alt/etc)
262
 
};
263
 
 
264
 
bool X11HotKey::failed;
265
 
 
266
 
class X11HotKeyGroup
267
 
{
268
 
public:
269
 
        X11HotKeyGroup()
270
 
        {
271
 
                list.setAutoDelete(true);
272
 
        }
273
 
 
274
 
        ~X11HotKeyGroup()
275
 
        {
276
 
        }
277
 
 
278
 
        static X11HotKeyGroup * bind(const QT_XK_KEYGROUP &kg, unsigned int mod, int qkey, int id)
279
 
        {
280
 
                QPtrList<X11HotKey> list;
281
 
                for(int n = 0; n < kg.num; ++n) {
282
 
                        X11HotKey *k = X11HotKey::bind(kg.sym[n], mod);
283
 
                        if(k)
284
 
                                list.append(k);
285
 
                }
286
 
                if(list.isEmpty())
287
 
                        return 0;
288
 
                X11HotKeyGroup *h = new X11HotKeyGroup;
289
 
                h->list = list;
290
 
                h->qkey = qkey;
291
 
                h->id = id;
292
 
                return h;
293
 
        }
294
 
 
295
 
        QPtrList<X11HotKey> list; // Associated X11HotKeys
296
 
        int qkey;                 // Qt keycode (with modifiers)
297
 
        int id;                   // GlobalAccelManager unique ID for this hotkey
298
 
};
299
 
 
300
 
class GlobalAccelManager::Private
301
 
{
302
 
public:
303
 
        Private(GlobalAccelManager *_man)
304
 
        {
305
 
                man = _man;
306
 
                id_at = 1;
307
 
                list.setAutoDelete(true);
308
 
                f = new Filter(this);
309
 
                qApp->installEventFilter(f);
310
 
        }
311
 
 
312
 
        ~Private()
313
 
        {
314
 
                qApp->removeEventFilter(f);
315
 
                delete f;
316
 
        }
317
 
 
318
 
        bool isThisYours(int qkey)
319
 
        {
320
 
                QPtrListIterator<X11HotKeyGroup> it(list);
321
 
                for(X11HotKeyGroup *k; (k = it.current()); ++it) {
322
 
                        if(k->qkey == qkey) {
323
 
                                man->triggerActivated(k->id);
324
 
                                return true;
325
 
                        }
326
 
                }
327
 
                return false;
328
 
        }
329
 
 
330
 
        class Filter : public QObject
331
 
        {
332
 
        public:
333
 
                Filter(Private *_p)
334
 
                {
335
 
                        p = _p;
336
 
                }
337
 
 
338
 
        protected:
339
 
                bool eventFilter(QObject *o, QEvent *e)
340
 
                {
341
 
                        if(e->type() == QEvent::KeyPress) {
342
 
                                QKeyEvent *k = (QKeyEvent *)e;
343
 
                                int qkey = k->key();
344
 
                                if(k->state() & ShiftButton)
345
 
                                        qkey |= Qt::SHIFT;
346
 
                                if(k->state() & ControlButton)
347
 
                                        qkey |= Qt::CTRL;
348
 
                                if(k->state() & AltButton)
349
 
                                        qkey |= Qt::ALT;
350
 
                                if(k->state() & MetaButton)
351
 
                                        qkey |= Qt::META;
352
 
 
353
 
                                if(p->isThisYours(qkey))
354
 
                                        return true;
355
 
                        }
356
 
                        return QObject::eventFilter(o, e);
357
 
                }
358
 
 
359
 
        private:
360
 
                Private *p;
361
 
        };
362
 
 
363
 
        GlobalAccelManager *man;
364
 
        int id_at;
365
 
        Filter *f;
366
 
        QPtrList<X11HotKeyGroup> list;
367
 
};
368
 
 
369
 
GlobalAccelManager::GlobalAccelManager()
370
 
{
371
 
        d = new Private(this);
372
 
}
373
 
 
374
 
GlobalAccelManager::~GlobalAccelManager()
375
 
{
376
 
        delete d;
377
 
}
378
 
 
379
 
int GlobalAccelManager::setAccel(const QKeySequence &ks)
380
 
{
381
 
        QT_XK_KEYGROUP kg;
382
 
        unsigned int mod;
383
 
        if(!convertKeySequence(ks, &mod, &kg))
384
 
                return 0;
385
 
 
386
 
        X11HotKeyGroup *h = X11HotKeyGroup::bind(kg, mod, ks, d->id_at++);
387
 
        if(!h)
388
 
                return 0;
389
 
        d->list.append(h);
390
 
 
391
 
        return h->id;
392
 
}
393
 
 
394
 
void GlobalAccelManager::removeAccel(int id)
395
 
{
396
 
        QPtrListIterator<X11HotKeyGroup> it(d->list);
397
 
        for(X11HotKeyGroup *hk = 0; (hk = it.current()); ++it) {
398
 
                if(hk->id == id) {
399
 
                        d->list.removeRef(hk);
400
 
                        return;
401
 
                }
402
 
        }
403
 
}