]> icculus.org git repositories - mikachu/openbox.git/blob - src/XDisplay.cc
make work with new i18n
[mikachu/openbox.git] / src / XDisplay.cc
1 // XDisplay.cc for Openbox
2 // Copyright (c) 2002 - 2002 Ben Janens (ben at orodu.net)
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21
22 #ifdef HAVE_CONFIG_H
23 # include "../config.h"
24 #endif
25
26 #ifdef HAVE_UNNISTD_H
27 # include <unistd.h>
28 #endif
29
30 #ifdef HAVE_FCNTL_H
31 # include <fcntl.h>
32 #endif
33
34 #ifdef SHAPE
35 # include <X11/extensions/shape.h>
36 #endif
37
38 #include "XDisplay.h"
39 #include "Util.h"
40 #include <iostream>
41 #include <algorithm>
42
43 using std::cerr;
44 using std::endl;
45
46 std::string XDisplay::_app_name;
47 Window      XDisplay::_last_bad_window = None;
48   
49 /*
50  * X error handler to handle all X errors while the application is
51  * running.
52  */
53 int XDisplay::errorHandler(Display *d, XErrorEvent *e) {
54 #ifdef DEBUG
55   char errtxt[128];
56   XGetErrorText(d, e->error_code, errtxt, sizeof(errtxt)/sizeof(char));
57   cerr << _app_name.c_str() << ": X error: " << 
58     errtxt << "(" << e->error_code << ") opcodes " <<
59     e->request_code << "/" << e->minor_code << endl;
60   cerr.flags(std::ios_base::hex);
61   cerr << "  resource 0x" << e->resourceid << endl;
62   cerr.flags(std::ios_base::dec);
63 #endif
64   
65   if (e->error_code == BadWindow)
66     _last_bad_window = e->resourceid;
67   
68   return False;
69 }
70
71
72 XDisplay::XDisplay(const std::string &application_name, const char *dpyname) {
73   _app_name = application_name;
74   _grabs = 0;
75   _hasshape = false;
76   
77   _display = XOpenDisplay(dpyname);
78   if (_display == NULL) {
79     cerr << "Could not open display. Connection to X server failed.\n";
80     ::exit(2);
81   }
82   if (-1 == fcntl(ConnectionNumber(_display), F_SETFD, 1)) {
83     cerr << "Could not mark display connection as close-on-exec.\n";
84     ::exit(2);
85   }
86   _name = XDisplayName(dpyname);
87
88   XSetErrorHandler(errorHandler);
89
90 #ifdef    SHAPE
91   int waste;
92   _hasshape = XShapeQueryExtension(_display, &_shape_event_base, &waste);
93 #endif // SHAPE
94
95 #ifndef NOCLOBBER
96   getLockModifiers();
97 #endif
98 }
99
100
101 XDisplay::~XDisplay() {
102   std::for_each(_screens.begin(), _screens.end(), PointerAssassin());
103   XCloseDisplay(_display);
104 }
105
106
107 /*
108  * Grab the X server
109  */
110 void XDisplay::grab() {
111   if (_grabs++ == 0)
112     XGrabServer(_display);
113 }
114
115
116 /*
117  * Release the X server from a grab
118  */
119 void XDisplay::ungrab() {
120   if (--_grabs == 0)
121     XUngrabServer(_display);
122 }
123
124
125 /*
126  * Gets the next event on the queue from the X server.
127  * 
128  * Returns: true if e contains a new event; false if there is no event to be
129  *          returned.
130  */
131 bool XDisplay::nextEvent(XEvent &e) {
132   if(!XPending(_display))
133     return false;
134   XNextEvent(_display, &e);
135   if (_last_bad_window != None) {
136     if (e.xany.window == _last_bad_window) {
137       cerr << "XDisplay::nextEvent(): Removing event for bad window from " <<
138         "event queue\n";
139       return false;
140     } else
141       _last_bad_window = None;
142   }
143   return true;
144 }
145
146
147 int XDisplay::connectionNumber() const {
148   return ConnectionNumber(_display);
149 }
150
151
152 /*
153  * Creates a font cursor in the X server and returns it.
154  */
155 Cursor createCursor(unsigned int shape) const {
156   return XCreateFontCursor(_display, shape);
157 }
158
159
160 #ifndef   NOCLOBBER
161 void XDisplay::getLockModifers() {
162   NumLockMask = ScrollLockMask = 0;
163
164   const XModifierKeymap* const modmap = XGetModifierMapping(display);
165   if (modmap && modmap->max_keypermod > 0) {
166     const int mask_table[] = {
167       ShiftMask, LockMask, ControlMask, Mod1Mask,
168       Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
169     };
170     const size_t size = (sizeof(mask_table) / sizeof(mask_table[0])) *
171       modmap->max_keypermod;
172     // get the values of the keyboard lock modifiers
173     // Note: Caps lock is not retrieved the same way as Scroll and Num lock
174     // since it doesn't need to be.
175     const KeyCode num_lock_code = XKeysymToKeycode(display, XK_Num_Lock);
176     const KeyCode scroll_lock_code = XKeysymToKeycode(display, XK_Scroll_Lock);
177
178     for (size_t cnt = 0; cnt < size; ++cnt) {
179       if (! modmap->modifiermap[cnt]) continue;
180
181       if (num_lock_code == modmap->modifiermap[cnt])
182         NumLockMask = mask_table[cnt / modmap->max_keypermod];
183       if (scroll_lock_code == modmap->modifiermap[cnt])
184         ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
185     }
186   }
187
188   MaskList[0] = 0;
189   MaskList[1] = LockMask;
190   MaskList[2] = NumLockMask;
191   MaskList[3] = ScrollLockMask;
192   MaskList[4] = LockMask | NumLockMask;
193   MaskList[5] = NumLockMask  | ScrollLockMask;
194   MaskList[6] = LockMask | ScrollLockMask;
195   MaskList[7] = LockMask | NumLockMask | ScrollLockMask;
196
197   if (modmap) XFreeModifiermap(const_cast<XModifierKeymap*>(modmap));
198 }
199 #endif // NOCLOBBER
200   
201 unsigned int XDisplay::stripModifiers(const unsigned int state) const {
202 #ifndef NOCLOBBER
203   return state &= ~(NumLockMask() | ScrollLockMask | LockMask);
204 #else
205   return state &= ~LockMask;
206 #endif
207 }
208
209
210 /*
211  * Verifies that a window has not requested to be destroyed/unmapped, so
212  * if it is a valid window or not.
213  * Returns: true if the window is valid; false if it is no longer valid.
214  */
215 bool XDisplay::validateWindow(Window window) {
216   XEvent event;
217   if (XCheckTypedWindowEvent(_display, window, DestroyNotify, &event)) {
218     XPutBackEvent(display, &event);
219     return false;
220   }
221   return true;
222 }
223
224
225 /*
226  * Grabs a button, but also grabs the button in every possible combination with
227  * the keyboard lock keys, so that they do not cancel out the event.
228  */
229 void BaseDisplay::grabButton(unsigned int button, unsigned int modifiers,
230                              Window grab_window, Bool owner_events,
231                              unsigned int event_mask, int pointer_mode,
232                              int keybaord_mode, Window confine_to,
233                              Cursor cursor) const
234 {
235 #ifndef   NOCLOBBER
236   for (size_t cnt = 0; cnt < 8; ++cnt)
237     XGrabButton(_display, button, modifiers | MaskList[cnt], grab_window,
238                 owner_events, event_mask, pointer_mode, keybaord_mode,
239                 confine_to, cursor);
240 #else  // NOCLOBBER
241   XGrabButton(_display, button, modifiers, grab_window,
242               owner_events, event_mask, pointer_mode, keybaord_mode,
243               confine_to, cursor);
244 #endif // NOCLOBBER
245 }
246
247
248 /*
249  * Releases the grab on a button, and ungrabs all possible combinations of the
250  * keyboard lock keys.
251  */
252 void BaseDisplay::ungrabButton(unsigned int button, unsigned int modifiers,
253                                Window grab_window) const {
254 #ifndef   NOCLOBBER
255   for (size_t cnt = 0; cnt < 8; ++cnt)
256     XUngrabButton(display, button, modifiers | MaskList[cnt], grab_window);
257 #else  // NOCLOBBER
258   XUngrabButton(display, button, modifiers, grab_window);
259 #endif // NOCLOBBER
260 }