~ctwm/ctwm/trunk

648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
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
648.1.5 by Matthew Fuller
Minor commenting.
15
/// Flag for "we got an error trying to take over".  Set in temporary
16
/// error handler.
17
static bool RedirectError;
18
19
// Our special during-takeover and normal operating error handlers.
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
20
static int CatchRedirectError(Display *display, XErrorEvent *event);
21
static int TwmErrorHandler(Display *display, XErrorEvent *event);
22
23
24
25
/**
26
 * Take over as WM for a screen
27
 */
28
bool
29
takeover_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
	 */
648.1.6 by Matthew Fuller
Comment takeover function a little.
50
	// Flush out any previous errors
51
	XSync(dpy, 0);
52
53
	// Set our event listening mask
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
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
692.1.5 by Matthew Fuller
Add ifdef's around references to Screen and CLargs members that are
62
#ifdef CAPTIVE
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
63
	if(CLarg.is_captive) {
64
		attrmask |= StructureNotifyMask;
65
	}
692.1.5 by Matthew Fuller
Add ifdef's around references to Screen and CLargs members that are
66
#endif
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
67
	XSelectInput(dpy, scr->Root, attrmask);
648.1.6 by Matthew Fuller
Comment takeover function a little.
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.
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
75
	XSetErrorHandler(TwmErrorHandler);
76
648.1.6 by Matthew Fuller
Comment takeover function a little.
77
	// So, did we fail?
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
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
648.1.6 by Matthew Fuller
Comment takeover function a little.
97
	// Nope, it's ours!
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
98
	return true;
99
}
100
101
648.1.4 by Matthew Fuller
Doc and comment error handler funcs. Some logic flow rewritten for
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...
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
110
 */
111
static int
112
CatchRedirectError(Display *display, XErrorEvent *event)
113
{
648.1.4 by Matthew Fuller
Doc and comment error handler funcs. Some logic flow rewritten for
114
	// Set the global flag
648.1.2 by Matthew Fuller
Minimal move of these takeover-related funcs to their own file to
115
	RedirectError = true;
116
	return 0;
117
}
648.1.4 by Matthew Fuller
Doc and comment error handler funcs. Some logic flow rewritten for
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
 */
125
static int
126
TwmErrorHandler(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
648.1.7 by Matthew Fuller
make indent
138
	                || (event->request_code == X_GetGeometry && event->error_code != BadDrawable)) {
648.1.4 by Matthew Fuller
Doc and comment error handler funcs. Some logic flow rewritten for
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
}