- changing MaxInstructions to 100 for cthulhain (crazy nut) =:)
[bbkeys.git] / src / BaseDisplay.cc
blob9a5eb54a2ec35ee2a11da35bfc8f37f8ae00e7b2
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 #include <X11/Xlib.h>
36 #include <X11/Xatom.h>
37 #include <X11/Xutil.h>
38 #include <X11/cursorfont.h>
40 #ifdef SHAPE
41 # include <X11/extensions/shape.h>
42 #endif // SHAPE
44 #include "BaseDisplay.hh"
45 #include "LinkedList.hh"
46 #include "Timer.hh"
48 #ifdef HAVE_FCNTL_H
49 # include <fcntl.h>
50 #endif // HAVE_FCNTL_H
52 #ifdef HAVE_STDIO_H
53 # include <stdio.h>
54 #endif // HAVE_STDIO_H
56 #ifdef STDC_HEADERS
57 # include <stdlib.h>
58 # include <string.h>
59 #endif // STDC_HEADERS
61 #if HAVE_STRINGS_H
62 # include <strings.h>
63 #endif
65 #ifdef HAVE_UNISTD_H
66 # include <sys/types.h>
67 # include <unistd.h>
68 #endif // HAVE_UNISTD_H
70 #ifdef HAVE_SYS_SELECT_H
71 # include <sys/select.h>
72 #endif // HAVE_SYS_SELECT_H
74 #ifdef HAVE_SIGNAL_H
75 # include <signal.h>
76 #endif // HAVE_SIGNAL_H
78 #ifdef HAVE_SYS_SIGNAL_H
79 // # include <sys/signal.h>
80 #endif // HAVE_SYS_SIGNAL_H
82 #ifndef SA_NODEFER
83 # ifdef SA_INTERRUPT
84 # define SA_NODEFER SA_INTERRUPT
85 # else // !SA_INTERRUPT
86 # define SA_NODEFER (0)
87 # endif // SA_INTERRUPT
88 #endif // SA_NODEFER
90 #ifdef HAVE_SYS_WAIT_H
91 # include <sys/types.h>
92 # include <sys/wait.h>
93 #endif // HAVE_SYS_WAIT_H
96 // X error handler to handle any and all X errors while the application is
97 // running
98 static Bool internal_error = False;
99 static Window last_bad_window = None;
101 BaseDisplay *base_display;
103 #ifdef DEBUG
104 static int handleXErrors(Display * d, XErrorEvent * e)
106 char errtxt[128];
108 XGetErrorText(d, e->error_code, errtxt, 128);
109 fprintf(stderr, "%s: X error: %s(%d) opcodes %d/%d\n"
110 " resource 0x%lx\n",
111 base_display->getApplicationName(), errtxt, e->error_code,
112 e->request_code, e->minor_code, e->resourceid);
113 #else // !DEBUG
114 static int handleXErrors(Display *, XErrorEvent * e)
116 #endif // DEBUG
118 if (e->error_code == BadWindow)
119 last_bad_window = e->resourceid;
120 if (internal_error)
121 abort();
123 return (False);
127 // signal handler to allow for proper and gentle shutdown
129 #ifndef HAVE_SIGACTION
130 static RETSIGTYPE signalhandler(int sig)
132 #else // HAVE_SIGACTION
133 static void signalhandler(int sig)
135 #endif // HAVE_SIGACTION
137 static int re_enter = 0;
139 switch (sig) {
140 case SIGCHLD:
141 int status;
142 waitpid(-1, &status, WNOHANG | WUNTRACED);
144 #ifndef HAVE_SIGACTION
145 // assume broken, braindead sysv signal semantics
146 signal(SIGCHLD, (RETSIGTYPE(*)(int)) signalhandler);
147 #endif // HAVE_SIGACTION
149 break;
151 default:
152 if (base_display->handleSignal(sig)) {
154 #ifndef HAVE_SIGACTION
155 // assume broken, braindead sysv signal semantics
156 signal(sig, (RETSIGTYPE(*)(int)) signalhandler);
157 #endif // HAVE_SIGACTION
159 return;
162 fprintf(stderr, "%s: signal %d caught\n",
163 base_display->getApplicationName(), sig);
165 if (!base_display->isStartup() && !re_enter) {
166 internal_error = True;
168 re_enter = 1;
169 fprintf(stderr, "shutting down\n");
170 base_display->shutdown();
173 if (sig != SIGTERM && sig != SIGINT) {
174 fprintf(stderr, "aborting... dumping core\n");
175 abort();
178 exit(0);
180 break;
185 BaseDisplay::BaseDisplay(char *app_name, char *dpy_name)
188 application_name = app_name;
190 _startup = True;
191 _shutdown = False;
192 server_grabs = 0;
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::grab(void)
472 if (!server_grabs++)
473 XGrabServer(display);
477 void BaseDisplay::ungrab(void)
479 if (!--server_grabs)
480 XUngrabServer(display);
482 if (server_grabs < 0)
483 server_grabs = 0;
487 void BaseDisplay::addTimer(BTimer * timer)
489 if (!timer)
490 return;
492 LinkedListIterator < BTimer > it(timerList);
493 int index = 0;
494 for (; it.current(); it++, index++)
495 if ((it.current()->getTimeout().tv_sec > timer->getTimeout().tv_sec) ||
496 ((it.current()->getTimeout().tv_sec == timer->getTimeout().tv_sec)
497 && (it.current()->getTimeout().tv_usec >=
498 timer->getTimeout().tv_usec))) break;
500 timerList->insert(timer, index);
504 void BaseDisplay::removeTimer(BTimer * timer)
506 timerList->remove(timer);
510 ScreenInfo::ScreenInfo(BaseDisplay * d, int num)
513 basedisplay = d;
514 screen_number = num;
516 root_window = RootWindow(basedisplay->getXDisplay(), screen_number);
517 depth = DefaultDepth(basedisplay->getXDisplay(), screen_number);
519 width =
520 WidthOfScreen(ScreenOfDisplay
521 (basedisplay->getXDisplay(), screen_number));
522 height =
523 HeightOfScreen(ScreenOfDisplay
524 (basedisplay->getXDisplay(), screen_number));
526 // search for a TrueColor Visual... if we can't find one... we will use the
527 // default visual for the screen
528 XVisualInfo vinfo_template, *vinfo_return;
529 int vinfo_nitems;
531 vinfo_template.screen = screen_number;
532 vinfo_template.c_class = TrueColor;
534 visual = (Visual *) 0;
536 if ((vinfo_return = XGetVisualInfo(basedisplay->getXDisplay(),
537 VisualScreenMask | VisualClassMask,
538 &vinfo_template, &vinfo_nitems)) &&
539 vinfo_nitems > 0) {
540 for (int i = 0; i < vinfo_nitems; i++) {
541 if (depth < (vinfo_return + i)->depth) {
542 depth = (vinfo_return + i)->depth;
543 visual = (vinfo_return + i)->visual;
547 XFree(vinfo_return);
550 if (!visual)
551 visual = DefaultVisual(basedisplay->getXDisplay(), screen_number);