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