1/* 2 * Taking over the screen 3 */ 4 5#include "ctwm.h" 6 7#include <stdio.h> 8#include <X11/Xproto.h> 9#include <X11/Xmu/Error.h> 10 11#include "ctwm_takeover.h" 12#include "screen.h" 13 14 15/// Flag for "we got an error trying to take over". Set in temporary 16/// error handler. 17static bool RedirectError; 18 19// Our special during-takeover and normal operating error handlers. 20static int CatchRedirectError(Display *display, XErrorEvent *event); 21static int TwmErrorHandler(Display *display, XErrorEvent *event); 22 23 24 25/** 26 * Take over as WM for a screen 27 */ 28bool 29takeover_screen(ScreenInfo *scr) 30{ 31 unsigned long attrmask; 32 33#ifdef EWMH 34 // Early EWMH setup. This tries to do the EWMH display takeover. 35 EwmhInitScreenEarly(scr); 36#endif 37 38 39 /* 40 * Subscribe to various events on the root window. Because X 41 * only allows a single client to subscribe to 42 * SubstructureRedirect and ButtonPress bits, this also serves to 43 * mutex who is The WM for the root window, and thus (aside from 44 * captive) the Screen. 45 * 46 * To catch whether that failed, we set a special one-shot error 47 * handler to flip a var that we test to find out whether the 48 * redirect failed. 49 */ 50 // Flush out any previous errors 51 XSync(dpy, 0); 52 53 // Set our event listening mask 54 RedirectError = false; 55 XSetErrorHandler(CatchRedirectError); 56 attrmask = ColormapChangeMask | EnterWindowMask | 57 PropertyChangeMask | SubstructureRedirectMask | 58 KeyPressMask | ButtonPressMask | ButtonReleaseMask; 59#ifdef EWMH 60 attrmask |= StructureNotifyMask; 61#endif 62#ifdef CAPTIVE 63 if(CLarg.is_captive) { 64 attrmask |= StructureNotifyMask; 65 } 66#endif 67 XSelectInput(dpy, scr->Root, attrmask); 68 69 // Make sure we flush out any errors that may have caused. This 70 // ensures our RedirectError flag will be set if the server sent us 71 // one. 72 XSync(dpy, 0); 73 74 // Go ahead and set our normal-operation error handler. 75 XSetErrorHandler(TwmErrorHandler); 76 77 // So, did we fail? 78 if(RedirectError) { 79 fprintf(stderr, "%s: another window manager is already running", 80 ProgramName); 81 if(CLarg.MultiScreen && NumScreens > 0) { 82 fprintf(stderr, " on screen %d?\n", scr->screen); 83 } 84 else { 85 fprintf(stderr, "?\n"); 86 } 87 88 // XSetErrorHandler() isn't local to the Screen; it's for the 89 // whole connection. We wind up in a slightly weird state 90 // once we've set it up, but decided we aren't taking over 91 // this screen, but resetting it would be a little weird too, 92 // because maybe we have taken over some other screen. So, 93 // just throw up our hands. 94 return false; 95 } 96 97 // Nope, it's ours! 98 return true; 99} 100 101 102 103/** 104 * Temporary error handler used during startup. We expect an 105 * error if we fail to take over some of the XSelectInput() events 106 * we're trying to (which only 1 thing at a time is allowed to). 107 * Probably that would be a BadAccess error type? But really, any error 108 * means we're in trouble and should skip over the display, so we don't 109 * check any more deeply... 110 */ 111static int 112CatchRedirectError(Display *display, XErrorEvent *event) 113{ 114 // Set the global flag 115 RedirectError = true; 116 return 0; 117} 118 119 120/** 121 * Error handler used in normal operation. Or, perhaps, error ignorer 122 * used in normal operation. If run with `-v`, we'll print out a lot of 123 * the errors we might get, though we always skip several. 124 */ 125static int 126TwmErrorHandler(Display *display, XErrorEvent *event) 127{ 128 if(!CLarg.PrintErrorMessages) { 129 // Not `-v`? Always be silent. 130 return 0; 131 } 132 133 // If a client dies and we try to touch it before we notice, we get a 134 // BadWindow error for most operations, except a few (GetGeometry 135 // being the big one?) where we'll get a BadDrawable. This isn't 136 // really an "error", just a harmless race. 137 if(event->error_code == BadWindow 138 || (event->request_code == X_GetGeometry && event->error_code != BadDrawable)) { 139 return 0; 140 } 141 142 // Else, we're `-v`'d, and it wasn't one of our 'expected' bits, so 143 // talk about it. 144 XmuPrintDefaultErrorMessage(display, event, stderr); 145 return 0; 146} 147