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

« back to all changes in this revision

Viewing changes to cutestuff/globalaccel/globalaccelman_x11.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2005-01-10 17:41:43 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050110174143-ltocv5zapl6blf5d
Tags: 0.9.3-1
* New upstream release
* Cleaned up debian/rules (some things are done by upstream Makefiles now)
* Fixed some lintian warnings:
  - removed executable bit from some .png files
  - moved psi.desktop to /usr/share/applications
* Updated menu files

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
                failed = false;
 
239
                XErrorHandler savedErrorHandler = XSetErrorHandler(XGrabErrorHandler);
 
240
                XGrabKey(dsp, code, mod, grab, False, GrabModeAsync, GrabModeAsync);
 
241
                XSync(dsp, False);
 
242
                XSetErrorHandler(savedErrorHandler);
 
243
                if(failed)
 
244
                        return 0;
 
245
                X11HotKey *k = new X11HotKey;
 
246
                k->dsp = dsp;
 
247
                k->grab = grab;
 
248
                k->code = code;
 
249
                k->mod = mod;
 
250
                return k;
 
251
        }
 
252
 
 
253
        Display *dsp;     // X11 display
 
254
        Window grab;      // Window (root window, in our case)
 
255
        int code;         // Keycode
 
256
        unsigned int mod; // modifiers (shift/alt/etc)
 
257
};
 
258
 
 
259
bool X11HotKey::failed;
 
260
 
 
261
class X11HotKeyGroup
 
262
{
 
263
public:
 
264
        X11HotKeyGroup()
 
265
        {
 
266
                list.setAutoDelete(true);
 
267
        }
 
268
 
 
269
        ~X11HotKeyGroup()
 
270
        {
 
271
        }
 
272
 
 
273
        static X11HotKeyGroup * bind(const QT_XK_KEYGROUP &kg, unsigned int mod, int qkey, int id)
 
274
        {
 
275
                QPtrList<X11HotKey> list;
 
276
                for(int n = 0; n < kg.num; ++n) {
 
277
                        X11HotKey *k = X11HotKey::bind(kg.sym[n], mod);
 
278
                        if(k)
 
279
                                list.append(k);
 
280
                }
 
281
                if(list.isEmpty())
 
282
                        return 0;
 
283
                X11HotKeyGroup *h = new X11HotKeyGroup;
 
284
                h->list = list;
 
285
                h->qkey = qkey;
 
286
                h->id = id;
 
287
                return h;
 
288
        }
 
289
 
 
290
        QPtrList<X11HotKey> list; // Associated X11HotKeys
 
291
        int qkey;                 // Qt keycode (with modifiers)
 
292
        int id;                   // GlobalAccelManager unique ID for this hotkey
 
293
};
 
294
 
 
295
class GlobalAccelManager::Private
 
296
{
 
297
public:
 
298
        Private(GlobalAccelManager *_man)
 
299
        {
 
300
                man = _man;
 
301
                id_at = 1;
 
302
                list.setAutoDelete(true);
 
303
                f = new Filter(this);
 
304
                qApp->installEventFilter(f);
 
305
        }
 
306
 
 
307
        ~Private()
 
308
        {
 
309
                qApp->removeEventFilter(f);
 
310
                delete f;
 
311
        }
 
312
 
 
313
        bool isThisYours(int qkey)
 
314
        {
 
315
                QPtrListIterator<X11HotKeyGroup> it(list);
 
316
                for(X11HotKeyGroup *k; (k = it.current()); ++it) {
 
317
                        if(k->qkey == qkey) {
 
318
                                man->triggerActivated(k->id);
 
319
                                return true;
 
320
                        }
 
321
                }
 
322
                return false;
 
323
        }
 
324
 
 
325
        class Filter : public QObject
 
326
        {
 
327
        public:
 
328
                Filter(Private *_p)
 
329
                {
 
330
                        p = _p;
 
331
                }
 
332
 
 
333
        protected:
 
334
                bool eventFilter(QObject *o, QEvent *e)
 
335
                {
 
336
                        if(e->type() == QEvent::KeyPress) {
 
337
                                QKeyEvent *k = (QKeyEvent *)e;
 
338
                                int qkey = k->key();
 
339
                                if(k->state() & ShiftButton)
 
340
                                        qkey |= Qt::SHIFT;
 
341
                                if(k->state() & ControlButton)
 
342
                                        qkey |= Qt::CTRL;
 
343
                                if(k->state() & AltButton)
 
344
                                        qkey |= Qt::ALT;
 
345
                                if(k->state() & MetaButton)
 
346
                                        qkey |= Qt::META;
 
347
 
 
348
                                if(p->isThisYours(qkey))
 
349
                                        return true;
 
350
                        }
 
351
                        return QObject::eventFilter(o, e);
 
352
                }
 
353
        
 
354
        private:
 
355
                Private *p;
 
356
        };
 
357
 
 
358
        GlobalAccelManager *man;
 
359
        int id_at;
 
360
        Filter *f;
 
361
        QPtrList<X11HotKeyGroup> list;
 
362
};
 
363
 
 
364
GlobalAccelManager::GlobalAccelManager()
 
365
{
 
366
        d = new Private(this);
 
367
}
 
368
 
 
369
GlobalAccelManager::~GlobalAccelManager()
 
370
{
 
371
        delete d;
 
372
}
 
373
 
 
374
int GlobalAccelManager::setAccel(const QKeySequence &ks)
 
375
{
 
376
        QT_XK_KEYGROUP kg;
 
377
        unsigned int mod;
 
378
        if(!convertKeySequence(ks, &mod, &kg))
 
379
                return 0;
 
380
 
 
381
        X11HotKeyGroup *h = X11HotKeyGroup::bind(kg, mod, ks, d->id_at++);
 
382
        if(!h)
 
383
                return 0;
 
384
        d->list.append(h);
 
385
 
 
386
        return h->id;
 
387
}
 
388
 
 
389
void GlobalAccelManager::removeAccel(int id)
 
390
{
 
391
        QPtrListIterator<X11HotKeyGroup> it(d->list);
 
392
        for(X11HotKeyGroup *hk = 0; (hk = it.current()); ++it) {
 
393
                if(hk->id == id) {
 
394
                        d->list.removeRef(hk);
 
395
                        return;
 
396
                }
 
397
        }
 
398
}