1 /* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License as published by
3 * the Free Software Foundation; either version 2 of the License, or
4 * (at your option) any later version.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "libs/fvwmlib.h"
27 #include "functions.h"
32 #include "module_interface.h"
38 /* ----------------------------- stack ring code --------------------------- */
40 static void RaiseOrLowerWindow(
41 FvwmWindow
*t
, Bool do_lower
, Bool allow_recursion
, Bool is_new_window
);
42 static void ResyncFvwmStackRing(void);
43 static void ResyncXStackingOrder(void);
44 static void BroadcastRestack(FvwmWindow
*s1
, FvwmWindow
*s2
);
46 /* debugging function */
47 static void dump_stack_ring(void)
52 fprintf(stderr
,"dumping stack ring:\n");
53 for (t1
= Scr
.FvwmRoot
.stack_next
; t1
!= &Scr
.FvwmRoot
; t1
= t1
->stack_next
)
55 fprintf(stderr
," l=%d fw=0x%08x f=0x%08x '%s'\n", t1
->layer
,
56 (int)t1
, (int)t1
->frame
, t1
->name
);
62 /* debugging function */
63 static void verify_stack_ring_consistency(void)
65 Window root
, parent
, *children
;
66 unsigned int nchildren
, i
;
72 t2
= Scr
.FvwmRoot
.stack_next
;
75 last_layer
= t2
->layer
;
77 for (t1
= t2
->stack_next
; t1
!= &Scr
.FvwmRoot
; t2
= t1
, t1
= t1
->stack_next
)
79 if (t1
->layer
> last_layer
)
83 "vsrc: stack ring is corrupt! "
84 "'%s' (layer %d) is above '%s' (layer %d)\n",
85 t1
->name
, t1
->layer
, t2
->name
, t2
->layer
);
89 last_layer
= t1
->layer
;
92 if (!XQueryTree(dpy
, Scr
.Root
, &root
, &parent
, &children
, &nchildren
))
98 last_index
= nchildren
;
99 for (t1
= Scr
.FvwmRoot
.stack_next
; t1
!= &Scr
.FvwmRoot
; t1
= t1
->stack_next
)
101 /* find window in window list */
102 for (i
= 0; i
< nchildren
&& t1
->frame
!= children
[i
]; i
++)
106 fprintf(stderr
,"vsrc: window already died: fw=0x%08x w=0x%08x '%s'\n",
107 (int)t1
, (int)t1
->frame
, t1
->name
);
109 else if (i
>= last_index
)
112 stderr
, "vsrc: window is at wrong position in stack ring: "
113 "fw=0x%08x f=0x%08x '%s'\n", (int)t1
, (int)t1
->frame
, t1
->name
);
115 fprintf(stderr
,"dumping X stacking order:\n");
116 for (i
= nchildren
; i
-- > 0; )
118 for (t1
= Scr
.FvwmRoot
.stack_next
; t1
!= &Scr
.FvwmRoot
;
121 /* only dump frame windows */
122 if (t1
->frame
== children
[i
])
124 fprintf(stderr
," f=0x%08x\n", (int)children
[i
]);
129 MyXUngrabServer (dpy
);
135 MyXUngrabServer(dpy
);
141 /* Remove a window from the stack ring */
142 void remove_window_from_stack_ring(FvwmWindow
*t
)
144 t
->stack_prev
->stack_next
= t
->stack_next
;
145 t
->stack_next
->stack_prev
= t
->stack_prev
;
149 /* Add window t to the stack ring after window t2 */
150 void add_window_to_stack_ring_after(FvwmWindow
*t
, FvwmWindow
*add_after_win
)
152 t
->stack_next
= add_after_win
->stack_next
;
153 add_after_win
->stack_next
->stack_prev
= t
;
154 t
->stack_prev
= add_after_win
;
155 add_after_win
->stack_next
= t
;
159 FvwmWindow
*get_next_window_in_stack_ring(FvwmWindow
*t
)
161 return t
->stack_next
;
164 FvwmWindow
*get_prev_window_in_stack_ring(FvwmWindow
*t
)
166 return t
->stack_prev
;
169 /* Takes a window from the top of the stack ring and puts it at the appropriate
170 * place. Called when new windows are created. */
171 Bool
position_new_window_in_stack_ring(FvwmWindow
*t
, Bool do_lower
)
173 if (t
->stack_prev
!= &Scr
.FvwmRoot
)
174 /* Not at top of stack ring, so it is already in place. add_window.c relies
177 /* RaiseWindow/LowerWindow will put the window in its layer */
178 RaiseOrLowerWindow(t
, do_lower
, False
, True
);
183 /********************************************************************
184 * Raise a target and all higher FVWM-managed windows above any
185 * override_redirects:
186 * - locate the highest override_redirect above our target
187 * - put all the FvwmWindows from the target to the highest FvwmWindow
188 * below the highest override_redirect in the restack list
189 * - configure our target window above the override_redirect sibling,
191 ********************************************************************/
192 static void raise_over_unmanaged(FvwmWindow
*t
)
203 FvwmWindow
*t2
= NULL
;
204 FvwmWindow
*junkwin
= NULL
;
206 XWindowChanges changes
;
207 XWindowAttributes wa
;
209 if (!XQueryTree(dpy
, Scr
.Root
, &junk
, &junk
, &tops
, &num
))
212 topwin
= Scr
.FvwmRoot
.stack_next
->frame
;
215 /********************************************************************
216 * Locate the highest override_redirect window above our target, and
217 * the highest of our windows below it.
218 ********************************************************************/
219 for (i
= 0; i
< num
; i
++) {
220 if (tops
[i
] == t
->frame
) {
225 It might be just as well (and quicker) just to check for the absence of
226 an FvwmContext instead of for override_redirect...
228 if (XGetWindowAttributes(dpy
, tops
[i
], &wa
)) {
229 if (wa
.override_redirect
== True
) {
230 /* There's always at least 1 OR lurking somewhere...NoFocusWin. */
232 if (XFindContext(dpy
, tops
[i
- 1],
233 FvwmContext
, (caddr_t
*) &junkwin
) != XCNOENT
) {
234 /* save next lower non-OR win below highest OR... */
235 topwin
= tops
[i
- 1];
243 DBUG("raise_over_unmanaged",
244 "Error - XGetWindowAttributes failed for window %8.8lx!\n",
251 /********************************************************************
252 * Count the windows we need to restack, then build the stack list.
253 ********************************************************************/
259 for (t2
= t
; (t2
!= &Scr
.FvwmRoot
&& ! found
); t2
= t2
->stack_prev
) {
261 if (IS_ICONIFIED(t2
) && ! IS_ICON_SUPPRESSED(t2
)) {
262 if (t2
->icon_w
!= None
) {
265 if (t2
->icon_pixmap_w
!= None
) {
269 if (t2
->frame
== topwin
) {
277 topwin
= Scr
.FvwmRoot
.stack_next
->frame
;
278 wins
= (Window
*) safemalloc (count
* sizeof (Window
));
279 for (t2
= t
; t2
!= &Scr
.FvwmRoot
&& ! found
; t2
= t2
->stack_prev
) {
280 wins
[i
++] = t2
->frame
;
281 if (IS_ICONIFIED(t2
) && ! IS_ICON_SUPPRESSED(t2
)) {
282 if (t2
->icon_w
!= None
) {
283 wins
[i
++] = t2
->icon_w
;
285 if (t2
->icon_pixmap_w
!= None
) {
286 wins
[i
++] = t2
->icon_pixmap_w
;
289 if (t2
->frame
== topwin
) {
294 memset(&changes
, '\0', sizeof(changes
));
295 changes
.sibling
= OR_Above
;
296 changes
.stack_mode
= Above
;
297 flags
= CWSibling
|CWStackMode
;
299 XConfigureWindow (dpy
, topwin
, flags
, &changes
);
300 XRestackWindows (dpy
, wins
, i
);
303 } /* end - we found an OR above our target */
311 static Bool
must_move_transients(
312 FvwmWindow
*t
, Bool do_lower
, Bool
*found_transient
)
314 *found_transient
= False
;
317 if ((!do_lower
&& DO_RAISE_TRANSIENT(t
)) ||
318 (do_lower
&& DO_LOWER_TRANSIENT(t
)))
320 Bool scanning_above_window
= True
;
323 for (q
= Scr
.FvwmRoot
.stack_next
; q
!= &Scr
.FvwmRoot
; q
= q
->stack_next
)
325 if (t
->layer
< q
->layer
)
327 /* We're not interested in higher layers. */
330 if (t
->layer
> q
->layer
)
332 /* We are at the end of this layer. Stop scanning windows. */
337 /* We found our window. All further transients are below it. */
338 scanning_above_window
= False
;
340 else if (IS_TRANSIENT(q
) && (q
->transientfor
== t
->w
))
342 /* found a transient */
343 *found_transient
= True
;
345 /* transients are not allowed below main in the same layer */
346 if ( !scanning_above_window
)
351 else if ((scanning_above_window
&& !do_lower
) ||
352 (*found_transient
&& do_lower
))
354 /* raise: The window is not raised, so itself and all transients will
356 /* lower: There is a transient above some other window, so we have to
365 static void RaiseOrLowerWindow(
366 FvwmWindow
*t
, Bool do_lower
, Bool allow_recursion
, Bool is_new_window
)
368 FvwmWindow
*s
, *r
, *t2
, *next
, tmp_r
;
371 XWindowChanges changes
;
373 Bool do_move_transients
;
374 Bool found_transient
;
378 /* Do not raise this window after command execution (see HandleButtonPress()).
380 SET_SCHEDULED_FOR_RAISE(t
, 0);
382 /* New windows are simply raised/lowered without touching the transientfor
383 * at first. Then, further down in the code, RaiseOrLowerWindow() is called
384 * again to raise/lower the transientfor if necessary. We can not do the
385 * recursion stuff for new windows because the must_move_transients() call
386 * needs a properly ordered stack ring - but the new window is still at the
387 * front of the stack ring. */
388 if (allow_recursion
&& !is_new_window
)
391 * This part makes Raise/Lower on a Transient act on its Main and sibling
394 * The recursion is limited to one level - which caters for most cases.
395 * This code does not handle the case where there are trees of Main +
396 * Transient (ie where a Main_window_with_Transients is itself Transient
397 * for another window).
399 * Another strategy is required to handle trees of Main+Transients
401 if (IS_TRANSIENT(t
) && DO_STACK_TRANSIENT_PARENT(t
))
403 for (t2
= Scr
.FvwmRoot
.stack_next
; t2
!= &Scr
.FvwmRoot
;
406 if (t2
->w
== t
->transientfor
)
408 if ((!do_lower
&& DO_RAISE_TRANSIENT(t2
)) ||
409 (do_lower
&& DO_LOWER_TRANSIENT(t2
)) )
411 RaiseOrLowerWindow(t2
,do_lower
,False
,False
);
422 do_move_transients
= False
;
426 do_move_transients
= must_move_transients(t
, do_lower
, &found_transient
);
429 * This part implements (Dont)FlipTransient style.
431 * must_move_transients() believes that main should always be below
432 * its transients. Therefore if it finds a transient but does not wish
433 * move it, this means main and its superior transients are already
434 * in the correct position at the top or bottom of the layer - depending
437 no_movement
= found_transient
&& !do_move_transients
;
442 /* detach t, so it doesn't make trouble in the loops */
443 remove_window_from_stack_ring(t
);
446 if (IS_ICONIFIED(t
) && !IS_ICON_SUPPRESSED(t
))
451 if (do_move_transients
)
453 /* collect the transients in a temp list */
454 tmp_r
.stack_prev
= &tmp_r
;
455 tmp_r
.stack_next
= &tmp_r
;
456 for (t2
= Scr
.FvwmRoot
.stack_next
; t2
!= &Scr
.FvwmRoot
; t2
= next
)
458 next
= t2
->stack_next
;
459 if ((IS_TRANSIENT(t2
)) && (t2
->transientfor
== t
->w
) &&
460 (t2
->layer
== t
->layer
))
462 /* t2 is a transient to lower */
464 if (IS_ICONIFIED(t2
) && !IS_ICON_SUPPRESSED(t2
))
470 remove_window_from_stack_ring(t2
);
472 /* put it above tmp_r */
473 t2
->stack_next
= &tmp_r
;
474 t2
->stack_prev
= tmp_r
.stack_prev
;
475 t2
->stack_prev
->stack_next
= t2
;
476 tmp_r
.stack_prev
= t2
;
479 if (tmp_r
.stack_next
== &tmp_r
)
481 do_move_transients
= False
;
485 test_layer
= t
->layer
;
490 /* now find the place to reinsert t and friends */
491 for (s
= Scr
.FvwmRoot
.stack_next
; s
!= &Scr
.FvwmRoot
; s
= s
->stack_next
)
493 if (test_layer
>= s
->layer
)
500 if (do_move_transients
&& tmp_r
.stack_next
!= &tmp_r
)
502 /* insert all transients between r and s. */
503 r
->stack_next
= tmp_r
.stack_next
;
504 tmp_r
.stack_next
->stack_prev
= r
;
505 s
->stack_prev
= tmp_r
.stack_prev
;
506 tmp_r
.stack_prev
->stack_next
= s
;
510 ** Re-insert t - below transients
512 add_window_to_stack_ring_after(t
, s
->stack_prev
);
514 if (is_new_window
&& IS_TRANSIENT(t
) && DO_STACK_TRANSIENT_PARENT(t
))
516 /* now that the new transient is properly positioned in the stack ring,
517 * raise/lower it again so that its parent is raised/lowered too */
518 RaiseOrLowerWindow(t
, do_lower
, True
, False
);
519 /* make sure the stacking order is correct - may be the sledge-hammer
520 * method, but the recursion ist too hard to understand. */
521 ResyncXStackingOrder();
526 wins
= (Window
*) safemalloc (count
* sizeof (Window
));
528 for (t2
= r
->stack_next
; t2
!= s
; t2
= t2
->stack_next
)
532 fvwm_msg (ERR
, "RaiseOrLowerWindow", "more transients than expected");
535 wins
[i
++] = t2
->frame
;
536 if (IS_ICONIFIED(t2
) && !IS_ICON_SUPPRESSED(t2
))
538 if(t2
->icon_w
!= None
)
539 wins
[i
++] = t2
->icon_w
;
540 if(t2
->icon_pixmap_w
!= None
)
541 wins
[i
++] = t2
->icon_pixmap_w
;
545 changes
.sibling
= s
->frame
;
546 if (changes
.sibling
!= None
)
548 changes
.stack_mode
= Above
;
549 flags
= CWSibling
|CWStackMode
;
553 changes
.stack_mode
= Below
;
557 XConfigureWindow (dpy
, r
->stack_next
->frame
, flags
, &changes
);
558 XRestackWindows (dpy
, wins
, count
);
560 /* send out (one or more) M_RESTACK packets for windows between r and s */
561 BroadcastRestack(r
, s
);
562 if (do_move_transients
&& tmp_r
.stack_next
!= &tmp_r
)
564 /* send out M_RESTACK for all windows, to make sure we don't forget
566 BroadcastRestackAllWindows();
574 /* This hack raises the target and all higher FVWM windows over any style
575 * grabfocusoff override_redirect windows that may be above it. This is
576 * used to cope with ill-bahaved applications that insist on using
577 * long-lived override_redirects. */
578 if (Scr
.bo
.RaiseOverUnmanaged
)
580 raise_over_unmanaged(t
);
585 * The following is a hack to raise X windows over native windows
586 * which is needed for some (all ?) X servers running under Windows
589 if (Scr
.bo
.RaiseHackNeeded
)
592 RBW - 09/20/1999. I find that trying to raise unmanaged windows
593 causes problems with some apps. If this seems to work well for
594 everyone, I'll remove the #if 0.
597 /* get *all* toplevels (even including override_redirects) */
598 XQueryTree(dpy
, Scr
.Root
, &junk
, &junk
, &tops
, &num
);
600 /* raise from tmp_win upwards to get them above NT windows */
601 for (i
= 0; i
< num
; i
++)
603 if (tops
[i
] == t
->frame
)
606 XRaiseWindow (dpy
, tops
[i
]);
610 for (t2
= t
; t2
!= &Scr
.FvwmRoot
; t2
= t2
->stack_prev
)
612 XRaiseWindow (dpy
, t2
->frame
);
617 /* This needs to be done after all the raise hacks. */
620 /* If the window has been raised, make sure the decorations are updated
621 * immediately in case we are in a complex function (e.g. raise, unshade). */
623 DrawDecorations(t
, DRAW_ALL
, (Scr
.Hilite
== t
), True
, None
);
627 Raise t and its transients to the top of its layer.
628 For the pager to work properly it is necessary that
629 RaiseWindow *always* sends a proper M_RESTACK packet,
630 even if the stacking order didn't change.
632 void RaiseWindow(FvwmWindow
*t
)
634 RaiseOrLowerWindow(t
, False
, True
, False
);
635 verify_stack_ring_consistency();
639 void LowerWindow(FvwmWindow
*t
)
641 RaiseOrLowerWindow(t
, True
, True
, False
);
642 verify_stack_ring_consistency();
648 intersect (int x0
, int y0
, int w0
, int h0
,
649 int x1
, int y1
, int w1
, int h1
)
651 return !((x0
>= x1
+ w1
) || (x0
+ w0
<= x1
) ||
652 (y0
>= y1
+ h1
) || (y0
+ h0
<= y1
));
656 overlap_box (FvwmWindow
*r
, int x
, int y
, int w
, int h
)
660 return ((r
->icon_pixmap_w
) &&
661 intersect (x
, y
, w
, h
, r
->icon_g
.x
, r
->icon_g
.y
,
662 r
->icon_p_width
, r
->icon_p_height
)) ||
664 intersect (x
, y
, w
, h
, r
->icon_xl_loc
,
665 r
->icon_g
.y
+ r
->icon_p_height
,
666 r
->icon_g
.width
, r
->icon_g
.height
));
670 return intersect (x
, y
, w
, h
, r
->frame_g
.x
, r
->frame_g
.y
,
671 r
->frame_g
.width
, r
->frame_g
.height
);
676 overlap (FvwmWindow
*r
, FvwmWindow
*s
)
678 if (r
->Desk
!= s
->Desk
)
685 return ((r
->icon_pixmap_w
) &&
686 overlap_box (s
, r
->icon_g
.x
, r
->icon_g
.y
,
687 r
->icon_p_width
, r
->icon_p_height
)) ||
689 overlap_box (s
, r
->icon_xl_loc
, r
->icon_g
.y
+ r
->icon_p_height
,
690 r
->icon_g
.width
, r
->icon_g
.height
));
694 return overlap_box (s
, r
->frame_g
.x
, r
->frame_g
.y
,
695 r
->frame_g
.width
, r
->frame_g
.height
);
699 /* return true if stacking order changed */
701 HandleUnusualStackmodes(unsigned int stack_mode
, FvwmWindow
*r
, Window rw
,
702 FvwmWindow
*s
, Window sw
)
707 /* DBUG("HandleUnusualStackmodes", "called with %d, %lx\n", stack_mode, s);*/
709 if (((rw
!= r
->w
) ^ IS_ICONIFIED(r
)) ||
710 (s
&& (((sw
!= s
->w
) ^ IS_ICONIFIED(s
)) || (r
->Desk
!= s
->Desk
))))
712 /* one of the relevant windows is unmapped */
719 for (t
= r
->stack_prev
; (t
!= &Scr
.FvwmRoot
) && !restack
;
722 restack
= (((s
== NULL
) || (s
== t
)) && overlap (t
, r
));
730 for (t
= r
->stack_next
; (t
!= &Scr
.FvwmRoot
) && !restack
;
733 restack
= (((s
== NULL
) || (s
== t
)) && overlap (t
, r
));
741 restack
= (HandleUnusualStackmodes (TopIf
, r
, rw
, s
, sw
) ||
742 HandleUnusualStackmodes (BottomIf
, r
, rw
, s
, sw
));
745 /* DBUG("HandleUnusualStackmodes", "\t---> %d\n", restack);*/
746 verify_stack_ring_consistency();
754 RBW - 01/07/1998 - this is here temporarily - I mean to move it to
755 libfvwm eventually, along with some other chain manipulation functions.
759 ResyncFvwmStackRing -
760 Rebuilds the stacking order ring of FVWM-managed windows. For use in cases
761 where apps raise/lower their own windows in a way that makes it difficult
762 to determine exactly where they ended up in the stacking order.
763 - Based on code from Matthias Clasen.
765 static void ResyncFvwmStackRing (void)
767 Window root
, parent
, *children
;
768 unsigned int nchildren
, i
;
773 if (!XQueryTree (dpy
, Scr
.Root
, &root
, &parent
, &children
, &nchildren
))
775 MyXUngrabServer (dpy
);
780 for (i
= 0; i
< nchildren
; i
++)
782 for (t1
= Scr
.FvwmRoot
.next
; t1
!= NULL
; t1
= t1
->next
)
784 if (IS_ICONIFIED(t1
) && !IS_ICON_SUPPRESSED(t1
))
786 if (t1
->icon_w
== children
[i
] || t1
->icon_pixmap_w
== children
[i
])
793 if (t1
->frame
== children
[i
])
800 if (t1
!= NULL
&& t1
!= t2
)
803 * Move the window to its new position, working from the bottom up
804 * (that's the way XQueryTree presents the list).
806 /* Pluck from chain. */
807 remove_window_from_stack_ring(t1
);
808 add_window_to_stack_ring_after(t1
, t2
->stack_prev
);
813 MyXUngrabServer (dpy
);
818 /* same as above but synchronizes the stacking order in X from the stack ring.
820 static void ResyncXStackingOrder(void)
827 for (count
= 0, t
= Scr
.FvwmRoot
.next
; t
!= None
; count
++, t
= t
->next
)
831 wins
= (Window
*)safemalloc(3 * count
* sizeof (Window
));
833 for (i
= 0, t
= Scr
.FvwmRoot
.stack_next
; count
--; t
= t
->stack_next
)
835 wins
[i
++] = t
->frame
;
836 if (IS_ICONIFIED(t
) && !IS_ICON_SUPPRESSED(t
))
838 if (t
->icon_w
!= None
)
839 wins
[i
++] = t
->icon_w
;
840 if (t
->icon_pixmap_w
!= None
)
841 wins
[i
++] = t
->icon_pixmap_w
;
844 XRestackWindows(dpy
, wins
, i
);
846 /* send out M_RESTACK for all windows, to make sure we don't forget
848 BroadcastRestackAllWindows();
853 /* send RESTACK packets for all windows between s1 and s2 */
854 static void BroadcastRestack (FvwmWindow
*s1
, FvwmWindow
*s2
)
858 unsigned long *body
, *bp
, length
;
859 extern Time lastTimestamp
;
861 if (s2
== &Scr
.FvwmRoot
)
864 if (s2
== &Scr
.FvwmRoot
)
867 if (s1
== &Scr
.FvwmRoot
)
870 if (t
== &Scr
.FvwmRoot
)
872 /* t has been moved to the top of stack */
874 BroadcastPacket (M_RAISE_WINDOW
, 3, t
->w
, t
->frame
, (unsigned long)t
);
875 if (t
->stack_next
== s2
)
877 /* avoid sending empty RESTACK packet */
887 /* A useful M_RESTACK packet must contain at least two windows. */
890 for (t2
= t
, num
= 1 ; t2
!= s2
&& t
!= &Scr
.FvwmRoot
;
891 t2
= t2
->stack_next
, num
++)
893 length
= FvwmPacketHeaderSize
+ 3*num
;
894 body
= (unsigned long *) safemalloc (length
*sizeof(unsigned long));
897 *(bp
++) = START_FLAG
;
900 *(bp
++) = lastTimestamp
;
901 for (t2
= t
; num
!= 0; num
--, t2
= t2
->stack_next
)
905 *(bp
++) = (unsigned long)t2
;
907 for (i
= 0; i
< npipes
; i
++)
908 PositiveWrite(i
, body
, length
*sizeof(unsigned long));
910 verify_stack_ring_consistency();
915 void BroadcastRestackAllWindows(void)
917 BroadcastRestack(Scr
.FvwmRoot
.stack_next
, Scr
.FvwmRoot
.stack_prev
);
921 /* send RESTACK packets for t, t->stack_prev and t->stack_next */
922 void BroadcastRestackThisWindow(FvwmWindow
*t
)
924 BroadcastRestack(t
->stack_prev
, t
->stack_next
);
928 /* ----------------------------- layer code -------------------------------- */
930 /* returns 0 if s and t are on the same layer, <1 if t is on a lower layer and
931 * >1 if t is on a higher layer. */
932 int compare_window_layers(FvwmWindow
*t
, FvwmWindow
*s
)
934 return t
->layer
- s
->layer
;
937 void set_default_layer(FvwmWindow
*t
, int layer
)
939 t
->default_layer
= layer
;
943 void set_layer(FvwmWindow
*t
, int layer
)
949 int get_layer(FvwmWindow
*t
)
954 void new_layer (FvwmWindow
*tmp_win
, int layer
)
956 FvwmWindow
*t2
, *next
;
958 if (layer
< tmp_win
->layer
)
960 tmp_win
->layer
= layer
;
961 /* temporary fix; new transient handling code assumes the layers are
962 * properly arranged when RaiseOrLowerWindow() is called. */
963 ResyncFvwmStackRing();
964 /* domivogt (9-Sep-1999): this was RaiseWindow before. The intent may
965 * have been good (put the window on top of the new lower layer), but it
966 * doesn't work with applications like the gnome panel that use the layer
967 * hint as a poor man's raise/lower, i.e. if panel is on the top level
968 * and requests to be lowered to the normal level it stays on top of all
969 * normal windows. This is not what was intended by lowering. */
970 LowerWindow(tmp_win
);
972 else if (layer
> tmp_win
->layer
)
974 if (DO_RAISE_TRANSIENT(tmp_win
))
976 /* this could be done much more efficiently */
977 for (t2
= Scr
.FvwmRoot
.stack_next
; t2
!= &Scr
.FvwmRoot
; t2
= next
)
979 next
= t2
->stack_next
;
980 if ((IS_TRANSIENT(t2
)) &&
981 (t2
->transientfor
== tmp_win
->w
) &&
983 (t2
->layer
>= tmp_win
->layer
) &&
991 tmp_win
->layer
= layer
;
992 /* see comment above */
993 ResyncFvwmStackRing();
994 /* see comment above */
995 RaiseWindow(tmp_win
);
998 GNOME_SetLayer (tmp_win
);
1001 /* ----------------------------- common functions -------------------------- */
1004 /* RBW - 11/13/1998 - 2 new fields to init - stacking order chain. */
1005 void init_stack_and_layers(void)
1007 Scr
.BottomLayer
= DEFAULT_BOTTOM_LAYER
;
1008 Scr
.DefaultLayer
= DEFAULT_DEFAULT_LAYER
;
1009 Scr
.TopLayer
= DEFAULT_TOP_LAYER
;
1010 Scr
.FvwmRoot
.stack_next
= &Scr
.FvwmRoot
;
1011 Scr
.FvwmRoot
.stack_prev
= &Scr
.FvwmRoot
;
1012 set_layer(&Scr
.FvwmRoot
, DEFAULT_ROOT_WINDOW_LAYER
);
1016 Bool
is_on_top_of_layer(FvwmWindow
*fw
)
1021 for (t
= fw
->stack_prev
; t
!= &Scr
.FvwmRoot
; t
= t
->stack_prev
)
1023 if (t
->layer
> fw
->layer
)
1029 if (!IS_TRANSIENT(t
) || t
->transientfor
!= fw
->w
||
1030 !DO_RAISE_TRANSIENT(fw
))
1041 /* ----------------------------- built in functions ------------------------ */
1043 void raise_function(F_CMD_ARGS
)
1045 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
, CRS_SELECT
,ButtonRelease
))
1048 RaiseWindow(tmp_win
);
1051 void lower_function(F_CMD_ARGS
)
1053 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
, CRS_SELECT
, ButtonRelease
))
1056 LowerWindow(tmp_win
);
1059 void raiselower_func(F_CMD_ARGS
)
1063 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
, CRS_SELECT
,ButtonRelease
))
1066 ontop
= is_on_top_of_layer(tmp_win
);
1069 LowerWindow(tmp_win
);
1071 RaiseWindow(tmp_win
);
1074 void change_layer(F_CMD_ARGS
)
1076 int n
, layer
, val
[2];
1079 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
, CRS_SELECT
,ButtonRelease
))
1085 token
= PeekToken(action
, NULL
);
1086 if (StrEquals("default", token
))
1088 layer
= tmp_win
->default_layer
;
1092 n
= GetIntegerArguments(action
, NULL
, val
, 2);
1094 layer
= tmp_win
->layer
;
1096 ((n
== 2) && (val
[0] != 0)))
1100 else if ((n
== 2) && (val
[1] >= 0))
1106 layer
= tmp_win
->default_layer
;
1113 new_layer(tmp_win
, layer
);
1115 verify_stack_ring_consistency();
1118 void SetDefaultLayers(F_CMD_ARGS
)
1125 bot
= PeekToken(action
, &action
);
1131 fvwm_msg(ERR
,"DefaultLayers", "Layer must be non-negative." );
1135 Scr
.BottomLayer
= i
;
1139 def
= PeekToken(action
, &action
);
1145 fvwm_msg(ERR
,"DefaultLayers", "Layer must be non-negative." );
1149 Scr
.DefaultLayer
= i
;
1153 top
= PeekToken(action
, &action
);
1159 fvwm_msg(ERR
,"DefaultLayers", "Layer must be non-negative." );
1167 verify_stack_ring_consistency();