~ctwm/ctwm/trunk

304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1
/*
554.1.8 by Matthew Fuller
Pull out long form of Stefan's license bits.
2
 * Copyright 1992, 2005 Stefan Monnier.
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
3
 *
4
 * Author:  Stefan Monnier [ monnier@lia.di.epfl.ch ]
240.1.20 by Olaf 'Rhialto' Seibert
The effects of calling XCirculateSubwindows(3) were not taken into
5
 * Adapted for use with more than one virtual screen by
6
 * Olaf "Rhialto" Seibert <rhialto@falu.nl>.
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
7
 *
8
 * $Id: otp.c,v 1.9 2005/04/08 16:59:25 monnier Exp $
9
 *
10
 * handles all the OnTopPriority-related issues.
11
 *
12
 */
13
395.1.1 by Matthew Fuller
Move ctwm.h to always be included first.
14
#include "ctwm.h"
15
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
16
#include <stdio.h>
491.1.14 by Matthew Fuller
Remove incorrect pre-ANSI potential override prototypes for malloc()
17
#include <stdlib.h>
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
18
#include <assert.h>
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
19
#include <X11/Xatom.h>
340.1.1 by Matthew Fuller
Rearrange includes to be in what we'll call the Proper Order.
20
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
21
#include "otp.h"
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
22
#include "ctwm_atoms.h"
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
23
#include "screen.h"
24
#include "util.h"
25
#include "icons.h"
26
#include "list.h"
240.1.27 by Olaf 'Rhialto' Seibert
After XCirculateSubwindows(), look ahead in the event queue if the expected
27
#include "events.h"
521.1.10 by Matthew Fuller
Break out the prototypes for the event handler functions into their
28
#include "event_handlers.h"
524.1.3 by Matthew Fuller
Pull vscreen.h out of screen.h and #include it directly in the files
29
#include "vscreen.h"
617.1.1 by Matthew Fuller
Fixup setting the OTP for transients of windows that are _FULLSCREEN
30
#include "win_utils.h"
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
31
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
32
#define DEBUG_OTP       0
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
33
#if DEBUG_OTP
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
34
#define DPRINTF(x)      fprintf x
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
35
#else
36
#define DPRINTF(x)
37
#endif
38
39
#if defined(NDEBUG)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
40
# define CHECK_OTP      0
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
41
#else
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
42
# define CHECK_OTP      1
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
43
#endif
44
45
/* number of priorities known to ctwm: [0..ONTOP_MAX] */
46
#define OTP_ZERO 8
47
#define OTP_MAX (OTP_ZERO * 2)
48
575.2.10 by Matthew Fuller
Trace the path down through OtpAdd() converting it to use the newer
49
/* Shorten code a little */
50
#define PRI(owl) OwlEffectivePriority(owl)
51
#define PRI_CP(from, to) do {                  \
52
            to->pri_base = from->pri_base;     \
53
            to->pri_aflags = from->pri_aflags; \
54
        } while(0)
55
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
56
struct OtpWinList {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
57
	OtpWinList *above;
58
	OtpWinList *below;
59
	TwmWindow  *twm_win;
60
	WinType     type;
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
61
	bool        switching;
575.2.1 by Matthew Fuller
Add separate fields in the OWL for tracking the base and alteration
62
	int         pri_base;   // Base priority
63
	unsigned    pri_aflags; // Flags that might alter it; OTP_AFLAG_*
575.2.76 by Matthew Fuller
Add tracking of whether we've got aflags stashed in a property on a
64
	bool        stashed_aflags;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
65
};
66
67
struct OtpPreferences {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
68
	name_list  *priorityL[OTP_MAX + 1];
69
	int         priority;
70
	name_list  *switchingL;
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
71
	bool        switching;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
72
};
73
74
typedef struct Box {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
75
	int x;
76
	int y;
77
	int width;
78
	int height;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
79
} Box;
80
81
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
82
static bool OtpCheckConsistencyVS(VirtualScreen *currentvs, Window vroot);
660.1.1 by Matthew Fuller
Add a func to pretty-print an OWL sequence, that we can use in dev.
83
static void OwlPrettyPrint(const OtpWinList *start);
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
84
static void OwlSetAflagMask(OtpWinList *owl, unsigned mask, unsigned setto);
85
static void OwlSetAflag(OtpWinList *owl, unsigned flag);
86
static void OwlClearAflag(OtpWinList *owl, unsigned flag);
87
static void OwlStashAflags(OtpWinList *owl);
88
static unsigned OwlGetStashedAflags(OtpWinList *owl, bool *gotit);
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
89
static int OwlEffectivePriority(OtpWinList *owl);
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
90
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
91
static Box BoxOfOwl(OtpWinList *owl)
92
{
93
	Box b;
94
95
	switch(owl->type) {
96
		case IconWin: {
97
			Icon *icon = owl->twm_win->icon;
98
99
			b.x = icon->w_x;
100
			b.y = icon->w_y;
101
			b.width = icon->w_width;
102
			b.height = icon->w_height;
103
			break;
104
		}
105
		case WinWin: {
106
			TwmWindow *twm_win = owl->twm_win;
107
108
			b.x = twm_win->frame_x;
109
			b.y = twm_win->frame_y;
110
			b.width = twm_win->frame_width;
111
			b.height = twm_win->frame_height;
112
			break;
113
		}
114
		default:
492.2.110 by Matthew Fuller
Correct some False's that should already be false's on
115
			assert(false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
116
	}
117
	return b;
118
}
119
120
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
121
static bool BoxesIntersect(Box *b1, Box *b2)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
122
{
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
123
	bool interX = (b1->x + b1->width > b2->x) && (b2->x + b2->width > b1->x);
124
	bool interY = (b1->y + b1->height > b2->y) && (b2->y + b2->height > b1->y);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
125
126
	return (interX && interY);
127
}
128
129
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
130
static bool isIntersectingWith(OtpWinList *owl1, OtpWinList *owl2)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
131
{
132
	Box b1 = BoxOfOwl(owl1);
133
	Box b2 = BoxOfOwl(owl2);
134
135
	return BoxesIntersect(&b1, &b2);
136
}
137
138
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
139
static bool isOnScreen(OtpWinList *owl)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
140
{
141
	TwmWindow *twm_win = owl->twm_win;
142
143
	return (((owl->type == IconWin) ? twm_win->iconified : twm_win->mapped)
144
	        && OCCUPY(twm_win, Scr->currentvs->wsw->currentwspc));
145
}
146
147
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
148
bool isTransientOf(TwmWindow *trans, TwmWindow *main)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
149
{
492.2.75 by Matthew Fuller
Convert a bunch of boolean flags in the TwmWindow structure
150
	return (trans->istransient && trans->transientfor == main->w);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
151
}
152
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
153
bool isGroupLeader(TwmWindow *twm_win)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
154
{
155
	return ((twm_win->group == 0)
156
	        || (twm_win->group == twm_win->w));
157
}
158
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
159
bool isGroupLeaderOf(TwmWindow *leader, TwmWindow *twm_win)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
160
{
161
	return (isGroupLeader(leader)
162
	        && !isGroupLeader(twm_win)
163
	        && (leader->group == twm_win->group));
164
}
165
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
166
bool isSmallTransientOf(TwmWindow *trans, TwmWindow *main)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
167
{
168
	int trans_area, main_area;
169
170
	if(isTransientOf(trans, main)) {
171
		assert(trans->frame);
172
		trans_area = trans->frame_width * trans->frame_height;
173
		main_area = main->frame_width * main->frame_height;
174
175
		return (trans_area < ((main_area * Scr->TransientOnTop) / 100));
176
	}
177
	else {
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
178
		return false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
179
	}
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
180
}
181
182
static Window WindowOfOwl(OtpWinList *owl)
183
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
184
	return (owl->type == IconWin)
185
	       ? owl->twm_win->icon->w : owl->twm_win->frame;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
186
}
187
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
188
bool OtpCheckConsistency(void)
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
189
{
190
#if DEBUG_OTP
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
191
	VirtualScreen *tvs;
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
192
	bool result = true;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
193
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
194
	for(tvs = Scr->vScreenList; tvs != NULL; tvs = tvs->next) {
195
		fprintf(stderr, "OtpCheckConsistencyVS: vs:(x,y)=(%d,%d)\n",
196
		        tvs->x, tvs->y);
197
		result = result && OtpCheckConsistencyVS(tvs, tvs->window);
198
	}
199
	return result;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
200
#else
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
201
	return OtpCheckConsistencyVS(Scr->currentvs, Scr->Root);
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
202
#endif
203
}
204
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
205
static bool OtpCheckConsistencyVS(VirtualScreen *currentvs, Window vroot)
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
206
{
207
#if CHECK_OTP
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
208
	OtpWinList *owl;
209
	TwmWindow *twm_win;
210
	Window root, parent, *children;
211
	unsigned int nchildren;
212
	int priority = 0;
213
	int stack = -1;
214
	int nwins = 0;
215
216
	XQueryTree(dpy, vroot, &root, &parent, &children, &nchildren);
217
218
#if DEBUG_OTP
219
	{
220
		int i;
221
		fprintf(stderr, "XQueryTree: %d children:\n", nchildren);
222
223
		for(i = 0; i < nchildren; i++) {
224
			fprintf(stderr, "[%d]=%x ", i, (unsigned int)children[i]);
225
		}
226
		fprintf(stderr, "\n");
227
	}
228
#endif
229
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
230
	for(owl = Scr->bottomOwl; owl != NULL; owl = owl->above) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
231
		twm_win = owl->twm_win;
232
233
		/* check the back arrows are correct */
234
		assert(((owl->type == IconWin) && (owl == twm_win->icon->otp))
235
		       || ((owl->type == WinWin) && (owl == twm_win->otp)));
236
237
		/* check the doubly linked list's consistency */
238
		if(owl->below == NULL) {
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
239
			assert(owl == Scr->bottomOwl);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
240
		}
241
		else {
242
			assert(owl->below->above == owl);
243
		}
244
575.2.20 by Matthew Fuller
Update the consistency checker to ensure things are in the order of
245
		/* Code already ensures this */
246
		assert(owl->pri_base <= OTP_MAX);
247
248
		/* List should be bottom->top, so effective pri better ascend */
660.1.2 by Matthew Fuller
Convert this assert() (which only tells us that it failed) into an
249
		{
250
			const int nextpri = PRI(owl);
251
			if(nextpri < priority) {
252
				fprintf(stderr, "%s(): Priority went backward "
663 by Matthew Fuller
make indent
253
				        "(%d:'%s' -> %d:'%s')\n",
254
				        __func__,
255
				        priority, owl->below->twm_win->name,
256
				        nextpri, owl->twm_win->name);
660.1.2 by Matthew Fuller
Convert this assert() (which only tells us that it failed) into an
257
				OwlPrettyPrint(Scr->bottomOwl);
258
				abort();
259
			}
260
			priority = nextpri;
261
		}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
262
263
#if DEBUG_OTP
264
265
		fprintf(stderr, "checking owl: pri %d w=%x stack=%d",
266
		        priority, (unsigned int)WindowOfOwl(owl), stack);
267
		if(twm_win) {
268
			fprintf(stderr, " title=%s occupation=%x ",
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
269
			        twm_win->name,
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
270
			        (unsigned int)twm_win->occupation);
271
			if(owl->twm_win->vs) {
272
				fprintf(stderr, " vs:(x,y)=(%d,%d)",
273
				        twm_win->vs->x,
274
				        twm_win->vs->y);
275
			}
276
			else {
277
				fprintf(stderr, " vs:NULL");
278
			}
279
			if(owl->twm_win->parent_vs) {
280
				fprintf(stderr, " parent_vs:(x,y)=(%d,%d)",
281
				        twm_win->parent_vs->x,
282
				        twm_win->parent_vs->y);
283
			}
284
			else {
285
				fprintf(stderr, " parent_vs:NULL");
286
			}
287
		}
288
		fprintf(stderr, " %s\n", (owl->type == WinWin ? "Window" : "Icon"));
289
#endif
290
291
		/* count the number of twm windows */
292
		if(owl->type == WinWin) {
293
			nwins++;
294
		}
295
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
296
#ifdef WINBOX
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
297
		if(twm_win->winbox) {
298
			/*
299
			 * We can't check windows in a WindowBox, since they are
300
			 * not direct children of the Root window.
301
			 */
302
			DPRINTF((stderr, "Can't check this window, it is in a WinBox\n"));
303
			continue;
304
		}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
305
#endif
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
306
307
		/*
308
		 * Check only windows from the current vitual screen; the others
309
		 * won't show up in the tree from XQueryTree().
310
		 */
311
		if(currentvs == twm_win->parent_vs) {
312
			/* check the window's existence. */
313
			Window windowOfOwl = WindowOfOwl(owl);
314
315
#if DEBUG_OTP
316
			int i;
317
			for(i = 0; i < nchildren && windowOfOwl != children[i];) {
318
				i++;
319
			}
320
			fprintf(stderr, "search for owl in stack -> i=%d\n", i);
321
			assert(i > stack && "Window not in good place in stack");
322
			assert(i < nchildren && "Window was not found in stack");
323
			if(0) {
324
				char buf[128];
325
				snprintf(buf, 128, "xwininfo -all -id %d", (int)windowOfOwl);
326
				system(buf);
327
			}
328
329
			/* we know that this always increases stack (assert i>stack) */
330
			stack = i;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
331
#else /* DEBUG_OTP */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
332
			/* check against the Xserver's stack */
333
			do {
334
				stack++;
335
				DPRINTF((stderr, "stack++: children[%d] = %x\n", stack,
336
				         (unsigned int)children[stack]));
337
				assert(stack < nchildren);
338
			}
339
			while(windowOfOwl != children[stack]);
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
340
#endif /* DEBUG_OTP */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
341
		}
342
	}
343
344
	XFree(children);
345
346
	/* by decrementing nwins, check that all the wins are in our list */
347
	for(twm_win = Scr->FirstWindow; twm_win != NULL; twm_win = twm_win->next) {
348
		nwins--;
349
	}
350
	/* if we just removed a win, it might still be somewhere, hence the -1 */
351
	assert((nwins <= 0) && (nwins >= -1));
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
352
#endif
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
353
	return true;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
354
}
355
356
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
357
static void RemoveOwl(OtpWinList *owl)
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
358
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
359
	if(owl->above != NULL) {
360
		owl->above->below = owl->below;
361
	}
362
	if(owl->below != NULL) {
363
		owl->below->above = owl->above;
364
	}
365
	else {
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
366
		Scr->bottomOwl = owl->above;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
367
	}
368
	owl->below = NULL;
369
	owl->above = NULL;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
370
}
371
372
373
/**
374
 * For the purpose of putting a window above another,
375
 * they need to have the same parent, i.e. be in the same
376
 * VirtualScreen.
377
 */
378
static OtpWinList *GetOwlAtOrBelowInVS(OtpWinList *owl, VirtualScreen *vs)
379
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
380
	while(owl != NULL && owl->twm_win->parent_vs != vs) {
381
		owl = owl->below;
382
	}
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
383
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
384
	return owl;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
385
}
386
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
387
#ifdef WINBOX
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
388
/*
389
 * Windows in a box don't really occur in the stacking order of the
390
 * root window.
391
 * In the OWL list, keep them just on top of their box, in their
392
 * respective order of course.
393
 * Therefore we may need to update the owl we're going to be above.
394
 */
395
static OtpWinList *GetOwlAtOrBelowInWinbox(OtpWinList **owlp, WindowBox *wb)
396
{
397
	OtpWinList *owl = *owlp;
398
399
	while(owl != NULL && owl->twm_win->winbox != wb) {
400
		owl = owl->below;
401
	}
402
403
	if(owl == NULL) {
404
		/* we have gone below the box: put it just on top of it */
405
		*owlp = wb->twmwin->otp;
406
	}
407
	else {
408
		*owlp = owl;
409
	}
410
	return owl;
411
}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
412
#endif
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
413
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
414
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
415
static void InsertOwlAbove(OtpWinList *owl, OtpWinList *other_owl)
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
416
{
417
#if DEBUG_OTP
579.1.1 by Matthew Fuller
Tweak debug messages.
418
	fprintf(stderr, "InsertOwlAbove owl->pri=%d w=0x%x parent_vs:(x,y)=(%d,%d)",
575.2.37 by Matthew Fuller
Update these debug prints to calc the effective priorities for display
419
	        PRI(owl),
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
420
	        (unsigned int)WindowOfOwl(owl),
421
	        owl->twm_win->parent_vs->x,
422
	        owl->twm_win->parent_vs->y);
423
	if(other_owl != NULL) {
579.1.1 by Matthew Fuller
Tweak debug messages.
424
		fprintf(stderr, "\n  other_owl->pri=%d w=0x%x parent_vs:(x,y)=(%d,%d)",
575.2.37 by Matthew Fuller
Update these debug prints to calc the effective priorities for display
425
		        PRI(other_owl),
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
426
		        (unsigned int)WindowOfOwl(other_owl),
427
		        owl->twm_win->parent_vs->x,
428
		        owl->twm_win->parent_vs->y);
429
	}
430
	fprintf(stderr, "\n");
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
431
#endif
432
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
433
	assert(owl->above == NULL);
434
	assert(owl->below == NULL);
435
436
437
	if(other_owl == NULL) {
438
		DPRINTF((stderr, "Bottom-most window overall\n"));
439
		/* special case for the lowest window overall */
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
440
		assert(PRI(owl) <= PRI(Scr->bottomOwl));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
441
442
		/* pass the action to the Xserver */
443
		XLowerWindow(dpy, WindowOfOwl(owl));
444
445
		/* update the list */
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
446
		owl->above = Scr->bottomOwl;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
447
		owl->above->below = owl;
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
448
		Scr->bottomOwl = owl;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
449
	}
450
	else {
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
451
#ifdef WINBOX
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
452
		WindowBox *winbox = owl->twm_win->winbox;
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
453
#endif
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
454
		OtpWinList *vs_owl;
455
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
456
		if(false) {
457
			// dummy
458
		}
459
#ifdef WINBOX
460
		else if(winbox != NULL) {
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
461
			vs_owl = GetOwlAtOrBelowInWinbox(&other_owl, winbox);
462
		}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
463
#endif
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
464
		else {
465
466
			vs_owl = GetOwlAtOrBelowInVS(other_owl, owl->twm_win->parent_vs);
467
		}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
468
575.2.10 by Matthew Fuller
Trace the path down through OtpAdd() converting it to use the newer
469
		assert(PRI(owl) >= PRI(other_owl));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
470
		if(other_owl->above != NULL) {
575.2.10 by Matthew Fuller
Trace the path down through OtpAdd() converting it to use the newer
471
			assert(PRI(owl) <= PRI(other_owl->above));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
472
		}
473
474
		if(vs_owl == NULL) {
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
475
			DPRINTF((stderr, "Bottom-most window in VirtualScreen or window box\n"));
476
			/* special case for the lowest window in this virtual screen or window box */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
477
478
			/* pass the action to the Xserver */
479
			XLowerWindow(dpy, WindowOfOwl(owl));
480
		}
481
		else {
482
			XWindowChanges xwc;
483
			int xwcm;
484
485
			DPRINTF((stderr, "General case\n"));
486
			/* general case */
575.2.10 by Matthew Fuller
Trace the path down through OtpAdd() converting it to use the newer
487
			assert(PRI(vs_owl) <= PRI(other_owl));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
488
			assert(owl->twm_win->parent_vs == vs_owl->twm_win->parent_vs);
489
490
			/* pass the action to the Xserver */
491
			xwcm = CWStackMode | CWSibling;
492
			xwc.sibling = WindowOfOwl(vs_owl);
493
			xwc.stack_mode = Above;
494
			XConfigureWindow(dpy, WindowOfOwl(owl), xwcm, &xwc);
495
		}
496
497
		/* update the list */
498
		owl->below = other_owl;
499
		owl->above = other_owl->above;
500
		owl->below->above = owl;
501
		if(owl->above != NULL) {
502
			owl->above->below = owl;
503
		}
504
	}
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
505
}
506
507
508
/* should owl stay above other_owl if other_owl was raised ? */
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
509
static bool shouldStayAbove(OtpWinList *owl, OtpWinList *other_owl)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
510
{
511
	return ((owl->type == WinWin)
512
	        && (other_owl->type == WinWin)
513
	        && isSmallTransientOf(owl->twm_win, other_owl->twm_win));
514
}
515
516
517
static void RaiseSmallTransientsOfAbove(OtpWinList *owl, OtpWinList *other_owl)
518
{
519
	OtpWinList *trans_owl, *tmp_owl;
520
521
	/* the icons have no transients and we can't have windows below NULL */
522
	if((owl->type != WinWin) || other_owl == NULL) {
523
		return;
524
	}
525
526
	/* beware: we modify the list as we scan it. This is the reason for tmp */
527
	for(trans_owl = other_owl->below; trans_owl != NULL; trans_owl = tmp_owl) {
528
		tmp_owl = trans_owl->below;
529
		if(shouldStayAbove(trans_owl, owl)) {
530
			RemoveOwl(trans_owl);
575.2.10 by Matthew Fuller
Trace the path down through OtpAdd() converting it to use the newer
531
			PRI_CP(owl, trans_owl);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
532
			InsertOwlAbove(trans_owl, other_owl);
533
		}
534
	}
535
}
536
537
538
static OtpWinList *OwlRightBelow(int priority)
539
{
540
	OtpWinList *owl1, *owl2;
541
542
	/* in case there isn't anything below */
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
543
	if(priority <= PRI(Scr->bottomOwl)) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
544
		return NULL;
545
	}
546
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
547
	for(owl1 = Scr->bottomOwl, owl2 = owl1->above;
575.2.14 by Matthew Fuller
Update the process of respositioning a win's transients so it does the
548
	                (owl2 != NULL) && (PRI(owl2) < priority);
575.2.104 by Matthew Fuller
Make this empty for more explicit about it.
549
	                owl1 = owl2, owl2 = owl2->above) {
550
		/* nada */;
551
	}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
552
553
	assert(owl2 == owl1->above);
575.2.14 by Matthew Fuller
Update the process of respositioning a win's transients so it does the
554
	assert(PRI(owl1) < priority);
555
	assert((owl2 == NULL) || (PRI(owl2) >= priority));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
556
557
558
	return owl1;
559
}
560
561
static void InsertOwl(OtpWinList *owl, int where)
562
{
563
	OtpWinList *other_owl;
564
	int priority;
565
566
	DPRINTF((stderr, "InsertOwl %s\n",
567
	         (where == Above) ? "Above" :
568
	         (where == Below) ? "Below" :
569
	         "???"));
570
	assert(owl->above == NULL);
571
	assert(owl->below == NULL);
572
	assert((where == Above) || (where == Below));
573
575.2.27 by Matthew Fuller
Whoops, got this condition backward in converting.
574
	priority = PRI(owl) - (where == Above ? 0 : 1);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
575
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
576
	if(Scr->bottomOwl == NULL) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
577
		/* for the first window: just insert it in the list */
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
578
		Scr->bottomOwl = owl;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
579
	}
580
	else {
581
		other_owl = OwlRightBelow(priority + 1);
582
583
		/* make sure other_owl is not one of the transients */
584
		while((other_owl != NULL)
585
		                && shouldStayAbove(other_owl, owl)) {
575.2.10 by Matthew Fuller
Trace the path down through OtpAdd() converting it to use the newer
586
			PRI_CP(owl, other_owl);
587
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
588
			other_owl = other_owl->below;
589
		}
590
591
		/* raise the transient windows that should stay on top */
592
		RaiseSmallTransientsOfAbove(owl, other_owl);
593
594
		/* now go ahead and put the window where it should go */
595
		InsertOwlAbove(owl, other_owl);
596
	}
597
}
598
599
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
600
static void SetOwlPriority(OtpWinList *owl, int new_pri, int where)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
601
{
602
	DPRINTF((stderr, "SetOwlPriority(%d)\n", new_pri));
603
604
	/* make sure the values are within bounds */
605
	if(new_pri < 0) {
606
		new_pri = 0;
607
	}
608
	if(new_pri > OTP_MAX) {
609
		new_pri = OTP_MAX;
610
	}
611
612
	RemoveOwl(owl);
575.2.17 by Matthew Fuller
Update SetOwlPriority() to set the base.
613
	owl->pri_base = new_pri;
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
614
	InsertOwl(owl, where);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
615
575.2.21 by Matthew Fuller
Correct assertion that checks what we just set.
616
	assert(owl->pri_base == new_pri);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
617
}
618
619
575.2.14 by Matthew Fuller
Update the process of respositioning a win's transients so it does the
620
/*
621
 * Shift transients of a window to a new [base] priority, preparatory to
622
 * moving that window itself there.
623
 */
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
624
static void TryToMoveTransientsOfTo(OtpWinList *owl, int priority, int where)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
625
{
575.2.107 by Matthew Fuller
Localize var.
626
	OtpWinList *other_owl;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
627
628
	/* the icons have no transients */
629
	if(owl->type != WinWin) {
630
		return;
631
	}
632
575.2.105 by Matthew Fuller
Add comment.
633
	/*
634
	 * We start looking for transients of owl at the bottom of its OTP
635
	 * layer.
636
	 */
575.2.14 by Matthew Fuller
Update the process of respositioning a win's transients so it does the
637
	other_owl = OwlRightBelow(PRI(owl));
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
638
	other_owl = (other_owl == NULL) ? Scr->bottomOwl : other_owl->above;
575.2.14 by Matthew Fuller
Update the process of respositioning a win's transients so it does the
639
	assert(PRI(other_owl) >= PRI(owl));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
640
641
	/* !beware! we're changing the list as we scan it, hence the tmp_owl */
575.2.14 by Matthew Fuller
Update the process of respositioning a win's transients so it does the
642
	while((other_owl != NULL) && (PRI(other_owl) == PRI(owl))) {
575.2.107 by Matthew Fuller
Localize var.
643
		OtpWinList *tmp_owl = other_owl->above;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
644
		if((other_owl->type == WinWin)
645
		                && isTransientOf(other_owl->twm_win, owl->twm_win)) {
575.2.14 by Matthew Fuller
Update the process of respositioning a win's transients so it does the
646
			/* Copy in our flags so it winds up in the right place */
575.2.103 by Matthew Fuller
We're about to override the pri_base anyway in SOP(), so just manually
647
			other_owl->pri_aflags = owl->pri_aflags;
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
648
			SetOwlPriority(other_owl, priority, where);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
649
		}
650
		other_owl = tmp_owl;
651
	}
652
}
653
654
static void TryToSwitch(OtpWinList *owl, int where)
655
{
656
	int priority;
657
658
	if(!owl->switching) {
659
		return;
660
	}
661
575.2.15 by Matthew Fuller
We need to write in the new pri_base here so the calculations in
662
	/*
663
	 * Switching is purely an adjustment to the base priority, so we
664
	 * don't need to figure stuff based on the effective.
665
	 */
666
	priority = OTP_MAX - owl->pri_base;
667
	if(((where == Above) && (priority > owl->pri_base)) ||
668
	                ((where == Below) && (priority < owl->pri_base))) {
575.2.106 by Matthew Fuller
This actually does need to be in the original order; return it and add
669
		/*
670
		 * TTMTOT() before changing pri_base since it uses the current
671
		 * state to find the transients.
672
		 */
673
		TryToMoveTransientsOfTo(owl, priority, where);
575.2.15 by Matthew Fuller
We need to write in the new pri_base here so the calculations in
674
		owl->pri_base = priority;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
675
	}
676
}
677
678
static void RaiseOwl(OtpWinList *owl)
679
{
680
	TryToSwitch(owl, Above);
681
	RemoveOwl(owl);
682
	InsertOwl(owl, Above);
683
}
684
685
686
static void LowerOwl(OtpWinList *owl)
687
{
688
	TryToSwitch(owl, Below);
689
	RemoveOwl(owl);
690
	InsertOwl(owl, Below);
691
}
692
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
693
static bool isHiddenBy(OtpWinList *owl, OtpWinList *other_owl)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
694
{
695
	/* doesn't check that owl is on screen */
696
	return (isOnScreen(other_owl)
697
	        && isIntersectingWith(owl, other_owl));
698
}
699
700
static void TinyRaiseOwl(OtpWinList *owl)
701
{
702
	OtpWinList *other_owl = owl->above;
703
575.2.22 by Matthew Fuller
These tiny{raise,lower} bits need to compare effective priorities.
704
	while((other_owl != NULL) && (PRI(other_owl) == PRI(owl))) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
705
		if(isHiddenBy(owl, other_owl)
706
		                && !shouldStayAbove(other_owl, owl)) {
707
			RemoveOwl(owl);
708
			RaiseSmallTransientsOfAbove(owl, other_owl);
709
			InsertOwlAbove(owl, other_owl);
710
			return;
711
		}
712
		else {
713
			other_owl = other_owl->above;
714
		}
715
	}
716
}
717
718
static void TinyLowerOwl(OtpWinList *owl)
719
{
720
	OtpWinList *other_owl = owl->below;
721
575.2.22 by Matthew Fuller
These tiny{raise,lower} bits need to compare effective priorities.
722
	while((other_owl != NULL) && (PRI(other_owl) == PRI(owl))) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
723
		if(isHiddenBy(owl, other_owl)) {
724
			RemoveOwl(owl);
725
			InsertOwlAbove(owl, other_owl->below);
726
			return;
727
		}
728
		else {
729
			other_owl = other_owl->below;
730
		}
731
	}
732
}
733
734
static void RaiseLowerOwl(OtpWinList *owl)
735
{
736
	OtpWinList *other_owl;
737
	int priority;
738
575.2.23 by Matthew Fuller
Update f.raiselower backend bits to NWO. This function doesn't make a
739
	/*
740
	 * abs(effective pri)
575.2.41 by Matthew Fuller
make indent
741
	 *
575.2.23 by Matthew Fuller
Update f.raiselower backend bits to NWO. This function doesn't make a
742
	 * XXX Why?  This seems like it's encoding the assumption
743
	 * "f.raiselower should assume any negative [user-level] priorities
744
	 * are a result of a window that should be positive being switched,
745
	 * and we should switch it positive before raising if we need to", or
746
	 * some such.
747
	 */
748
	priority = MAX(PRI(owl), OTP_MAX - PRI(owl));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
749
750
	for(other_owl = owl->above;
575.2.23 by Matthew Fuller
Update f.raiselower backend bits to NWO. This function doesn't make a
751
	                (other_owl != NULL) && (PRI(other_owl) <= priority);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
752
	                other_owl = other_owl->above) {
753
		if(isHiddenBy(owl, other_owl)
754
		                && !shouldStayAbove(other_owl, owl)) {
755
			RaiseOwl(owl);
756
			return;
757
		}
758
	}
759
	LowerOwl(owl);
760
}
761
762
763
void OtpRaise(TwmWindow *twm_win, WinType wintype)
764
{
765
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
766
	assert(owl != NULL);
767
768
	RaiseOwl(owl);
769
770
	OtpCheckConsistency();
302.1.37 by Olaf 'Rhialto' Seibert
Add _NET_CLIENT_LIST_STACKING. Flesh out _NET_WM_DESKTOP (obey initial value
771
#ifdef EWMH
772
	EwmhSet_NET_CLIENT_LIST_STACKING();
773
#endif /* EWMH */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
774
}
775
776
777
void OtpLower(TwmWindow *twm_win, WinType wintype)
778
{
779
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
780
	assert(owl != NULL);
781
782
	LowerOwl(owl);
783
784
	OtpCheckConsistency();
302.1.37 by Olaf 'Rhialto' Seibert
Add _NET_CLIENT_LIST_STACKING. Flesh out _NET_WM_DESKTOP (obey initial value
785
#ifdef EWMH
786
	EwmhSet_NET_CLIENT_LIST_STACKING();
787
#endif /* EWMH */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
788
}
789
790
791
void OtpRaiseLower(TwmWindow *twm_win, WinType wintype)
792
{
793
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
794
	assert(owl != NULL);
795
796
	RaiseLowerOwl(owl);
797
798
	OtpCheckConsistency();
302.1.37 by Olaf 'Rhialto' Seibert
Add _NET_CLIENT_LIST_STACKING. Flesh out _NET_WM_DESKTOP (obey initial value
799
#ifdef EWMH
800
	EwmhSet_NET_CLIENT_LIST_STACKING();
801
#endif /* EWMH */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
802
}
803
804
805
void OtpTinyRaise(TwmWindow *twm_win, WinType wintype)
806
{
807
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
808
	assert(owl != NULL);
809
810
	TinyRaiseOwl(owl);
811
812
	OtpCheckConsistency();
302.1.37 by Olaf 'Rhialto' Seibert
Add _NET_CLIENT_LIST_STACKING. Flesh out _NET_WM_DESKTOP (obey initial value
813
#ifdef EWMH
814
	EwmhSet_NET_CLIENT_LIST_STACKING();
815
#endif /* EWMH */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
816
}
817
818
819
void OtpTinyLower(TwmWindow *twm_win, WinType wintype)
820
{
821
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
822
	assert(owl != NULL);
823
824
	TinyLowerOwl(owl);
825
826
	OtpCheckConsistency();
302.1.37 by Olaf 'Rhialto' Seibert
Add _NET_CLIENT_LIST_STACKING. Flesh out _NET_WM_DESKTOP (obey initial value
827
#ifdef EWMH
828
	EwmhSet_NET_CLIENT_LIST_STACKING();
829
#endif /* EWMH */
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
830
}
831
832
240.1.20 by Olaf 'Rhialto' Seibert
The effects of calling XCirculateSubwindows(3) were not taken into
833
/*
834
 * XCirculateSubwindows() is complicated by the fact that it restacks only
835
 * in case of overlapping windows. Therefore it seems easier to not
836
 * try to emulate that but to leave it to the X server.
837
 *
838
 * If XCirculateSubwindows() actually does something, it sends a
839
 * CirculateNotify event, but you only receive it if
840
 * SubstructureNotifyMask is selected on the root window.
841
 * However... if that is done from the beginning, for some reason all
842
 * windows disappear when ctwm starts or exits.
843
 * Maybe SubstructureNotifyMask interferes with SubstructureRedirectMask?
844
 *
845
 * To get around that, the SubstructureNotifyMask is selected only
846
 * temporarily here when wanted.
847
 */
848
849
void OtpCirculateSubwindows(VirtualScreen *vs, int direction)
850
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
851
	Window w = vs->window;
852
	XWindowAttributes winattrs;
853
	Bool circulated;
854
855
	DPRINTF((stderr, "OtpCirculateSubwindows %d\n", direction));
856
857
	XGetWindowAttributes(dpy, w, &winattrs);
858
	XSelectInput(dpy, w, winattrs.your_event_mask | SubstructureNotifyMask);
859
	XCirculateSubwindows(dpy, w, direction);
860
	XSelectInput(dpy, w, winattrs.your_event_mask);
861
	/*
862
	 * Now we should get the CirculateNotify event.
863
	 * It usually seems to arrive soon enough, but just to be sure, look
864
	 * ahead in the message queue to see if it can be expedited.
865
	 */
866
	circulated = XCheckTypedWindowEvent(dpy, w, CirculateNotify, &Event);
867
	if(circulated) {
868
		HandleCirculateNotify();
869
	}
240.1.20 by Olaf 'Rhialto' Seibert
The effects of calling XCirculateSubwindows(3) were not taken into
870
}
871
872
/*
873
 * Update our list of Owls after the Circulate action, and also
874
 * enforce the priority by possibly restacking the window again.
875
 */
876
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
877
void OtpHandleCirculateNotify(VirtualScreen *vs, TwmWindow *twm_win,
878
                              WinType wintype, int place)
879
{
880
	switch(place) {
881
		case PlaceOnTop:
882
			OtpRaise(twm_win, wintype);
883
			break;
884
		case PlaceOnBottom:
885
			OtpLower(twm_win, wintype);
886
			break;
887
		default:
888
			DPRINTF((stderr, "OtpHandleCirculateNotify: place=%d\n", place));
889
			assert(0 &&
890
			       "OtpHandleCirculateNotify: place equals PlaceOnTop nor PlaceOnBottom");
891
	}
892
}
893
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
894
void OtpSetPriority(TwmWindow *twm_win, WinType wintype, int new_pri, int where)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
895
{
896
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
897
	int priority = OTP_ZERO + new_pri;
898
899
	DPRINTF((stderr, "OtpSetPriority: new_pri=%d\n", new_pri));
900
	assert(owl != NULL);
901
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
902
#ifdef WINBOX
313.1.16 by Olaf 'Rhialto' Seibert
Simplify a few tests.
903
	if(twm_win->winbox != NULL || twm_win->iswinbox) {
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
904
		return;
905
	}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
906
#endif
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
907
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
908
	if(ABS(new_pri) > OTP_ZERO) {
909
		DPRINTF((stderr, "invalid OnTopPriority value: %d\n", new_pri));
910
	}
911
	else {
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
912
		TryToMoveTransientsOfTo(owl, priority, where);
913
		SetOwlPriority(owl, priority, where);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
914
	}
915
916
	OtpCheckConsistency();
917
}
918
919
920
void OtpChangePriority(TwmWindow *twm_win, WinType wintype, int relpriority)
921
{
922
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
575.2.16 by Matthew Fuller
Make the f.changepriority and f.switchpriority bits adjust the
923
	int priority = owl->pri_base + relpriority;
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
924
	int where;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
925
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
926
#ifdef WINBOX
313.1.16 by Olaf 'Rhialto' Seibert
Simplify a few tests.
927
	if(twm_win->winbox != NULL || twm_win->iswinbox) {
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
928
		return;
929
	}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
930
#endif
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
931
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
932
	where = relpriority < 0 ? Below : Above;
933
934
	TryToMoveTransientsOfTo(owl, priority, where);
935
	SetOwlPriority(owl, priority, where);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
936
937
	OtpCheckConsistency();
938
}
939
940
941
void OtpSwitchPriority(TwmWindow *twm_win, WinType wintype)
942
{
943
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
575.2.16 by Matthew Fuller
Make the f.changepriority and f.switchpriority bits adjust the
944
	int priority = OTP_MAX - owl->pri_base;
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
945
	int where;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
946
947
	assert(owl != NULL);
948
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
949
#ifdef WINBOX
313.1.16 by Olaf 'Rhialto' Seibert
Simplify a few tests.
950
	if(twm_win->winbox != NULL || twm_win->iswinbox) {
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
951
		return;
952
	}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
953
#endif
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
954
302.1.64 by Olaf 'Rhialto' Seibert
Make sure that windows which leave the F_FULLSCREENZOOM state also get
955
	where = priority < OTP_ZERO ? Below : Above;
956
	TryToMoveTransientsOfTo(owl, priority, where);
957
	SetOwlPriority(owl, priority, where);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
958
959
	OtpCheckConsistency();
960
}
961
962
963
void OtpToggleSwitching(TwmWindow *twm_win, WinType wintype)
964
{
965
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
966
	assert(owl != NULL);
967
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
968
#ifdef WINBOX
313.1.16 by Olaf 'Rhialto' Seibert
Simplify a few tests.
969
	if(twm_win->winbox != NULL || twm_win->iswinbox) {
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
970
		return;
971
	}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
972
#endif
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
973
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
974
	owl->switching = !owl->switching;
975
976
	OtpCheckConsistency();
977
}
978
979
575.2.19 by Matthew Fuller
Comment ForcePlacement and implement a best guess as to how it should
980
/*
981
 * This is triggered as a result of a StackMode ConfigureRequest.  We
982
 * choose to interpret this as restacking relative to the base
983
 * priorities, since all the alterations are EWMH-related, and those
575.2.108 by Matthew Fuller
Expand comment a little; I'm not entirely sure of the best choice
984
 * should probably override.
985
 *
986
 * XXX Or should they?  Maybe we should alter until our effective is
987
 * positioned as desired relative to their effective?  This may also need
988
 * revisiting if we grow alterations that aren't a result of EWMH stuff.
575.2.19 by Matthew Fuller
Comment ForcePlacement and implement a best guess as to how it should
989
 */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
990
void OtpForcePlacement(TwmWindow *twm_win, int where, TwmWindow *other_win)
991
{
992
	OtpWinList *owl = twm_win->otp;
993
	OtpWinList *other_owl = other_win->otp;
994
995
	assert(twm_win->otp != NULL);
996
	assert(other_win->otp != NULL);
997
998
	if(where == BottomIf) {
999
		where = Below;
1000
	}
1001
	if(where != Below) {
1002
		where = Above;
1003
	}
1004
1005
	/* remove the owl to change it */
1006
	RemoveOwl(owl);
1007
575.2.19 by Matthew Fuller
Comment ForcePlacement and implement a best guess as to how it should
1008
	/*
1009
	 * Base our priority base off that other win.  Don't use PRI_CP since
1010
	 * we shouldn't suddenly get its flags as well.
1011
	 */
1012
	owl->pri_base = other_owl->pri_base;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1013
1014
	/* put the owl back into the list */
1015
	if(where == Below) {
1016
		other_owl = other_owl->below;
1017
	}
1018
	InsertOwlAbove(owl, other_owl);
1019
1020
	OtpCheckConsistency();
1021
}
1022
1023
1024
static void ApplyPreferences(OtpPreferences *prefs, OtpWinList *owl)
1025
{
1026
	int i;
1027
	TwmWindow *twm_win = owl->twm_win;
1028
1029
	/* check PrioritySwitch */
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
1030
	if(LookInList(prefs->switchingL, twm_win->name, &twm_win->class)) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1031
		owl->switching = !prefs->switching;
1032
	}
1033
1034
	/* check OnTopPriority */
1035
	for(i = 0; i <= OTP_MAX; i++) {
1036
		if(LookInList(prefs->priorityL[i],
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
1037
		                twm_win->name, &twm_win->class)) {
575.2.4 by Matthew Fuller
Start setting into pri_base instead of priority in the setup and
1038
			owl->pri_base = i;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1039
		}
1040
	}
1041
}
1042
575.2.18 by Matthew Fuller
Rename these funcs to better describe just what they do, and make them
1043
1044
/*
1045
 * Reset stuff based on preferences; called during property changes if
1046
 * AutoPriority set.
1047
 */
1048
static void RecomputeOwlPrefs(OtpPreferences *prefs, OtpWinList *owl)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1049
{
1050
	int old_pri;
1051
575.2.18 by Matthew Fuller
Rename these funcs to better describe just what they do, and make them
1052
	old_pri = owl->pri_base;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1053
	ApplyPreferences(prefs, owl);
575.2.18 by Matthew Fuller
Rename these funcs to better describe just what they do, and make them
1054
	if(old_pri != owl->pri_base) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1055
		RemoveOwl(owl);
1056
		InsertOwl(owl, Above);
575.2.87 by Matthew Fuller
Sketch in still-commented-out bits for setting priority bits.
1057
1058
		/*
575.2.91 by Matthew Fuller
Simplify this logic a bit.
1059
		 * Stash flags if we don't have any yet, since we just changed
1060
		 * the priority.
575.2.88 by Matthew Fuller
Setup stashing as necessary on recompute.
1061
		 */
575.2.91 by Matthew Fuller
Simplify this logic a bit.
1062
		if(!owl->stashed_aflags) {
1063
			OwlStashAflags(owl);
1064
		}
1065
575.2.88 by Matthew Fuller
Setup stashing as necessary on recompute.
1066
#ifdef EWMH
575.2.91 by Matthew Fuller
Simplify this logic a bit.
1067
		/* Let other things know we did something with stacking */
1068
		EwmhSet_NET_WM_STATE(owl->twm_win, EWMH_STATE_ABOVE);
575.2.88 by Matthew Fuller
Setup stashing as necessary on recompute.
1069
#endif
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1070
	}
1071
}
1072
575.2.18 by Matthew Fuller
Rename these funcs to better describe just what they do, and make them
1073
void OtpRecomputePrefs(TwmWindow *twm_win)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1074
{
1075
	assert(twm_win->otp != NULL);
1076
575.2.18 by Matthew Fuller
Rename these funcs to better describe just what they do, and make them
1077
	RecomputeOwlPrefs(Scr->OTP, twm_win->otp);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1078
	if(twm_win->icon != NULL) {
575.2.18 by Matthew Fuller
Rename these funcs to better describe just what they do, and make them
1079
		RecomputeOwlPrefs(Scr->IconOTP, twm_win->icon->otp);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1080
	}
1081
1082
	OtpCheckConsistency();
1083
}
1084
1085
1086
static void free_OtpWinList(OtpWinList *owl)
1087
{
1088
	assert(owl->above == NULL);
1089
	assert(owl->below == NULL);
1090
	free(owl);
1091
}
1092
1093
1094
void OtpRemove(TwmWindow *twm_win, WinType wintype)
1095
{
1096
	OtpWinList **owlp;
1097
	owlp = (wintype == IconWin) ? &twm_win->icon->otp : &twm_win->otp;
1098
1099
	assert(*owlp != NULL);
1100
1101
	RemoveOwl(*owlp);
1102
	free_OtpWinList(*owlp);
1103
	*owlp = NULL;
1104
1105
	OtpCheckConsistency();
1106
}
1107
1108
1109
static OtpWinList *new_OtpWinList(TwmWindow *twm_win,
1110
                                  WinType wintype,
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
1111
                                  bool switching,
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1112
                                  int priority)
1113
{
491.1.8 by Matthew Fuller
Stop casting return values of [mc]alloc(). void * has existed for 27
1114
	OtpWinList *owl = malloc(sizeof(OtpWinList));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1115
1116
	owl->above = NULL;
1117
	owl->below = NULL;
1118
	owl->twm_win = twm_win;
1119
	owl->type = wintype;
1120
	owl->switching = switching;
575.2.2 by Matthew Fuller
Init new fields.
1121
	owl->pri_base = priority;
1122
	owl->pri_aflags = 0;
575.2.92 by Matthew Fuller
Pre-initialize stashed to true for icons; they don't need anything
1123
1124
	/*
1125
	 * We never need to stash anything for icons, they don't persist
575.2.109 by Matthew Fuller
Slightly improve comment.
1126
	 * across restart anyway.  So pretend we did stash already to
1127
	 * discourage other code from trying to stash.
575.2.92 by Matthew Fuller
Pre-initialize stashed to true for icons; they don't need anything
1128
	 */
1129
	owl->stashed_aflags = (wintype == WinWin ? false : true);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1130
1131
	return owl;
1132
}
1133
1134
static OtpWinList *AddNewOwl(TwmWindow *twm_win, WinType wintype,
1135
                             OtpWinList *parent)
1136
{
1137
	OtpWinList *owl;
1138
	OtpPreferences *prefs = (wintype == IconWin) ? Scr->IconOTP : Scr->OTP;
1139
1140
	/* make the new owl */
1141
	owl = new_OtpWinList(twm_win, wintype,
1142
	                     prefs->switching, prefs->priority);
1143
1144
	/* inherit the default attributes from the parent window if appropriate */
1145
	if(parent != NULL) {
575.2.110 by Matthew Fuller
If we're pulling from a parent here, we should inherit its flags as
1146
		PRI_CP(parent, owl);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1147
		owl->switching = parent->switching;
1148
	}
1149
1150
	/* now see if the preferences have something to say */
492.2.75 by Matthew Fuller
Convert a bunch of boolean flags in the TwmWindow structure
1151
	if(!(parent != NULL && twm_win->istransient)) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1152
		ApplyPreferences(prefs, owl);
1153
	}
1154
575.2.32 by Matthew Fuller
Check EWMH stuff in AddNewOwl() to allow DESKTOP/DOCK to default
1155
#ifdef EWMH
1156
	/* If nothing came in, EWMH might have something to say */
1157
	if(owl->pri_base == 0) {
575.2.100 by Matthew Fuller
Use OTP_ZERO to properly offset comparisons against display-style
1158
		owl->pri_base = EwmhGetInitPriority(twm_win) + OTP_ZERO;
575.2.32 by Matthew Fuller
Check EWMH stuff in AddNewOwl() to allow DESKTOP/DOCK to default
1159
	}
1160
#endif
1161
575.2.97 by Matthew Fuller
Fixup dealing with these stashed flags when built without EWMH.
1162
	/*
1163
	 * Initialize flags.  Right now, the only stashed flags are related
1164
	 * to EWMH requests, so in a sense this whole thing could be dropped
1165
	 * under #ifdef.  But I'll assume that might not always be the case,
1166
	 * so for now the !(EWMH) case is just a twisty noop.
1167
	 */
575.2.81 by Matthew Fuller
Inline the logic from getting stashed info. It winds up being less
1168
	{
575.2.97 by Matthew Fuller
Fixup dealing with these stashed flags when built without EWMH.
1169
		bool gotflags = false;
1170
		unsigned aflags = 0, fromstash = 0;
1171
1172
		aflags = OwlGetStashedAflags(owl, &gotflags);
1173
1174
#ifdef EWMH
1175
		fromstash = (OTP_AFLAG_ABOVE | OTP_AFLAG_BELOW);
1176
#endif
575.2.81 by Matthew Fuller
Inline the logic from getting stashed info. It winds up being less
1177
1178
		if(gotflags) {
1179
			/*
1180
			 * Got stashed OTP flags; use 'em.  Explicitly mask in only
575.2.97 by Matthew Fuller
Fixup dealing with these stashed flags when built without EWMH.
1181
			 * the flags we're caring about; the others aren't telling us
1182
			 * info we need to persist.
575.2.81 by Matthew Fuller
Inline the logic from getting stashed info. It winds up being less
1183
			 */
575.2.97 by Matthew Fuller
Fixup dealing with these stashed flags when built without EWMH.
1184
			aflags &= fromstash;
575.2.81 by Matthew Fuller
Inline the logic from getting stashed info. It winds up being less
1185
		}
1186
575.2.13 by Matthew Fuller
Set flags from EWMH bits when creating the OWL for a window.
1187
#ifdef EWMH
575.2.81 by Matthew Fuller
Inline the logic from getting stashed info. It winds up being less
1188
		/* FULLSCREEN we get from the normal EWMH prop no matter what */
1189
		if(twm_win->ewmhFlags & EWMH_STATE_FULLSCREEN) {
1190
			aflags |= OTP_AFLAG_FULLSCREEN;
1191
		}
1192
1193
		if(!gotflags) {
1194
			/* Nothing from OTP about above/below; check EWMH */
1195
			aflags = 0;
1196
			if(twm_win->ewmhFlags & EWMH_STATE_ABOVE) {
1197
				aflags |= OTP_AFLAG_ABOVE;
1198
			}
1199
			if(twm_win->ewmhFlags & EWMH_STATE_BELOW) {
1200
				aflags |= OTP_AFLAG_BELOW;
1201
			}
1202
		}
575.2.97 by Matthew Fuller
Fixup dealing with these stashed flags when built without EWMH.
1203
#endif // EWMH
575.2.13 by Matthew Fuller
Set flags from EWMH bits when creating the OWL for a window.
1204
575.2.96 by Matthew Fuller
Tweak comments/whitespace.
1205
		/* Set whatever we figured */
575.2.81 by Matthew Fuller
Inline the logic from getting stashed info. It winds up being less
1206
		owl->pri_aflags |= aflags;
575.2.85 by Matthew Fuller
Mark whether we found stashed aflags.
1207
		owl->stashed_aflags = gotflags;
575.2.86 by Matthew Fuller
Initialize the stashed aflags if we don't have any and the effective
1208
575.2.96 by Matthew Fuller
Tweak comments/whitespace.
1209
		/* If we set a priority or flags, we should stash away flags */
575.2.90 by Matthew Fuller
Actually, even if pri=0, we should store if flags != 0 too.
1210
		if((PRI(owl) != OTP_ZERO || owl->pri_aflags != 0)
1211
		                && !owl->stashed_aflags) {
575.2.86 by Matthew Fuller
Initialize the stashed aflags if we don't have any and the effective
1212
			OwlStashAflags(owl);
1213
		}
575.2.81 by Matthew Fuller
Inline the logic from getting stashed info. It winds up being less
1214
	}
1215
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1216
	/* finally put the window where it should go */
1217
	InsertOwl(owl, Above);
1218
1219
	return owl;
1220
}
1221
1222
void OtpAdd(TwmWindow *twm_win, WinType wintype)
1223
{
1224
	TwmWindow *other_win;
1225
	OtpWinList *parent = NULL;
1226
	OtpWinList **owlp;
1227
	owlp = (wintype == IconWin) ? &twm_win->icon->otp : &twm_win->otp;
1228
1229
	assert(*owlp == NULL);
1230
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
1231
	if(false) {
1232
		// dummy
1233
	}
1234
#ifdef WINBOX
1235
	else if(twm_win->winbox) {
1236
		/* windows in boxes *must* inherit priority from the box */
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
1237
		parent = twm_win->winbox->twmwin->otp;
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
1238
		parent->switching = false;
313.1.4 by Olaf 'Rhialto' Seibert
Unbreak window boxes wrt the OTP consistency check.
1239
	}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
1240
#endif
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1241
	/* in case it's a transient, find the parent */
492.2.89 by Matthew Fuller
make indent.
1242
	else if(wintype == WinWin && (twm_win->istransient
1243
	                              || !isGroupLeader(twm_win))) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1244
		other_win = Scr->FirstWindow;
1245
		while(other_win != NULL
1246
		                && !isTransientOf(twm_win, other_win)
1247
		                && !isGroupLeaderOf(other_win, twm_win)) {
1248
			other_win = other_win->next;
1249
		}
1250
		if(other_win != NULL) {
1251
			parent = other_win->otp;
1252
		}
1253
	}
1254
1255
	/* make the new owl */
1256
	*owlp = AddNewOwl(twm_win, wintype, parent);
1257
1258
	assert(*owlp != NULL);
1259
	OtpCheckConsistency();
1260
}
1261
302.1.31 by Olaf 'Rhialto' Seibert
Code re-indented.
1262
void OtpReassignIcon(TwmWindow *twm_win, Icon *old_icon)
1263
{
1264
	if(old_icon != NULL) {
1265
		/* Transfer OWL to new Icon */
1266
		Icon *new_icon = twm_win->icon;
1267
		if(new_icon != NULL) {
1268
			new_icon->otp = old_icon->otp;
1269
			old_icon->otp = NULL;
1270
		}
1271
	}
1272
	else {
1273
		/* Create a new OWL for this Icon */
1274
		OtpAdd(twm_win, IconWin);
1275
	}
1276
}
1277
1278
void OtpFreeIcon(TwmWindow *twm_win)
1279
{
1280
	/* Remove the icon's OWL, if any */
1281
	Icon *cur_icon = twm_win->icon;
1282
	if(cur_icon != NULL) {
1283
		OtpRemove(twm_win, IconWin);
1284
	}
1285
}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1286
1287
name_list **OtpScrSwitchingL(ScreenInfo *scr, WinType wintype)
1288
{
1289
	OtpPreferences *prefs = (wintype == IconWin) ? scr->IconOTP : scr->OTP;
1290
1291
	assert(prefs != NULL);
1292
1293
	return &(prefs->switchingL);
1294
}
1295
1296
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
1297
void OtpScrSetSwitching(ScreenInfo *scr, WinType wintype, bool switching)
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1298
{
306 by Matthew Fuller
Add #ifndef to avoid an unused var warning when building -DNDEBUG.
1299
#ifndef NDEBUG
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1300
	OtpPreferences *prefs = (wintype == IconWin) ? scr->IconOTP : scr->OTP;
1301
1302
	assert(prefs != NULL);
306 by Matthew Fuller
Add #ifndef to avoid an unused var warning when building -DNDEBUG.
1303
#endif
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1304
1305
	scr->OTP->switching = switching;
1306
}
1307
1308
1309
void OtpScrSetZero(ScreenInfo *scr, WinType wintype, int priority)
1310
{
1311
	OtpPreferences *prefs = (wintype == IconWin) ? scr->IconOTP : scr->OTP;
1312
1313
	assert(prefs != NULL);
1314
1315
	if(ABS(priority) > OTP_ZERO) {
1316
		fprintf(stderr, "invalid OnTopPriority value: %d\n", priority);
1317
		return;
1318
	}
1319
1320
	prefs->priority = priority + OTP_ZERO;
1321
}
1322
1323
1324
name_list **OtpScrPriorityL(ScreenInfo *scr, WinType wintype, int priority)
1325
{
1326
	OtpPreferences *prefs = (wintype == IconWin) ? scr->IconOTP : scr->OTP;
1327
1328
	assert(prefs != NULL);
1329
1330
	if(ABS(priority) > OTP_ZERO) {
1331
		fprintf(stderr, "invalid OnTopPriority value: %d\n", priority);
1332
		priority = 0;
1333
	}
1334
	return &(prefs->priorityL[priority + OTP_ZERO]);
1335
}
1336
1337
1338
static OtpPreferences *new_OtpPreferences(void)
1339
{
491.1.8 by Matthew Fuller
Stop casting return values of [mc]alloc(). void * has existed for 27
1340
	OtpPreferences *pref = malloc(sizeof(OtpPreferences));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1341
	int i;
1342
1343
	/* initialize default values */
1344
	for(i = 0; i <= OTP_MAX; i++) {
1345
		pref->priorityL[i] = NULL;
1346
	}
1347
	pref->priority = OTP_ZERO;
1348
	pref->switchingL = NULL;
492.2.62 by Matthew Fuller
bool-ify otp. Most of these are completely trivial uses for the type
1349
	pref->switching = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1350
1351
	return pref;
1352
}
1353
1354
static void free_OtpPreferences(OtpPreferences *pref)
1355
{
1356
	int i;
1357
1358
	FreeList(&pref->switchingL);
1359
	for(i = 0; i <= OTP_MAX; i++) {
1360
		FreeList(&pref->priorityL[i]);
1361
	}
1362
1363
	free(pref);
1364
}
1365
1366
void OtpScrInitData(ScreenInfo *scr)
1367
{
1368
	if(scr->OTP != NULL) {
1369
		free_OtpPreferences(scr->OTP);
1370
	}
1371
	if(scr->IconOTP != NULL) {
1372
		free_OtpPreferences(scr->IconOTP);
1373
	}
1374
	scr->OTP = new_OtpPreferences();
1375
	scr->IconOTP = new_OtpPreferences();
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1376
}
1377
1378
int ReparentWindow(Display *display, TwmWindow *twm_win, WinType wintype,
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1379
                   Window parent, int x, int y)
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1380
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1381
	int result;
1382
	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
1383
	OtpWinList *other = owl->below;
1384
	assert(owl != NULL);
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1385
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1386
	DPRINTF((stderr, "ReparentWindow: w=%x type=%d\n",
1387
	         (unsigned int)WindowOfOwl(owl), wintype));
1388
	result = XReparentWindow(display, WindowOfOwl(owl), parent, x, y);
1389
	/* The raise was already done by XReparentWindow, so this call
1390
	   just re-places the window at the right spot in the list
1391
	   and enforces priority settings. */
1392
	RemoveOwl(owl);
1393
	InsertOwlAbove(owl, other);
1394
	OtpCheckConsistency();
1395
	return result;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1396
}
1397
311.1.16 by Matthew Fuller
Storing results from two different calls into a single variable
1398
void
1399
ReparentWindowAndIcon(Display *display, TwmWindow *twm_win,
1400
                      Window parent, int win_x, int win_y,
1401
                      int icon_x, int icon_y)
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1402
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1403
	OtpWinList *win_owl = twm_win->otp;
1404
	assert(twm_win->icon != NULL);
1405
	OtpWinList *icon_owl = twm_win->icon->otp;
1406
	assert(win_owl != NULL);
1407
	assert(icon_owl != NULL);
1408
	OtpWinList *below_win = win_owl->below;
1409
	OtpWinList *below_icon = icon_owl->below;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1410
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1411
	DPRINTF((stderr, "ReparentWindowAndIcon %x\n", (unsigned int)twm_win->frame));
311.1.16 by Matthew Fuller
Storing results from two different calls into a single variable
1412
	XReparentWindow(display, twm_win->frame, parent, win_x, win_y);
1413
	XReparentWindow(display, twm_win->icon->w, parent, icon_x, icon_y);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1414
	/* The raise was already done by XReparentWindow, so this call
1415
	   just re-places the window at the right spot in the list
1416
	   and enforces priority settings. */
1417
	RemoveOwl(win_owl);
1418
	RemoveOwl(icon_owl);
1419
	if(below_win != icon_owl) {
1420
		/*
1421
		 * Only insert the window above something if it isn't the icon,
1422
		 * because that isn't back yet.
1423
		 */
1424
		InsertOwlAbove(win_owl, below_win);
1425
		InsertOwlAbove(icon_owl, below_icon);
1426
	}
1427
	else {
1428
		/* In such a case, do it in the opposite order. */
1429
		InsertOwlAbove(icon_owl, below_icon);
1430
		InsertOwlAbove(win_owl, below_win);
1431
	}
1432
	OtpCheckConsistency();
311.1.16 by Matthew Fuller
Storing results from two different calls into a single variable
1433
	return;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1434
}
1435
1436
/* Iterators.  */
691.1.1 by Matthew Fuller
Be explicit about void arguments; current compilers are starting to
1437
TwmWindow *OtpBottomWin(void)
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1438
{
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
1439
	OtpWinList *owl = Scr->bottomOwl;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1440
	while(owl && owl->type != WinWin) {
1441
		owl = owl->above;
1442
	}
1443
	return owl ? owl->twm_win : NULL;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1444
}
1445
691.1.1 by Matthew Fuller
Be explicit about void arguments; current compilers are starting to
1446
TwmWindow *OtpTopWin(void)
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1447
{
607.1.1 by Matthew Fuller
Move the bottomOwl pointer into the ScreenInfo struct. If we have
1448
	OtpWinList *owl = Scr->bottomOwl, *top = NULL;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1449
	while(owl) {
1450
		if(owl->type == WinWin) {
1451
			top = owl;
1452
		}
1453
		owl = owl->above;
1454
	}
1455
	return top ? top->twm_win : NULL;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1456
}
1457
1458
TwmWindow *OtpNextWinUp(TwmWindow *twm_win)
1459
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1460
	OtpWinList *owl = twm_win->otp->above;
1461
	while(owl && owl->type != WinWin) {
1462
		owl = owl->above;
1463
	}
1464
	return owl ? owl->twm_win : NULL;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1465
}
1466
1467
TwmWindow *OtpNextWinDown(TwmWindow *twm_win)
1468
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1469
	OtpWinList *owl = twm_win->otp->below;
1470
	while(owl && owl->type != WinWin) {
1471
		owl = owl->below;
1472
	}
1473
	return owl ? owl->twm_win : NULL;
240.1.3 by Rhialto
4 - Added the remaining OnTopPriority changes from Stefan Monnier
1474
}
1475
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
1476
660.1.1 by Matthew Fuller
Add a func to pretty-print an OWL sequence, that we can use in dev.
1477
1478
/*
1479
 * Outputting info to understand the state of OTP stuff.
1480
 */
1481
1482
/// Pretty-print a whole OWL stack.  Works upward from the arg;
1483
/// generally, you'd call this with Scr->bottomOwl.
1484
static void
1485
OwlPrettyPrint(const OtpWinList *start)
1486
{
1487
	fprintf(stderr, "%s():\n", __func__);
1488
1489
	for(const OtpWinList *owl = start ; owl != NULL ; owl = owl->above) {
660.1.3 by Matthew Fuller
Show the X Window value on the main line for each entry, and show them
1490
		fprintf(stderr, "  pri=%2d (%+d) %s 0x%lx:'%1.50s'\n",
660.1.1 by Matthew Fuller
Add a func to pretty-print an OWL sequence, that we can use in dev.
1491
		        OtpEffectivePriority(owl->twm_win),
1492
		        OtpEffectiveDisplayPriority(owl->twm_win),
1493
		        (owl->type == WinWin ? "win" : "ico"),
660.1.3 by Matthew Fuller
Show the X Window value on the main line for each entry, and show them
1494
		        owl->twm_win->w, owl->twm_win->name);
660.1.1 by Matthew Fuller
Add a func to pretty-print an OWL sequence, that we can use in dev.
1495
		fprintf(stderr, "         basepri=%d %s%s%s\n",
1496
		        owl->pri_base,
667 by Matthew Fuller
Fix !USE_EWMH build.
1497
#ifdef EWMH
660.1.1 by Matthew Fuller
Add a func to pretty-print an OWL sequence, that we can use in dev.
1498
		        (owl->pri_aflags & OTP_AFLAG_ABOVE ? " _ABOVE" : ""),
1499
		        (owl->pri_aflags & OTP_AFLAG_BELOW ? " _BELOW" : ""),
1500
		        (owl->pri_aflags & OTP_AFLAG_FULLSCREEN ? " _FULLSCREEN" : "")
667 by Matthew Fuller
Fix !USE_EWMH build.
1501
#else
668 by Matthew Fuller
make indent
1502
		        "", "", ""
667 by Matthew Fuller
Fix !USE_EWMH build.
1503
#endif
660.1.1 by Matthew Fuller
Add a func to pretty-print an OWL sequence, that we can use in dev.
1504
		       );
1505
		if(owl->twm_win->istransient) {
1506
			const TwmWindow *parent = GetTwmWindow(owl->twm_win->transientfor);
660.1.3 by Matthew Fuller
Show the X Window value on the main line for each entry, and show them
1507
			fprintf(stderr, "         transient for 0x%lx:%1.50s\n",
660.1.1 by Matthew Fuller
Add a func to pretty-print an OWL sequence, that we can use in dev.
1508
			        parent->w, parent->name);
1509
		}
1510
	}
1511
1512
	fprintf(stderr, "  Done.\n");
1513
}
1514
1515
1516
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
1517
/*
575.2.47 by Matthew Fuller
Add funcs to specifically set/clear flags.
1518
 * Stuff for messing with pri_aflags
575.2.25 by Matthew Fuller
Rework the accepting of above/below messages in EWMH to set the flags
1519
 */
575.2.50 by Matthew Fuller
We need to set/clear the bits directly in the OTH stuff here when we
1520
/* Set the masked bits to exactly what's given */
1521
void
575.2.55 by Matthew Fuller
These flag bitmaps are unsigned, so make stuff manipulating them so as
1522
OtpSetAflagMask(TwmWindow *twm_win, unsigned mask, unsigned setto)
575.2.50 by Matthew Fuller
We need to set/clear the bits directly in the OTH stuff here when we
1523
{
1524
	assert(twm_win != NULL);
1525
	assert(twm_win->otp != NULL);
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1526
	OwlSetAflagMask(twm_win->otp, mask, setto);
1527
}
1528
1529
static void
1530
OwlSetAflagMask(OtpWinList *owl, unsigned mask, unsigned setto)
1531
{
1532
	assert(owl != NULL);
1533
1534
	owl->pri_aflags &= ~mask;
1535
	owl->pri_aflags |= (setto & mask);
1536
	OwlStashAflags(owl);
575.2.50 by Matthew Fuller
We need to set/clear the bits directly in the OTH stuff here when we
1537
}
1538
575.2.51 by Matthew Fuller
GC now unused function.
1539
/* Set/clear individual ones */
575.2.47 by Matthew Fuller
Add funcs to specifically set/clear flags.
1540
void
575.2.55 by Matthew Fuller
These flag bitmaps are unsigned, so make stuff manipulating them so as
1541
OtpSetAflag(TwmWindow *twm_win, unsigned flag)
575.2.47 by Matthew Fuller
Add funcs to specifically set/clear flags.
1542
{
1543
	assert(twm_win != NULL);
1544
	assert(twm_win->otp != NULL);
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
1545
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1546
	OwlSetAflag(twm_win->otp, flag);
1547
}
1548
1549
static void
1550
OwlSetAflag(OtpWinList *owl, unsigned flag)
1551
{
1552
	assert(owl != NULL);
1553
1554
	owl->pri_aflags |= flag;
1555
	OwlStashAflags(owl);
575.2.47 by Matthew Fuller
Add funcs to specifically set/clear flags.
1556
}
1557
1558
void
575.2.55 by Matthew Fuller
These flag bitmaps are unsigned, so make stuff manipulating them so as
1559
OtpClearAflag(TwmWindow *twm_win, unsigned flag)
575.2.47 by Matthew Fuller
Add funcs to specifically set/clear flags.
1560
{
1561
	assert(twm_win != NULL);
1562
	assert(twm_win->otp != NULL);
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
1563
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1564
	OwlClearAflag(twm_win->otp, flag);
1565
}
1566
1567
static void
1568
OwlClearAflag(OtpWinList *owl, unsigned flag)
1569
{
1570
	assert(owl != NULL);
1571
1572
	owl->pri_aflags &= ~flag;
1573
	OwlStashAflags(owl);
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
1574
}
1575
1576
/*
1577
 * Stash up flags in a property.  We use this to keep track of whether we
1578
 * have above/below flags set in the OTP info, so we can know what to set
1579
 * when we restart.  Otherwise we can't tell whether stuff like EWMH
1580
 * _NET_WM_STATE flags are saying 'above' because the above flag got set
1581
 * at some point, or whether other OTP config happens to have already
1582
 * raised it.
1583
 */
575.2.77 by Matthew Fuller
Add a func to conditionally stash.
1584
void
575.2.78 by Matthew Fuller
Better name.
1585
OtpStashAflagsFirstTime(TwmWindow *twm_win)
575.2.77 by Matthew Fuller
Add a func to conditionally stash.
1586
{
1587
	if(!twm_win->otp->stashed_aflags) {
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1588
		OwlStashAflags(twm_win->otp);
575.2.77 by Matthew Fuller
Add a func to conditionally stash.
1589
	}
1590
}
1591
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
1592
static void
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1593
OwlStashAflags(OtpWinList *owl)
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
1594
{
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1595
	unsigned long of_prop = owl->pri_aflags;
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
1596
575.2.93 by Matthew Fuller
Don't bother saving/searching for stashed flags on non-WinWin windows.
1597
	/* Only "real" windows need stashed flags */
1598
	if(owl->type != WinWin) {
1599
		return;
1600
	}
1601
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1602
	XChangeProperty(dpy, owl->twm_win->w, XA_CTWM_OTP_AFLAGS, XA_INTEGER,
575.2.67 by Matthew Fuller
Stop setting the OTP property inline in EWMH handling. Move the
1603
	                32, PropModeReplace, (unsigned char *)&of_prop, 1);
575.2.76 by Matthew Fuller
Add tracking of whether we've got aflags stashed in a property on a
1604
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1605
	owl->stashed_aflags = true;
575.2.47 by Matthew Fuller
Add funcs to specifically set/clear flags.
1606
}
1607
575.2.83 by Matthew Fuller
Staticize getting stash; it's only used internally now.
1608
static unsigned
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1609
OwlGetStashedAflags(OtpWinList *owl, bool *gotit)
575.2.68 by Matthew Fuller
Move code for looking up stashes OTP aflags into a func in otp.c.
1610
{
1611
	/* Lotta dummy args */
1612
	int ret;
1613
	Atom act_type;
1614
	int d_fmt;
1615
	unsigned long nitems, d_after;
1616
	unsigned long aflags, *aflags_p;
1617
575.2.93 by Matthew Fuller
Don't bother saving/searching for stashed flags on non-WinWin windows.
1618
	/* Only on real windows */
1619
	if(owl->type != WinWin) {
1620
		*gotit = false;
1621
		return 0;
1622
	}
1623
575.2.84 by Matthew Fuller
Add and internally use direct OWL variants of these funcs. Leave OTP
1624
	ret = XGetWindowProperty(dpy, owl->twm_win->w, XA_CTWM_OTP_AFLAGS, 0, 1,
575.2.68 by Matthew Fuller
Move code for looking up stashes OTP aflags into a func in otp.c.
1625
	                         False, XA_INTEGER, &act_type, &d_fmt, &nitems,
1626
	                         &d_after, (unsigned char **)&aflags_p);
1627
	if(ret == Success && act_type == XA_INTEGER && aflags_p != NULL) {
1628
		aflags = *aflags_p;
1629
		XFree(aflags_p);
575.2.79 by Matthew Fuller
Actually, we can't store into twm_win->owl because the owl is not
1630
		*gotit = true;
575.2.68 by Matthew Fuller
Move code for looking up stashes OTP aflags into a func in otp.c.
1631
	}
1632
	else {
575.2.79 by Matthew Fuller
Actually, we can't store into twm_win->owl because the owl is not
1633
		*gotit = false;
575.2.68 by Matthew Fuller
Move code for looking up stashes OTP aflags into a func in otp.c.
1634
		aflags = 0;
1635
	}
1636
1637
	return aflags;
1638
}
1639
575.2.25 by Matthew Fuller
Rework the accepting of above/below messages in EWMH to set the flags
1640
1641
/*
575.2.26 by Matthew Fuller
Break out the 'redo stacking' inner bit there into a separate func.
1642
 * Figure where a window should be stacked based on the current world,
1643
 * and move it there.  This function pretty much assumes it's not already
1644
 * there; callers should generally be figuring that out before calling
1645
 * this.
1646
 */
1647
void
1648
OtpRestackWindow(TwmWindow *twm_win)
1649
{
1650
	OtpWinList *owl = twm_win->otp;
1651
1652
	RemoveOwl(owl);
1653
	InsertOwl(owl, Above);
1654
	OtpCheckConsistency();
1655
}
1656
1657
659.2.1 by Matthew Fuller
Commit original run at avoiding crashes with transient windows of
1658
1659
/**
1660
 * Focus/unfocus backend.  This is used on windows whose stacking is
1661
 * focus-dependent (e.g., EWMH fullscreen), to move them and their
1662
 * transients around.  For these windows, getting/losing focus is
1663
 * practically the same as a f.setpriority, except it's on the calculated
1664
 * rather than the base parts.  And it's hard to re-use our existing
1665
 * functions to do it because we have to move Scr->Focus before the main
1666
 * window changes, but then it's too late to see where all the transients
1667
 * were.
1668
 *
1669
 * There are a number of unpleasant assumptions in here relating to where
1670
 * the transients are, and IWBNI we could be smarter and quicker about
1671
 * dealing with them.  But this gets us past the simple to cause
1672
 * assertion failures, anyway...
1673
 */
1674
static void
1675
OtpFocusWindowBE(TwmWindow *twm_win, int oldprio)
1676
{
1677
	OtpWinList *owl = twm_win->otp;
1678
1679
	// This one comes off the list, and goes back in its new place.
1680
	RemoveOwl(owl);
1681
	InsertOwl(owl, Above);
1682
659.2.2 by Matthew Fuller
It turns out that this is an insufficient way of finding the
1683
	// Now root around for any transients of it, and
659.2.1 by Matthew Fuller
Commit original run at avoiding crashes with transient windows of
1684
	// nudge them into the new location.  The whole Above/Below thing is
1685
	// kinda a heavy-handed guess, but...
1686
	//
659.2.2 by Matthew Fuller
It turns out that this is an insufficient way of finding the
1687
	// This is nearly a reimplementation of TryToMoveTransientsOfTo(),
1688
	// but the assumption that we can find the transients by starting
1689
	// from where the old priority was in the list turns out to be deeply
1690
	// broken.  So just walk the whole thing.  Which isn't ideal, but...
1691
	//
659.2.5 by Matthew Fuller
This isn't really an XXX, just a note.
1692
	// We also need to do loop detection, since otherwise we'll get stuck
1693
	// when a window has multiple transients to move around.  Since we
1694
	// read from the bottom up, if a window is moving up the stack, then
1695
	// its transients move up, and we run into them again and again.
1696
	//
659.2.2 by Matthew Fuller
It turns out that this is an insufficient way of finding the
1697
	// XXX It should not be this freakin' hard to find a window's
1698
	// transients.  We should fix that more globally.
663 by Matthew Fuller
make indent
1699
659.2.4 by Matthew Fuller
Since we move the transients up to the top of the list, if we have
1700
	// XXX Let's just get a friggin' vector implementation already...
1701
	size_t tlsz = 32;  // Should hardly ever be too small
1702
	size_t tlused = 0;
1703
	OtpWinList **tlst = calloc(tlsz, sizeof(OtpWinList *));
1704
	if(tlst == NULL) {
1705
		fprintf(stderr, "%s(): realloc() failed\n", __func__);
1706
		abort();
1707
	}
1708
1709
	// Loop through and find them all
659.2.2 by Matthew Fuller
It turns out that this is an insufficient way of finding the
1710
	OtpWinList *trans = Scr->bottomOwl;
659.2.1 by Matthew Fuller
Commit original run at avoiding crashes with transient windows of
1711
	while((trans != NULL)) {
659.2.2 by Matthew Fuller
It turns out that this is an insufficient way of finding the
1712
		// Gotta pre-stash, since we're sometimes about to move trans.
659.2.1 by Matthew Fuller
Commit original run at avoiding crashes with transient windows of
1713
		OtpWinList *next = trans->above;
1714
1715
		if((trans->type == WinWin)
663 by Matthew Fuller
make indent
1716
		                && isTransientOf(trans->twm_win, twm_win)) {
659.2.4 by Matthew Fuller
Since we move the transients up to the top of the list, if we have
1717
			// Got one, stash it
1718
			tlst[tlused++] = trans;
659.2.6 by Matthew Fuller
Minor whitespace/comment tweaks.
1719
1720
			// Grow?
659.2.4 by Matthew Fuller
Since we move the transients up to the top of the list, if we have
1721
			if(tlused == tlsz) {
1722
				tlsz *= 2;
1723
				OtpWinList **tln = realloc(tlst, (tlsz * sizeof(OtpWinList *)));
1724
				if(tln == NULL) {
1725
					fprintf(stderr, "%s(): realloc() failed\n", __func__);
1726
					abort();
1727
				}
1728
				tlst = tln;
1729
			}
659.2.1 by Matthew Fuller
Commit original run at avoiding crashes with transient windows of
1730
		}
1731
659.2.4 by Matthew Fuller
Since we move the transients up to the top of the list, if we have
1732
		// And onward
659.2.1 by Matthew Fuller
Commit original run at avoiding crashes with transient windows of
1733
		trans = next;
1734
	}
1735
659.2.4 by Matthew Fuller
Since we move the transients up to the top of the list, if we have
1736
1737
	// Now loop over them and shuffle them up
1738
	for(int i = 0 ; i < tlused ; i++) {
1739
		RemoveOwl(tlst[i]);
1740
		InsertOwl(tlst[i], Above);
1741
	}
659.2.6 by Matthew Fuller
Minor whitespace/comment tweaks.
1742
659.2.4 by Matthew Fuller
Since we move the transients up to the top of the list, if we have
1743
	free(tlst);
1744
659.2.1 by Matthew Fuller
Commit original run at avoiding crashes with transient windows of
1745
	OtpCheckConsistency();
1746
}
1747
1748
/**
1749
 * Unfocus a window.  This needs to know internals of OTP because of
1750
 * focus-dependent stacking of it and its transients.
1751
 */
1752
void
1753
OtpUnfocusWindow(TwmWindow *twm_win)
1754
{
1755
	// Stash where it currently appears to be.  We assume all its
1756
	// transients currently have the same effective priority.  See also
1757
	// TryToMoveTransientsOfTo() which makes the same assumption.  I'm
1758
	// not sure that's entirely warranted...
1759
	int oldprio = PRI(twm_win->otp);
1760
1761
	// Now tell ourselves it's unfocused
1762
	assert(Scr->Focus == twm_win);
1763
	Scr->Focus = NULL;
1764
1765
	// And do the work
1766
	OtpFocusWindowBE(twm_win, oldprio);
1767
}
1768
1769
/**
1770
 * Focus a window.  This needs to know internals of OTP because of
1771
 * focus-dependent stacking of it and its transients.
1772
 */
1773
void
1774
OtpFocusWindow(TwmWindow *twm_win)
1775
{
1776
	// X-ref OtoUnfocusWindow() comments.
1777
	int oldprio = PRI(twm_win->otp);
1778
1779
	assert(Scr->Focus != twm_win);
1780
	Scr->Focus = twm_win;
1781
1782
	OtpFocusWindowBE(twm_win, oldprio);
1783
}
1784
1785
1786
575.2.26 by Matthew Fuller
Break out the 'redo stacking' inner bit there into a separate func.
1787
/*
575.2.8 by Matthew Fuller
Improve comment.
1788
 * Calculating effective priority.  Take the base priority (what gets
1789
 * set/altered by various OTP config and functions), and then tack on
1790
 * whatever alterations more ephemeral things might apply.  This
1791
 * currently pretty much means EWMH bits.
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
1792
 */
1793
int
575.2.24 by Matthew Fuller
Create a special function to get the display-form OTP, and use it in
1794
OtpEffectiveDisplayPriority(TwmWindow *twm_win)
1795
{
1796
	assert(twm_win != NULL);
1797
	assert(twm_win->otp != NULL);
1798
575.2.43 by Matthew Fuller
Fixup math for display priority.
1799
	return(OwlEffectivePriority(twm_win->otp) - OTP_ZERO);
575.2.24 by Matthew Fuller
Create a special function to get the display-form OTP, and use it in
1800
}
1801
1802
int
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
1803
OtpEffectivePriority(TwmWindow *twm_win)
1804
{
1805
	assert(twm_win != NULL);
1806
	assert(twm_win->otp != NULL);
1807
1808
	return OwlEffectivePriority(twm_win->otp);
1809
}
1810
1811
static int
1812
OwlEffectivePriority(OtpWinList *owl)
1813
{
1814
	int pri;
1815
1816
	assert(owl != NULL);
1817
1818
	pri = owl->pri_base;
575.2.7 by Matthew Fuller
Actually, add back _FULLSCREEN as an aflag, and add handling to it in
1819
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
1820
#ifdef EWMH
575.2.7 by Matthew Fuller
Actually, add back _FULLSCREEN as an aflag, and add handling to it in
1821
	/* ABOVE/BELOW states shift a bit relative to the base */
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
1822
	if(owl->pri_aflags & OTP_AFLAG_ABOVE) {
1823
		pri += EWMH_PRI_ABOVE;
1824
	}
1825
	if(owl->pri_aflags & OTP_AFLAG_BELOW) {
1826
		pri -= EWMH_PRI_ABOVE;
1827
	}
575.2.7 by Matthew Fuller
Actually, add back _FULLSCREEN as an aflag, and add handling to it in
1828
575.2.42 by Matthew Fuller
Try and handle the magic BELOW+DOCK case EWMH specifies.
1829
	/*
1830
	 * Special magic: EWMH says that _BELOW + _DOCK = (just _BELOW).
1831
	 * So if both are set, and its base is where we'd expect just a _DOCK
1832
	 * to be, try cancelling that out.
1833
	 */
1834
	{
1835
		EwmhWindowType ewt = owl->twm_win->ewmhWindowType;
1836
		if((owl->pri_aflags & OTP_AFLAG_BELOW) && (ewt == wt_Dock) &&
575.2.100 by Matthew Fuller
Use OTP_ZERO to properly offset comparisons against display-style
1837
		                (owl->pri_base == EWMH_PRI_DOCK + OTP_ZERO)) {
575.2.42 by Matthew Fuller
Try and handle the magic BELOW+DOCK case EWMH specifies.
1838
			pri -= EWMH_PRI_DOCK;
1839
		}
1840
	}
1841
575.2.99 by Matthew Fuller
Use EWMH_PRI_FULLSCREEN instead of OTP_MAX; the user should be able to
1842
	/*
1843
	 * If FULLSCREEN and focused, jam to (nearly; let the user still win
617.1.1 by Matthew Fuller
Fixup setting the OTP for transients of windows that are _FULLSCREEN
1844
	 * if they try) the top.  We also need to handle transients; they
1845
	 * might not have focus, but still need to be on top of the window
1846
	 * they're coming up transient for, or else they'll be hidden
1847
	 * forever.
575.2.99 by Matthew Fuller
Use EWMH_PRI_FULLSCREEN instead of OTP_MAX; the user should be able to
1848
	 */
617.1.1 by Matthew Fuller
Fixup setting the OTP for transients of windows that are _FULLSCREEN
1849
	if(owl->pri_aflags & OTP_AFLAG_FULLSCREEN) {
1850
		if(Scr->Focus == owl->twm_win) {
1851
			// It's focused, shift it up
1852
			pri = EWMH_PRI_FULLSCREEN + OTP_ZERO;
1853
		}
1854
		else if(owl->twm_win->istransient) {
1855
			// It's a transient of something else; if that something else
1856
			// has the fullscreen/focus combo, we should pop this up top
1857
			// too.  Technically, we should perhaps test whether its
1858
			// parent is also OTP_AFLAG_FULLSCREEN, but if the transient
1859
			// has it, the parent probably does too.  Worry about that
1860
			// detail if it ever becomes a problem.
1861
			TwmWindow *parent = GetTwmWindow(owl->twm_win->transientfor);
1862
			if(Scr->Focus == parent) {
1863
				// Shift this up so we stay on top
1864
				pri = EWMH_PRI_FULLSCREEN + OTP_ZERO;
1865
			}
1866
		}
575.2.7 by Matthew Fuller
Actually, add back _FULLSCREEN as an aflag, and add handling to it in
1867
	}
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
1868
#endif
1869
575.2.7 by Matthew Fuller
Actually, add back _FULLSCREEN as an aflag, and add handling to it in
1870
	/* Constrain */
1871
	pri = MAX(pri, 0);
1872
	pri = MIN(pri, OTP_MAX);
1873
575.2.6 by Matthew Fuller
Add some functions for calcing the current effective priority of a
1874
	return pri;
1875
}
579.1.2 by Matthew Fuller
Add functions to give a quick answer as to whether a window's OTP is
1876
1877
1878
/*
1879
 * Does the priority of a window depend on its focus state?  External
1880
 * code needs to know, to know when it might need restacking.
1881
 */
1882
bool
1883
OtpIsFocusDependent(TwmWindow *twm_win)
1884
{
1885
	assert(twm_win != NULL);
1886
	assert(twm_win->otp != NULL);
1887
579.1.7 by Matthew Fuller
Add #ifdef's around these bits that only apply when EWMH is built.
1888
#ifdef EWMH
579.1.8 by Matthew Fuller
Add a bit of a comment.
1889
	/*
1890
	 * EWMH says _FULLSCREEN and focused windows get shoved to the top;
1891
	 * this implies that _FULLSCREEN and _not_ focused don't.  So if the
1892
	 * focus is changing, that means we may need to restack.
1893
	 */
579.1.2 by Matthew Fuller
Add functions to give a quick answer as to whether a window's OTP is
1894
	if(twm_win->otp->pri_aflags & OTP_AFLAG_FULLSCREEN) {
1895
		return true;
1896
	}
579.1.7 by Matthew Fuller
Add #ifdef's around these bits that only apply when EWMH is built.
1897
#endif
579.1.8 by Matthew Fuller
Add a bit of a comment.
1898
579.1.2 by Matthew Fuller
Add functions to give a quick answer as to whether a window's OTP is
1899
	return false;
1900
}