close_delete_destroy upgrade
[fvwm.git] / fvwm / stack.c
bloba8805def770d669e5a99bcc64ec948ab77ce71d2
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
16 #include "config.h"
18 #include <stdio.h>
19 #include <sys/time.h>
20 #include <signal.h>
21 #include <stdarg.h>
23 #include "libs/fvwmlib.h"
24 #include "fvwm.h"
25 #include "externs.h"
26 #include "cursor.h"
27 #include "functions.h"
28 #include "bindings.h"
29 #include "misc.h"
30 #include "screen.h"
31 #include "defaults.h"
32 #include "module_interface.h"
33 #include "stack.h"
34 #include "borders.h"
35 #include "virtual.h"
36 #include "gnome.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)
49 FvwmWindow *t1;
51 XBell(dpy, 0);
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);
59 return;
62 /* debugging function */
63 static void verify_stack_ring_consistency(void)
65 Window root, parent, *children;
66 unsigned int nchildren, i;
67 FvwmWindow *t1, *t2;
68 int last_layer;
69 int last_index;
71 XSync(dpy, 0);
72 t2 = Scr.FvwmRoot.stack_next;
73 if (!t2)
74 return;
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)
81 fprintf(
82 stderr,
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);
86 dump_stack_ring();
87 return;
89 last_layer = t1->layer;
91 MyXGrabServer(dpy);
92 if (!XQueryTree(dpy, Scr.Root, &root, &parent, &children, &nchildren))
94 MyXUngrabServer(dpy);
95 return;
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++)
104 if (i == nchildren)
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)
111 fprintf(
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);
114 dump_stack_ring();
115 fprintf(stderr,"dumping X stacking order:\n");
116 for (i = nchildren; i-- > 0; )
118 for (t1 = Scr.FvwmRoot.stack_next; t1 != &Scr.FvwmRoot;
119 t1 = t1->stack_next)
121 /* only dump frame windows */
122 if (t1->frame == children[i])
124 fprintf(stderr," f=0x%08x\n", (int)children[i]);
125 break;
129 MyXUngrabServer (dpy);
130 XFree (children);
131 return;
133 last_index = i;
135 MyXUngrabServer(dpy);
136 XFree(children);
138 return;
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;
146 return;
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;
156 return;
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
175 * on this. */
176 return False;
177 /* RaiseWindow/LowerWindow will put the window in its layer */
178 RaiseOrLowerWindow(t, do_lower, False, True);
179 return 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,
190 * and restack.
191 ********************************************************************/
192 static void raise_over_unmanaged(FvwmWindow *t)
194 Window junk;
195 Window *tops;
196 int i;
197 unsigned int num;
198 Bool found = False;
199 Window OR_Above = 0;
200 Window topwin;
201 Window *wins;
202 int count = 0;
203 FvwmWindow *t2 = NULL;
204 FvwmWindow *junkwin = NULL;
205 unsigned int flags;
206 XWindowChanges changes;
207 XWindowAttributes wa;
209 if (!XQueryTree(dpy, Scr.Root, &junk, &junk, &tops, &num))
210 return;
211 topwin = 0;
212 topwin = Scr.FvwmRoot.stack_next->frame;
213 found = False;
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) {
221 found = True;
223 if (found) {
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. */
231 if (i > 0) {
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];
238 OR_Above = tops[i];
242 else {
243 DBUG("raise_over_unmanaged",
244 "Error - XGetWindowAttributes failed for window %8.8lx!\n",
245 tops[i]);
248 } /* end if found */
249 } /* end for */
251 /********************************************************************
252 * Count the windows we need to restack, then build the stack list.
253 ********************************************************************/
254 if (OR_Above)
256 i = 0;
257 count = 0;
258 found = False;
259 for (t2 = t; (t2 != &Scr.FvwmRoot && ! found); t2 = t2->stack_prev) {
260 count++;
261 if (IS_ICONIFIED(t2) && ! IS_ICON_SUPPRESSED(t2)) {
262 if (t2->icon_w != None) {
263 count++;
265 if (t2->icon_pixmap_w != None) {
266 count++;
269 if (t2->frame == topwin) {
270 found = True;
274 i = 0;
275 found = False;
276 if (count > 0) {
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) {
290 found = True;
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);
301 free (wins);
303 } /* end - we found an OR above our target */
306 XFree (tops);
307 return;
311 static Bool must_move_transients(
312 FvwmWindow *t, Bool do_lower, Bool *found_transient)
314 *found_transient = False;
316 /* raise */
317 if ((!do_lower && DO_RAISE_TRANSIENT(t)) ||
318 (do_lower && DO_LOWER_TRANSIENT(t)))
320 Bool scanning_above_window = True;
321 FvwmWindow *q;
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. */
328 continue;
330 if (t->layer > q->layer)
332 /* We are at the end of this layer. Stop scanning windows. */
333 break;
335 else if (t == q)
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 )
348 return True;
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
355 * be raised. */
356 /* lower: There is a transient above some other window, so we have to
357 * lower. */
358 return True;
362 return False;
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;
369 unsigned int flags;
370 int i, count;
371 XWindowChanges changes;
372 Window *wins;
373 Bool do_move_transients;
374 Bool found_transient;
375 Bool no_movement;
376 int test_layer;
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
392 * Transients.
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;
404 t2 = t2->stack_next)
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);
412 return;
419 if (is_new_window)
421 no_movement = False;
422 do_move_transients = False;
424 else
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
435 * on do_lower.
437 no_movement = found_transient && !do_move_transients;
440 if (!no_movement)
442 /* detach t, so it doesn't make trouble in the loops */
443 remove_window_from_stack_ring(t);
445 count = 1;
446 if (IS_ICONIFIED(t) && !IS_ICON_SUPPRESSED(t))
448 count += 2;
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 */
463 count++;
464 if (IS_ICONIFIED(t2) && !IS_ICON_SUPPRESSED(t2))
466 count += 2;
469 /* unplug it */
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;
486 if (do_lower)
488 test_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)
495 break;
498 r = s->stack_prev;
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();
522 return;
524 else
526 wins = (Window*) safemalloc (count * sizeof (Window));
527 i = 0;
528 for (t2 = r->stack_next; t2 != s; t2 = t2->stack_next)
530 if (i >= count)
532 fvwm_msg (ERR, "RaiseOrLowerWindow", "more transients than expected");
533 break;
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;
551 else
553 changes.stack_mode = Below;
554 flags = CWStackMode;
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
565 * anything. */
566 BroadcastRestackAllWindows();
568 free (wins);
572 if (!do_lower)
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
587 * or Windows NT.
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.
596 #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)
604 found = True;
605 if (found)
606 XRaiseWindow (dpy, tops[i]);
608 XFree (tops);
609 #endif
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. */
618 raisePanFrames();
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). */
622 if (!do_lower)
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();
636 return;
639 void LowerWindow(FvwmWindow *t)
641 RaiseOrLowerWindow(t, True, True, False);
642 verify_stack_ring_consistency();
643 return;
647 static Bool
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));
655 static Bool
656 overlap_box (FvwmWindow *r, int x, int y, int w, int h)
658 if (IS_ICONIFIED(r))
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)) ||
663 ((r->icon_w) &&
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));
668 else
670 return intersect (x, y, w, h, r->frame_g.x, r->frame_g.y,
671 r->frame_g.width, r->frame_g.height);
675 static Bool
676 overlap (FvwmWindow *r, FvwmWindow *s)
678 if (r->Desk != s->Desk)
680 return 0;
683 if (IS_ICONIFIED(r))
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)) ||
688 ((r->icon_w) &&
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));
692 else
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 */
700 Bool
701 HandleUnusualStackmodes(unsigned int stack_mode, FvwmWindow *r, Window rw,
702 FvwmWindow *s, Window sw)
704 Bool restack = 0;
705 FvwmWindow *t;
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 */
713 return 0;
716 switch (stack_mode)
718 case TopIf:
719 for (t = r->stack_prev; (t != &Scr.FvwmRoot) && !restack;
720 t = t->stack_prev)
722 restack = (((s == NULL) || (s == t)) && overlap (t, r));
724 if (restack)
726 RaiseWindow (r);
728 break;
729 case BottomIf:
730 for (t = r->stack_next; (t != &Scr.FvwmRoot) && !restack;
731 t = t->stack_next)
733 restack = (((s == NULL) || (s == t)) && overlap (t, r));
735 if (restack)
737 LowerWindow (r);
739 break;
740 case Opposite:
741 restack = (HandleUnusualStackmodes (TopIf, r, rw, s, sw) ||
742 HandleUnusualStackmodes (BottomIf, r, rw, s, sw));
743 break;
745 /* DBUG("HandleUnusualStackmodes", "\t---> %d\n", restack);*/
746 verify_stack_ring_consistency();
747 return restack;
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;
769 FvwmWindow *t1, *t2;
771 MyXGrabServer (dpy);
773 if (!XQueryTree (dpy, Scr.Root, &root, &parent, &children, &nchildren))
775 MyXUngrabServer (dpy);
776 return;
779 t2 = &Scr.FvwmRoot;
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])
788 break;
791 else
793 if (t1->frame == children[i])
795 break;
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);
809 t2 = t1;
813 MyXUngrabServer (dpy);
815 XFree (children);
818 /* same as above but synchronizes the stacking order in X from the stack ring.
820 static void ResyncXStackingOrder(void)
822 Window *wins;
823 FvwmWindow *t;
824 int count;
825 int i;
827 for (count = 0, t = Scr.FvwmRoot.next; t != None; count++, t = t->next)
829 if (count > 0)
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);
845 free(wins);
846 /* send out M_RESTACK for all windows, to make sure we don't forget
847 * anything. */
848 BroadcastRestackAllWindows();
853 /* send RESTACK packets for all windows between s1 and s2 */
854 static void BroadcastRestack (FvwmWindow *s1, FvwmWindow *s2)
856 FvwmWindow *t, *t2;
857 int num, i;
858 unsigned long *body, *bp, length;
859 extern Time lastTimestamp;
861 if (s2 == &Scr.FvwmRoot)
863 s2 = s2->stack_prev;
864 if (s2 == &Scr.FvwmRoot)
865 return;
867 if (s1 == &Scr.FvwmRoot)
869 t = s1->stack_next;
870 if (t == &Scr.FvwmRoot)
871 return;
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 */
878 return;
881 else
883 t = s1;
885 if (s1 == s2)
887 /* A useful M_RESTACK packet must contain at least two windows. */
888 return;
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));
896 bp = body;
897 *(bp++) = START_FLAG;
898 *(bp++) = M_RESTACK;
899 *(bp++) = length;
900 *(bp++) = lastTimestamp;
901 for (t2 = t; num != 0; num--, t2 = t2->stack_next)
903 *(bp++) = t2->w;
904 *(bp++) = t2->frame;
905 *(bp++) = (unsigned long)t2;
907 for (i = 0; i < npipes; i++)
908 PositiveWrite(i, body, length*sizeof(unsigned long));
909 free(body);
910 verify_stack_ring_consistency();
912 return;
915 void BroadcastRestackAllWindows(void)
917 BroadcastRestack(Scr.FvwmRoot.stack_next, Scr.FvwmRoot.stack_prev);
918 return;
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);
925 return;
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;
940 return;
943 void set_layer(FvwmWindow *t, int layer)
945 t->layer = layer;
946 return;
949 int get_layer(FvwmWindow *t)
951 return t->layer;
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) &&
982 (t2 != tmp_win) &&
983 (t2->layer >= tmp_win->layer) &&
984 (t2->layer < layer))
986 t2->layer = layer;
987 LowerWindow(t2);
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);
1013 return;
1016 Bool is_on_top_of_layer(FvwmWindow *fw)
1018 FvwmWindow *t;
1019 Bool ontop = True;
1021 for (t = fw->stack_prev; t != &Scr.FvwmRoot; t = t->stack_prev)
1023 if (t->layer > fw->layer)
1025 break;
1027 if (overlap(fw, t))
1029 if (!IS_TRANSIENT(t) || t->transientfor != fw->w ||
1030 !DO_RAISE_TRANSIENT(fw))
1032 ontop = False;
1033 break;
1038 return ontop;
1041 /* ----------------------------- built in functions ------------------------ */
1043 void raise_function(F_CMD_ARGS)
1045 if (DeferExecution(eventp,&w,&tmp_win,&context, CRS_SELECT,ButtonRelease))
1046 return;
1048 RaiseWindow(tmp_win);
1051 void lower_function(F_CMD_ARGS)
1053 if (DeferExecution(eventp,&w,&tmp_win,&context, CRS_SELECT, ButtonRelease))
1054 return;
1056 LowerWindow(tmp_win);
1059 void raiselower_func(F_CMD_ARGS)
1061 Bool ontop;
1063 if (DeferExecution(eventp,&w,&tmp_win,&context, CRS_SELECT,ButtonRelease))
1064 return;
1066 ontop = is_on_top_of_layer(tmp_win);
1068 if (ontop)
1069 LowerWindow(tmp_win);
1070 else
1071 RaiseWindow(tmp_win);
1074 void change_layer(F_CMD_ARGS)
1076 int n, layer, val[2];
1077 char *token;
1079 if (DeferExecution(eventp,&w,&tmp_win,&context, CRS_SELECT,ButtonRelease))
1080 return;
1082 if(tmp_win == NULL)
1083 return;
1085 token = PeekToken(action, NULL);
1086 if (StrEquals("default", token))
1088 layer = tmp_win->default_layer;
1090 else
1092 n = GetIntegerArguments(action, NULL, val, 2);
1094 layer = tmp_win->layer;
1095 if ((n == 1) ||
1096 ((n == 2) && (val[0] != 0)))
1098 layer += val[0];
1100 else if ((n == 2) && (val[1] >= 0))
1102 layer = val[1];
1104 else
1106 layer = tmp_win->default_layer;
1109 if (layer < 0)
1111 layer = 0;
1113 new_layer(tmp_win, layer);
1115 verify_stack_ring_consistency();
1118 void SetDefaultLayers(F_CMD_ARGS)
1120 char *bot = NULL;
1121 char *def = NULL;
1122 char *top = NULL;
1123 int i;
1125 bot = PeekToken(action, &action);
1126 if (bot)
1128 i = atoi (bot);
1129 if (i < 0)
1131 fvwm_msg(ERR,"DefaultLayers", "Layer must be non-negative." );
1133 else
1135 Scr.BottomLayer = i;
1139 def = PeekToken(action, &action);
1140 if (def)
1142 i = atoi (def);
1143 if (i < 0)
1145 fvwm_msg(ERR,"DefaultLayers", "Layer must be non-negative." );
1147 else
1149 Scr.DefaultLayer = i;
1153 top = PeekToken(action, &action);
1154 if (top)
1156 i = atoi (top);
1157 if (i < 0)
1159 fvwm_msg(ERR,"DefaultLayers", "Layer must be non-negative." );
1161 else
1163 Scr.TopLayer = i;
1167 verify_stack_ring_consistency();