otp.c revision 0bbfda8a
10bbfda8aSnia/*
20bbfda8aSnia * Copyright 1992, 2005 Stefan Monnier.
30bbfda8aSnia *
40bbfda8aSnia * Author:  Stefan Monnier [ monnier@lia.di.epfl.ch ]
50bbfda8aSnia * Adapted for use with more than one virtual screen by
60bbfda8aSnia * Olaf "Rhialto" Seibert <rhialto@falu.nl>.
70bbfda8aSnia *
80bbfda8aSnia * $Id: otp.c,v 1.1.1.1 2021/04/11 08:36:52 nia Exp $
90bbfda8aSnia *
100bbfda8aSnia * handles all the OnTopPriority-related issues.
110bbfda8aSnia *
120bbfda8aSnia */
130bbfda8aSnia
140bbfda8aSnia#include "ctwm.h"
150bbfda8aSnia
160bbfda8aSnia#include <stdio.h>
170bbfda8aSnia#include <stdlib.h>
180bbfda8aSnia#include <assert.h>
190bbfda8aSnia#include <X11/Xatom.h>
200bbfda8aSnia
210bbfda8aSnia#include "otp.h"
220bbfda8aSnia#include "ctwm_atoms.h"
230bbfda8aSnia#include "screen.h"
240bbfda8aSnia#include "util.h"
250bbfda8aSnia#include "icons.h"
260bbfda8aSnia#include "list.h"
270bbfda8aSnia#include "events.h"
280bbfda8aSnia#include "event_handlers.h"
290bbfda8aSnia#include "vscreen.h"
300bbfda8aSnia#include "win_utils.h"
310bbfda8aSnia
320bbfda8aSnia#define DEBUG_OTP       0
330bbfda8aSnia#if DEBUG_OTP
340bbfda8aSnia#define DPRINTF(x)      fprintf x
350bbfda8aSnia#else
360bbfda8aSnia#define DPRINTF(x)
370bbfda8aSnia#endif
380bbfda8aSnia
390bbfda8aSnia#if defined(NDEBUG)
400bbfda8aSnia# define CHECK_OTP      0
410bbfda8aSnia#else
420bbfda8aSnia# define CHECK_OTP      1
430bbfda8aSnia#endif
440bbfda8aSnia
450bbfda8aSnia/* number of priorities known to ctwm: [0..ONTOP_MAX] */
460bbfda8aSnia#define OTP_ZERO 8
470bbfda8aSnia#define OTP_MAX (OTP_ZERO * 2)
480bbfda8aSnia
490bbfda8aSnia/* Shorten code a little */
500bbfda8aSnia#define PRI(owl) OwlEffectivePriority(owl)
510bbfda8aSnia#define PRI_CP(from, to) do {                  \
520bbfda8aSnia            to->pri_base = from->pri_base;     \
530bbfda8aSnia            to->pri_aflags = from->pri_aflags; \
540bbfda8aSnia        } while(0)
550bbfda8aSnia
560bbfda8aSniastruct OtpWinList {
570bbfda8aSnia	OtpWinList *above;
580bbfda8aSnia	OtpWinList *below;
590bbfda8aSnia	TwmWindow  *twm_win;
600bbfda8aSnia	WinType     type;
610bbfda8aSnia	bool        switching;
620bbfda8aSnia	int         pri_base;   // Base priority
630bbfda8aSnia	unsigned    pri_aflags; // Flags that might alter it; OTP_AFLAG_*
640bbfda8aSnia	bool        stashed_aflags;
650bbfda8aSnia};
660bbfda8aSnia
670bbfda8aSniastruct OtpPreferences {
680bbfda8aSnia	name_list  *priorityL[OTP_MAX + 1];
690bbfda8aSnia	int         priority;
700bbfda8aSnia	name_list  *switchingL;
710bbfda8aSnia	bool        switching;
720bbfda8aSnia};
730bbfda8aSnia
740bbfda8aSniatypedef struct Box {
750bbfda8aSnia	int x;
760bbfda8aSnia	int y;
770bbfda8aSnia	int width;
780bbfda8aSnia	int height;
790bbfda8aSnia} Box;
800bbfda8aSnia
810bbfda8aSnia
820bbfda8aSniastatic bool OtpCheckConsistencyVS(VirtualScreen *currentvs, Window vroot);
830bbfda8aSniastatic void OwlSetAflagMask(OtpWinList *owl, unsigned mask, unsigned setto);
840bbfda8aSniastatic void OwlSetAflag(OtpWinList *owl, unsigned flag);
850bbfda8aSniastatic void OwlClearAflag(OtpWinList *owl, unsigned flag);
860bbfda8aSniastatic void OwlStashAflags(OtpWinList *owl);
870bbfda8aSniastatic unsigned OwlGetStashedAflags(OtpWinList *owl, bool *gotit);
880bbfda8aSniastatic int OwlEffectivePriority(OtpWinList *owl);
890bbfda8aSnia
900bbfda8aSniastatic Box BoxOfOwl(OtpWinList *owl)
910bbfda8aSnia{
920bbfda8aSnia	Box b;
930bbfda8aSnia
940bbfda8aSnia	switch(owl->type) {
950bbfda8aSnia		case IconWin: {
960bbfda8aSnia			Icon *icon = owl->twm_win->icon;
970bbfda8aSnia
980bbfda8aSnia			b.x = icon->w_x;
990bbfda8aSnia			b.y = icon->w_y;
1000bbfda8aSnia			b.width = icon->w_width;
1010bbfda8aSnia			b.height = icon->w_height;
1020bbfda8aSnia			break;
1030bbfda8aSnia		}
1040bbfda8aSnia		case WinWin: {
1050bbfda8aSnia			TwmWindow *twm_win = owl->twm_win;
1060bbfda8aSnia
1070bbfda8aSnia			b.x = twm_win->frame_x;
1080bbfda8aSnia			b.y = twm_win->frame_y;
1090bbfda8aSnia			b.width = twm_win->frame_width;
1100bbfda8aSnia			b.height = twm_win->frame_height;
1110bbfda8aSnia			break;
1120bbfda8aSnia		}
1130bbfda8aSnia		default:
1140bbfda8aSnia			assert(false);
1150bbfda8aSnia	}
1160bbfda8aSnia	return b;
1170bbfda8aSnia}
1180bbfda8aSnia
1190bbfda8aSnia
1200bbfda8aSniastatic bool BoxesIntersect(Box *b1, Box *b2)
1210bbfda8aSnia{
1220bbfda8aSnia	bool interX = (b1->x + b1->width > b2->x) && (b2->x + b2->width > b1->x);
1230bbfda8aSnia	bool interY = (b1->y + b1->height > b2->y) && (b2->y + b2->height > b1->y);
1240bbfda8aSnia
1250bbfda8aSnia	return (interX && interY);
1260bbfda8aSnia}
1270bbfda8aSnia
1280bbfda8aSnia
1290bbfda8aSniastatic bool isIntersectingWith(OtpWinList *owl1, OtpWinList *owl2)
1300bbfda8aSnia{
1310bbfda8aSnia	Box b1 = BoxOfOwl(owl1);
1320bbfda8aSnia	Box b2 = BoxOfOwl(owl2);
1330bbfda8aSnia
1340bbfda8aSnia	return BoxesIntersect(&b1, &b2);
1350bbfda8aSnia}
1360bbfda8aSnia
1370bbfda8aSnia
1380bbfda8aSniastatic bool isOnScreen(OtpWinList *owl)
1390bbfda8aSnia{
1400bbfda8aSnia	TwmWindow *twm_win = owl->twm_win;
1410bbfda8aSnia
1420bbfda8aSnia	return (((owl->type == IconWin) ? twm_win->iconified : twm_win->mapped)
1430bbfda8aSnia	        && OCCUPY(twm_win, Scr->currentvs->wsw->currentwspc));
1440bbfda8aSnia}
1450bbfda8aSnia
1460bbfda8aSnia
1470bbfda8aSniabool isTransientOf(TwmWindow *trans, TwmWindow *main)
1480bbfda8aSnia{
1490bbfda8aSnia	return (trans->istransient && trans->transientfor == main->w);
1500bbfda8aSnia}
1510bbfda8aSnia
1520bbfda8aSniabool isGroupLeader(TwmWindow *twm_win)
1530bbfda8aSnia{
1540bbfda8aSnia	return ((twm_win->group == 0)
1550bbfda8aSnia	        || (twm_win->group == twm_win->w));
1560bbfda8aSnia}
1570bbfda8aSnia
1580bbfda8aSniabool isGroupLeaderOf(TwmWindow *leader, TwmWindow *twm_win)
1590bbfda8aSnia{
1600bbfda8aSnia	return (isGroupLeader(leader)
1610bbfda8aSnia	        && !isGroupLeader(twm_win)
1620bbfda8aSnia	        && (leader->group == twm_win->group));
1630bbfda8aSnia}
1640bbfda8aSnia
1650bbfda8aSniabool isSmallTransientOf(TwmWindow *trans, TwmWindow *main)
1660bbfda8aSnia{
1670bbfda8aSnia	int trans_area, main_area;
1680bbfda8aSnia
1690bbfda8aSnia	if(isTransientOf(trans, main)) {
1700bbfda8aSnia		assert(trans->frame);
1710bbfda8aSnia		trans_area = trans->frame_width * trans->frame_height;
1720bbfda8aSnia		main_area = main->frame_width * main->frame_height;
1730bbfda8aSnia
1740bbfda8aSnia		return (trans_area < ((main_area * Scr->TransientOnTop) / 100));
1750bbfda8aSnia	}
1760bbfda8aSnia	else {
1770bbfda8aSnia		return false;
1780bbfda8aSnia	}
1790bbfda8aSnia}
1800bbfda8aSnia
1810bbfda8aSniastatic Window WindowOfOwl(OtpWinList *owl)
1820bbfda8aSnia{
1830bbfda8aSnia	return (owl->type == IconWin)
1840bbfda8aSnia	       ? owl->twm_win->icon->w : owl->twm_win->frame;
1850bbfda8aSnia}
1860bbfda8aSnia
1870bbfda8aSniabool OtpCheckConsistency(void)
1880bbfda8aSnia{
1890bbfda8aSnia#if DEBUG_OTP
1900bbfda8aSnia	VirtualScreen *tvs;
1910bbfda8aSnia	bool result = true;
1920bbfda8aSnia
1930bbfda8aSnia	for(tvs = Scr->vScreenList; tvs != NULL; tvs = tvs->next) {
1940bbfda8aSnia		fprintf(stderr, "OtpCheckConsistencyVS: vs:(x,y)=(%d,%d)\n",
1950bbfda8aSnia		        tvs->x, tvs->y);
1960bbfda8aSnia		result = result && OtpCheckConsistencyVS(tvs, tvs->window);
1970bbfda8aSnia	}
1980bbfda8aSnia	return result;
1990bbfda8aSnia#else
2000bbfda8aSnia	return OtpCheckConsistencyVS(Scr->currentvs, Scr->Root);
2010bbfda8aSnia#endif
2020bbfda8aSnia}
2030bbfda8aSnia
2040bbfda8aSniastatic bool OtpCheckConsistencyVS(VirtualScreen *currentvs, Window vroot)
2050bbfda8aSnia{
2060bbfda8aSnia#if CHECK_OTP
2070bbfda8aSnia	OtpWinList *owl;
2080bbfda8aSnia	TwmWindow *twm_win;
2090bbfda8aSnia	Window root, parent, *children;
2100bbfda8aSnia	unsigned int nchildren;
2110bbfda8aSnia	int priority = 0;
2120bbfda8aSnia	int stack = -1;
2130bbfda8aSnia	int nwins = 0;
2140bbfda8aSnia
2150bbfda8aSnia	XQueryTree(dpy, vroot, &root, &parent, &children, &nchildren);
2160bbfda8aSnia
2170bbfda8aSnia#if DEBUG_OTP
2180bbfda8aSnia	{
2190bbfda8aSnia		int i;
2200bbfda8aSnia		fprintf(stderr, "XQueryTree: %d children:\n", nchildren);
2210bbfda8aSnia
2220bbfda8aSnia		for(i = 0; i < nchildren; i++) {
2230bbfda8aSnia			fprintf(stderr, "[%d]=%x ", i, (unsigned int)children[i]);
2240bbfda8aSnia		}
2250bbfda8aSnia		fprintf(stderr, "\n");
2260bbfda8aSnia	}
2270bbfda8aSnia#endif
2280bbfda8aSnia
2290bbfda8aSnia	for(owl = Scr->bottomOwl; owl != NULL; owl = owl->above) {
2300bbfda8aSnia		twm_win = owl->twm_win;
2310bbfda8aSnia
2320bbfda8aSnia		/* check the back arrows are correct */
2330bbfda8aSnia		assert(((owl->type == IconWin) && (owl == twm_win->icon->otp))
2340bbfda8aSnia		       || ((owl->type == WinWin) && (owl == twm_win->otp)));
2350bbfda8aSnia
2360bbfda8aSnia		/* check the doubly linked list's consistency */
2370bbfda8aSnia		if(owl->below == NULL) {
2380bbfda8aSnia			assert(owl == Scr->bottomOwl);
2390bbfda8aSnia		}
2400bbfda8aSnia		else {
2410bbfda8aSnia			assert(owl->below->above == owl);
2420bbfda8aSnia		}
2430bbfda8aSnia
2440bbfda8aSnia		/* Code already ensures this */
2450bbfda8aSnia		assert(owl->pri_base <= OTP_MAX);
2460bbfda8aSnia
2470bbfda8aSnia		/* List should be bottom->top, so effective pri better ascend */
2480bbfda8aSnia		assert(PRI(owl) >= priority);
2490bbfda8aSnia		priority = PRI(owl);
2500bbfda8aSnia
2510bbfda8aSnia#if DEBUG_OTP
2520bbfda8aSnia
2530bbfda8aSnia		fprintf(stderr, "checking owl: pri %d w=%x stack=%d",
2540bbfda8aSnia		        priority, (unsigned int)WindowOfOwl(owl), stack);
2550bbfda8aSnia		if(twm_win) {
2560bbfda8aSnia			fprintf(stderr, " title=%s occupation=%x ",
2570bbfda8aSnia			        twm_win->name,
2580bbfda8aSnia			        (unsigned int)twm_win->occupation);
2590bbfda8aSnia			if(owl->twm_win->vs) {
2600bbfda8aSnia				fprintf(stderr, " vs:(x,y)=(%d,%d)",
2610bbfda8aSnia				        twm_win->vs->x,
2620bbfda8aSnia				        twm_win->vs->y);
2630bbfda8aSnia			}
2640bbfda8aSnia			else {
2650bbfda8aSnia				fprintf(stderr, " vs:NULL");
2660bbfda8aSnia			}
2670bbfda8aSnia			if(owl->twm_win->parent_vs) {
2680bbfda8aSnia				fprintf(stderr, " parent_vs:(x,y)=(%d,%d)",
2690bbfda8aSnia				        twm_win->parent_vs->x,
2700bbfda8aSnia				        twm_win->parent_vs->y);
2710bbfda8aSnia			}
2720bbfda8aSnia			else {
2730bbfda8aSnia				fprintf(stderr, " parent_vs:NULL");
2740bbfda8aSnia			}
2750bbfda8aSnia		}
2760bbfda8aSnia		fprintf(stderr, " %s\n", (owl->type == WinWin ? "Window" : "Icon"));
2770bbfda8aSnia#endif
2780bbfda8aSnia
2790bbfda8aSnia		/* count the number of twm windows */
2800bbfda8aSnia		if(owl->type == WinWin) {
2810bbfda8aSnia			nwins++;
2820bbfda8aSnia		}
2830bbfda8aSnia
2840bbfda8aSnia		if(twm_win->winbox) {
2850bbfda8aSnia			/*
2860bbfda8aSnia			 * We can't check windows in a WindowBox, since they are
2870bbfda8aSnia			 * not direct children of the Root window.
2880bbfda8aSnia			 */
2890bbfda8aSnia			DPRINTF((stderr, "Can't check this window, it is in a WinBox\n"));
2900bbfda8aSnia			continue;
2910bbfda8aSnia		}
2920bbfda8aSnia
2930bbfda8aSnia		/*
2940bbfda8aSnia		 * Check only windows from the current vitual screen; the others
2950bbfda8aSnia		 * won't show up in the tree from XQueryTree().
2960bbfda8aSnia		 */
2970bbfda8aSnia		if(currentvs == twm_win->parent_vs) {
2980bbfda8aSnia			/* check the window's existence. */
2990bbfda8aSnia			Window windowOfOwl = WindowOfOwl(owl);
3000bbfda8aSnia
3010bbfda8aSnia#if DEBUG_OTP
3020bbfda8aSnia			int i;
3030bbfda8aSnia			for(i = 0; i < nchildren && windowOfOwl != children[i];) {
3040bbfda8aSnia				i++;
3050bbfda8aSnia			}
3060bbfda8aSnia			fprintf(stderr, "search for owl in stack -> i=%d\n", i);
3070bbfda8aSnia			assert(i > stack && "Window not in good place in stack");
3080bbfda8aSnia			assert(i < nchildren && "Window was not found in stack");
3090bbfda8aSnia			if(0) {
3100bbfda8aSnia				char buf[128];
3110bbfda8aSnia				snprintf(buf, 128, "xwininfo -all -id %d", (int)windowOfOwl);
3120bbfda8aSnia				system(buf);
3130bbfda8aSnia			}
3140bbfda8aSnia
3150bbfda8aSnia			/* we know that this always increases stack (assert i>stack) */
3160bbfda8aSnia			stack = i;
3170bbfda8aSnia#else /* DEBUG_OTP */
3180bbfda8aSnia			/* check against the Xserver's stack */
3190bbfda8aSnia			do {
3200bbfda8aSnia				stack++;
3210bbfda8aSnia				DPRINTF((stderr, "stack++: children[%d] = %x\n", stack,
3220bbfda8aSnia				         (unsigned int)children[stack]));
3230bbfda8aSnia				assert(stack < nchildren);
3240bbfda8aSnia			}
3250bbfda8aSnia			while(windowOfOwl != children[stack]);
3260bbfda8aSnia#endif /* DEBUG_OTP */
3270bbfda8aSnia		}
3280bbfda8aSnia	}
3290bbfda8aSnia
3300bbfda8aSnia	XFree(children);
3310bbfda8aSnia
3320bbfda8aSnia	/* by decrementing nwins, check that all the wins are in our list */
3330bbfda8aSnia	for(twm_win = Scr->FirstWindow; twm_win != NULL; twm_win = twm_win->next) {
3340bbfda8aSnia		nwins--;
3350bbfda8aSnia	}
3360bbfda8aSnia	/* if we just removed a win, it might still be somewhere, hence the -1 */
3370bbfda8aSnia	assert((nwins <= 0) && (nwins >= -1));
3380bbfda8aSnia#endif
3390bbfda8aSnia	return true;
3400bbfda8aSnia}
3410bbfda8aSnia
3420bbfda8aSnia
3430bbfda8aSniastatic void RemoveOwl(OtpWinList *owl)
3440bbfda8aSnia{
3450bbfda8aSnia	if(owl->above != NULL) {
3460bbfda8aSnia		owl->above->below = owl->below;
3470bbfda8aSnia	}
3480bbfda8aSnia	if(owl->below != NULL) {
3490bbfda8aSnia		owl->below->above = owl->above;
3500bbfda8aSnia	}
3510bbfda8aSnia	else {
3520bbfda8aSnia		Scr->bottomOwl = owl->above;
3530bbfda8aSnia	}
3540bbfda8aSnia	owl->below = NULL;
3550bbfda8aSnia	owl->above = NULL;
3560bbfda8aSnia}
3570bbfda8aSnia
3580bbfda8aSnia
3590bbfda8aSnia/**
3600bbfda8aSnia * For the purpose of putting a window above another,
3610bbfda8aSnia * they need to have the same parent, i.e. be in the same
3620bbfda8aSnia * VirtualScreen.
3630bbfda8aSnia */
3640bbfda8aSniastatic OtpWinList *GetOwlAtOrBelowInVS(OtpWinList *owl, VirtualScreen *vs)
3650bbfda8aSnia{
3660bbfda8aSnia	while(owl != NULL && owl->twm_win->parent_vs != vs) {
3670bbfda8aSnia		owl = owl->below;
3680bbfda8aSnia	}
3690bbfda8aSnia
3700bbfda8aSnia	return owl;
3710bbfda8aSnia}
3720bbfda8aSnia
3730bbfda8aSnia/*
3740bbfda8aSnia * Windows in a box don't really occur in the stacking order of the
3750bbfda8aSnia * root window.
3760bbfda8aSnia * In the OWL list, keep them just on top of their box, in their
3770bbfda8aSnia * respective order of course.
3780bbfda8aSnia * Therefore we may need to update the owl we're going to be above.
3790bbfda8aSnia */
3800bbfda8aSniastatic OtpWinList *GetOwlAtOrBelowInWinbox(OtpWinList **owlp, WindowBox *wb)
3810bbfda8aSnia{
3820bbfda8aSnia	OtpWinList *owl = *owlp;
3830bbfda8aSnia
3840bbfda8aSnia	while(owl != NULL && owl->twm_win->winbox != wb) {
3850bbfda8aSnia		owl = owl->below;
3860bbfda8aSnia	}
3870bbfda8aSnia
3880bbfda8aSnia	if(owl == NULL) {
3890bbfda8aSnia		/* we have gone below the box: put it just on top of it */
3900bbfda8aSnia		*owlp = wb->twmwin->otp;
3910bbfda8aSnia	}
3920bbfda8aSnia	else {
3930bbfda8aSnia		*owlp = owl;
3940bbfda8aSnia	}
3950bbfda8aSnia	return owl;
3960bbfda8aSnia}
3970bbfda8aSnia
3980bbfda8aSnia
3990bbfda8aSniastatic void InsertOwlAbove(OtpWinList *owl, OtpWinList *other_owl)
4000bbfda8aSnia{
4010bbfda8aSnia#if DEBUG_OTP
4020bbfda8aSnia	fprintf(stderr, "InsertOwlAbove owl->pri=%d w=0x%x parent_vs:(x,y)=(%d,%d)",
4030bbfda8aSnia	        PRI(owl),
4040bbfda8aSnia	        (unsigned int)WindowOfOwl(owl),
4050bbfda8aSnia	        owl->twm_win->parent_vs->x,
4060bbfda8aSnia	        owl->twm_win->parent_vs->y);
4070bbfda8aSnia	if(other_owl != NULL) {
4080bbfda8aSnia		fprintf(stderr, "\n  other_owl->pri=%d w=0x%x parent_vs:(x,y)=(%d,%d)",
4090bbfda8aSnia		        PRI(other_owl),
4100bbfda8aSnia		        (unsigned int)WindowOfOwl(other_owl),
4110bbfda8aSnia		        owl->twm_win->parent_vs->x,
4120bbfda8aSnia		        owl->twm_win->parent_vs->y);
4130bbfda8aSnia	}
4140bbfda8aSnia	fprintf(stderr, "\n");
4150bbfda8aSnia#endif
4160bbfda8aSnia
4170bbfda8aSnia	assert(owl->above == NULL);
4180bbfda8aSnia	assert(owl->below == NULL);
4190bbfda8aSnia
4200bbfda8aSnia
4210bbfda8aSnia	if(other_owl == NULL) {
4220bbfda8aSnia		DPRINTF((stderr, "Bottom-most window overall\n"));
4230bbfda8aSnia		/* special case for the lowest window overall */
4240bbfda8aSnia		assert(PRI(owl) <= PRI(Scr->bottomOwl));
4250bbfda8aSnia
4260bbfda8aSnia		/* pass the action to the Xserver */
4270bbfda8aSnia		XLowerWindow(dpy, WindowOfOwl(owl));
4280bbfda8aSnia
4290bbfda8aSnia		/* update the list */
4300bbfda8aSnia		owl->above = Scr->bottomOwl;
4310bbfda8aSnia		owl->above->below = owl;
4320bbfda8aSnia		Scr->bottomOwl = owl;
4330bbfda8aSnia	}
4340bbfda8aSnia	else {
4350bbfda8aSnia		WindowBox *winbox = owl->twm_win->winbox;
4360bbfda8aSnia		OtpWinList *vs_owl;
4370bbfda8aSnia
4380bbfda8aSnia		if(winbox != NULL) {
4390bbfda8aSnia			vs_owl = GetOwlAtOrBelowInWinbox(&other_owl, winbox);
4400bbfda8aSnia		}
4410bbfda8aSnia		else {
4420bbfda8aSnia
4430bbfda8aSnia			vs_owl = GetOwlAtOrBelowInVS(other_owl, owl->twm_win->parent_vs);
4440bbfda8aSnia		}
4450bbfda8aSnia
4460bbfda8aSnia		assert(PRI(owl) >= PRI(other_owl));
4470bbfda8aSnia		if(other_owl->above != NULL) {
4480bbfda8aSnia			assert(PRI(owl) <= PRI(other_owl->above));
4490bbfda8aSnia		}
4500bbfda8aSnia
4510bbfda8aSnia		if(vs_owl == NULL) {
4520bbfda8aSnia			DPRINTF((stderr, "Bottom-most window in VirtualScreen or window box\n"));
4530bbfda8aSnia			/* special case for the lowest window in this virtual screen or window box */
4540bbfda8aSnia
4550bbfda8aSnia			/* pass the action to the Xserver */
4560bbfda8aSnia			XLowerWindow(dpy, WindowOfOwl(owl));
4570bbfda8aSnia		}
4580bbfda8aSnia		else {
4590bbfda8aSnia			XWindowChanges xwc;
4600bbfda8aSnia			int xwcm;
4610bbfda8aSnia
4620bbfda8aSnia			DPRINTF((stderr, "General case\n"));
4630bbfda8aSnia			/* general case */
4640bbfda8aSnia			assert(PRI(vs_owl) <= PRI(other_owl));
4650bbfda8aSnia			assert(owl->twm_win->parent_vs == vs_owl->twm_win->parent_vs);
4660bbfda8aSnia
4670bbfda8aSnia			/* pass the action to the Xserver */
4680bbfda8aSnia			xwcm = CWStackMode | CWSibling;
4690bbfda8aSnia			xwc.sibling = WindowOfOwl(vs_owl);
4700bbfda8aSnia			xwc.stack_mode = Above;
4710bbfda8aSnia			XConfigureWindow(dpy, WindowOfOwl(owl), xwcm, &xwc);
4720bbfda8aSnia		}
4730bbfda8aSnia
4740bbfda8aSnia		/* update the list */
4750bbfda8aSnia		owl->below = other_owl;
4760bbfda8aSnia		owl->above = other_owl->above;
4770bbfda8aSnia		owl->below->above = owl;
4780bbfda8aSnia		if(owl->above != NULL) {
4790bbfda8aSnia			owl->above->below = owl;
4800bbfda8aSnia		}
4810bbfda8aSnia	}
4820bbfda8aSnia}
4830bbfda8aSnia
4840bbfda8aSnia
4850bbfda8aSnia/* should owl stay above other_owl if other_owl was raised ? */
4860bbfda8aSniastatic bool shouldStayAbove(OtpWinList *owl, OtpWinList *other_owl)
4870bbfda8aSnia{
4880bbfda8aSnia	return ((owl->type == WinWin)
4890bbfda8aSnia	        && (other_owl->type == WinWin)
4900bbfda8aSnia	        && isSmallTransientOf(owl->twm_win, other_owl->twm_win));
4910bbfda8aSnia}
4920bbfda8aSnia
4930bbfda8aSnia
4940bbfda8aSniastatic void RaiseSmallTransientsOfAbove(OtpWinList *owl, OtpWinList *other_owl)
4950bbfda8aSnia{
4960bbfda8aSnia	OtpWinList *trans_owl, *tmp_owl;
4970bbfda8aSnia
4980bbfda8aSnia	/* the icons have no transients and we can't have windows below NULL */
4990bbfda8aSnia	if((owl->type != WinWin) || other_owl == NULL) {
5000bbfda8aSnia		return;
5010bbfda8aSnia	}
5020bbfda8aSnia
5030bbfda8aSnia	/* beware: we modify the list as we scan it. This is the reason for tmp */
5040bbfda8aSnia	for(trans_owl = other_owl->below; trans_owl != NULL; trans_owl = tmp_owl) {
5050bbfda8aSnia		tmp_owl = trans_owl->below;
5060bbfda8aSnia		if(shouldStayAbove(trans_owl, owl)) {
5070bbfda8aSnia			RemoveOwl(trans_owl);
5080bbfda8aSnia			PRI_CP(owl, trans_owl);
5090bbfda8aSnia			InsertOwlAbove(trans_owl, other_owl);
5100bbfda8aSnia		}
5110bbfda8aSnia	}
5120bbfda8aSnia}
5130bbfda8aSnia
5140bbfda8aSnia
5150bbfda8aSniastatic OtpWinList *OwlRightBelow(int priority)
5160bbfda8aSnia{
5170bbfda8aSnia	OtpWinList *owl1, *owl2;
5180bbfda8aSnia
5190bbfda8aSnia	/* in case there isn't anything below */
5200bbfda8aSnia	if(priority <= PRI(Scr->bottomOwl)) {
5210bbfda8aSnia		return NULL;
5220bbfda8aSnia	}
5230bbfda8aSnia
5240bbfda8aSnia	for(owl1 = Scr->bottomOwl, owl2 = owl1->above;
5250bbfda8aSnia	                (owl2 != NULL) && (PRI(owl2) < priority);
5260bbfda8aSnia	                owl1 = owl2, owl2 = owl2->above) {
5270bbfda8aSnia		/* nada */;
5280bbfda8aSnia	}
5290bbfda8aSnia
5300bbfda8aSnia	assert(owl2 == owl1->above);
5310bbfda8aSnia	assert(PRI(owl1) < priority);
5320bbfda8aSnia	assert((owl2 == NULL) || (PRI(owl2) >= priority));
5330bbfda8aSnia
5340bbfda8aSnia
5350bbfda8aSnia	return owl1;
5360bbfda8aSnia}
5370bbfda8aSnia
5380bbfda8aSniastatic void InsertOwl(OtpWinList *owl, int where)
5390bbfda8aSnia{
5400bbfda8aSnia	OtpWinList *other_owl;
5410bbfda8aSnia	int priority;
5420bbfda8aSnia
5430bbfda8aSnia	DPRINTF((stderr, "InsertOwl %s\n",
5440bbfda8aSnia	         (where == Above) ? "Above" :
5450bbfda8aSnia	         (where == Below) ? "Below" :
5460bbfda8aSnia	         "???"));
5470bbfda8aSnia	assert(owl->above == NULL);
5480bbfda8aSnia	assert(owl->below == NULL);
5490bbfda8aSnia	assert((where == Above) || (where == Below));
5500bbfda8aSnia
5510bbfda8aSnia	priority = PRI(owl) - (where == Above ? 0 : 1);
5520bbfda8aSnia
5530bbfda8aSnia	if(Scr->bottomOwl == NULL) {
5540bbfda8aSnia		/* for the first window: just insert it in the list */
5550bbfda8aSnia		Scr->bottomOwl = owl;
5560bbfda8aSnia	}
5570bbfda8aSnia	else {
5580bbfda8aSnia		other_owl = OwlRightBelow(priority + 1);
5590bbfda8aSnia
5600bbfda8aSnia		/* make sure other_owl is not one of the transients */
5610bbfda8aSnia		while((other_owl != NULL)
5620bbfda8aSnia		                && shouldStayAbove(other_owl, owl)) {
5630bbfda8aSnia			PRI_CP(owl, other_owl);
5640bbfda8aSnia
5650bbfda8aSnia			other_owl = other_owl->below;
5660bbfda8aSnia		}
5670bbfda8aSnia
5680bbfda8aSnia		/* raise the transient windows that should stay on top */
5690bbfda8aSnia		RaiseSmallTransientsOfAbove(owl, other_owl);
5700bbfda8aSnia
5710bbfda8aSnia		/* now go ahead and put the window where it should go */
5720bbfda8aSnia		InsertOwlAbove(owl, other_owl);
5730bbfda8aSnia	}
5740bbfda8aSnia}
5750bbfda8aSnia
5760bbfda8aSnia
5770bbfda8aSniastatic void SetOwlPriority(OtpWinList *owl, int new_pri, int where)
5780bbfda8aSnia{
5790bbfda8aSnia	DPRINTF((stderr, "SetOwlPriority(%d)\n", new_pri));
5800bbfda8aSnia
5810bbfda8aSnia	/* make sure the values are within bounds */
5820bbfda8aSnia	if(new_pri < 0) {
5830bbfda8aSnia		new_pri = 0;
5840bbfda8aSnia	}
5850bbfda8aSnia	if(new_pri > OTP_MAX) {
5860bbfda8aSnia		new_pri = OTP_MAX;
5870bbfda8aSnia	}
5880bbfda8aSnia
5890bbfda8aSnia	RemoveOwl(owl);
5900bbfda8aSnia	owl->pri_base = new_pri;
5910bbfda8aSnia	InsertOwl(owl, where);
5920bbfda8aSnia
5930bbfda8aSnia	assert(owl->pri_base == new_pri);
5940bbfda8aSnia}
5950bbfda8aSnia
5960bbfda8aSnia
5970bbfda8aSnia/*
5980bbfda8aSnia * Shift transients of a window to a new [base] priority, preparatory to
5990bbfda8aSnia * moving that window itself there.
6000bbfda8aSnia */
6010bbfda8aSniastatic void TryToMoveTransientsOfTo(OtpWinList *owl, int priority, int where)
6020bbfda8aSnia{
6030bbfda8aSnia	OtpWinList *other_owl;
6040bbfda8aSnia
6050bbfda8aSnia	/* the icons have no transients */
6060bbfda8aSnia	if(owl->type != WinWin) {
6070bbfda8aSnia		return;
6080bbfda8aSnia	}
6090bbfda8aSnia
6100bbfda8aSnia	/*
6110bbfda8aSnia	 * We start looking for transients of owl at the bottom of its OTP
6120bbfda8aSnia	 * layer.
6130bbfda8aSnia	 */
6140bbfda8aSnia	other_owl = OwlRightBelow(PRI(owl));
6150bbfda8aSnia	other_owl = (other_owl == NULL) ? Scr->bottomOwl : other_owl->above;
6160bbfda8aSnia	assert(PRI(other_owl) >= PRI(owl));
6170bbfda8aSnia
6180bbfda8aSnia	/* !beware! we're changing the list as we scan it, hence the tmp_owl */
6190bbfda8aSnia	while((other_owl != NULL) && (PRI(other_owl) == PRI(owl))) {
6200bbfda8aSnia		OtpWinList *tmp_owl = other_owl->above;
6210bbfda8aSnia		if((other_owl->type == WinWin)
6220bbfda8aSnia		                && isTransientOf(other_owl->twm_win, owl->twm_win)) {
6230bbfda8aSnia			/* Copy in our flags so it winds up in the right place */
6240bbfda8aSnia			other_owl->pri_aflags = owl->pri_aflags;
6250bbfda8aSnia			SetOwlPriority(other_owl, priority, where);
6260bbfda8aSnia		}
6270bbfda8aSnia		other_owl = tmp_owl;
6280bbfda8aSnia	}
6290bbfda8aSnia}
6300bbfda8aSnia
6310bbfda8aSniastatic void TryToSwitch(OtpWinList *owl, int where)
6320bbfda8aSnia{
6330bbfda8aSnia	int priority;
6340bbfda8aSnia
6350bbfda8aSnia	if(!owl->switching) {
6360bbfda8aSnia		return;
6370bbfda8aSnia	}
6380bbfda8aSnia
6390bbfda8aSnia	/*
6400bbfda8aSnia	 * Switching is purely an adjustment to the base priority, so we
6410bbfda8aSnia	 * don't need to figure stuff based on the effective.
6420bbfda8aSnia	 */
6430bbfda8aSnia	priority = OTP_MAX - owl->pri_base;
6440bbfda8aSnia	if(((where == Above) && (priority > owl->pri_base)) ||
6450bbfda8aSnia	                ((where == Below) && (priority < owl->pri_base))) {
6460bbfda8aSnia		/*
6470bbfda8aSnia		 * TTMTOT() before changing pri_base since it uses the current
6480bbfda8aSnia		 * state to find the transients.
6490bbfda8aSnia		 */
6500bbfda8aSnia		TryToMoveTransientsOfTo(owl, priority, where);
6510bbfda8aSnia		owl->pri_base = priority;
6520bbfda8aSnia	}
6530bbfda8aSnia}
6540bbfda8aSnia
6550bbfda8aSniastatic void RaiseOwl(OtpWinList *owl)
6560bbfda8aSnia{
6570bbfda8aSnia	TryToSwitch(owl, Above);
6580bbfda8aSnia	RemoveOwl(owl);
6590bbfda8aSnia	InsertOwl(owl, Above);
6600bbfda8aSnia}
6610bbfda8aSnia
6620bbfda8aSnia
6630bbfda8aSniastatic void LowerOwl(OtpWinList *owl)
6640bbfda8aSnia{
6650bbfda8aSnia	TryToSwitch(owl, Below);
6660bbfda8aSnia	RemoveOwl(owl);
6670bbfda8aSnia	InsertOwl(owl, Below);
6680bbfda8aSnia}
6690bbfda8aSnia
6700bbfda8aSniastatic bool isHiddenBy(OtpWinList *owl, OtpWinList *other_owl)
6710bbfda8aSnia{
6720bbfda8aSnia	/* doesn't check that owl is on screen */
6730bbfda8aSnia	return (isOnScreen(other_owl)
6740bbfda8aSnia	        && isIntersectingWith(owl, other_owl));
6750bbfda8aSnia}
6760bbfda8aSnia
6770bbfda8aSniastatic void TinyRaiseOwl(OtpWinList *owl)
6780bbfda8aSnia{
6790bbfda8aSnia	OtpWinList *other_owl = owl->above;
6800bbfda8aSnia
6810bbfda8aSnia	while((other_owl != NULL) && (PRI(other_owl) == PRI(owl))) {
6820bbfda8aSnia		if(isHiddenBy(owl, other_owl)
6830bbfda8aSnia		                && !shouldStayAbove(other_owl, owl)) {
6840bbfda8aSnia			RemoveOwl(owl);
6850bbfda8aSnia			RaiseSmallTransientsOfAbove(owl, other_owl);
6860bbfda8aSnia			InsertOwlAbove(owl, other_owl);
6870bbfda8aSnia			return;
6880bbfda8aSnia		}
6890bbfda8aSnia		else {
6900bbfda8aSnia			other_owl = other_owl->above;
6910bbfda8aSnia		}
6920bbfda8aSnia	}
6930bbfda8aSnia}
6940bbfda8aSnia
6950bbfda8aSniastatic void TinyLowerOwl(OtpWinList *owl)
6960bbfda8aSnia{
6970bbfda8aSnia	OtpWinList *other_owl = owl->below;
6980bbfda8aSnia
6990bbfda8aSnia	while((other_owl != NULL) && (PRI(other_owl) == PRI(owl))) {
7000bbfda8aSnia		if(isHiddenBy(owl, other_owl)) {
7010bbfda8aSnia			RemoveOwl(owl);
7020bbfda8aSnia			InsertOwlAbove(owl, other_owl->below);
7030bbfda8aSnia			return;
7040bbfda8aSnia		}
7050bbfda8aSnia		else {
7060bbfda8aSnia			other_owl = other_owl->below;
7070bbfda8aSnia		}
7080bbfda8aSnia	}
7090bbfda8aSnia}
7100bbfda8aSnia
7110bbfda8aSniastatic void RaiseLowerOwl(OtpWinList *owl)
7120bbfda8aSnia{
7130bbfda8aSnia	OtpWinList *other_owl;
7140bbfda8aSnia	int priority;
7150bbfda8aSnia
7160bbfda8aSnia	/*
7170bbfda8aSnia	 * abs(effective pri)
7180bbfda8aSnia	 *
7190bbfda8aSnia	 * XXX Why?  This seems like it's encoding the assumption
7200bbfda8aSnia	 * "f.raiselower should assume any negative [user-level] priorities
7210bbfda8aSnia	 * are a result of a window that should be positive being switched,
7220bbfda8aSnia	 * and we should switch it positive before raising if we need to", or
7230bbfda8aSnia	 * some such.
7240bbfda8aSnia	 */
7250bbfda8aSnia	priority = MAX(PRI(owl), OTP_MAX - PRI(owl));
7260bbfda8aSnia
7270bbfda8aSnia	for(other_owl = owl->above;
7280bbfda8aSnia	                (other_owl != NULL) && (PRI(other_owl) <= priority);
7290bbfda8aSnia	                other_owl = other_owl->above) {
7300bbfda8aSnia		if(isHiddenBy(owl, other_owl)
7310bbfda8aSnia		                && !shouldStayAbove(other_owl, owl)) {
7320bbfda8aSnia			RaiseOwl(owl);
7330bbfda8aSnia			return;
7340bbfda8aSnia		}
7350bbfda8aSnia	}
7360bbfda8aSnia	LowerOwl(owl);
7370bbfda8aSnia}
7380bbfda8aSnia
7390bbfda8aSnia
7400bbfda8aSniavoid OtpRaise(TwmWindow *twm_win, WinType wintype)
7410bbfda8aSnia{
7420bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
7430bbfda8aSnia	assert(owl != NULL);
7440bbfda8aSnia
7450bbfda8aSnia	RaiseOwl(owl);
7460bbfda8aSnia
7470bbfda8aSnia	OtpCheckConsistency();
7480bbfda8aSnia#ifdef EWMH
7490bbfda8aSnia	EwmhSet_NET_CLIENT_LIST_STACKING();
7500bbfda8aSnia#endif /* EWMH */
7510bbfda8aSnia}
7520bbfda8aSnia
7530bbfda8aSnia
7540bbfda8aSniavoid OtpLower(TwmWindow *twm_win, WinType wintype)
7550bbfda8aSnia{
7560bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
7570bbfda8aSnia	assert(owl != NULL);
7580bbfda8aSnia
7590bbfda8aSnia	LowerOwl(owl);
7600bbfda8aSnia
7610bbfda8aSnia	OtpCheckConsistency();
7620bbfda8aSnia#ifdef EWMH
7630bbfda8aSnia	EwmhSet_NET_CLIENT_LIST_STACKING();
7640bbfda8aSnia#endif /* EWMH */
7650bbfda8aSnia}
7660bbfda8aSnia
7670bbfda8aSnia
7680bbfda8aSniavoid OtpRaiseLower(TwmWindow *twm_win, WinType wintype)
7690bbfda8aSnia{
7700bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
7710bbfda8aSnia	assert(owl != NULL);
7720bbfda8aSnia
7730bbfda8aSnia	RaiseLowerOwl(owl);
7740bbfda8aSnia
7750bbfda8aSnia	OtpCheckConsistency();
7760bbfda8aSnia#ifdef EWMH
7770bbfda8aSnia	EwmhSet_NET_CLIENT_LIST_STACKING();
7780bbfda8aSnia#endif /* EWMH */
7790bbfda8aSnia}
7800bbfda8aSnia
7810bbfda8aSnia
7820bbfda8aSniavoid OtpTinyRaise(TwmWindow *twm_win, WinType wintype)
7830bbfda8aSnia{
7840bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
7850bbfda8aSnia	assert(owl != NULL);
7860bbfda8aSnia
7870bbfda8aSnia	TinyRaiseOwl(owl);
7880bbfda8aSnia
7890bbfda8aSnia	OtpCheckConsistency();
7900bbfda8aSnia#ifdef EWMH
7910bbfda8aSnia	EwmhSet_NET_CLIENT_LIST_STACKING();
7920bbfda8aSnia#endif /* EWMH */
7930bbfda8aSnia}
7940bbfda8aSnia
7950bbfda8aSnia
7960bbfda8aSniavoid OtpTinyLower(TwmWindow *twm_win, WinType wintype)
7970bbfda8aSnia{
7980bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
7990bbfda8aSnia	assert(owl != NULL);
8000bbfda8aSnia
8010bbfda8aSnia	TinyLowerOwl(owl);
8020bbfda8aSnia
8030bbfda8aSnia	OtpCheckConsistency();
8040bbfda8aSnia#ifdef EWMH
8050bbfda8aSnia	EwmhSet_NET_CLIENT_LIST_STACKING();
8060bbfda8aSnia#endif /* EWMH */
8070bbfda8aSnia}
8080bbfda8aSnia
8090bbfda8aSnia
8100bbfda8aSnia/*
8110bbfda8aSnia * XCirculateSubwindows() is complicated by the fact that it restacks only
8120bbfda8aSnia * in case of overlapping windows. Therefore it seems easier to not
8130bbfda8aSnia * try to emulate that but to leave it to the X server.
8140bbfda8aSnia *
8150bbfda8aSnia * If XCirculateSubwindows() actually does something, it sends a
8160bbfda8aSnia * CirculateNotify event, but you only receive it if
8170bbfda8aSnia * SubstructureNotifyMask is selected on the root window.
8180bbfda8aSnia * However... if that is done from the beginning, for some reason all
8190bbfda8aSnia * windows disappear when ctwm starts or exits.
8200bbfda8aSnia * Maybe SubstructureNotifyMask interferes with SubstructureRedirectMask?
8210bbfda8aSnia *
8220bbfda8aSnia * To get around that, the SubstructureNotifyMask is selected only
8230bbfda8aSnia * temporarily here when wanted.
8240bbfda8aSnia */
8250bbfda8aSnia
8260bbfda8aSniavoid OtpCirculateSubwindows(VirtualScreen *vs, int direction)
8270bbfda8aSnia{
8280bbfda8aSnia	Window w = vs->window;
8290bbfda8aSnia	XWindowAttributes winattrs;
8300bbfda8aSnia	Bool circulated;
8310bbfda8aSnia
8320bbfda8aSnia	DPRINTF((stderr, "OtpCirculateSubwindows %d\n", direction));
8330bbfda8aSnia
8340bbfda8aSnia	XGetWindowAttributes(dpy, w, &winattrs);
8350bbfda8aSnia	XSelectInput(dpy, w, winattrs.your_event_mask | SubstructureNotifyMask);
8360bbfda8aSnia	XCirculateSubwindows(dpy, w, direction);
8370bbfda8aSnia	XSelectInput(dpy, w, winattrs.your_event_mask);
8380bbfda8aSnia	/*
8390bbfda8aSnia	 * Now we should get the CirculateNotify event.
8400bbfda8aSnia	 * It usually seems to arrive soon enough, but just to be sure, look
8410bbfda8aSnia	 * ahead in the message queue to see if it can be expedited.
8420bbfda8aSnia	 */
8430bbfda8aSnia	circulated = XCheckTypedWindowEvent(dpy, w, CirculateNotify, &Event);
8440bbfda8aSnia	if(circulated) {
8450bbfda8aSnia		HandleCirculateNotify();
8460bbfda8aSnia	}
8470bbfda8aSnia}
8480bbfda8aSnia
8490bbfda8aSnia/*
8500bbfda8aSnia * Update our list of Owls after the Circulate action, and also
8510bbfda8aSnia * enforce the priority by possibly restacking the window again.
8520bbfda8aSnia */
8530bbfda8aSnia
8540bbfda8aSniavoid OtpHandleCirculateNotify(VirtualScreen *vs, TwmWindow *twm_win,
8550bbfda8aSnia                              WinType wintype, int place)
8560bbfda8aSnia{
8570bbfda8aSnia	switch(place) {
8580bbfda8aSnia		case PlaceOnTop:
8590bbfda8aSnia			OtpRaise(twm_win, wintype);
8600bbfda8aSnia			break;
8610bbfda8aSnia		case PlaceOnBottom:
8620bbfda8aSnia			OtpLower(twm_win, wintype);
8630bbfda8aSnia			break;
8640bbfda8aSnia		default:
8650bbfda8aSnia			DPRINTF((stderr, "OtpHandleCirculateNotify: place=%d\n", place));
8660bbfda8aSnia			assert(0 &&
8670bbfda8aSnia			       "OtpHandleCirculateNotify: place equals PlaceOnTop nor PlaceOnBottom");
8680bbfda8aSnia	}
8690bbfda8aSnia}
8700bbfda8aSnia
8710bbfda8aSniavoid OtpSetPriority(TwmWindow *twm_win, WinType wintype, int new_pri, int where)
8720bbfda8aSnia{
8730bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
8740bbfda8aSnia	int priority = OTP_ZERO + new_pri;
8750bbfda8aSnia
8760bbfda8aSnia	DPRINTF((stderr, "OtpSetPriority: new_pri=%d\n", new_pri));
8770bbfda8aSnia	assert(owl != NULL);
8780bbfda8aSnia
8790bbfda8aSnia	if(twm_win->winbox != NULL || twm_win->iswinbox) {
8800bbfda8aSnia		return;
8810bbfda8aSnia	}
8820bbfda8aSnia
8830bbfda8aSnia	if(ABS(new_pri) > OTP_ZERO) {
8840bbfda8aSnia		DPRINTF((stderr, "invalid OnTopPriority value: %d\n", new_pri));
8850bbfda8aSnia	}
8860bbfda8aSnia	else {
8870bbfda8aSnia		TryToMoveTransientsOfTo(owl, priority, where);
8880bbfda8aSnia		SetOwlPriority(owl, priority, where);
8890bbfda8aSnia	}
8900bbfda8aSnia
8910bbfda8aSnia	OtpCheckConsistency();
8920bbfda8aSnia}
8930bbfda8aSnia
8940bbfda8aSnia
8950bbfda8aSniavoid OtpChangePriority(TwmWindow *twm_win, WinType wintype, int relpriority)
8960bbfda8aSnia{
8970bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
8980bbfda8aSnia	int priority = owl->pri_base + relpriority;
8990bbfda8aSnia	int where;
9000bbfda8aSnia
9010bbfda8aSnia	if(twm_win->winbox != NULL || twm_win->iswinbox) {
9020bbfda8aSnia		return;
9030bbfda8aSnia	}
9040bbfda8aSnia
9050bbfda8aSnia	where = relpriority < 0 ? Below : Above;
9060bbfda8aSnia
9070bbfda8aSnia	TryToMoveTransientsOfTo(owl, priority, where);
9080bbfda8aSnia	SetOwlPriority(owl, priority, where);
9090bbfda8aSnia
9100bbfda8aSnia	OtpCheckConsistency();
9110bbfda8aSnia}
9120bbfda8aSnia
9130bbfda8aSnia
9140bbfda8aSniavoid OtpSwitchPriority(TwmWindow *twm_win, WinType wintype)
9150bbfda8aSnia{
9160bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
9170bbfda8aSnia	int priority = OTP_MAX - owl->pri_base;
9180bbfda8aSnia	int where;
9190bbfda8aSnia
9200bbfda8aSnia	assert(owl != NULL);
9210bbfda8aSnia
9220bbfda8aSnia	if(twm_win->winbox != NULL || twm_win->iswinbox) {
9230bbfda8aSnia		return;
9240bbfda8aSnia	}
9250bbfda8aSnia
9260bbfda8aSnia	where = priority < OTP_ZERO ? Below : Above;
9270bbfda8aSnia	TryToMoveTransientsOfTo(owl, priority, where);
9280bbfda8aSnia	SetOwlPriority(owl, priority, where);
9290bbfda8aSnia
9300bbfda8aSnia	OtpCheckConsistency();
9310bbfda8aSnia}
9320bbfda8aSnia
9330bbfda8aSnia
9340bbfda8aSniavoid OtpToggleSwitching(TwmWindow *twm_win, WinType wintype)
9350bbfda8aSnia{
9360bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
9370bbfda8aSnia	assert(owl != NULL);
9380bbfda8aSnia
9390bbfda8aSnia	if(twm_win->winbox != NULL || twm_win->iswinbox) {
9400bbfda8aSnia		return;
9410bbfda8aSnia	}
9420bbfda8aSnia
9430bbfda8aSnia	owl->switching = !owl->switching;
9440bbfda8aSnia
9450bbfda8aSnia	OtpCheckConsistency();
9460bbfda8aSnia}
9470bbfda8aSnia
9480bbfda8aSnia
9490bbfda8aSnia/*
9500bbfda8aSnia * This is triggered as a result of a StackMode ConfigureRequest.  We
9510bbfda8aSnia * choose to interpret this as restacking relative to the base
9520bbfda8aSnia * priorities, since all the alterations are EWMH-related, and those
9530bbfda8aSnia * should probably override.
9540bbfda8aSnia *
9550bbfda8aSnia * XXX Or should they?  Maybe we should alter until our effective is
9560bbfda8aSnia * positioned as desired relative to their effective?  This may also need
9570bbfda8aSnia * revisiting if we grow alterations that aren't a result of EWMH stuff.
9580bbfda8aSnia */
9590bbfda8aSniavoid OtpForcePlacement(TwmWindow *twm_win, int where, TwmWindow *other_win)
9600bbfda8aSnia{
9610bbfda8aSnia	OtpWinList *owl = twm_win->otp;
9620bbfda8aSnia	OtpWinList *other_owl = other_win->otp;
9630bbfda8aSnia
9640bbfda8aSnia	assert(twm_win->otp != NULL);
9650bbfda8aSnia	assert(other_win->otp != NULL);
9660bbfda8aSnia
9670bbfda8aSnia	if(where == BottomIf) {
9680bbfda8aSnia		where = Below;
9690bbfda8aSnia	}
9700bbfda8aSnia	if(where != Below) {
9710bbfda8aSnia		where = Above;
9720bbfda8aSnia	}
9730bbfda8aSnia
9740bbfda8aSnia	/* remove the owl to change it */
9750bbfda8aSnia	RemoveOwl(owl);
9760bbfda8aSnia
9770bbfda8aSnia	/*
9780bbfda8aSnia	 * Base our priority base off that other win.  Don't use PRI_CP since
9790bbfda8aSnia	 * we shouldn't suddenly get its flags as well.
9800bbfda8aSnia	 */
9810bbfda8aSnia	owl->pri_base = other_owl->pri_base;
9820bbfda8aSnia
9830bbfda8aSnia	/* put the owl back into the list */
9840bbfda8aSnia	if(where == Below) {
9850bbfda8aSnia		other_owl = other_owl->below;
9860bbfda8aSnia	}
9870bbfda8aSnia	InsertOwlAbove(owl, other_owl);
9880bbfda8aSnia
9890bbfda8aSnia	OtpCheckConsistency();
9900bbfda8aSnia}
9910bbfda8aSnia
9920bbfda8aSnia
9930bbfda8aSniastatic void ApplyPreferences(OtpPreferences *prefs, OtpWinList *owl)
9940bbfda8aSnia{
9950bbfda8aSnia	int i;
9960bbfda8aSnia	TwmWindow *twm_win = owl->twm_win;
9970bbfda8aSnia
9980bbfda8aSnia	/* check PrioritySwitch */
9990bbfda8aSnia	if(LookInList(prefs->switchingL, twm_win->name, &twm_win->class)) {
10000bbfda8aSnia		owl->switching = !prefs->switching;
10010bbfda8aSnia	}
10020bbfda8aSnia
10030bbfda8aSnia	/* check OnTopPriority */
10040bbfda8aSnia	for(i = 0; i <= OTP_MAX; i++) {
10050bbfda8aSnia		if(LookInList(prefs->priorityL[i],
10060bbfda8aSnia		                twm_win->name, &twm_win->class)) {
10070bbfda8aSnia			owl->pri_base = i;
10080bbfda8aSnia		}
10090bbfda8aSnia	}
10100bbfda8aSnia}
10110bbfda8aSnia
10120bbfda8aSnia
10130bbfda8aSnia/*
10140bbfda8aSnia * Reset stuff based on preferences; called during property changes if
10150bbfda8aSnia * AutoPriority set.
10160bbfda8aSnia */
10170bbfda8aSniastatic void RecomputeOwlPrefs(OtpPreferences *prefs, OtpWinList *owl)
10180bbfda8aSnia{
10190bbfda8aSnia	int old_pri;
10200bbfda8aSnia
10210bbfda8aSnia	old_pri = owl->pri_base;
10220bbfda8aSnia	ApplyPreferences(prefs, owl);
10230bbfda8aSnia	if(old_pri != owl->pri_base) {
10240bbfda8aSnia		RemoveOwl(owl);
10250bbfda8aSnia		InsertOwl(owl, Above);
10260bbfda8aSnia
10270bbfda8aSnia		/*
10280bbfda8aSnia		 * Stash flags if we don't have any yet, since we just changed
10290bbfda8aSnia		 * the priority.
10300bbfda8aSnia		 */
10310bbfda8aSnia		if(!owl->stashed_aflags) {
10320bbfda8aSnia			OwlStashAflags(owl);
10330bbfda8aSnia		}
10340bbfda8aSnia
10350bbfda8aSnia#ifdef EWMH
10360bbfda8aSnia		/* Let other things know we did something with stacking */
10370bbfda8aSnia		EwmhSet_NET_WM_STATE(owl->twm_win, EWMH_STATE_ABOVE);
10380bbfda8aSnia#endif
10390bbfda8aSnia	}
10400bbfda8aSnia}
10410bbfda8aSnia
10420bbfda8aSniavoid OtpRecomputePrefs(TwmWindow *twm_win)
10430bbfda8aSnia{
10440bbfda8aSnia	assert(twm_win->otp != NULL);
10450bbfda8aSnia
10460bbfda8aSnia	RecomputeOwlPrefs(Scr->OTP, twm_win->otp);
10470bbfda8aSnia	if(twm_win->icon != NULL) {
10480bbfda8aSnia		RecomputeOwlPrefs(Scr->IconOTP, twm_win->icon->otp);
10490bbfda8aSnia	}
10500bbfda8aSnia
10510bbfda8aSnia	OtpCheckConsistency();
10520bbfda8aSnia}
10530bbfda8aSnia
10540bbfda8aSnia
10550bbfda8aSniastatic void free_OtpWinList(OtpWinList *owl)
10560bbfda8aSnia{
10570bbfda8aSnia	assert(owl->above == NULL);
10580bbfda8aSnia	assert(owl->below == NULL);
10590bbfda8aSnia	free(owl);
10600bbfda8aSnia}
10610bbfda8aSnia
10620bbfda8aSnia
10630bbfda8aSniavoid OtpRemove(TwmWindow *twm_win, WinType wintype)
10640bbfda8aSnia{
10650bbfda8aSnia	OtpWinList **owlp;
10660bbfda8aSnia	owlp = (wintype == IconWin) ? &twm_win->icon->otp : &twm_win->otp;
10670bbfda8aSnia
10680bbfda8aSnia	assert(*owlp != NULL);
10690bbfda8aSnia
10700bbfda8aSnia	RemoveOwl(*owlp);
10710bbfda8aSnia	free_OtpWinList(*owlp);
10720bbfda8aSnia	*owlp = NULL;
10730bbfda8aSnia
10740bbfda8aSnia	OtpCheckConsistency();
10750bbfda8aSnia}
10760bbfda8aSnia
10770bbfda8aSnia
10780bbfda8aSniastatic OtpWinList *new_OtpWinList(TwmWindow *twm_win,
10790bbfda8aSnia                                  WinType wintype,
10800bbfda8aSnia                                  bool switching,
10810bbfda8aSnia                                  int priority)
10820bbfda8aSnia{
10830bbfda8aSnia	OtpWinList *owl = malloc(sizeof(OtpWinList));
10840bbfda8aSnia
10850bbfda8aSnia	owl->above = NULL;
10860bbfda8aSnia	owl->below = NULL;
10870bbfda8aSnia	owl->twm_win = twm_win;
10880bbfda8aSnia	owl->type = wintype;
10890bbfda8aSnia	owl->switching = switching;
10900bbfda8aSnia	owl->pri_base = priority;
10910bbfda8aSnia	owl->pri_aflags = 0;
10920bbfda8aSnia
10930bbfda8aSnia	/*
10940bbfda8aSnia	 * We never need to stash anything for icons, they don't persist
10950bbfda8aSnia	 * across restart anyway.  So pretend we did stash already to
10960bbfda8aSnia	 * discourage other code from trying to stash.
10970bbfda8aSnia	 */
10980bbfda8aSnia	owl->stashed_aflags = (wintype == WinWin ? false : true);
10990bbfda8aSnia
11000bbfda8aSnia	return owl;
11010bbfda8aSnia}
11020bbfda8aSnia
11030bbfda8aSniastatic OtpWinList *AddNewOwl(TwmWindow *twm_win, WinType wintype,
11040bbfda8aSnia                             OtpWinList *parent)
11050bbfda8aSnia{
11060bbfda8aSnia	OtpWinList *owl;
11070bbfda8aSnia	OtpPreferences *prefs = (wintype == IconWin) ? Scr->IconOTP : Scr->OTP;
11080bbfda8aSnia
11090bbfda8aSnia	/* make the new owl */
11100bbfda8aSnia	owl = new_OtpWinList(twm_win, wintype,
11110bbfda8aSnia	                     prefs->switching, prefs->priority);
11120bbfda8aSnia
11130bbfda8aSnia	/* inherit the default attributes from the parent window if appropriate */
11140bbfda8aSnia	if(parent != NULL) {
11150bbfda8aSnia		PRI_CP(parent, owl);
11160bbfda8aSnia		owl->switching = parent->switching;
11170bbfda8aSnia	}
11180bbfda8aSnia
11190bbfda8aSnia	/* now see if the preferences have something to say */
11200bbfda8aSnia	if(!(parent != NULL && twm_win->istransient)) {
11210bbfda8aSnia		ApplyPreferences(prefs, owl);
11220bbfda8aSnia	}
11230bbfda8aSnia
11240bbfda8aSnia#ifdef EWMH
11250bbfda8aSnia	/* If nothing came in, EWMH might have something to say */
11260bbfda8aSnia	if(owl->pri_base == 0) {
11270bbfda8aSnia		owl->pri_base = EwmhGetInitPriority(twm_win) + OTP_ZERO;
11280bbfda8aSnia	}
11290bbfda8aSnia#endif
11300bbfda8aSnia
11310bbfda8aSnia	/*
11320bbfda8aSnia	 * Initialize flags.  Right now, the only stashed flags are related
11330bbfda8aSnia	 * to EWMH requests, so in a sense this whole thing could be dropped
11340bbfda8aSnia	 * under #ifdef.  But I'll assume that might not always be the case,
11350bbfda8aSnia	 * so for now the !(EWMH) case is just a twisty noop.
11360bbfda8aSnia	 */
11370bbfda8aSnia	{
11380bbfda8aSnia		bool gotflags = false;
11390bbfda8aSnia		unsigned aflags = 0, fromstash = 0;
11400bbfda8aSnia
11410bbfda8aSnia		aflags = OwlGetStashedAflags(owl, &gotflags);
11420bbfda8aSnia
11430bbfda8aSnia#ifdef EWMH
11440bbfda8aSnia		fromstash = (OTP_AFLAG_ABOVE | OTP_AFLAG_BELOW);
11450bbfda8aSnia#endif
11460bbfda8aSnia
11470bbfda8aSnia		if(gotflags) {
11480bbfda8aSnia			/*
11490bbfda8aSnia			 * Got stashed OTP flags; use 'em.  Explicitly mask in only
11500bbfda8aSnia			 * the flags we're caring about; the others aren't telling us
11510bbfda8aSnia			 * info we need to persist.
11520bbfda8aSnia			 */
11530bbfda8aSnia			aflags &= fromstash;
11540bbfda8aSnia		}
11550bbfda8aSnia
11560bbfda8aSnia#ifdef EWMH
11570bbfda8aSnia		/* FULLSCREEN we get from the normal EWMH prop no matter what */
11580bbfda8aSnia		if(twm_win->ewmhFlags & EWMH_STATE_FULLSCREEN) {
11590bbfda8aSnia			aflags |= OTP_AFLAG_FULLSCREEN;
11600bbfda8aSnia		}
11610bbfda8aSnia
11620bbfda8aSnia		if(!gotflags) {
11630bbfda8aSnia			/* Nothing from OTP about above/below; check EWMH */
11640bbfda8aSnia			aflags = 0;
11650bbfda8aSnia			if(twm_win->ewmhFlags & EWMH_STATE_ABOVE) {
11660bbfda8aSnia				aflags |= OTP_AFLAG_ABOVE;
11670bbfda8aSnia			}
11680bbfda8aSnia			if(twm_win->ewmhFlags & EWMH_STATE_BELOW) {
11690bbfda8aSnia				aflags |= OTP_AFLAG_BELOW;
11700bbfda8aSnia			}
11710bbfda8aSnia		}
11720bbfda8aSnia#endif // EWMH
11730bbfda8aSnia
11740bbfda8aSnia		/* Set whatever we figured */
11750bbfda8aSnia		owl->pri_aflags |= aflags;
11760bbfda8aSnia		owl->stashed_aflags = gotflags;
11770bbfda8aSnia
11780bbfda8aSnia		/* If we set a priority or flags, we should stash away flags */
11790bbfda8aSnia		if((PRI(owl) != OTP_ZERO || owl->pri_aflags != 0)
11800bbfda8aSnia		                && !owl->stashed_aflags) {
11810bbfda8aSnia			OwlStashAflags(owl);
11820bbfda8aSnia		}
11830bbfda8aSnia	}
11840bbfda8aSnia
11850bbfda8aSnia	/* finally put the window where it should go */
11860bbfda8aSnia	InsertOwl(owl, Above);
11870bbfda8aSnia
11880bbfda8aSnia	return owl;
11890bbfda8aSnia}
11900bbfda8aSnia
11910bbfda8aSniavoid OtpAdd(TwmWindow *twm_win, WinType wintype)
11920bbfda8aSnia{
11930bbfda8aSnia	TwmWindow *other_win;
11940bbfda8aSnia	OtpWinList *parent = NULL;
11950bbfda8aSnia	OtpWinList **owlp;
11960bbfda8aSnia	owlp = (wintype == IconWin) ? &twm_win->icon->otp : &twm_win->otp;
11970bbfda8aSnia
11980bbfda8aSnia	assert(*owlp == NULL);
11990bbfda8aSnia
12000bbfda8aSnia	/* windows in boxes *must* inherit priority from the box */
12010bbfda8aSnia	if(twm_win->winbox) {
12020bbfda8aSnia		parent = twm_win->winbox->twmwin->otp;
12030bbfda8aSnia		parent->switching = false;
12040bbfda8aSnia	}
12050bbfda8aSnia	/* in case it's a transient, find the parent */
12060bbfda8aSnia	else if(wintype == WinWin && (twm_win->istransient
12070bbfda8aSnia	                              || !isGroupLeader(twm_win))) {
12080bbfda8aSnia		other_win = Scr->FirstWindow;
12090bbfda8aSnia		while(other_win != NULL
12100bbfda8aSnia		                && !isTransientOf(twm_win, other_win)
12110bbfda8aSnia		                && !isGroupLeaderOf(other_win, twm_win)) {
12120bbfda8aSnia			other_win = other_win->next;
12130bbfda8aSnia		}
12140bbfda8aSnia		if(other_win != NULL) {
12150bbfda8aSnia			parent = other_win->otp;
12160bbfda8aSnia		}
12170bbfda8aSnia	}
12180bbfda8aSnia
12190bbfda8aSnia	/* make the new owl */
12200bbfda8aSnia	*owlp = AddNewOwl(twm_win, wintype, parent);
12210bbfda8aSnia
12220bbfda8aSnia	assert(*owlp != NULL);
12230bbfda8aSnia	OtpCheckConsistency();
12240bbfda8aSnia}
12250bbfda8aSnia
12260bbfda8aSniavoid OtpReassignIcon(TwmWindow *twm_win, Icon *old_icon)
12270bbfda8aSnia{
12280bbfda8aSnia	if(old_icon != NULL) {
12290bbfda8aSnia		/* Transfer OWL to new Icon */
12300bbfda8aSnia		Icon *new_icon = twm_win->icon;
12310bbfda8aSnia		if(new_icon != NULL) {
12320bbfda8aSnia			new_icon->otp = old_icon->otp;
12330bbfda8aSnia			old_icon->otp = NULL;
12340bbfda8aSnia		}
12350bbfda8aSnia	}
12360bbfda8aSnia	else {
12370bbfda8aSnia		/* Create a new OWL for this Icon */
12380bbfda8aSnia		OtpAdd(twm_win, IconWin);
12390bbfda8aSnia	}
12400bbfda8aSnia}
12410bbfda8aSnia
12420bbfda8aSniavoid OtpFreeIcon(TwmWindow *twm_win)
12430bbfda8aSnia{
12440bbfda8aSnia	/* Remove the icon's OWL, if any */
12450bbfda8aSnia	Icon *cur_icon = twm_win->icon;
12460bbfda8aSnia	if(cur_icon != NULL) {
12470bbfda8aSnia		OtpRemove(twm_win, IconWin);
12480bbfda8aSnia	}
12490bbfda8aSnia}
12500bbfda8aSnia
12510bbfda8aSnianame_list **OtpScrSwitchingL(ScreenInfo *scr, WinType wintype)
12520bbfda8aSnia{
12530bbfda8aSnia	OtpPreferences *prefs = (wintype == IconWin) ? scr->IconOTP : scr->OTP;
12540bbfda8aSnia
12550bbfda8aSnia	assert(prefs != NULL);
12560bbfda8aSnia
12570bbfda8aSnia	return &(prefs->switchingL);
12580bbfda8aSnia}
12590bbfda8aSnia
12600bbfda8aSnia
12610bbfda8aSniavoid OtpScrSetSwitching(ScreenInfo *scr, WinType wintype, bool switching)
12620bbfda8aSnia{
12630bbfda8aSnia#ifndef NDEBUG
12640bbfda8aSnia	OtpPreferences *prefs = (wintype == IconWin) ? scr->IconOTP : scr->OTP;
12650bbfda8aSnia
12660bbfda8aSnia	assert(prefs != NULL);
12670bbfda8aSnia#endif
12680bbfda8aSnia
12690bbfda8aSnia	scr->OTP->switching = switching;
12700bbfda8aSnia}
12710bbfda8aSnia
12720bbfda8aSnia
12730bbfda8aSniavoid OtpScrSetZero(ScreenInfo *scr, WinType wintype, int priority)
12740bbfda8aSnia{
12750bbfda8aSnia	OtpPreferences *prefs = (wintype == IconWin) ? scr->IconOTP : scr->OTP;
12760bbfda8aSnia
12770bbfda8aSnia	assert(prefs != NULL);
12780bbfda8aSnia
12790bbfda8aSnia	if(ABS(priority) > OTP_ZERO) {
12800bbfda8aSnia		fprintf(stderr, "invalid OnTopPriority value: %d\n", priority);
12810bbfda8aSnia		return;
12820bbfda8aSnia	}
12830bbfda8aSnia
12840bbfda8aSnia	prefs->priority = priority + OTP_ZERO;
12850bbfda8aSnia}
12860bbfda8aSnia
12870bbfda8aSnia
12880bbfda8aSnianame_list **OtpScrPriorityL(ScreenInfo *scr, WinType wintype, int priority)
12890bbfda8aSnia{
12900bbfda8aSnia	OtpPreferences *prefs = (wintype == IconWin) ? scr->IconOTP : scr->OTP;
12910bbfda8aSnia
12920bbfda8aSnia	assert(prefs != NULL);
12930bbfda8aSnia
12940bbfda8aSnia	if(ABS(priority) > OTP_ZERO) {
12950bbfda8aSnia		fprintf(stderr, "invalid OnTopPriority value: %d\n", priority);
12960bbfda8aSnia		priority = 0;
12970bbfda8aSnia	}
12980bbfda8aSnia	return &(prefs->priorityL[priority + OTP_ZERO]);
12990bbfda8aSnia}
13000bbfda8aSnia
13010bbfda8aSnia
13020bbfda8aSniastatic OtpPreferences *new_OtpPreferences(void)
13030bbfda8aSnia{
13040bbfda8aSnia	OtpPreferences *pref = malloc(sizeof(OtpPreferences));
13050bbfda8aSnia	int i;
13060bbfda8aSnia
13070bbfda8aSnia	/* initialize default values */
13080bbfda8aSnia	for(i = 0; i <= OTP_MAX; i++) {
13090bbfda8aSnia		pref->priorityL[i] = NULL;
13100bbfda8aSnia	}
13110bbfda8aSnia	pref->priority = OTP_ZERO;
13120bbfda8aSnia	pref->switchingL = NULL;
13130bbfda8aSnia	pref->switching = false;
13140bbfda8aSnia
13150bbfda8aSnia	return pref;
13160bbfda8aSnia}
13170bbfda8aSnia
13180bbfda8aSniastatic void free_OtpPreferences(OtpPreferences *pref)
13190bbfda8aSnia{
13200bbfda8aSnia	int i;
13210bbfda8aSnia
13220bbfda8aSnia	FreeList(&pref->switchingL);
13230bbfda8aSnia	for(i = 0; i <= OTP_MAX; i++) {
13240bbfda8aSnia		FreeList(&pref->priorityL[i]);
13250bbfda8aSnia	}
13260bbfda8aSnia
13270bbfda8aSnia	free(pref);
13280bbfda8aSnia}
13290bbfda8aSnia
13300bbfda8aSniavoid OtpScrInitData(ScreenInfo *scr)
13310bbfda8aSnia{
13320bbfda8aSnia	if(scr->OTP != NULL) {
13330bbfda8aSnia		free_OtpPreferences(scr->OTP);
13340bbfda8aSnia	}
13350bbfda8aSnia	if(scr->IconOTP != NULL) {
13360bbfda8aSnia		free_OtpPreferences(scr->IconOTP);
13370bbfda8aSnia	}
13380bbfda8aSnia	scr->OTP = new_OtpPreferences();
13390bbfda8aSnia	scr->IconOTP = new_OtpPreferences();
13400bbfda8aSnia}
13410bbfda8aSnia
13420bbfda8aSniaint ReparentWindow(Display *display, TwmWindow *twm_win, WinType wintype,
13430bbfda8aSnia                   Window parent, int x, int y)
13440bbfda8aSnia{
13450bbfda8aSnia	int result;
13460bbfda8aSnia	OtpWinList *owl = (wintype == IconWin) ? twm_win->icon->otp : twm_win->otp;
13470bbfda8aSnia	OtpWinList *other = owl->below;
13480bbfda8aSnia	assert(owl != NULL);
13490bbfda8aSnia
13500bbfda8aSnia	DPRINTF((stderr, "ReparentWindow: w=%x type=%d\n",
13510bbfda8aSnia	         (unsigned int)WindowOfOwl(owl), wintype));
13520bbfda8aSnia	result = XReparentWindow(display, WindowOfOwl(owl), parent, x, y);
13530bbfda8aSnia	/* The raise was already done by XReparentWindow, so this call
13540bbfda8aSnia	   just re-places the window at the right spot in the list
13550bbfda8aSnia	   and enforces priority settings. */
13560bbfda8aSnia	RemoveOwl(owl);
13570bbfda8aSnia	InsertOwlAbove(owl, other);
13580bbfda8aSnia	OtpCheckConsistency();
13590bbfda8aSnia	return result;
13600bbfda8aSnia}
13610bbfda8aSnia
13620bbfda8aSniavoid
13630bbfda8aSniaReparentWindowAndIcon(Display *display, TwmWindow *twm_win,
13640bbfda8aSnia                      Window parent, int win_x, int win_y,
13650bbfda8aSnia                      int icon_x, int icon_y)
13660bbfda8aSnia{
13670bbfda8aSnia	OtpWinList *win_owl = twm_win->otp;
13680bbfda8aSnia	assert(twm_win->icon != NULL);
13690bbfda8aSnia	OtpWinList *icon_owl = twm_win->icon->otp;
13700bbfda8aSnia	assert(win_owl != NULL);
13710bbfda8aSnia	assert(icon_owl != NULL);
13720bbfda8aSnia	OtpWinList *below_win = win_owl->below;
13730bbfda8aSnia	OtpWinList *below_icon = icon_owl->below;
13740bbfda8aSnia
13750bbfda8aSnia	DPRINTF((stderr, "ReparentWindowAndIcon %x\n", (unsigned int)twm_win->frame));
13760bbfda8aSnia	XReparentWindow(display, twm_win->frame, parent, win_x, win_y);
13770bbfda8aSnia	XReparentWindow(display, twm_win->icon->w, parent, icon_x, icon_y);
13780bbfda8aSnia	/* The raise was already done by XReparentWindow, so this call
13790bbfda8aSnia	   just re-places the window at the right spot in the list
13800bbfda8aSnia	   and enforces priority settings. */
13810bbfda8aSnia	RemoveOwl(win_owl);
13820bbfda8aSnia	RemoveOwl(icon_owl);
13830bbfda8aSnia	if(below_win != icon_owl) {
13840bbfda8aSnia		/*
13850bbfda8aSnia		 * Only insert the window above something if it isn't the icon,
13860bbfda8aSnia		 * because that isn't back yet.
13870bbfda8aSnia		 */
13880bbfda8aSnia		InsertOwlAbove(win_owl, below_win);
13890bbfda8aSnia		InsertOwlAbove(icon_owl, below_icon);
13900bbfda8aSnia	}
13910bbfda8aSnia	else {
13920bbfda8aSnia		/* In such a case, do it in the opposite order. */
13930bbfda8aSnia		InsertOwlAbove(icon_owl, below_icon);
13940bbfda8aSnia		InsertOwlAbove(win_owl, below_win);
13950bbfda8aSnia	}
13960bbfda8aSnia	OtpCheckConsistency();
13970bbfda8aSnia	return;
13980bbfda8aSnia}
13990bbfda8aSnia
14000bbfda8aSnia/* Iterators.  */
14010bbfda8aSniaTwmWindow *OtpBottomWin()
14020bbfda8aSnia{
14030bbfda8aSnia	OtpWinList *owl = Scr->bottomOwl;
14040bbfda8aSnia	while(owl && owl->type != WinWin) {
14050bbfda8aSnia		owl = owl->above;
14060bbfda8aSnia	}
14070bbfda8aSnia	return owl ? owl->twm_win : NULL;
14080bbfda8aSnia}
14090bbfda8aSnia
14100bbfda8aSniaTwmWindow *OtpTopWin()
14110bbfda8aSnia{
14120bbfda8aSnia	OtpWinList *owl = Scr->bottomOwl, *top = NULL;
14130bbfda8aSnia	while(owl) {
14140bbfda8aSnia		if(owl->type == WinWin) {
14150bbfda8aSnia			top = owl;
14160bbfda8aSnia		}
14170bbfda8aSnia		owl = owl->above;
14180bbfda8aSnia	}
14190bbfda8aSnia	return top ? top->twm_win : NULL;
14200bbfda8aSnia}
14210bbfda8aSnia
14220bbfda8aSniaTwmWindow *OtpNextWinUp(TwmWindow *twm_win)
14230bbfda8aSnia{
14240bbfda8aSnia	OtpWinList *owl = twm_win->otp->above;
14250bbfda8aSnia	while(owl && owl->type != WinWin) {
14260bbfda8aSnia		owl = owl->above;
14270bbfda8aSnia	}
14280bbfda8aSnia	return owl ? owl->twm_win : NULL;
14290bbfda8aSnia}
14300bbfda8aSnia
14310bbfda8aSniaTwmWindow *OtpNextWinDown(TwmWindow *twm_win)
14320bbfda8aSnia{
14330bbfda8aSnia	OtpWinList *owl = twm_win->otp->below;
14340bbfda8aSnia	while(owl && owl->type != WinWin) {
14350bbfda8aSnia		owl = owl->below;
14360bbfda8aSnia	}
14370bbfda8aSnia	return owl ? owl->twm_win : NULL;
14380bbfda8aSnia}
14390bbfda8aSnia
14400bbfda8aSnia
14410bbfda8aSnia/*
14420bbfda8aSnia * Stuff for messing with pri_aflags
14430bbfda8aSnia */
14440bbfda8aSnia/* Set the masked bits to exactly what's given */
14450bbfda8aSniavoid
14460bbfda8aSniaOtpSetAflagMask(TwmWindow *twm_win, unsigned mask, unsigned setto)
14470bbfda8aSnia{
14480bbfda8aSnia	assert(twm_win != NULL);
14490bbfda8aSnia	assert(twm_win->otp != NULL);
14500bbfda8aSnia	OwlSetAflagMask(twm_win->otp, mask, setto);
14510bbfda8aSnia}
14520bbfda8aSnia
14530bbfda8aSniastatic void
14540bbfda8aSniaOwlSetAflagMask(OtpWinList *owl, unsigned mask, unsigned setto)
14550bbfda8aSnia{
14560bbfda8aSnia	assert(owl != NULL);
14570bbfda8aSnia
14580bbfda8aSnia	owl->pri_aflags &= ~mask;
14590bbfda8aSnia	owl->pri_aflags |= (setto & mask);
14600bbfda8aSnia	OwlStashAflags(owl);
14610bbfda8aSnia}
14620bbfda8aSnia
14630bbfda8aSnia/* Set/clear individual ones */
14640bbfda8aSniavoid
14650bbfda8aSniaOtpSetAflag(TwmWindow *twm_win, unsigned flag)
14660bbfda8aSnia{
14670bbfda8aSnia	assert(twm_win != NULL);
14680bbfda8aSnia	assert(twm_win->otp != NULL);
14690bbfda8aSnia
14700bbfda8aSnia	OwlSetAflag(twm_win->otp, flag);
14710bbfda8aSnia}
14720bbfda8aSnia
14730bbfda8aSniastatic void
14740bbfda8aSniaOwlSetAflag(OtpWinList *owl, unsigned flag)
14750bbfda8aSnia{
14760bbfda8aSnia	assert(owl != NULL);
14770bbfda8aSnia
14780bbfda8aSnia	owl->pri_aflags |= flag;
14790bbfda8aSnia	OwlStashAflags(owl);
14800bbfda8aSnia}
14810bbfda8aSnia
14820bbfda8aSniavoid
14830bbfda8aSniaOtpClearAflag(TwmWindow *twm_win, unsigned flag)
14840bbfda8aSnia{
14850bbfda8aSnia	assert(twm_win != NULL);
14860bbfda8aSnia	assert(twm_win->otp != NULL);
14870bbfda8aSnia
14880bbfda8aSnia	OwlClearAflag(twm_win->otp, flag);
14890bbfda8aSnia}
14900bbfda8aSnia
14910bbfda8aSniastatic void
14920bbfda8aSniaOwlClearAflag(OtpWinList *owl, unsigned flag)
14930bbfda8aSnia{
14940bbfda8aSnia	assert(owl != NULL);
14950bbfda8aSnia
14960bbfda8aSnia	owl->pri_aflags &= ~flag;
14970bbfda8aSnia	OwlStashAflags(owl);
14980bbfda8aSnia}
14990bbfda8aSnia
15000bbfda8aSnia/*
15010bbfda8aSnia * Stash up flags in a property.  We use this to keep track of whether we
15020bbfda8aSnia * have above/below flags set in the OTP info, so we can know what to set
15030bbfda8aSnia * when we restart.  Otherwise we can't tell whether stuff like EWMH
15040bbfda8aSnia * _NET_WM_STATE flags are saying 'above' because the above flag got set
15050bbfda8aSnia * at some point, or whether other OTP config happens to have already
15060bbfda8aSnia * raised it.
15070bbfda8aSnia */
15080bbfda8aSniavoid
15090bbfda8aSniaOtpStashAflagsFirstTime(TwmWindow *twm_win)
15100bbfda8aSnia{
15110bbfda8aSnia	if(!twm_win->otp->stashed_aflags) {
15120bbfda8aSnia		OwlStashAflags(twm_win->otp);
15130bbfda8aSnia	}
15140bbfda8aSnia}
15150bbfda8aSnia
15160bbfda8aSniastatic void
15170bbfda8aSniaOwlStashAflags(OtpWinList *owl)
15180bbfda8aSnia{
15190bbfda8aSnia	unsigned long of_prop = owl->pri_aflags;
15200bbfda8aSnia
15210bbfda8aSnia	/* Only "real" windows need stashed flags */
15220bbfda8aSnia	if(owl->type != WinWin) {
15230bbfda8aSnia		return;
15240bbfda8aSnia	}
15250bbfda8aSnia
15260bbfda8aSnia	XChangeProperty(dpy, owl->twm_win->w, XA_CTWM_OTP_AFLAGS, XA_INTEGER,
15270bbfda8aSnia	                32, PropModeReplace, (unsigned char *)&of_prop, 1);
15280bbfda8aSnia
15290bbfda8aSnia	owl->stashed_aflags = true;
15300bbfda8aSnia}
15310bbfda8aSnia
15320bbfda8aSniastatic unsigned
15330bbfda8aSniaOwlGetStashedAflags(OtpWinList *owl, bool *gotit)
15340bbfda8aSnia{
15350bbfda8aSnia	/* Lotta dummy args */
15360bbfda8aSnia	int ret;
15370bbfda8aSnia	Atom act_type;
15380bbfda8aSnia	int d_fmt;
15390bbfda8aSnia	unsigned long nitems, d_after;
15400bbfda8aSnia	unsigned long aflags, *aflags_p;
15410bbfda8aSnia
15420bbfda8aSnia	/* Only on real windows */
15430bbfda8aSnia	if(owl->type != WinWin) {
15440bbfda8aSnia		*gotit = false;
15450bbfda8aSnia		return 0;
15460bbfda8aSnia	}
15470bbfda8aSnia
15480bbfda8aSnia	ret = XGetWindowProperty(dpy, owl->twm_win->w, XA_CTWM_OTP_AFLAGS, 0, 1,
15490bbfda8aSnia	                         False, XA_INTEGER, &act_type, &d_fmt, &nitems,
15500bbfda8aSnia	                         &d_after, (unsigned char **)&aflags_p);
15510bbfda8aSnia	if(ret == Success && act_type == XA_INTEGER && aflags_p != NULL) {
15520bbfda8aSnia		aflags = *aflags_p;
15530bbfda8aSnia		XFree(aflags_p);
15540bbfda8aSnia		*gotit = true;
15550bbfda8aSnia	}
15560bbfda8aSnia	else {
15570bbfda8aSnia		*gotit = false;
15580bbfda8aSnia		aflags = 0;
15590bbfda8aSnia	}
15600bbfda8aSnia
15610bbfda8aSnia	return aflags;
15620bbfda8aSnia}
15630bbfda8aSnia
15640bbfda8aSnia
15650bbfda8aSnia/*
15660bbfda8aSnia * Figure where a window should be stacked based on the current world,
15670bbfda8aSnia * and move it there.  This function pretty much assumes it's not already
15680bbfda8aSnia * there; callers should generally be figuring that out before calling
15690bbfda8aSnia * this.
15700bbfda8aSnia */
15710bbfda8aSniavoid
15720bbfda8aSniaOtpRestackWindow(TwmWindow *twm_win)
15730bbfda8aSnia{
15740bbfda8aSnia	OtpWinList *owl = twm_win->otp;
15750bbfda8aSnia
15760bbfda8aSnia	RemoveOwl(owl);
15770bbfda8aSnia	InsertOwl(owl, Above);
15780bbfda8aSnia	OtpCheckConsistency();
15790bbfda8aSnia}
15800bbfda8aSnia
15810bbfda8aSnia
15820bbfda8aSnia
15830bbfda8aSnia/**
15840bbfda8aSnia * Focus/unfocus backend.  This is used on windows whose stacking is
15850bbfda8aSnia * focus-dependent (e.g., EWMH fullscreen), to move them and their
15860bbfda8aSnia * transients around.  For these windows, getting/losing focus is
15870bbfda8aSnia * practically the same as a f.setpriority, except it's on the calculated
15880bbfda8aSnia * rather than the base parts.  And it's hard to re-use our existing
15890bbfda8aSnia * functions to do it because we have to move Scr->Focus before the main
15900bbfda8aSnia * window changes, but then it's too late to see where all the transients
15910bbfda8aSnia * were.
15920bbfda8aSnia *
15930bbfda8aSnia * There are a number of unpleasant assumptions in here relating to where
15940bbfda8aSnia * the transients are, and IWBNI we could be smarter and quicker about
15950bbfda8aSnia * dealing with them.  But this gets us past the simple to cause
15960bbfda8aSnia * assertion failures, anyway...
15970bbfda8aSnia */
15980bbfda8aSniastatic void
15990bbfda8aSniaOtpFocusWindowBE(TwmWindow *twm_win, int oldprio)
16000bbfda8aSnia{
16010bbfda8aSnia	OtpWinList *owl = twm_win->otp;
16020bbfda8aSnia
16030bbfda8aSnia	// This one comes off the list, and goes back in its new place.
16040bbfda8aSnia	RemoveOwl(owl);
16050bbfda8aSnia	InsertOwl(owl, Above);
16060bbfda8aSnia
16070bbfda8aSnia	// Now root around for any transients of it, and
16080bbfda8aSnia	// nudge them into the new location.  The whole Above/Below thing is
16090bbfda8aSnia	// kinda a heavy-handed guess, but...
16100bbfda8aSnia	//
16110bbfda8aSnia	// This is nearly a reimplementation of TryToMoveTransientsOfTo(),
16120bbfda8aSnia	// but the assumption that we can find the transients by starting
16130bbfda8aSnia	// from where the old priority was in the list turns out to be deeply
16140bbfda8aSnia	// broken.  So just walk the whole thing.  Which isn't ideal, but...
16150bbfda8aSnia	//
16160bbfda8aSnia	// We also need to do loop detection, since otherwise we'll get stuck
16170bbfda8aSnia	// when a window has multiple transients to move around.  Since we
16180bbfda8aSnia	// read from the bottom up, if a window is moving up the stack, then
16190bbfda8aSnia	// its transients move up, and we run into them again and again.
16200bbfda8aSnia	//
16210bbfda8aSnia	// XXX It should not be this freakin' hard to find a window's
16220bbfda8aSnia	// transients.  We should fix that more globally.
16230bbfda8aSnia
16240bbfda8aSnia	// XXX Let's just get a friggin' vector implementation already...
16250bbfda8aSnia	size_t tlsz = 32;  // Should hardly ever be too small
16260bbfda8aSnia	size_t tlused = 0;
16270bbfda8aSnia	OtpWinList **tlst = calloc(tlsz, sizeof(OtpWinList *));
16280bbfda8aSnia	if(tlst == NULL) {
16290bbfda8aSnia		fprintf(stderr, "%s(): realloc() failed\n", __func__);
16300bbfda8aSnia		abort();
16310bbfda8aSnia	}
16320bbfda8aSnia
16330bbfda8aSnia	// Loop through and find them all
16340bbfda8aSnia	OtpWinList *trans = Scr->bottomOwl;
16350bbfda8aSnia	while((trans != NULL)) {
16360bbfda8aSnia		// Gotta pre-stash, since we're sometimes about to move trans.
16370bbfda8aSnia		OtpWinList *next = trans->above;
16380bbfda8aSnia
16390bbfda8aSnia		if((trans->type == WinWin)
16400bbfda8aSnia				&& isTransientOf(trans->twm_win, twm_win)) {
16410bbfda8aSnia			// Got one, stash it
16420bbfda8aSnia			tlst[tlused++] = trans;
16430bbfda8aSnia
16440bbfda8aSnia			// Grow?
16450bbfda8aSnia			if(tlused == tlsz) {
16460bbfda8aSnia				tlsz *= 2;
16470bbfda8aSnia				OtpWinList **tln = realloc(tlst, (tlsz * sizeof(OtpWinList *)));
16480bbfda8aSnia				if(tln == NULL) {
16490bbfda8aSnia					fprintf(stderr, "%s(): realloc() failed\n", __func__);
16500bbfda8aSnia					abort();
16510bbfda8aSnia				}
16520bbfda8aSnia				tlst = tln;
16530bbfda8aSnia			}
16540bbfda8aSnia		}
16550bbfda8aSnia
16560bbfda8aSnia		// And onward
16570bbfda8aSnia		trans = next;
16580bbfda8aSnia	}
16590bbfda8aSnia
16600bbfda8aSnia
16610bbfda8aSnia	// Now loop over them and shuffle them up
16620bbfda8aSnia	for(int i = 0 ; i < tlused ; i++) {
16630bbfda8aSnia		RemoveOwl(tlst[i]);
16640bbfda8aSnia		InsertOwl(tlst[i], Above);
16650bbfda8aSnia	}
16660bbfda8aSnia
16670bbfda8aSnia	free(tlst);
16680bbfda8aSnia
16690bbfda8aSnia	OtpCheckConsistency();
16700bbfda8aSnia}
16710bbfda8aSnia
16720bbfda8aSnia/**
16730bbfda8aSnia * Unfocus a window.  This needs to know internals of OTP because of
16740bbfda8aSnia * focus-dependent stacking of it and its transients.
16750bbfda8aSnia */
16760bbfda8aSniavoid
16770bbfda8aSniaOtpUnfocusWindow(TwmWindow *twm_win)
16780bbfda8aSnia{
16790bbfda8aSnia	// Stash where it currently appears to be.  We assume all its
16800bbfda8aSnia	// transients currently have the same effective priority.  See also
16810bbfda8aSnia	// TryToMoveTransientsOfTo() which makes the same assumption.  I'm
16820bbfda8aSnia	// not sure that's entirely warranted...
16830bbfda8aSnia	int oldprio = PRI(twm_win->otp);
16840bbfda8aSnia
16850bbfda8aSnia	// Now tell ourselves it's unfocused
16860bbfda8aSnia	assert(Scr->Focus == twm_win);
16870bbfda8aSnia	Scr->Focus = NULL;
16880bbfda8aSnia
16890bbfda8aSnia	// And do the work
16900bbfda8aSnia	OtpFocusWindowBE(twm_win, oldprio);
16910bbfda8aSnia}
16920bbfda8aSnia
16930bbfda8aSnia/**
16940bbfda8aSnia * Focus a window.  This needs to know internals of OTP because of
16950bbfda8aSnia * focus-dependent stacking of it and its transients.
16960bbfda8aSnia */
16970bbfda8aSniavoid
16980bbfda8aSniaOtpFocusWindow(TwmWindow *twm_win)
16990bbfda8aSnia{
17000bbfda8aSnia	// X-ref OtoUnfocusWindow() comments.
17010bbfda8aSnia	int oldprio = PRI(twm_win->otp);
17020bbfda8aSnia
17030bbfda8aSnia	assert(Scr->Focus != twm_win);
17040bbfda8aSnia	Scr->Focus = twm_win;
17050bbfda8aSnia
17060bbfda8aSnia	OtpFocusWindowBE(twm_win, oldprio);
17070bbfda8aSnia}
17080bbfda8aSnia
17090bbfda8aSnia
17100bbfda8aSnia
17110bbfda8aSnia/*
17120bbfda8aSnia * Calculating effective priority.  Take the base priority (what gets
17130bbfda8aSnia * set/altered by various OTP config and functions), and then tack on
17140bbfda8aSnia * whatever alterations more ephemeral things might apply.  This
17150bbfda8aSnia * currently pretty much means EWMH bits.
17160bbfda8aSnia */
17170bbfda8aSniaint
17180bbfda8aSniaOtpEffectiveDisplayPriority(TwmWindow *twm_win)
17190bbfda8aSnia{
17200bbfda8aSnia	assert(twm_win != NULL);
17210bbfda8aSnia	assert(twm_win->otp != NULL);
17220bbfda8aSnia
17230bbfda8aSnia	return(OwlEffectivePriority(twm_win->otp) - OTP_ZERO);
17240bbfda8aSnia}
17250bbfda8aSnia
17260bbfda8aSniaint
17270bbfda8aSniaOtpEffectivePriority(TwmWindow *twm_win)
17280bbfda8aSnia{
17290bbfda8aSnia	assert(twm_win != NULL);
17300bbfda8aSnia	assert(twm_win->otp != NULL);
17310bbfda8aSnia
17320bbfda8aSnia	return OwlEffectivePriority(twm_win->otp);
17330bbfda8aSnia}
17340bbfda8aSnia
17350bbfda8aSniastatic int
17360bbfda8aSniaOwlEffectivePriority(OtpWinList *owl)
17370bbfda8aSnia{
17380bbfda8aSnia	int pri;
17390bbfda8aSnia
17400bbfda8aSnia	assert(owl != NULL);
17410bbfda8aSnia
17420bbfda8aSnia	pri = owl->pri_base;
17430bbfda8aSnia
17440bbfda8aSnia#ifdef EWMH
17450bbfda8aSnia	/* ABOVE/BELOW states shift a bit relative to the base */
17460bbfda8aSnia	if(owl->pri_aflags & OTP_AFLAG_ABOVE) {
17470bbfda8aSnia		pri += EWMH_PRI_ABOVE;
17480bbfda8aSnia	}
17490bbfda8aSnia	if(owl->pri_aflags & OTP_AFLAG_BELOW) {
17500bbfda8aSnia		pri -= EWMH_PRI_ABOVE;
17510bbfda8aSnia	}
17520bbfda8aSnia
17530bbfda8aSnia	/*
17540bbfda8aSnia	 * Special magic: EWMH says that _BELOW + _DOCK = (just _BELOW).
17550bbfda8aSnia	 * So if both are set, and its base is where we'd expect just a _DOCK
17560bbfda8aSnia	 * to be, try cancelling that out.
17570bbfda8aSnia	 */
17580bbfda8aSnia	{
17590bbfda8aSnia		EwmhWindowType ewt = owl->twm_win->ewmhWindowType;
17600bbfda8aSnia		if((owl->pri_aflags & OTP_AFLAG_BELOW) && (ewt == wt_Dock) &&
17610bbfda8aSnia		                (owl->pri_base == EWMH_PRI_DOCK + OTP_ZERO)) {
17620bbfda8aSnia			pri -= EWMH_PRI_DOCK;
17630bbfda8aSnia		}
17640bbfda8aSnia	}
17650bbfda8aSnia
17660bbfda8aSnia	/*
17670bbfda8aSnia	 * If FULLSCREEN and focused, jam to (nearly; let the user still win
17680bbfda8aSnia	 * if they try) the top.  We also need to handle transients; they
17690bbfda8aSnia	 * might not have focus, but still need to be on top of the window
17700bbfda8aSnia	 * they're coming up transient for, or else they'll be hidden
17710bbfda8aSnia	 * forever.
17720bbfda8aSnia	 */
17730bbfda8aSnia	if(owl->pri_aflags & OTP_AFLAG_FULLSCREEN) {
17740bbfda8aSnia		if(Scr->Focus == owl->twm_win) {
17750bbfda8aSnia			// It's focused, shift it up
17760bbfda8aSnia			pri = EWMH_PRI_FULLSCREEN + OTP_ZERO;
17770bbfda8aSnia		}
17780bbfda8aSnia		else if(owl->twm_win->istransient) {
17790bbfda8aSnia			// It's a transient of something else; if that something else
17800bbfda8aSnia			// has the fullscreen/focus combo, we should pop this up top
17810bbfda8aSnia			// too.  Technically, we should perhaps test whether its
17820bbfda8aSnia			// parent is also OTP_AFLAG_FULLSCREEN, but if the transient
17830bbfda8aSnia			// has it, the parent probably does too.  Worry about that
17840bbfda8aSnia			// detail if it ever becomes a problem.
17850bbfda8aSnia			TwmWindow *parent = GetTwmWindow(owl->twm_win->transientfor);
17860bbfda8aSnia			if(Scr->Focus == parent) {
17870bbfda8aSnia				// Shift this up so we stay on top
17880bbfda8aSnia				pri = EWMH_PRI_FULLSCREEN + OTP_ZERO;
17890bbfda8aSnia			}
17900bbfda8aSnia		}
17910bbfda8aSnia	}
17920bbfda8aSnia#endif
17930bbfda8aSnia
17940bbfda8aSnia	/* Constrain */
17950bbfda8aSnia	pri = MAX(pri, 0);
17960bbfda8aSnia	pri = MIN(pri, OTP_MAX);
17970bbfda8aSnia
17980bbfda8aSnia	return pri;
17990bbfda8aSnia}
18000bbfda8aSnia
18010bbfda8aSnia
18020bbfda8aSnia/*
18030bbfda8aSnia * Does the priority of a window depend on its focus state?  External
18040bbfda8aSnia * code needs to know, to know when it might need restacking.
18050bbfda8aSnia */
18060bbfda8aSniabool
18070bbfda8aSniaOtpIsFocusDependent(TwmWindow *twm_win)
18080bbfda8aSnia{
18090bbfda8aSnia	assert(twm_win != NULL);
18100bbfda8aSnia	assert(twm_win->otp != NULL);
18110bbfda8aSnia
18120bbfda8aSnia#ifdef EWMH
18130bbfda8aSnia	/*
18140bbfda8aSnia	 * EWMH says _FULLSCREEN and focused windows get shoved to the top;
18150bbfda8aSnia	 * this implies that _FULLSCREEN and _not_ focused don't.  So if the
18160bbfda8aSnia	 * focus is changing, that means we may need to restack.
18170bbfda8aSnia	 */
18180bbfda8aSnia	if(twm_win->otp->pri_aflags & OTP_AFLAG_FULLSCREEN) {
18190bbfda8aSnia		return true;
18200bbfda8aSnia	}
18210bbfda8aSnia#endif
18220bbfda8aSnia
18230bbfda8aSnia	return false;
18240bbfda8aSnia}
1825