]> Dogcows Code - chaz/openbox/blob - src/basedisplay.cc
rename, remove bullshit. ya
[chaz/openbox] / src / basedisplay.cc
1 // -*- mode: C++; indent-tabs-mode: nil; -*-
2 // BaseDisplay.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef HAVE_CONFIG_H
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <X11/Xlib.h>
30 #include <X11/Xatom.h>
31 #include <X11/Xutil.h>
32 #include <X11/keysym.h>
33
34 #ifdef SHAPE
35 # include <X11/extensions/shape.h>
36 #endif // SHAPE
37
38 #ifdef XINERAMA
39 # include <X11/extensions/Xinerama.h>
40 #endif // XINERAMA
41
42 #ifdef HAVE_FCNTL_H
43 # include <fcntl.h>
44 #endif // HAVE_FCNTL_H
45
46 #ifdef HAVE_STDIO_H
47 # include <stdio.h>
48 #endif // HAVE_STDIO_H
49
50 #ifdef HAVE_STDLIB_H
51 # include <stdlib.h>
52 #endif // HAVE_STDLIB_H
53
54 #ifdef HAVE_STRING_H
55 # include <string.h>
56 #endif // HAVE_STRING_H
57
58 #ifdef HAVE_UNISTD_H
59 # include <sys/types.h>
60 # include <unistd.h>
61 #endif // HAVE_UNISTD_H
62
63 #ifdef HAVE_SYS_SELECT_H
64 # include <sys/select.h>
65 #endif // HAVE_SYS_SELECT_H
66
67 #ifdef HAVE_SIGNAL_H
68 # include <signal.h>
69 #endif // HAVE_SIGNAL_H
70
71 #ifndef SA_NODEFER
72 # ifdef SA_INTERRUPT
73 # define SA_NODEFER SA_INTERRUPT
74 # else // !SA_INTERRUPT
75 # define SA_NODEFER (0)
76 # endif // SA_INTERRUPT
77 #endif // SA_NODEFER
78
79 #ifdef HAVE_SYS_WAIT_H
80 # include <sys/types.h>
81 # include <sys/wait.h>
82 #endif // HAVE_SYS_WAIT_H
83 }
84
85 #include <string>
86 using std::string;
87
88 #include "basedisplay.hh"
89 #include "gccache.hh"
90 #include "timer.hh"
91 #include "util.hh"
92
93
94 // X error handler to handle any and all X errors while the application is
95 // running
96 static bool internal_error = False;
97
98 BaseDisplay *base_display;
99
100 static int handleXErrors(Display *d, XErrorEvent *e) {
101 #ifdef DEBUG
102 char errtxt[128];
103
104 XGetErrorText(d, e->error_code, errtxt, 128);
105 fprintf(stderr,
106 i18n(BaseDisplaySet, BaseDisplayXError,
107 "%s: X error: %s(%d) opcodes %d/%d\n resource 0x%lx\n"),
108 base_display->getApplicationName(), errtxt, e->error_code,
109 e->request_code, e->minor_code, e->resourceid);
110 #else
111 // shutup gcc
112 (void) d;
113 (void) e;
114 #endif // DEBUG
115
116 if (internal_error) abort();
117
118 return(False);
119 }
120
121
122 // signal handler to allow for proper and gentle shutdown
123
124 #ifndef HAVE_SIGACTION
125 static RETSIGTYPE signalhandler(int sig) {
126 #else // HAVE_SIGACTION
127 static void signalhandler(int sig) {
128 #endif // HAVE_SIGACTION
129
130 static int re_enter = 0;
131
132 switch (sig) {
133 case SIGCHLD:
134 int status;
135 waitpid(-1, &status, WNOHANG | WUNTRACED);
136
137 #ifndef HAVE_SIGACTION
138 // assume broken, braindead sysv signal semantics
139 signal(SIGCHLD, (RETSIGTYPE (*)(int)) signalhandler);
140 #endif // HAVE_SIGACTION
141
142 break;
143
144 default:
145 if (base_display->handleSignal(sig)) {
146
147 #ifndef HAVE_SIGACTION
148 // assume broken, braindead sysv signal semantics
149 signal(sig, (RETSIGTYPE (*)(int)) signalhandler);
150 #endif // HAVE_SIGACTION
151
152 return;
153 }
154
155 fprintf(stderr, i18n(BaseDisplaySet, BaseDisplaySignalCaught,
156 "%s: signal %d caught\n"),
157 base_display->getApplicationName(), sig);
158
159 if (! base_display->isStartup() && ! re_enter) {
160 internal_error = True;
161
162 re_enter = 1;
163 fprintf(stderr, i18n(BaseDisplaySet, BaseDisplayShuttingDown,
164 "shutting down\n"));
165 base_display->shutdown();
166 }
167
168 if (sig != SIGTERM && sig != SIGINT) {
169 fprintf(stderr, i18n(BaseDisplaySet, BaseDisplayAborting,
170 "aborting... dumping core\n"));
171 abort();
172 }
173
174 exit(0);
175
176 break;
177 }
178 }
179
180
181 BaseDisplay::BaseDisplay(const char *app_name, const char *dpy_name) {
182 application_name = app_name;
183
184 run_state = STARTUP;
185
186 ::base_display = this;
187
188 #ifdef HAVE_SIGACTION
189 struct sigaction action;
190
191 action.sa_handler = signalhandler;
192 action.sa_mask = sigset_t();
193 action.sa_flags = SA_NOCLDSTOP | SA_NODEFER;
194
195 sigaction(SIGPIPE, &action, NULL);
196 sigaction(SIGSEGV, &action, NULL);
197 sigaction(SIGFPE, &action, NULL);
198 sigaction(SIGTERM, &action, NULL);
199 sigaction(SIGINT, &action, NULL);
200 sigaction(SIGCHLD, &action, NULL);
201 sigaction(SIGHUP, &action, NULL);
202 sigaction(SIGUSR1, &action, NULL);
203 sigaction(SIGUSR2, &action, NULL);
204 #else // !HAVE_SIGACTION
205 signal(SIGPIPE, (RETSIGTYPE (*)(int)) signalhandler);
206 signal(SIGSEGV, (RETSIGTYPE (*)(int)) signalhandler);
207 signal(SIGFPE, (RETSIGTYPE (*)(int)) signalhandler);
208 signal(SIGTERM, (RETSIGTYPE (*)(int)) signalhandler);
209 signal(SIGINT, (RETSIGTYPE (*)(int)) signalhandler);
210 signal(SIGUSR1, (RETSIGTYPE (*)(int)) signalhandler);
211 signal(SIGUSR2, (RETSIGTYPE (*)(int)) signalhandler);
212 signal(SIGHUP, (RETSIGTYPE (*)(int)) signalhandler);
213 signal(SIGCHLD, (RETSIGTYPE (*)(int)) signalhandler);
214 #endif // HAVE_SIGACTION
215
216 if (! (display = XOpenDisplay(dpy_name))) {
217 fprintf(stderr,
218 i18n(BaseDisplaySet, BaseDisplayXConnectFail,
219 "BaseDisplay::BaseDisplay: connection to X server failed.\n"));
220 ::exit(2);
221 } else if (fcntl(ConnectionNumber(display), F_SETFD, 1) == -1) {
222 fprintf(stderr,
223 i18n(BaseDisplaySet, BaseDisplayCloseOnExecFail,
224 "BaseDisplay::BaseDisplay: couldn't mark display connection "
225 "as close-on-exec\n"));
226 ::exit(2);
227 }
228
229 display_name = XDisplayName(dpy_name);
230
231 #ifdef SHAPE
232 shape.extensions = XShapeQueryExtension(display, &shape.event_basep,
233 &shape.error_basep);
234 #else // !SHAPE
235 shape.extensions = False;
236 #endif // SHAPE
237
238 #ifdef XINERAMA
239 if (XineramaQueryExtension(display, &xinerama.event_basep,
240 &xinerama.error_basep) &&
241 XineramaQueryVersion(display, &xinerama.major, &xinerama.minor)) {
242 #ifdef DEBUG
243 fprintf(stderr,
244 "BaseDisplay::BaseDisplay: Found Xinerama version %d.%d\n",
245 xinerama.major, xinerama.minor);
246 #endif // DEBUG
247 xinerama.extensions = True;
248 } else {
249 xinerama.extensions = False;
250 }
251 #endif // XINERAMA
252
253 XSetErrorHandler((XErrorHandler) handleXErrors);
254
255 screenInfoList.reserve(ScreenCount(display));
256 for (int i = 0; i < ScreenCount(display); ++i)
257 screenInfoList.push_back(ScreenInfo(this, i));
258
259 NumLockMask = ScrollLockMask = 0;
260
261 const XModifierKeymap* const modmap = XGetModifierMapping(display);
262 if (modmap && modmap->max_keypermod > 0) {
263 const int mask_table[] = {
264 ShiftMask, LockMask, ControlMask, Mod1Mask,
265 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
266 };
267 const size_t size = (sizeof(mask_table) / sizeof(mask_table[0])) *
268 modmap->max_keypermod;
269 // get the values of the keyboard lock modifiers
270 // Note: Caps lock is not retrieved the same way as Scroll and Num lock
271 // since it doesn't need to be.
272 const KeyCode num_lock = XKeysymToKeycode(display, XK_Num_Lock);
273 const KeyCode scroll_lock = XKeysymToKeycode(display, XK_Scroll_Lock);
274
275 for (size_t cnt = 0; cnt < size; ++cnt) {
276 if (! modmap->modifiermap[cnt]) continue;
277
278 if (num_lock == modmap->modifiermap[cnt])
279 NumLockMask = mask_table[cnt / modmap->max_keypermod];
280 if (scroll_lock == modmap->modifiermap[cnt])
281 ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
282 }
283 }
284
285 MaskList[0] = 0;
286 MaskList[1] = LockMask;
287 MaskList[2] = NumLockMask;
288 MaskList[3] = LockMask | NumLockMask;
289 MaskList[4] = ScrollLockMask;
290 MaskList[5] = ScrollLockMask | LockMask;
291 MaskList[6] = ScrollLockMask | NumLockMask;
292 MaskList[7] = ScrollLockMask | LockMask | NumLockMask;
293 MaskListLength = sizeof(MaskList) / sizeof(MaskList[0]);
294
295 if (modmap) XFreeModifiermap(const_cast<XModifierKeymap*>(modmap));
296
297 gccache = (BGCCache *) 0;
298 }
299
300
301 BaseDisplay::~BaseDisplay(void) {
302 delete gccache;
303
304 XCloseDisplay(display);
305 }
306
307
308 void BaseDisplay::eventLoop(void) {
309 run();
310
311 const int xfd = ConnectionNumber(display);
312
313 while (run_state == RUNNING && ! internal_error) {
314 if (XPending(display)) {
315 XEvent e;
316 XNextEvent(display, &e);
317 process_event(&e);
318 } else {
319 fd_set rfds;
320 timeval now, tm, *timeout = (timeval *) 0;
321
322 FD_ZERO(&rfds);
323 FD_SET(xfd, &rfds);
324
325 if (! timerList.empty()) {
326 const BTimer* const timer = timerList.top();
327
328 gettimeofday(&now, 0);
329 tm = timer->timeRemaining(now);
330
331 timeout = &tm;
332 }
333
334 select(xfd + 1, &rfds, 0, 0, timeout);
335
336 // check for timer timeout
337 gettimeofday(&now, 0);
338
339 // there is a small chance for deadlock here:
340 // *IF* the timer list keeps getting refreshed *AND* the time between
341 // timer->start() and timer->shouldFire() is within the timer's period
342 // then the timer will keep firing. This should be VERY near impossible.
343 while (! timerList.empty()) {
344 BTimer *timer = timerList.top();
345 if (! timer->shouldFire(now))
346 break;
347
348 timerList.pop();
349
350 timer->fireTimeout();
351 timer->halt();
352 if (timer->isRecurring())
353 timer->start();
354 }
355 }
356 }
357 }
358
359
360 void BaseDisplay::addTimer(BTimer *timer) {
361 if (! timer) return;
362
363 timerList.push(timer);
364 }
365
366
367 void BaseDisplay::removeTimer(BTimer *timer) {
368 timerList.release(timer);
369 }
370
371
372 /*
373 * Grabs a button, but also grabs the button in every possible combination
374 * with the keyboard lock keys, so that they do not cancel out the event.
375
376 * if allow_scroll_lock is true then only the top half of the lock mask
377 * table is used and scroll lock is ignored. This value defaults to false.
378 */
379 void BaseDisplay::grabButton(unsigned int button, unsigned int modifiers,
380 Window grab_window, bool owner_events,
381 unsigned int event_mask, int pointer_mode,
382 int keyboard_mode, Window confine_to,
383 Cursor cursor, bool allow_scroll_lock) const {
384 unsigned int length = (allow_scroll_lock) ? MaskListLength / 2:
385 MaskListLength;
386 for (size_t cnt = 0; cnt < length; ++cnt)
387 XGrabButton(display, button, modifiers | MaskList[cnt], grab_window,
388 owner_events, event_mask, pointer_mode, keyboard_mode,
389 confine_to, cursor);
390 }
391
392
393 /*
394 * Releases the grab on a button, and ungrabs all possible combinations of the
395 * keyboard lock keys.
396 */
397 void BaseDisplay::ungrabButton(unsigned int button, unsigned int modifiers,
398 Window grab_window) const {
399 for (size_t cnt = 0; cnt < MaskListLength; ++cnt)
400 XUngrabButton(display, button, modifiers | MaskList[cnt], grab_window);
401 }
402
403
404 const ScreenInfo* BaseDisplay::getScreenInfo(unsigned int s) const {
405 if (s < screenInfoList.size())
406 return &screenInfoList[s];
407 return (const ScreenInfo*) 0;
408 }
409
410
411 BGCCache* BaseDisplay::gcCache(void) const {
412 if (! gccache)
413 gccache = new BGCCache(this, screenInfoList.size());
414
415 return gccache;
416 }
417
418
419 ScreenInfo::ScreenInfo(BaseDisplay *d, unsigned int num) {
420 basedisplay = d;
421 screen_number = num;
422
423 root_window = RootWindow(basedisplay->getXDisplay(), screen_number);
424
425 rect.setSize(WidthOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(),
426 screen_number)),
427 HeightOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(),
428 screen_number)));
429 /*
430 If the default depth is at least 8 we will use that,
431 otherwise we try to find the largest TrueColor visual.
432 Preference is given to 24 bit over larger depths if 24 bit is an option.
433 */
434
435 depth = DefaultDepth(basedisplay->getXDisplay(), screen_number);
436 visual = DefaultVisual(basedisplay->getXDisplay(), screen_number);
437 colormap = DefaultColormap(basedisplay->getXDisplay(), screen_number);
438
439 if (depth < 8) {
440 // search for a TrueColor Visual... if we can't find one...
441 // we will use the default visual for the screen
442 XVisualInfo vinfo_template, *vinfo_return;
443 int vinfo_nitems;
444 int best = -1;
445
446 vinfo_template.screen = screen_number;
447 vinfo_template.c_class = TrueColor;
448
449 vinfo_return = XGetVisualInfo(basedisplay->getXDisplay(),
450 VisualScreenMask | VisualClassMask,
451 &vinfo_template, &vinfo_nitems);
452 if (vinfo_return) {
453 int max_depth = 1;
454 for (int i = 0; i < vinfo_nitems; ++i) {
455 if (vinfo_return[i].depth > max_depth) {
456 if (max_depth == 24 && vinfo_return[i].depth > 24)
457 break; // prefer 24 bit over 32
458 max_depth = vinfo_return[i].depth;
459 best = i;
460 }
461 }
462 if (max_depth < depth) best = -1;
463 }
464
465 if (best != -1) {
466 depth = vinfo_return[best].depth;
467 visual = vinfo_return[best].visual;
468 colormap = XCreateColormap(basedisplay->getXDisplay(), root_window,
469 visual, AllocNone);
470 }
471
472 XFree(vinfo_return);
473 }
474
475 // get the default display string and strip the screen number
476 string default_string = DisplayString(basedisplay->getXDisplay());
477 const string::size_type pos = default_string.rfind(".");
478 if (pos != string::npos)
479 default_string.resize(pos);
480
481 display_string = string("DISPLAY=") + default_string + '.' +
482 itostring(static_cast<unsigned long>(screen_number));
483
484 #ifdef XINERAMA
485 xinerama_active = False;
486
487 if (d->hasXineramaExtensions()) {
488 if (d->getXineramaMajorVersion() == 1) {
489 // we know the version 1(.1?) protocol
490
491 /*
492 in this version of Xinerama, we can't query on a per-screen basis, but
493 in future versions we should be able, so the 'activeness' is checked
494 on a pre-screen basis anyways.
495 */
496 if (XineramaIsActive(d->getXDisplay())) {
497 /*
498 If Xinerama is being used, there there is only going to be one screen
499 present. We still, of course, want to use the screen class, but that
500 is why no screen number is used in this function call. There should
501 never be more than one screen present with Xinerama active.
502 */
503 int num;
504 XineramaScreenInfo *info = XineramaQueryScreens(d->getXDisplay(), &num);
505 if (num > 0 && info) {
506 xinerama_areas.reserve(num);
507 for (int i = 0; i < num; ++i) {
508 xinerama_areas.push_back(Rect(info[i].x_org, info[i].y_org,
509 info[i].width, info[i].height));
510 }
511 XFree(info);
512
513 // if we can't find any xinerama regions, then we act as if it is not
514 // active, even though it said it was
515 xinerama_active = True;
516 }
517 }
518 }
519 }
520 #endif // XINERAMA
521 }
This page took 0.057237 seconds and 5 git commands to generate.