2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 /* ---------------------------- included header files ---------------------- */
25 #include "libs/ftime.h"
26 #include "libs/fvwmlib.h"
27 #include "libs/gravity.h"
28 #include "libs/Grab.h"
29 #include "libs/Parse.h"
30 #include "libs/defaults.h"
34 #include "functions.h"
38 #include "module_list.h"
39 #include "module_interface.h"
51 /* ---------------------------- local definitions -------------------------- */
53 /* If more than this many transients are in a single branch of a transient
54 * tree, they will end up in more or less random stacking order. */
55 #define MAX_TRANSIENTS_IN_BRANCH 200000
56 /* Same for total levels of transients. */
57 #define MAX_TRANSIENT_LEVELS 10000
58 /* This number must fit in a signed int! */
59 #define LOWER_PENALTY (MAX_TRANSIENTS_IN_BRANCH * MAX_TRANSIENT_LEVELS)
61 /* ---------------------------- local macros ------------------------------- */
63 /* ---------------------------- imports ------------------------------------ */
65 /* ---------------------------- included code files ------------------------ */
67 /* ---------------------------- local types -------------------------------- */
71 SM_RAISE
= MARK_RAISE
,
72 SM_LOWER
= MARK_LOWER
,
73 SM_RESTACK
= MARK_RESTACK
76 /* ---------------------------- forward declarations ----------------------- */
78 static void __raise_or_lower_window(
79 FvwmWindow
*t
, stack_mode_t mode
, Bool allow_recursion
,
80 Bool is_new_window
, Bool is_client_request
);
81 static void raise_or_lower_window(
82 FvwmWindow
*t
, stack_mode_t mode
, Bool allow_recursion
,
83 Bool is_new_window
, Bool is_client_request
);
85 static void ResyncFvwmStackRing(void);
87 static void ResyncXStackingOrder(void);
88 static void BroadcastRestack(FvwmWindow
*s1
, FvwmWindow
*s2
);
89 static Bool
is_above_unmanaged(FvwmWindow
*fw
, Window
*umtop
);
90 static int collect_transients_recursive(
91 FvwmWindow
*t
, FvwmWindow
*list_head
, int layer
, stack_mode_t mode
,
92 Bool do_include_target_window
);
94 /* ---------------------------- local variables ---------------------------- */
96 /* ---------------------------- exported variables (globals) --------------- */
98 /* ---------------------------- local functions ---------------------------- */
100 #define DEBUG_STACK_RING 1
101 #ifdef DEBUG_STACK_RING
102 /* debugging function */
103 static void dump_stack_ring(void)
107 if (!debugging_stack_ring
)
112 fprintf(stderr
,"dumping stack ring:\n");
114 t1
= Scr
.FvwmRoot
.stack_next
; t1
!= &Scr
.FvwmRoot
;
117 fprintf(stderr
," l=%d fw=%p f=0x%08x '%s'\n", t1
->layer
,
118 t1
, (int)FW_W_FRAME(t1
), t1
->name
.name
);
124 /* debugging function */
125 void verify_stack_ring_consistency(void)
127 Window root
, parent
, *children
;
128 unsigned int nchildren
;
134 if (!debugging_stack_ring
)
139 t2
= Scr
.FvwmRoot
.stack_next
;
140 if (t2
== &Scr
.FvwmRoot
)
144 last_layer
= t2
->layer
;
147 t1
= t2
->stack_next
; t1
!= &Scr
.FvwmRoot
;
148 t2
= t1
, t1
= t1
->stack_next
)
150 if (t1
->layer
> last_layer
)
154 "vsrc: stack ring is corrupt! '%s' (layer %d)"
155 " is above '%s' (layer %d/%d)\n",
156 t1
->name
.name
, t1
->layer
, t2
->name
.name
,
157 t2
->layer
, last_layer
);
161 last_layer
= t1
->layer
;
165 t1
= t2
->stack_next
; t1
!= &Scr
.FvwmRoot
;
166 t2
= t1
, t1
= t1
->stack_next
)
168 if (t1
->stack_prev
!= t2
)
173 if (t1
!= &Scr
.FvwmRoot
|| t1
->stack_prev
!= t2
)
177 "vsrc: stack ring is corrupt -"
178 " fvwm will probably crash! %p -> %p but %p <- %p",
179 t2
, t1
, t1
->stack_prev
, t1
);
184 if (!XQueryTree(dpy
, Scr
.Root
, &root
, &parent
, &children
, &nchildren
))
186 MyXUngrabServer(dpy
);
190 last_index
= nchildren
;
192 t1
= Scr
.FvwmRoot
.stack_next
; t1
!= &Scr
.FvwmRoot
;
195 /* find window in window list */
197 i
= 0; i
< nchildren
&& FW_W_FRAME(t1
) != children
[i
];
200 /* nothing to do here */
205 stderr
,"vsrc: window already died:"
206 " fw=%p w=0x%08x '%s'\n",
207 t1
, (int)FW_W_FRAME(t1
), t1
->name
.name
);
209 else if (i
>= last_index
)
212 stderr
, "vsrc: window is at wrong position"
213 " in stack ring: fw=%p f=0x%08x '%s'\n",
214 t1
, (int)FW_W_FRAME(t1
),
217 fprintf(stderr
,"dumping X stacking order:\n");
218 for (i
= nchildren
; i
-- > 0; )
221 t1
= Scr
.FvwmRoot
.stack_next
;
225 /* only dump frame windows */
226 if (FW_W_FRAME(t1
) == children
[i
])
229 stderr
, " f=0x%08x\n",
235 MyXUngrabServer(dpy
);
241 MyXUngrabServer(dpy
);
248 /* Add a whole ring of windows. The list_head itself will not be added. */
249 static void add_windowlist_to_stack_ring_after(
250 FvwmWindow
*list_head
, FvwmWindow
*add_after_win
)
252 add_after_win
->stack_next
->stack_prev
= list_head
->stack_prev
;
253 list_head
->stack_prev
->stack_next
= add_after_win
->stack_next
;
254 add_after_win
->stack_next
= list_head
->stack_next
;
255 list_head
->stack_next
->stack_prev
= add_after_win
;
260 static FvwmWindow
*get_transientfor_top_fvwmwindow(FvwmWindow
*t
)
265 while (s
&& IS_TRANSIENT(s
) && DO_STACK_TRANSIENT_PARENT(s
))
267 s
= get_transientfor_fvwmwindow(s
);
278 * Raise a target and all higher fvwm-managed windows above any
279 * override_redirects:
280 * - locate the highest override_redirect above our target
281 * - put all the FvwmWindows from the target to the highest FvwmWindow
282 * below the highest override_redirect in the restack list
283 * - configure our target window above the override_redirect sibling,
286 static void raise_over_unmanaged(FvwmWindow
*t
)
289 Window OR_Above
= None
;
292 FvwmWindow
*t2
= NULL
;
294 XWindowChanges changes
;
298 * Locate the highest override_redirect window above our target, and
299 * the highest of our windows below it.
301 * Count the windows we need to restack, then build the stack list.
303 if (!is_above_unmanaged(t
, &OR_Above
))
306 count
= 0, t2
= Scr
.FvwmRoot
.stack_next
;
307 t2
!= &Scr
.FvwmRoot
; t2
= t2
->stack_next
)
310 count
+= get_visible_icon_window_count(t2
);
319 wins
= (Window
*) safemalloc (count
* sizeof (Window
));
321 i
= 0, t2
= Scr
.FvwmRoot
.stack_next
;
322 t2
!= &Scr
.FvwmRoot
; t2
= t2
->stack_next
)
324 wins
[i
++] = FW_W_FRAME(t2
);
325 if (IS_ICONIFIED(t2
) &&
326 ! IS_ICON_SUPPRESSED(t2
))
328 if (FW_W_ICON_TITLE(t2
) != None
)
330 wins
[i
++] = FW_W_ICON_TITLE(t2
);
332 if (FW_W_ICON_PIXMAP(t2
) != None
)
335 FW_W_ICON_PIXMAP(t2
);
344 memset(&changes
, '\0', sizeof(changes
));
345 changes
.sibling
= OR_Above
;
346 changes
.stack_mode
= Above
;
347 flags
= CWSibling
|CWStackMode
;
350 dpy
, FW_W_FRAME(t
)/*topwin*/, flags
, &changes
);
353 XRestackWindows(dpy
, wins
, i
);
357 }/* end - we found an OR above our target */
362 static Bool
__is_restack_transients_needed(
363 FvwmWindow
*t
, stack_mode_t mode
)
365 if (DO_RAISE_TRANSIENT(t
))
367 if (mode
== SM_RAISE
|| mode
== SM_RESTACK
)
372 if (DO_LOWER_TRANSIENT(t
))
374 if (mode
== SM_LOWER
|| mode
== SM_RESTACK
)
383 static Bool
__must_move_transients(
384 FvwmWindow
*t
, stack_mode_t mode
)
391 if (__is_restack_transients_needed(t
, mode
) == True
)
393 Bool scanning_above_window
= True
;
397 q
= Scr
.FvwmRoot
.stack_next
;
398 q
!= &Scr
.FvwmRoot
&& t
->layer
<= q
->layer
;
401 if (t
->layer
< q
->layer
)
403 /* We're not interested in higher layers. */
406 else if (mode
== SM_RESTACK
&& IS_TRANSIENT(q
) &&
407 FW_W_TRANSIENTFOR(q
) == FW_W(t
))
413 /* We found our window. All further transients
415 scanning_above_window
= False
;
417 else if (IS_TRANSIENT(q
) &&
418 FW_W_TRANSIENTFOR(q
) == FW_W(t
))
422 else if (scanning_above_window
&& mode
== SM_RAISE
)
424 /* raise: The window is not raised, so itself
425 * and all transients will be raised. */
434 static Window
__get_stacking_sibling(FvwmWindow
*fw
, Bool do_stack_below
)
438 /* default to frame window */
440 if (IS_ICONIFIED(fw
) && do_stack_below
== True
)
442 /* override with icon windows when stacking below */
443 if (FW_W_ICON_PIXMAP(fw
) != None
)
445 w
= FW_W_ICON_PIXMAP(fw
);
447 else if (FW_W_ICON_TITLE(fw
) != None
)
449 w
= FW_W_ICON_TITLE(fw
);
456 static void __sort_transient_ring(FvwmWindow
*ring
)
463 if (ring
->stack_next
->stack_next
== ring
)
465 /* only one or zero windows */
468 /* Implementation note: this sorting algorithm is about the most
469 * inefficient possible. It just swaps the position of two adjacent
470 * windows in the ring if they are in the wrong order. Since
471 * transient windows are rare, this should not cause any notable
472 * performance hit. Because it is important that the order of windows
473 * with the same key is not changed, we can not just use qsort() here.
476 t
= ring
->stack_next
, prev
= ring
; t
->stack_next
!= ring
;
477 prev
= t
->stack_prev
)
480 if (t
->scratch
.i
< s
->scratch
.i
)
489 s
->stack_prev
->stack_next
= s
;
490 t
->stack_next
->stack_prev
= t
;
493 /* move further up the ring? */
498 /* hit start of ring */
503 /* correct order, advance one window */
511 static void __restack_window_list(
512 FvwmWindow
*r
, FvwmWindow
*s
, int count
, Bool do_broadcast_all
,
518 XWindowChanges changes
;
525 for (count
= 0, t
= r
->stack_next
; t
!= s
; t
= t
->stack_next
)
528 count
+= get_visible_icon_window_count(t
);
531 /* restack the windows between r and s */
532 wins
= (Window
*)safemalloc((count
+ 3) * sizeof(Window
));
533 for (t
= r
->stack_next
, i
= 0; t
!= s
; t
= t
->stack_next
)
538 ERR
, "__restack_window_list",
539 "more transients than expected");
542 wins
[i
++] = FW_W_FRAME(t
);
543 if (IS_ICONIFIED(t
) && !IS_ICON_SUPPRESSED(t
))
545 if (FW_W_ICON_TITLE(t
) != None
)
547 wins
[i
++] = FW_W_ICON_TITLE(t
);
549 if (FW_W_ICON_PIXMAP(t
) != None
)
551 wins
[i
++] = FW_W_ICON_PIXMAP(t
);
555 changes
.sibling
= __get_stacking_sibling(r
, True
);
556 if (changes
.sibling
== None
)
558 changes
.sibling
= __get_stacking_sibling(s
, False
);
565 if (changes
.sibling
== None
)
567 do_stack_above
= !do_lower
;
573 flags
= CWStackMode
| CWSibling
;
575 changes
.stack_mode
= (do_stack_above
^ is_reversed
) ? Above
: Below
;
576 XConfigureWindow(dpy
, FW_W_FRAME(r
->stack_next
), flags
, &changes
);
579 XRestackWindows(dpy
, wins
, count
);
582 EWMH_SetClientListStacking();
583 if (do_broadcast_all
)
585 /* send out M_RESTACK for all windows, to make sure we don't
586 * forget anything. */
587 BroadcastRestackAllWindows();
591 /* send out (one or more) M_RESTACK packets for windows
593 BroadcastRestack(r
, s
);
599 FvwmWindow
*__get_window_to_insert_after(FvwmWindow
*fw
, stack_mode_t mode
)
607 test_layer
= fw
->layer
- 1;
612 test_layer
= fw
->layer
;
616 s
= Scr
.FvwmRoot
.stack_next
; s
!= &Scr
.FvwmRoot
;
623 if (test_layer
>= s
->layer
)
632 static void __mark_group_member(
633 FvwmWindow
*fw
, FvwmWindow
*start
, FvwmWindow
*end
)
637 for (t
= start
; t
!= end
; t
= t
->stack_next
)
639 if (FW_W(t
) == fw
->wmhints
->window_group
||
640 (t
->wmhints
&& (t
->wmhints
->flags
& WindowGroupHint
) &&
641 t
->wmhints
->window_group
== fw
->wmhints
->window_group
))
643 if (IS_IN_TRANSIENT_SUBTREE(t
))
645 /* have to move this one too */
646 SET_IN_TRANSIENT_SUBTREE(fw
, 1);
655 static Bool
__mark_transient_subtree_test(
656 FvwmWindow
*s
, FvwmWindow
*start
, FvwmWindow
*end
, int mark_mode
,
657 Bool do_ignore_icons
, Bool use_window_group_hint
)
659 Bool use_group_hint
= False
;
662 if (IS_IN_TRANSIENT_SUBTREE(s
))
666 if (use_window_group_hint
&&
667 DO_ICONIFY_WINDOW_GROUPS(s
) && s
->wmhints
&&
668 (s
->wmhints
->flags
& WindowGroupHint
) &&
669 (s
->wmhints
->window_group
!= None
) &&
670 (s
->wmhints
->window_group
!= FW_W(s
)) &&
671 (s
->wmhints
->window_group
!= Scr
.Root
))
673 use_group_hint
= True
;
675 if (!IS_TRANSIENT(s
) && !use_group_hint
)
679 if (do_ignore_icons
&& IS_ICONIFIED(s
))
683 r
= (FvwmWindow
*)s
->scratch
.p
;
686 if (r
&& IS_IN_TRANSIENT_SUBTREE(r
) &&
687 ((mark_mode
== MARK_ALL
) ||
688 __is_restack_transients_needed(
689 r
, (stack_mode_t
)mark_mode
) == True
))
691 /* have to move this one too */
692 SET_IN_TRANSIENT_SUBTREE(s
, 1);
693 /* used for stacking transients */
694 s
->scratch
.i
+= r
->scratch
.i
+ 1;
698 if (use_group_hint
&& !IS_IN_TRANSIENT_SUBTREE(s
))
700 __mark_group_member(s
, start
, end
);
701 if (IS_IN_TRANSIENT_SUBTREE(s
))
703 /* need another scan through the list */
711 /* heavaly borrowed from mark_transient_subtree. This will mark a subtree as
712 * long as it is straight, and return true if the operation is succussful. It
713 * will abort and return False as soon as some inconsitance is hit. */
715 static Bool
is_transient_subtree_straight(
716 FvwmWindow
*t
, int layer
, stack_mode_t mode
, Bool do_ignore_icons
,
717 Bool use_window_group_hint
)
729 mark_mode
= MARK_RAISE
;
732 mark_mode
= MARK_LOWER
;
738 if (layer
>= 0 && t
->layer
!= layer
)
742 if (t
->stack_prev
== NULL
|| t
->stack_next
== NULL
)
744 /* the window is not placed correctly in the stack ring
745 * (probably about to be destroyed) */
748 /* find out on which windows to operate */
749 /* iteration are done reverse (bottom up, since that's the way the
750 * transients wil be stacked if all is well */
753 /* only work on the given layer */
754 start
= &Scr
.FvwmRoot
;
757 s
= Scr
.FvwmRoot
.stack_prev
;
758 s
!= &Scr
.FvwmRoot
&& s
->layer
<= layer
;
761 if (s
->layer
== layer
)
763 if (start
== &Scr
.FvwmRoot
)
773 /* work on complete window list */
774 start
= Scr
.FvwmRoot
.stack_prev
;
777 /* clean the temporary flag in all windows and precalculate the
778 * transient frame windows */
780 s
= Scr
.FvwmRoot
.stack_next
; s
!= &Scr
.FvwmRoot
;
783 SET_IN_TRANSIENT_SUBTREE(s
, 0);
784 if (IS_TRANSIENT(s
) && (layer
< 0 || layer
== s
->layer
))
786 s
->scratch
.p
= get_transientfor_fvwmwindow(s
);
793 /* Indicate that no cleening is needed */
794 Scr
.FvwmRoot
.scratch
.i
= 1;
795 /* now loop over the windows and mark the ones we need to move */
796 SET_IN_TRANSIENT_SUBTREE(t
, 1);
800 if (mode
== SM_LOWER
&& t
!= start
)
805 /* check that all transients above the window are in a sorted line
806 * with no other windows between them */
807 for (s
= t
->stack_prev
; s
!= end
&& !(is_in_gap
&& mode
== SM_RAISE
);
811 __mark_transient_subtree_test(
812 s
, start
, end
, mark_mode
,
814 use_window_group_hint
))
820 else if (s
->scratch
.i
< min_i
)
824 min_i
= s
->scratch
.i
;
831 if (is_in_gap
&& mode
== SM_RAISE
)
835 /* check that there are no transients left beneth the window */
836 for (s
= start
; s
!= t
; s
= s
->stack_prev
)
839 __mark_transient_subtree_test(
840 s
, start
, end
, mark_mode
,
842 use_window_group_hint
))
851 /* function to test if all windows are at correct place from start. */
852 static Bool
__is_restack_needed(
853 FvwmWindow
*t
, stack_mode_t mode
, Bool do_restack_transients
,
860 else if (t
->stack_prev
== NULL
|| t
->stack_next
== NULL
)
862 /* the window is about to be destroyed, and has been removed
863 * from the stack ring. No need to restack. */
867 if (mode
== SM_RESTACK
)
871 if (do_restack_transients
)
873 return !is_transient_subtree_straight(
874 t
, t
->layer
, mode
, True
, False
);
876 else if (mode
== SM_LOWER
)
878 return (t
->stack_next
!= &Scr
.FvwmRoot
&&
879 t
->stack_next
->layer
== t
->layer
);
881 else if (mode
== SM_RAISE
)
883 return (t
->stack_prev
!= &Scr
.FvwmRoot
&&
884 t
->stack_prev
->layer
== t
->layer
);
890 static Bool
__restack_window(
891 FvwmWindow
*t
, stack_mode_t mode
, Bool do_restack_transients
,
892 Bool is_new_window
, Bool is_client_request
)
894 FvwmWindow
*s
= NULL
;
895 FvwmWindow
*r
= NULL
;
899 if (!__is_restack_needed(
900 t
, mode
, do_restack_transients
, is_new_window
))
902 /* need to cancel out the effect of any M_RAISE/M_LOWER that
903 * might already be send out. This is ugly. Better would be to
904 * not send the messages in the first place. */
905 if (do_restack_transients
)
912 while (IS_IN_TRANSIENT_SUBTREE(s
))
916 BroadcastRestack(t
->stack_prev
, s
);
919 /* native/unmanaged windows might have raised. However some
920 * buggy clients will keep issuing requests if the raise hacks
921 * are done after processing their requests. */
922 return is_client_request
;
926 if (do_restack_transients
)
928 /* collect the transients in a temp list */
929 tmp_r
.stack_prev
= &tmp_r
;
930 tmp_r
.stack_next
= &tmp_r
;
931 count
= collect_transients_recursive(
932 t
, &tmp_r
, t
->layer
, mode
, False
);
935 do_restack_transients
= False
;
938 count
+= 1 + get_visible_icon_window_count(t
);
939 /* now find the place to reinsert t and friends */
940 if (mode
== SM_RESTACK
)
946 s
= __get_window_to_insert_after(t
, mode
);
948 remove_window_from_stack_ring(t
);
950 if (do_restack_transients
)
952 /* re-sort the transient windows according to their scratch.i
954 __sort_transient_ring(&tmp_r
);
955 /* insert all transients between r and s. */
956 add_windowlist_to_stack_ring_after(&tmp_r
, r
);
960 ** Re-insert t - below transients
962 add_window_to_stack_ring_after(t
, s
->stack_prev
);
964 if (is_new_window
&& IS_TRANSIENT(t
) &&
965 DO_STACK_TRANSIENT_PARENT(t
) && !IS_ICONIFIED(t
))
967 /* now that the new transient is properly positioned in the
968 * stack ring, raise/lower it again so that its parent is
969 * raised/lowered too */
970 raise_or_lower_window(t
, mode
, True
, False
, is_client_request
);
971 /* make sure the stacking order is correct - may be the
972 * sledge-hammer method, but the recursion ist too hard to
974 ResyncXStackingOrder();
976 /* if the transient is on the top of the top layer pan frames
977 * will have ended up under all windows after this. */
978 return (t
->stack_prev
!= &Scr
.FvwmRoot
);
982 /* restack the windows between r and s */
983 __restack_window_list(
984 r
, s
, count
, do_restack_transients
,
985 mode
== (SM_LOWER
) ? True
: False
);
991 static Bool
__raise_lower_recursion(
992 FvwmWindow
*t
, stack_mode_t mode
, Bool is_client_request
)
997 t2
= Scr
.FvwmRoot
.stack_next
; t2
!= &Scr
.FvwmRoot
;
1000 if (FW_W(t2
) == FW_W_TRANSIENTFOR(t
))
1006 if (IS_ICONIFIED(t2
) || t
->layer
!= t2
->layer
)
1010 if (mode
== SM_LOWER
&&
1011 (!IS_TRANSIENT(t2
) ||
1012 !DO_STACK_TRANSIENT_PARENT(t2
)))
1014 /* hit the highest level transient; lower this
1015 * subtree below all other subtrees of the
1017 t
->scratch
.i
= -LOWER_PENALTY
;
1021 /* Add a bonus to the stack ring position for
1022 * this branch of the transient tree over all
1023 * other branches. */
1024 t
->scratch
.i
= MAX_TRANSIENTS_IN_BRANCH
;
1026 __raise_or_lower_window(
1027 t2
, mode
, True
, False
, is_client_request
);
1028 if (__is_restack_transients_needed(t2
, mode
))
1030 /* moving the parent moves our window already */
1039 static void __raise_or_lower_window(
1040 FvwmWindow
*t
, stack_mode_t mode
, Bool allow_recursion
,
1041 Bool is_new_window
, Bool is_client_request
)
1044 Bool do_move_transients
;
1046 /* Do not raise this window after command execution (see
1047 * HandleButtonPress()). */
1048 SET_SCHEDULED_FOR_RAISE(t
, 0);
1050 /* New windows are simply raised/lowered without touching the
1051 * transientfor at first. Then, further down in the code,
1052 * __raise_or_lower_window() is called again to raise/lower the
1053 * transientfor if necessary. We can not do the recursion stuff for
1054 * new windows because the __must_move_transients() call needs a
1055 * properly ordered stack ring - but the new window is still at the
1056 * front of the stack ring. */
1057 if (allow_recursion
&& !is_new_window
&& !IS_ICONIFIED(t
))
1059 /* This part makes Raise/Lower on a Transient act on its Main
1060 * and sibling Transients.
1062 * The recursion is limited to one level - which caters for
1063 * most cases. This code does not handle the case where there
1064 * are trees of Main + Transient (i.e. where a
1065 * Main_window_with_Transients is itself Transient for another
1067 if (IS_TRANSIENT(t
) && DO_STACK_TRANSIENT_PARENT(t
))
1069 if (__raise_lower_recursion(
1070 t
, mode
, is_client_request
) == True
)
1079 do_move_transients
= False
;
1083 do_move_transients
= __must_move_transients(t
, mode
);
1085 if (__restack_window(
1086 t
, mode
, do_move_transients
, is_new_window
,
1087 is_client_request
) == True
)
1092 if (mode
== SM_RAISE
)
1094 /* This hack raises the target and all higher fvwm windows over
1095 * any style grabfocusoff override_redirect windows that may be
1096 * above it. This is used to cope with ill-behaved applications
1097 * that insist on using long-lived override_redirects. */
1098 if (Scr
.bo
.do_raise_over_unmanaged
)
1100 raise_over_unmanaged(t
);
1104 * The following is a hack to raise X windows over native
1105 * windows which is needed for some (all ?) X servers running
1106 * under Windows or Windows NT. */
1107 if (Scr
.bo
.is_raise_hack_needed
)
1109 /* RBW - 09/20/1999. I find that trying to raise
1110 * unmanaged windows causes problems with some apps. If
1111 * this seems to work well for everyone, I'll remove
1114 /* get *all* toplevels (even including
1115 * override_redirects) */
1116 XQueryTree(dpy
, Scr
.Root
, &junk
, &junk
, &tops
, &num
);
1118 /* raise from fw upwards to get them above NT windows */
1119 for (i
= 0; i
< num
; i
++)
1121 if (tops
[i
] == FW_W_FRAME(t
))
1127 XRaiseWindow (dpy
, tops
[i
]);
1132 for (t2
= t
; t2
!= &Scr
.FvwmRoot
; t2
= t2
->stack_prev
)
1134 XRaiseWindow(dpy
, FW_W_FRAME(t2
));
1137 /* This needs to be done after all the raise hacks. */
1139 /* If the window has been raised, make sure the decorations are
1140 * updated immediately in case we are in a complex function
1141 * (e.g. raise, unshade). */
1143 handle_all_expose();
1149 static void raise_or_lower_window(
1150 FvwmWindow
*t
, stack_mode_t mode
, Bool allow_recursion
,
1151 Bool is_new_window
, Bool is_client_request
)
1155 /* clean the auxiliary registers used in stacking transients */
1156 for (fw
= Scr
.FvwmRoot
.next
; fw
!= NULL
; fw
= fw
->next
)
1160 __raise_or_lower_window(
1161 t
, mode
, allow_recursion
, is_new_window
, is_client_request
);
1166 static Bool
intersect(
1167 int x0
, int y0
, int w0
, int h0
, int x1
, int y1
, int w1
, int h1
)
1169 return !((x0
>= x1
+ w1
) || (x0
+ w0
<= x1
) ||
1170 (y0
>= y1
+ h1
) || (y0
+ h0
<= y1
));
1173 static Bool
overlap(FvwmWindow
*r
, FvwmWindow
*s
)
1179 if (r
->Desk
!= s
->Desk
)
1183 rc
= get_visible_window_or_icon_geometry(r
, &g1
);
1188 rc
= get_visible_window_or_icon_geometry(s
, &g2
);
1194 g1
.x
, g1
.y
, g1
.width
, g1
.height
,
1195 g2
.x
, g2
.y
, g2
.width
, g2
.height
);
1202 ResyncFvwmStackRing -
1203 Rebuilds the stacking order ring of fvwm-managed windows. For use in cases
1204 where apps raise/lower their own windows in a way that makes it difficult
1205 to determine exactly where they ended up in the stacking order.
1206 - Based on code from Matthias Clasen.
1208 static void ResyncFvwmStackRing (void)
1210 Window root
, parent
, *children
;
1211 unsigned int nchildren
;
1213 FvwmWindow
*t1
, *t2
;
1215 MyXGrabServer (dpy
);
1217 if (!XQueryTree (dpy
, Scr
.Root
, &root
, &parent
, &children
, &nchildren
))
1219 MyXUngrabServer (dpy
);
1224 for (i
= 0; i
< nchildren
; i
++)
1226 for (t1
= Scr
.FvwmRoot
.next
; t1
!= NULL
; t1
= t1
->next
)
1228 if (IS_ICONIFIED(t1
) && !IS_ICON_SUPPRESSED(t1
))
1230 if (FW_W_ICON_TITLE(t1
) == children
[i
] ||
1231 FW_W_ICON_PIXMAP(t1
) == children
[i
])
1238 if (FW_W_FRAME(t1
) == children
[i
])
1245 if (t1
!= NULL
&& t1
!= t2
)
1247 /* Move the window to its new position, working from
1248 * the bottom up (that's the way XQueryTree presents
1250 /* Pluck from chain. */
1251 remove_window_from_stack_ring(t1
);
1252 add_window_to_stack_ring_after(t1
, t2
->stack_prev
);
1253 if (t2
!= &Scr
.FvwmRoot
&& t2
->layer
> t1
->layer
)
1255 /* oops, now our stack ring is out of order! */
1257 t1
->layer
= t2
->layer
;
1263 MyXUngrabServer (dpy
);
1269 /* same as above but synchronizes the stacking order in X from the stack ring.
1271 static void ResyncXStackingOrder(void)
1278 for (count
= 0, t
= Scr
.FvwmRoot
.next
; t
!= NULL
; count
++, t
= t
->next
)
1280 /* nothing to do here */
1284 wins
= (Window
*)safemalloc(3 * count
* sizeof (Window
));
1286 i
= 0, t
= Scr
.FvwmRoot
.stack_next
; count
--;
1289 wins
[i
++] = FW_W_FRAME(t
);
1290 if (IS_ICONIFIED(t
) && !IS_ICON_SUPPRESSED(t
))
1292 if (FW_W_ICON_TITLE(t
) != None
)
1294 wins
[i
++] = FW_W_ICON_TITLE(t
);
1296 if (FW_W_ICON_PIXMAP(t
) != None
)
1298 wins
[i
++] = FW_W_ICON_PIXMAP(t
);
1302 XRestackWindows(dpy
, wins
, i
);
1304 /* send out M_RESTACK for all windows, to make sure we don't
1305 * forget anything. */
1306 BroadcastRestackAllWindows();
1312 /* send RESTACK packets for all windows between s1 and s2 */
1313 static void BroadcastRestack(FvwmWindow
*s1
, FvwmWindow
*s2
)
1319 fmodule_list_itr moditr
;
1321 unsigned long *body
, *bp
, length
;
1322 unsigned long max_wins_per_packet
;
1324 if (s2
== &Scr
.FvwmRoot
)
1326 s2
= s2
->stack_prev
;
1327 if (s2
== &Scr
.FvwmRoot
)
1332 if (s1
== &Scr
.FvwmRoot
)
1334 s1
= s1
->stack_next
;
1335 if (s1
== &Scr
.FvwmRoot
)
1339 /* s1 has been moved to the top of stack */
1341 M_RAISE_WINDOW
, 3, (long)FW_W(s1
),
1342 (long)FW_W_FRAME(s1
), (unsigned long)s1
);
1343 if (s1
->stack_next
== s2
)
1345 /* avoid sending empty RESTACK packet */
1351 /* A useful M_RESTACK packet must contain at least two windows.
1356 fw
= s1
, num
= 1; fw
!= s2
&& fw
!= &Scr
.FvwmRoot
;
1357 fw
= fw
->stack_next
, num
++)
1361 max_wins_per_packet
= (FvwmPacketMaxSize
- FvwmPacketHeaderSize
) / 3;
1362 /* split packet if it is too long */
1363 for ( ; num
> 1; s1
= fw
, num
-= n
)
1365 n
= min(num
, max_wins_per_packet
) - 1;
1366 length
= FvwmPacketHeaderSize
+ 3 * (n
+ 1);
1367 body
= (unsigned long *)safemalloc(
1368 length
* sizeof(unsigned long));
1370 *(bp
++) = START_FLAG
;
1371 *(bp
++) = M_RESTACK
;
1373 *(bp
++) = fev_get_evtime();
1374 for (fw
= s1
, i
= 0; i
<= n
; i
++, fw
= fw
->stack_next
)
1377 *(bp
++) = FW_W_FRAME(fw
);
1378 *(bp
++) = (unsigned long)fw
;
1380 /* The last window has to be in the header of the next part */
1381 fw
= fw
->stack_prev
;
1382 module_list_itr_init(&moditr
);
1383 while ( (module
= module_list_itr_next(&moditr
)) != NULL
)
1386 module
,body
,length
*sizeof(unsigned long));
1390 #ifdef DEBUG_STACK_RING
1391 verify_stack_ring_consistency();
1397 static int collect_transients_recursive(
1398 FvwmWindow
*t
, FvwmWindow
*list_head
, int layer
, stack_mode_t mode
,
1399 Bool do_include_target_window
)
1417 /* can not happen */
1421 mark_transient_subtree(t
, layer
, m
, True
, False
);
1422 /* now collect the marked windows in a separate list */
1423 for (s
= Scr
.FvwmRoot
.stack_next
; s
!= &Scr
.FvwmRoot
; )
1427 if (s
== t
&& do_include_target_window
== False
)
1429 /* ignore the target window */
1433 tmp
= s
->stack_next
;
1434 if (IS_IN_TRANSIENT_SUBTREE(s
))
1436 remove_window_from_stack_ring(s
);
1437 add_window_to_stack_ring_after(
1438 s
, list_head
->stack_prev
);
1440 count
+= get_visible_icon_window_count(t
);
1448 static Bool
is_above_unmanaged(FvwmWindow
*fw
, Window
*umtop
)
1451 Chase through the entire stack of the server's windows looking
1452 for any unmanaged window that's higher than the target.
1453 Called from raise_over_unmanaged and is_on_top_of_layer.
1460 Window OR_Above
= None
;
1461 XWindowAttributes wa
;
1463 if (fw
->Desk
!= Scr
.CurrentDesk
)
1467 if (!XQueryTree(dpy
, Scr
.Root
, &junk
, &junk
, &tops
, &num
))
1473 * Locate the highest override_redirect window above our target, and
1474 * the highest of our windows below it.
1476 for (i
= 0; i
< num
&& tops
[i
] != FW_W_FRAME(fw
); i
++)
1478 /* look for target window in list */
1480 for (; i
< num
; i
++)
1482 /* It might be just as well (and quicker) just to check for the
1483 * absence of an FvwmContext instead of for
1484 * override_redirect... */
1485 if (!XGetWindowAttributes(dpy
, tops
[i
], &wa
))
1490 Don't forget to ignore the hidden frame resizing windows...
1492 if (wa
.override_redirect
== True
1493 && wa
.class != InputOnly
1494 && tops
[i
] != Scr
.NoFocusWin
1495 && (!is_frame_hide_window(tops
[i
])))
1512 static Bool
is_on_top_of_layer_ignore_rom(FvwmWindow
*fw
)
1517 if (IS_SCHEDULED_FOR_DESTROY(fw
))
1519 /* stack ring members are no longer valid */
1522 if (DO_RAISE_TRANSIENT(fw
))
1524 mark_transient_subtree(fw
, fw
->layer
, MARK_RAISE
, True
, False
);
1526 for (t
= fw
->stack_prev
; t
!= &Scr
.FvwmRoot
; t
= t
->stack_prev
)
1528 if (t
->layer
> fw
->layer
)
1532 if (t
->Desk
!= fw
->Desk
)
1536 /* For RaiseOverUnmanaged we can not determine if the window is
1537 * on top by checking if the window overlaps another one. If
1538 * it was below unmanaged windows, but on top of its layer, it
1539 * would be considered on top. */
1540 if (Scr
.bo
.do_raise_over_unmanaged
|| overlap(fw
, t
))
1542 if (!DO_RAISE_TRANSIENT(fw
) ||
1543 (!IS_IN_TRANSIENT_SUBTREE(t
) && t
!= fw
))
1554 static Bool
__is_on_top_of_layer(FvwmWindow
*fw
, Bool client_entered
)
1558 if (Scr
.bo
.do_raise_over_unmanaged
)
1561 #define EXPERIMENTAL_ROU_HANDLING
1562 #ifdef EXPERIMENTAL_ROU_HANDLING
1565 RaiseOverUnmanaged adds some overhead. The only way to let our
1566 caller know for sure whether we need to grab the mouse buttons
1567 because we may need to raise this window is to query the
1568 server's tree and look for any override_redirect windows above
1570 But this function is called far too often to do this every
1571 time. Only if the window is at the top of the FvwmWindow
1572 stack do we need more information from the server; and then
1573 only at the last moment in HandleEnterNotify when we really
1574 need to know whether a raise will be needed if the user
1575 clicks in the client window.
1576 is_on_top_of_layer_and_above_unmanaged is called in that case.
1578 if (is_on_top_of_layer_ignore_rom(fw
))
1581 /* FIXME! - perhaps we should only do if MFCR */
1584 printf("RBW-iotol - %8.8lx is on top,"
1585 " checking server tree. ***\n",
1588 ontop
= is_above_unmanaged(fw
, &junk
);
1590 printf(" returning %d\n", (int) ontop
);
1596 printf("RBW-iotol - %8.8lx is on top,"
1597 " *** NOT checking server tree.\n",
1609 return False
; /* Old pre-2002/08/22 handling. */
1614 return is_on_top_of_layer_ignore_rom(fw
);
1618 /* ---------------------------- interface functions ------------------------ */
1620 /* Remove a window from the stack ring */
1621 void remove_window_from_stack_ring(FvwmWindow
*t
)
1623 if (IS_SCHEDULED_FOR_DESTROY(t
))
1627 t
->stack_prev
->stack_next
= t
->stack_next
;
1628 t
->stack_next
->stack_prev
= t
->stack_prev
;
1629 /* not really necessary, but gives a little more saftey */
1630 t
->stack_prev
= NULL
;
1631 t
->stack_next
= NULL
;
1636 /* Add window t to the stack ring after window t */
1637 void add_window_to_stack_ring_after(FvwmWindow
*t
, FvwmWindow
*add_after_win
)
1639 if (IS_SCHEDULED_FOR_DESTROY(t
))
1643 if (t
== add_after_win
|| t
== add_after_win
->stack_next
)
1645 /* tried to add the window before or after itself */
1647 ERR
, "add_window_to_stack_ring_after",
1648 "BUG: tried to add window '%s' %s itself in stack"
1650 t
->name
.name
, (t
== add_after_win
) ?
1651 "after" : "before");
1654 t
->stack_next
= add_after_win
->stack_next
;
1655 add_after_win
->stack_next
->stack_prev
= t
;
1656 t
->stack_prev
= add_after_win
;
1657 add_after_win
->stack_next
= t
;
1662 FvwmWindow
*get_next_window_in_stack_ring(const FvwmWindow
*t
)
1664 return t
->stack_next
;
1667 FvwmWindow
*get_prev_window_in_stack_ring(const FvwmWindow
*t
)
1669 return t
->stack_prev
;
1672 FvwmWindow
*get_transientfor_fvwmwindow(const FvwmWindow
*t
)
1676 if (!t
|| !IS_TRANSIENT(t
) || FW_W_TRANSIENTFOR(t
) == Scr
.Root
||
1677 FW_W_TRANSIENTFOR(t
) == None
)
1681 for (s
= Scr
.FvwmRoot
.next
; s
!= NULL
; s
= s
->next
)
1683 if (FW_W(s
) == FW_W_TRANSIENTFOR(t
))
1685 return (s
== t
) ? NULL
: s
;
1692 /* Takes a window from the top of the stack ring and puts it at the appropriate
1693 * place. Called when new windows are created. */
1694 Bool
position_new_window_in_stack_ring(FvwmWindow
*t
, Bool do_lower
)
1696 if (t
->stack_prev
!= &Scr
.FvwmRoot
)
1698 /* Not at top of stack ring, so it is already in place.
1699 * add_window.c relies on this. */
1702 /* RaiseWindow/LowerWindow will put the window in its layer */
1703 raise_or_lower_window(
1704 t
, (do_lower
) ? SM_LOWER
: SM_RAISE
, False
, True
, False
);
1709 /* Raise t and its transients to the top of its layer. For the pager to work
1710 * properly it is necessary that RaiseWindow *always* sends a proper M_RESTACK
1711 * packet, even if the stacking order didn't change. */
1712 void RaiseWindow(FvwmWindow
*t
, Bool is_client_request
)
1715 M_RAISE_WINDOW
, 3, (long)FW_W(t
), (long)FW_W_FRAME(t
),
1717 raise_or_lower_window(t
, SM_RAISE
, True
, False
, is_client_request
);
1718 focus_grab_buttons_on_layer(t
->layer
);
1719 #ifdef DEBUG_STACK_RING
1720 verify_stack_ring_consistency();
1725 void LowerWindow(FvwmWindow
*t
, Bool is_client_request
)
1728 M_LOWER_WINDOW
, 3, (long)FW_W(t
), (long)FW_W_FRAME(t
),
1730 raise_or_lower_window(t
, SM_LOWER
, True
, False
, is_client_request
);
1731 focus_grab_buttons_on_layer(t
->layer
);
1732 #ifdef DEBUG_STACK_RING
1733 verify_stack_ring_consistency();
1738 void RestackWindow(FvwmWindow
*t
, Bool is_client_request
)
1740 raise_or_lower_window(t
, SM_RESTACK
, True
, False
, is_client_request
);
1741 focus_grab_buttons_on_layer(t
->layer
);
1742 #ifdef DEBUG_STACK_RING
1743 verify_stack_ring_consistency();
1748 /* return true if stacking order changed */
1749 Bool
HandleUnusualStackmodes(
1750 unsigned int stack_mode
, FvwmWindow
*r
, Window rw
, FvwmWindow
*s
,
1756 /* DBUG("HandleUnusualStackmodes", "called with %d, %lx\n",
1760 ((rw
!= FW_W(r
)) ^ IS_ICONIFIED(r
)) ||
1761 (s
&& (((sw
!= FW_W(s
)) ^ IS_ICONIFIED(s
)) ||
1762 (r
->Desk
!= s
->Desk
))))
1764 /* one of the relevant windows is unmapped */
1772 t
= r
->stack_prev
; t
!= &Scr
.FvwmRoot
&& !do_restack
;
1775 do_restack
= ((s
== NULL
|| s
== t
) && overlap(t
, r
));
1779 RaiseWindow (r
, True
);
1784 t
= r
->stack_next
; t
!= &Scr
.FvwmRoot
&& !do_restack
;
1787 do_restack
= ((s
== NULL
|| s
== t
) && overlap(t
, r
));
1791 LowerWindow (r
, True
);
1796 HandleUnusualStackmodes(TopIf
, r
, rw
, s
, sw
) ||
1797 HandleUnusualStackmodes(BottomIf
, r
, rw
, s
, sw
));
1800 /* DBUG("HandleUnusualStackmodes", "\t---> %d\n", do_restack);*/
1801 #ifdef DEBUG_STACK_RING
1802 verify_stack_ring_consistency();
1808 RBW - 01/07/1998 - this is here temporarily - I mean to move it to
1809 libfvwm eventually, along with some other chain manipulation functions.
1812 void BroadcastRestackAllWindows(void)
1814 BroadcastRestack(Scr
.FvwmRoot
.stack_next
, Scr
.FvwmRoot
.stack_prev
);
1818 /* send RESTACK packets for t, t->stack_prev and t->stack_next */
1819 void BroadcastRestackThisWindow(FvwmWindow
*t
)
1821 BroadcastRestack(t
->stack_prev
, t
->stack_next
);
1825 /* returns 0 if s and t are on the same layer, <1 if t is on a lower layer and
1826 * >1 if t is on a higher layer. */
1827 int compare_window_layers(FvwmWindow
*t
, FvwmWindow
*s
)
1829 return t
->layer
- s
->layer
;
1832 void set_default_layer(FvwmWindow
*t
, int layer
)
1834 t
->default_layer
= layer
;
1838 void set_layer(FvwmWindow
*t
, int layer
)
1844 int get_layer(FvwmWindow
*t
)
1849 /* This function recursively finds the transients of the window t and sets their
1850 * is_in_transient_subtree flag. If a layer is given, only windows in this
1851 * layer are checked. If the layer is < 0, all windows are considered.
1853 void mark_transient_subtree(
1854 FvwmWindow
*t
, int layer
, int mark_mode
, Bool do_ignore_icons
,
1855 Bool use_window_group_hint
)
1862 if (layer
>= 0 && t
->layer
!= layer
)
1866 /* find out on which windows to operate */
1869 /* only work on the given layer */
1870 start
= &Scr
.FvwmRoot
;
1871 end
= &Scr
.FvwmRoot
;
1873 s
= Scr
.FvwmRoot
.stack_next
;
1874 s
!= &Scr
.FvwmRoot
&& s
->layer
>= layer
;
1879 /* ignore the target window */
1882 if (s
->layer
== layer
)
1884 if (start
== &Scr
.FvwmRoot
)
1888 end
= s
->stack_next
;
1894 /* work on complete window list */
1895 start
= Scr
.FvwmRoot
.stack_next
;
1896 end
= &Scr
.FvwmRoot
;
1898 /* clean the temporary flag in all windows and precalculate the
1899 * transient frame windows */
1900 if (Scr
.FvwmRoot
.scratch
.i
== 0)
1903 s
= Scr
.FvwmRoot
.stack_next
; s
!= &Scr
.FvwmRoot
;
1906 SET_IN_TRANSIENT_SUBTREE(s
, 0);
1909 (layer
< 0 || layer
== s
->layer
))
1911 s
->scratch
.p
= get_transientfor_fvwmwindow(s
);
1915 s
->scratch
.p
= NULL
;
1919 Scr
.FvwmRoot
.scratch
.i
= 0;
1921 /* now loop over the windows and mark the ones we need to move */
1922 SET_IN_TRANSIENT_SUBTREE(t
, 1);
1923 is_finished
= False
;
1924 while (!is_finished
)
1926 /* recursively search for all transient windows */
1928 for (s
= start
; s
!= end
; s
= s
->stack_next
)
1932 __mark_transient_subtree_test(
1933 s
, start
, end
, mark_mode
,
1935 use_window_group_hint
))
1937 is_finished
= False
;
1945 void new_layer(FvwmWindow
*fw
, int layer
)
1950 FvwmWindow list_head
;
1951 int add_after_layer
;
1960 fw
= get_transientfor_top_fvwmwindow(fw
);
1961 if (layer
== fw
->layer
)
1965 old_layer
= fw
->layer
;
1966 list_head
.stack_next
= &list_head
;
1967 list_head
.stack_prev
= &list_head
;
1968 count
= collect_transients_recursive(
1969 fw
, &list_head
, fw
->layer
,
1970 (layer
< fw
->layer
) ? SM_LOWER
: SM_RAISE
, True
);
1973 /* no windows to move */
1976 add_after_layer
= layer
;
1977 if (layer
< fw
->layer
)
1979 /* lower below the windows in the new (lower) layer */
1980 add_after_layer
= layer
;
1985 /* raise above the windows in the new (higher) layer */
1986 add_after_layer
= layer
+ 1;
1989 /* find the place to insert the windows */
1991 target
= Scr
.FvwmRoot
.stack_next
; target
!= &Scr
.FvwmRoot
;
1992 target
= target
->stack_next
)
1994 if (target
->layer
< add_after_layer
)
1996 /* add all windows before the current window */
2000 /* insert windows at new position */
2001 add_windowlist_to_stack_ring_after(&list_head
, target
->stack_prev
);
2004 s
= list_head
.stack_next
; prev
!= list_head
.stack_prev
;
2005 prev
= s
, s
= s
->stack_next
)
2008 /* redraw title and buttons to update layer buttons */
2009 border_draw_decorations(
2010 s
, PART_TITLEBAR
, (Scr
.Hilite
== fw
), True
, CLEAR_NONE
,
2013 EWMH_SetWMState(fw
, False
);
2015 /* move the windows without modifying their stacking order */
2016 __restack_window_list(
2017 list_head
.stack_next
->stack_prev
, target
, count
, (count
> 1),
2019 focus_grab_buttons_on_layer(layer
);
2020 focus_grab_buttons_on_layer(old_layer
);
2025 /* RBW - 11/13/1998 - 2 new fields to init - stacking order chain. */
2026 void init_stack_and_layers(void)
2028 Scr
.BottomLayer
= DEFAULT_BOTTOM_LAYER
;
2029 Scr
.DefaultLayer
= DEFAULT_DEFAULT_LAYER
;
2030 Scr
.TopLayer
= DEFAULT_TOP_LAYER
;
2031 Scr
.FvwmRoot
.stack_next
= &Scr
.FvwmRoot
;
2032 Scr
.FvwmRoot
.stack_prev
= &Scr
.FvwmRoot
;
2033 set_layer(&Scr
.FvwmRoot
, DEFAULT_ROOT_WINDOW_LAYER
);
2037 Bool
is_on_top_of_layer(FvwmWindow
*fw
)
2039 return __is_on_top_of_layer(fw
, False
);
2042 Bool
is_on_top_of_layer_and_above_unmanaged(FvwmWindow
*fw
)
2044 return __is_on_top_of_layer(fw
, True
);
2047 /* ----------------------------- built in functions ----------------------- */
2049 void CMD_Raise(F_CMD_ARGS
)
2051 RaiseWindow(exc
->w
.fw
, False
);
2056 void CMD_Lower(F_CMD_ARGS
)
2058 LowerWindow(exc
->w
.fw
, False
);
2063 void CMD_RestackTransients(F_CMD_ARGS
)
2065 RestackWindow(exc
->w
.fw
, False
);
2070 void CMD_RaiseLower(F_CMD_ARGS
)
2073 FvwmWindow
* const fw
= exc
->w
.fw
;
2075 ontop
= is_on_top_of_layer_ignore_rom(fw
);
2078 LowerWindow(fw
, False
);
2082 RaiseWindow(fw
, False
);
2088 void CMD_Layer(F_CMD_ARGS
)
2090 int n
, layer
, val
[2];
2092 FvwmWindow
* const fw
= exc
->w
.fw
;
2098 token
= PeekToken(action
, NULL
);
2099 if (StrEquals("default", token
))
2101 layer
= fw
->default_layer
;
2105 n
= GetIntegerArguments(action
, NULL
, val
, 2);
2109 ((n
== 2) && (val
[0] != 0)))
2113 else if ((n
== 2) && (val
[1] >= 0))
2119 layer
= fw
->default_layer
;
2126 new_layer(fw
, layer
);
2127 #ifdef DEBUG_STACK_RING
2128 verify_stack_ring_consistency();
2134 void CMD_DefaultLayers(F_CMD_ARGS
)
2141 bot
= PeekToken(action
, &action
);
2148 ERR
, "DefaultLayers",
2149 "Layer must be non-negative." );
2153 Scr
.BottomLayer
= i
;
2156 def
= PeekToken(action
, &action
);
2163 ERR
, "DefaultLayers",
2164 "Layer must be non-negative." );
2168 Scr
.DefaultLayer
= i
;
2171 top
= PeekToken(action
, &action
);
2178 ERR
, "DefaultLayers",
2179 "Layer must be non-negative." );
2186 #ifdef DEBUG_STACK_RING
2187 verify_stack_ring_consistency();