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