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