]> icculus.org git repositories - dana/openbox.git/blob - otk/display.cc
merge the C branch into HEAD
[dana/openbox.git] / otk / display.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #include "config.h"
4
5 #include "display.hh"
6 #include "util.hh"
7
8 extern "C" {
9 #include <X11/keysym.h>
10
11 #ifdef    XKB
12 #include <X11/XKBlib.h>
13 #endif // XKB
14
15 #ifdef    SHAPE
16 #include <X11/extensions/shape.h>
17 #endif // SHAPE
18
19 #ifdef    XINERAMA
20 #include <X11/extensions/Xinerama.h>
21 #endif // XINERAMA
22
23 #ifdef    HAVE_SIGNAL_H
24 #  include <signal.h>
25 #endif // HAVE_SIGNAL_H
26
27 #ifdef    HAVE_FCNTL_H
28 #  include <fcntl.h>
29 #endif // HAVE_FCNTL_H
30
31 #ifdef    HAVE_UNISTD_H
32 #  include <sys/types.h>
33 #  include <unistd.h>
34 #endif // HAVE_UNISTD_H
35
36 #include "../src/gettext.h"
37 #define _(str) gettext(str)
38 }
39
40 #include <cstdio>
41
42 namespace otk {
43
44
45 Display *display = (Display*) 0;
46
47 static int xerrorHandler(::Display *d, XErrorEvent *e)
48 {
49   if (!display->ignoreErrors()) {
50 #ifdef DEBUG
51     char errtxt[128];
52
53     //if (e->error_code != BadWindow)
54     {
55       XGetErrorText(d, e->error_code, errtxt, 127);
56       printf("X Error: %s\n", errtxt);
57       if (e->error_code != BadWindow)
58         abort();
59     }
60 #else
61     (void)d;
62     (void)e;
63 #endif
64   }
65   return false;
66 }
67
68
69 Display::Display(::Display *d)
70   : _display(d),
71     _xkb(false),
72     _xkb_event_basep(0),
73     _shape(false),
74     _shape_event_basep(0),
75     _xinerama(false),
76     _xinerama_event_basep(0),
77     _mask_list(),
78     _num_lock_mask(0),
79     _scroll_lock_mask(0),
80     _grab_count(0)
81 {
82   int junk;
83   (void)junk;
84
85   assert(_display);
86   
87   display = this;
88   
89   if (fcntl(ConnectionNumber(_display), F_SETFD, 1) == -1) {
90     printf(_("Couldn't mark display connection as close-on-exec.\n\n"));
91     ::exit(1);
92   }
93   if (!XSupportsLocale())
94     printf(_("X server does not support locale.\n"));
95   if (!XSetLocaleModifiers(""))
96     printf(_("Cannot set locale modifiers for the X server.\n"));
97   
98   // set our error handler for X errors
99   XSetErrorHandler(xerrorHandler);
100
101   // set the DISPLAY environment variable for any lauched children, to the
102   // display we're using, so they open in the right place.
103   putenv(std::string("DISPLAY=") + DisplayString(_display));
104   
105   // find the availability of X extensions we like to use
106 #ifdef XKB
107   _xkb = XkbQueryExtension(_display, &junk, &_xkb_event_basep, &junk, NULL, 
108                            NULL);
109 #endif
110
111 #ifdef SHAPE
112   _shape = XShapeQueryExtension(_display, &_shape_event_basep, &junk);
113 #endif
114
115 #ifdef XINERAMA
116   _xinerama = XineramaQueryExtension(_display, &_xinerama_event_basep, &junk);
117 #endif // XINERAMA
118
119   // get lock masks that are defined by the display (not constant)
120   _modmap = XGetModifierMapping(_display);
121   assert(_modmap);
122   if (_modmap && _modmap->max_keypermod > 0) {
123     const int mask_table[] = {
124       ShiftMask, LockMask, ControlMask, Mod1Mask,
125       Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
126     };
127     const size_t size = (sizeof(mask_table) / sizeof(mask_table[0])) *
128       _modmap->max_keypermod;
129     // get the values of the keyboard lock modifiers
130     // Note: Caps lock is not retrieved the same way as Scroll and Num lock
131     // since it doesn't need to be.
132     const KeyCode num_lock = XKeysymToKeycode(_display, XK_Num_Lock);
133     const KeyCode scroll_lock = XKeysymToKeycode(_display, XK_Scroll_Lock);
134
135     for (size_t cnt = 0; cnt < size; ++cnt) {
136       if (! _modmap->modifiermap[cnt]) continue;
137
138       if (num_lock == _modmap->modifiermap[cnt])
139         _num_lock_mask = mask_table[cnt / _modmap->max_keypermod];
140       if (scroll_lock == _modmap->modifiermap[cnt])
141         _scroll_lock_mask = mask_table[cnt / _modmap->max_keypermod];
142     }
143   }
144
145   _mask_list[0] = 0;
146   _mask_list[1] = LockMask;
147   _mask_list[2] = _num_lock_mask;
148   _mask_list[3] = LockMask | _num_lock_mask;
149   _mask_list[4] = _scroll_lock_mask;
150   _mask_list[5] = _scroll_lock_mask | LockMask;
151   _mask_list[6] = _scroll_lock_mask | _num_lock_mask;
152   _mask_list[7] = _scroll_lock_mask | LockMask | _num_lock_mask;
153
154   /*
155     If the default depth is at least 8 we will use that,
156     otherwise we try to find the largest TrueColor visual.
157     Preference is given to 24 bit over larger depths if 24 bit is an option.
158   */
159
160   int screen = DefaultScreen(_display);
161   _depth = DefaultDepth(_display, screen);
162   _visual = DefaultVisual(_display, screen);
163   _colormap = DefaultColormap(_display, screen);
164   
165   if (_depth < 8) {
166     // search for a TrueColor Visual... if we can't find one...
167     // we will use the default visual for the screen
168     XVisualInfo vinfo_template, *vinfo_return;
169     int vinfo_nitems;
170     int best = -1;
171
172     vinfo_template.screen = screen;
173     vinfo_template.c_class = TrueColor;
174
175     vinfo_return = XGetVisualInfo(_display,
176                                   VisualScreenMask | VisualClassMask,
177                                   &vinfo_template, &vinfo_nitems);
178     if (vinfo_return) {
179       int max_depth = 1;
180       for (int i = 0; i < vinfo_nitems; ++i) {
181         if (vinfo_return[i].depth > max_depth) {
182           if (max_depth == 24 && vinfo_return[i].depth > 24)
183             break;          // prefer 24 bit over 32
184           max_depth = vinfo_return[i].depth;
185           best = i;
186         }
187       }
188       if (max_depth < _depth) best = -1;
189     }
190
191     if (best != -1) {
192       _depth = vinfo_return[best].depth;
193       _visual = vinfo_return[best].visual;
194       _colormap = XCreateColormap(_display, RootWindow(_display, screen),
195                                   _visual, AllocNone);
196     }
197
198     XFree(vinfo_return);
199   }
200 }
201
202
203 Display::~Display()
204 {
205   while (_grab_count > 0)
206     ungrab();
207
208   XFreeModifiermap(_modmap);
209   
210   XCloseDisplay(_display);
211 }
212
213
214 void Display::setIgnoreErrors(bool t)
215 {
216   // sync up so that anything already sent is/isn't ignored!
217   XSync(_display, false);
218   _ignore_errors = t;
219 }
220
221 void Display::grab()
222 {
223   if (_grab_count == 0) {
224     XGrabServer(_display);
225     XSync(_display, false); // make sure it kicks in
226   }
227   _grab_count++;
228 }
229
230
231 void Display::ungrab()
232 {
233   if (_grab_count == 0) return;
234   _grab_count--;
235   if (_grab_count == 0) {
236     XUngrabServer(_display);
237     XFlush(_display); // ungrab as soon as possible
238   }
239 }
240
241
242
243
244
245
246
247 /*
248  * Grabs a button, but also grabs the button in every possible combination
249  * with the keyboard lock keys, so that they do not cancel out the event.
250
251  * if allow_scroll_lock is true then only the top half of the lock mask
252  * table is used and scroll lock is ignored.  This value defaults to false.
253  */
254 void Display::grabButton(unsigned int button, unsigned int modifiers,
255                          Window grab_window, bool owner_events,
256                          unsigned int event_mask, int pointer_mode,
257                          int keyboard_mode, Window confine_to,
258                          Cursor cursor, bool allow_scroll_lock) const
259 {
260   unsigned int length = (allow_scroll_lock) ? 8 / 2:
261                                               8;
262   for (size_t cnt = 0; cnt < length; ++cnt)
263     XGrabButton(_display, button, modifiers | _mask_list[cnt],
264                 grab_window, owner_events, event_mask, pointer_mode,
265                 keyboard_mode, confine_to, cursor);
266 }
267
268
269 /*
270  * Releases the grab on a button, and ungrabs all possible combinations of the
271  * keyboard lock keys.
272  */
273 void Display::ungrabButton(unsigned int button, unsigned int modifiers,
274                            Window grab_window) const
275 {
276   for (size_t cnt = 0; cnt < 8; ++cnt)
277     XUngrabButton(_display, button, modifiers | _mask_list[cnt],
278                   grab_window);
279 }
280
281 void Display::grabKey(unsigned int keycode, unsigned int modifiers,
282                         Window grab_window, bool owner_events,
283                         int pointer_mode, int keyboard_mode,
284                         bool allow_scroll_lock) const
285 {
286   unsigned int length = (allow_scroll_lock) ? 8 / 2:
287                                               8;
288   for (size_t cnt = 0; cnt < length; ++cnt)
289     XGrabKey(_display, keycode, modifiers | _mask_list[cnt],
290                 grab_window, owner_events, pointer_mode, keyboard_mode);
291 }
292
293 void Display::ungrabKey(unsigned int keycode, unsigned int modifiers,
294                           Window grab_window) const
295 {
296   for (size_t cnt = 0; cnt < 8; ++cnt)
297     XUngrabKey(_display, keycode, modifiers | _mask_list[cnt],
298                grab_window);
299 }
300
301 void Display::ungrabAllKeys(Window grab_window) const
302 {
303   XUngrabKey(_display, AnyKey, AnyModifier, grab_window);
304 }
305
306 }