fixing parse error in execcommand
[bbkeys.git] / src / BaseDisplay.cc
blob52047ca9ee0aebdae47019b9af6146ec7aeae3c3
1 // BaseDisplay.cc for Blackbox - an X11 Window manager
2 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.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:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
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.
22 // $Id$
24 // stupid macros needed to access some functions in version 2 of the GNU C
25 // library
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE
29 #endif // _GNU_SOURCE
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif // HAVE_CONFIG_H
35 #ifdef SHAPE
36 # include <X11/extensions/shape.h>
37 #endif // SHAPE
39 #ifdef HAVE_FCNTL_H
40 # include <fcntl.h>
41 #endif // HAVE_FCNTL_H
43 #ifdef HAVE_STDIO_H
44 # include <stdio.h>
45 #endif // HAVE_STDIO_H
47 #ifdef STDC_HEADERS
48 # include <stdlib.h>
49 # include <string.h>
50 #endif // STDC_HEADERS
52 #if HAVE_STRINGS_H
53 # include <strings.h>
54 #endif
56 #ifdef HAVE_UNISTD_H
57 # include <sys/types.h>
58 # include <unistd.h>
59 #endif // HAVE_UNISTD_H
61 #ifdef HAVE_SYS_SELECT_H
62 # include <sys/select.h>
63 #endif // HAVE_SYS_SELECT_H
65 #ifdef HAVE_SIGNAL_H
66 # include <signal.h>
67 #endif // HAVE_SIGNAL_H
69 #ifdef HAVE_SYS_SIGNAL_H
70 // # include <sys/signal.h>
71 #endif // HAVE_SYS_SIGNAL_H
73 #ifndef SA_NODEFER
74 # ifdef SA_INTERRUPT
75 # define SA_NODEFER SA_INTERRUPT
76 # else // !SA_INTERRUPT
77 # define SA_NODEFER (0)
78 # endif // SA_INTERRUPT
79 #endif // SA_NODEFER
81 #ifdef HAVE_SYS_WAIT_H
82 # include <sys/types.h>
83 # include <sys/wait.h>
84 #endif // HAVE_SYS_WAIT_H
86 extern "C" {
87 #include <X11/Xlib.h>
88 #include <X11/Xatom.h>
89 #include <X11/Xutil.h>
90 #include <X11/cursorfont.h>
93 #include "BaseDisplay.hh"
94 #include "LinkedList.hh"
95 #include "Timer.hh"
97 // X error handler to handle any and all X errors while the application is
98 // running
99 static Bool internal_error = False;
100 static Window last_bad_window = None;
102 BaseDisplay *base_display;
104 #ifdef DEBUG
105 static int handleXErrors(Display * d, XErrorEvent * e)
107 char errtxt[128];
109 XGetErrorText(d, e->error_code, errtxt, 128);
110 fprintf(stderr, "%s: X error: %s(%d) opcodes %d/%d\n"
111 " resource 0x%lx\n",
112 base_display->getApplicationName(), errtxt, e->error_code,
113 e->request_code, e->minor_code, e->resourceid);
114 #else // !DEBUG
115 static int handleXErrors(Display *, XErrorEvent * e)
117 #endif // DEBUG
119 if (e->error_code == BadWindow)
120 last_bad_window = e->resourceid;
121 if (internal_error)
122 abort();
124 return (False);
128 // signal handler to allow for proper and gentle shutdown
130 #ifndef HAVE_SIGACTION
131 extern "C" RETSIGTYPE signalhandler(int sig)
133 #else // HAVE_SIGACTION
134 extern "C" void signalhandler(int sig)
136 #endif // HAVE_SIGACTION
138 static int re_enter = 0;
140 switch (sig) {
141 case SIGCHLD:
142 int status;
143 waitpid(-1, &status, WNOHANG | WUNTRACED);
145 #ifndef HAVE_SIGACTION
146 // assume broken, braindead sysv signal semantics
147 signal(SIGCHLD, (RETSIGTYPE(*)(int)) signalhandler);
148 #endif // HAVE_SIGACTION
150 break;
152 default:
153 if (base_display->handleSignal(sig)) {
155 #ifndef HAVE_SIGACTION
156 // assume broken, braindead sysv signal semantics
157 signal(sig, (RETSIGTYPE(*)(int)) signalhandler);
158 #endif // HAVE_SIGACTION
160 return;
163 fprintf(stderr, "%s: signal %d caught\n",
164 base_display->getApplicationName(), sig);
166 if (!base_display->isStartup() && !re_enter) {
167 internal_error = True;
169 re_enter = 1;
170 fprintf(stderr, "shutting down\n");
171 base_display->shutdown();
174 if (sig != SIGTERM && sig != SIGINT) {
175 fprintf(stderr, "aborting... dumping core\n");
176 abort();
179 exit(0);
181 break;
186 BaseDisplay::BaseDisplay(char *app_name, char *dpy_name)
189 application_name = app_name;
191 _startup = True;
192 _shutdown = False;
193 last_bad_window = None;
195 ::base_display = this;
197 #ifdef HAVE_SIGACTION
198 struct sigaction action;
200 action.sa_handler = signalhandler;
201 action.sa_mask = sigset_t();
202 action.sa_flags = SA_NOCLDSTOP | SA_NODEFER;
204 sigaction(SIGSEGV, &action, NULL);
205 sigaction(SIGFPE, &action, NULL);
206 sigaction(SIGTERM, &action, NULL);
207 sigaction(SIGINT, &action, NULL);
208 sigaction(SIGCHLD, &action, NULL);
209 sigaction(SIGHUP, &action, NULL);
210 sigaction(SIGUSR1, &action, NULL);
211 sigaction(SIGUSR2, &action, NULL);
212 #else // !HAVE_SIGACTION
213 signal(SIGSEGV, (RETSIGTYPE(*)(int)) signalhandler);
214 signal(SIGFPE, (RETSIGTYPE(*)(int)) signalhandler);
215 signal(SIGTERM, (RETSIGTYPE(*)(int)) signalhandler);
216 signal(SIGINT, (RETSIGTYPE(*)(int)) signalhandler);
217 signal(SIGUSR1, (RETSIGTYPE(*)(int)) signalhandler);
218 signal(SIGUSR2, (RETSIGTYPE(*)(int)) signalhandler);
219 signal(SIGHUP, (RETSIGTYPE(*)(int)) signalhandler);
220 signal(SIGCHLD, (RETSIGTYPE(*)(int)) signalhandler);
221 #endif // HAVE_SIGACTION
223 if (!(display = XOpenDisplay(dpy_name))) {
224 fprintf(stderr,
225 "BaseDisplay::BaseDisplay: connection to X server failed.\n");
226 ::exit(2);
227 } else if (fcntl(ConnectionNumber(display), F_SETFD, 1) == -1) {
228 fprintf(stderr,
229 "BaseDisplay::BaseDisplay: couldn't mark display connection "
230 "as close-on-exec\n");
231 ::exit(2);
234 number_of_screens = ScreenCount(display);
235 display_name = XDisplayName(dpy_name);
237 #ifdef SHAPE
238 shape.extensions = XShapeQueryExtension(display, &shape.event_basep,
239 &shape.error_basep);
240 #else // !SHAPE
241 shape.extensions = False;
242 #endif // SHAPE
244 xa_wm_colormap_windows =
245 XInternAtom(display, "WM_COLORMAP_WINDOWS", False);
246 xa_wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False);
247 xa_wm_state = XInternAtom(display, "WM_STATE", False);
248 xa_wm_change_state = XInternAtom(display, "WM_CHANGE_STATE", False);
249 xa_wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
250 xa_wm_take_focus = XInternAtom(display, "WM_TAKE_FOCUS", False);
251 motif_wm_hints = XInternAtom(display, "_MOTIF_WM_HINTS", False);
253 blackbox_hints = XInternAtom(display, "_BLACKBOX_HINTS", False);
254 blackbox_attributes =
255 XInternAtom(display, "_BLACKBOX_ATTRIBUTES", False);
256 blackbox_change_attributes =
257 XInternAtom(display, "_BLACKBOX_CHANGE_ATTRIBUTES", False);
259 blackbox_structure_messages =
260 XInternAtom(display, "_BLACKBOX_STRUCTURE_MESSAGES", False);
261 blackbox_notify_startup =
262 XInternAtom(display, "_BLACKBOX_NOTIFY_STARTUP", False);
263 blackbox_notify_window_add =
264 XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_ADD", False);
265 blackbox_notify_window_del =
266 XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_DEL", False);
267 blackbox_notify_current_workspace =
268 XInternAtom(display, "_BLACKBOX_NOTIFY_CURRENT_WORKSPACE", False);
269 blackbox_notify_workspace_count =
270 XInternAtom(display, "_BLACKBOX_NOTIFY_WORKSPACE_COUNT", False);
271 blackbox_notify_window_focus =
272 XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_FOCUS", False);
273 blackbox_notify_window_raise =
274 XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_RAISE", False);
275 blackbox_notify_window_lower =
276 XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_LOWER", False);
278 blackbox_change_workspace =
279 XInternAtom(display, "_BLACKBOX_CHANGE_WORKSPACE", False);
280 blackbox_change_window_focus =
281 XInternAtom(display, "_BLACKBOX_CHANGE_WINDOW_FOCUS", False);
282 blackbox_cycle_window_focus =
283 XInternAtom(display, "_BLACKBOX_CYCLE_WINDOW_FOCUS", False);
285 #ifdef NEWWMSPEC
287 net_supported = XInternAtom(display, "_NET_SUPPORTED", False);
288 net_client_list = XInternAtom(display, "_NET_CLIENT_LIST", False);
289 net_client_list_stacking =
290 XInternAtom(display, "_NET_CLIENT_LIST_STACKING", False);
291 net_number_of_desktops =
292 XInternAtom(display, "_NET_NUMBER_OF_DESKTOPS", False);
293 net_desktop_geometry =
294 XInternAtom(display, "_NET_DESKTOP_GEOMETRY", False);
295 net_desktop_viewport =
296 XInternAtom(display, "_NET_DESKTOP_VIEWPORT", False);
297 net_current_desktop =
298 XInternAtom(display, "_NET_CURRENT_DESKTOP", False);
299 net_desktop_names = XInternAtom(display, "_NET_DESKTOP_NAMES", False);
300 net_active_window = XInternAtom(display, "_NET_ACTIVE_WINDOW", False);
301 net_workarea = XInternAtom(display, "_NET_WORKAREA", False);
302 net_supporting_wm_check =
303 XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
304 net_virtual_roots = XInternAtom(display, "_NET_VIRTUAL_ROOTS", False);
306 net_close_window = XInternAtom(display, "_NET_CLOSE_WINDOW", False);
307 net_wm_moveresize = XInternAtom(display, "_NET_WM_MOVERESIZE", False);
309 net_properties = XInternAtom(display, "_NET_PROPERTIES", False);
310 net_wm_name = XInternAtom(display, "_NET_WM_NAME", False);
311 net_wm_desktop = XInternAtom(display, "_NET_WM_DESKTOP", False);
312 net_wm_window_type = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
313 net_wm_state = XInternAtom(display, "_NET_WM_STATE", False);
314 net_wm_strut = XInternAtom(display, "_NET_WM_STRUT", False);
315 net_wm_icon_geometry =
316 XInternAtom(display, "_NET_WM_ICON_GEOMETRY", False);
317 net_wm_icon = XInternAtom(display, "_NET_WM_ICON", False);
318 net_wm_pid = XInternAtom(display, "_NET_WM_PID", False);
319 net_wm_handled_icons =
320 XInternAtom(display, "_NET_WM_HANDLED_ICONS", False);
322 net_wm_ping = XInternAtom(display, "_NET_WM_PING", False);
324 #endif // NEWWMSPEC
326 cursor.session = XCreateFontCursor(display, XC_left_ptr);
327 cursor.move = XCreateFontCursor(display, XC_fleur);
328 cursor.ll_angle = XCreateFontCursor(display, XC_ll_angle);
329 cursor.lr_angle = XCreateFontCursor(display, XC_lr_angle);
331 XSetErrorHandler((XErrorHandler) handleXErrors);
333 timerList = new LinkedList < BTimer >;
335 screenInfoList = new LinkedList < ScreenInfo >;
336 int i;
337 for (i = 0; i < number_of_screens; i++) {
338 ScreenInfo *screeninfo = new ScreenInfo(this, i);
339 screenInfoList->insert(screeninfo);
344 BaseDisplay::~BaseDisplay(void)
347 while (screenInfoList->count()) {
348 ScreenInfo *si = screenInfoList->first();
350 screenInfoList->remove(si);
351 delete si;
354 delete screenInfoList;
356 // we don't create the BTimers, we don't delete them
357 while (timerList->count())
358 timerList->remove(0);
360 delete timerList;
362 XCloseDisplay(display);
366 void BaseDisplay::eventLoop(void)
368 run();
370 int xfd = ConnectionNumber(display);
371 time_t lastCheck = time(NULL);
373 while ((!_shutdown) && (!internal_error)) {
374 if (XPending(display)) {
375 XEvent e;
376 XNextEvent(display, &e);
378 if (last_bad_window != None && e.xany.window == last_bad_window) {
379 #ifdef DEBUG
380 fprintf(stderr, "BaseDisplay::eventLoop(): "
381 "removing bad window from event queue\n");
382 #endif // DEBUG
383 } else {
384 last_bad_window = None;
385 process_event(&e);
387 } else if (time(NULL) - lastCheck > 10) {
388 CheckConfig();
389 lastCheck = time(NULL);
391 } else {
392 fd_set rfds;
393 timeval now, tm, *timeout = (timeval *) 0;
395 FD_ZERO(&rfds);
396 FD_SET(xfd, &rfds);
398 if (timerList->count()) {
399 gettimeofday(&now, 0);
401 tm.tv_sec = tm.tv_usec = 0l;
403 BTimer *timer = timerList->first();
405 tm.tv_sec = timer->getStartTime().tv_sec +
406 timer->getTimeout().tv_sec - now.tv_sec;
407 tm.tv_usec = timer->getStartTime().tv_usec +
408 timer->getTimeout().tv_usec - now.tv_usec;
410 while (tm.tv_usec >= 1000000) {
411 tm.tv_sec++;
412 tm.tv_usec -= 1000000;
415 while (tm.tv_usec < 0) {
416 if (tm.tv_sec > 0) {
417 tm.tv_sec--;
418 tm.tv_usec += 1000000;
419 } else {
420 tm.tv_usec = 0;
421 break;
425 timeout = &tm;
428 select(xfd + 1, &rfds, 0, 0, timeout);
430 // check for timer timeout
431 gettimeofday(&now, 0);
433 LinkedListIterator < BTimer > it(timerList);
434 for (; it.current(); it++) {
435 tm.tv_sec = it.current()->getStartTime().tv_sec +
436 it.current()->getTimeout().tv_sec;
437 tm.tv_usec = it.current()->getStartTime().tv_usec +
438 it.current()->getTimeout().tv_usec;
440 if ((now.tv_sec < tm.tv_sec) ||
441 (now.tv_sec == tm.tv_sec && now.tv_usec < tm.tv_usec))
442 break;
444 it.current()->fireTimeout();
446 // restart the current timer so that the start time is updated
447 if (!it.current()->doOnce())
448 it.current()->start();
449 else
450 it.current()->stop();
457 const Bool BaseDisplay::validateWindow(Window window)
459 XEvent event;
460 if (XCheckTypedWindowEvent(display, window, DestroyNotify, &event)) {
461 XPutBackEvent(display, &event);
463 return False;
466 return True;
470 void BaseDisplay::addTimer(BTimer * timer)
472 if (!timer)
473 return;
475 LinkedListIterator < BTimer > it(timerList);
476 int index = 0;
477 for (; it.current(); it++, index++)
478 if ((it.current()->getTimeout().tv_sec > timer->getTimeout().tv_sec) ||
479 ((it.current()->getTimeout().tv_sec == timer->getTimeout().tv_sec)
480 && (it.current()->getTimeout().tv_usec >=
481 timer->getTimeout().tv_usec))) break;
483 timerList->insert(timer, index);
487 void BaseDisplay::removeTimer(BTimer * timer)
489 timerList->remove(timer);
493 ScreenInfo::ScreenInfo(BaseDisplay * d, int num)
496 basedisplay = d;
497 screen_number = num;
499 root_window = RootWindow(basedisplay->getXDisplay(), screen_number);
500 depth = DefaultDepth(basedisplay->getXDisplay(), screen_number);
502 width =
503 WidthOfScreen(ScreenOfDisplay
504 (basedisplay->getXDisplay(), screen_number));
505 height =
506 HeightOfScreen(ScreenOfDisplay
507 (basedisplay->getXDisplay(), screen_number));
509 // search for a TrueColor Visual... if we can't find one... we will use the
510 // default visual for the screen
511 XVisualInfo vinfo_template, *vinfo_return;
512 int vinfo_nitems;
514 vinfo_template.screen = screen_number;
515 vinfo_template.c_class = TrueColor;
517 visual = (Visual *) 0;
519 if ((vinfo_return = XGetVisualInfo(basedisplay->getXDisplay(),
520 VisualScreenMask | VisualClassMask,
521 &vinfo_template, &vinfo_nitems)) &&
522 vinfo_nitems > 0) {
523 for (int i = 0; i < vinfo_nitems; i++) {
524 if (depth < (vinfo_return + i)->depth) {
525 depth = (vinfo_return + i)->depth;
526 visual = (vinfo_return + i)->visual;
530 XFree(vinfo_return);
533 if (!visual)
534 visual = DefaultVisual(basedisplay->getXDisplay(), screen_number);