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