2 * Window Maker window manager
4 * Copyright (c) 1997, 1998 Alfredo K. Kojima
5 * Copyright (c) 1998 Dan Pascu
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
29 #include <X11/Xutil.h>
31 #include "WindowMaker.h"
36 #include "properties.h"
42 /*** Global Variables ***/
43 extern XContext wStackContext
;
45 extern WPreferences wPreferences
;
49 *----------------------------------------------------------------------
51 * Remakes the stacking_list for the screen, getting the real
52 * stacking order from the server and reordering windows that are not
53 * in the correct stacking.
56 * The stacking order list and the actual window stacking
57 * may be changed (corrected)
59 *----------------------------------------------------------------------
62 RemakeStackList(WScreen
*scr
)
65 unsigned int nwindows
;
68 WCoreWindow
*onbotw
[MAX_WINDOW_LEVELS
];
72 if (!XQueryTree(dpy
, scr
->root_win
, &junkr
, &junkp
, &windows
, &nwindows
)) {
73 wwarning(_("could not get window list!!"));
76 for (i
=0; i
<MAX_WINDOW_LEVELS
; i
++) {
77 scr
->stacking_list
[i
] = NULL
;
79 /* scr->window_level_count[i] = 0;*/
81 /* verify list integrity */
83 for (i
=0; i
<nwindows
; i
++) {
84 if (XFindContext(dpy
, windows
[i
], wStackContext
, (XPointer
*)&frame
)
90 level
= frame
->stacking
->window_level
;
92 onbotw
[level
]->stacking
->above
= frame
;
93 frame
->stacking
->under
= onbotw
[level
];
94 frame
->stacking
->above
= NULL
;
95 onbotw
[level
] = frame
;
96 /* scr->window_level_count[level]++;*/
100 if (c
!=scr
->window_count
) {
101 puts("Found different number of windows than in window lists!!!");
104 scr
->window_count
= c
;
106 /* now, just concatenate the lists */
107 for (i
=0; i
<MAX_WINDOW_LEVELS
; i
++) {
108 scr
->stacking_list
[i
] = onbotw
[i
];
110 onbotw
[i
]->stacking
->above
= NULL
;
117 *----------------------------------------------------------------------
119 * Reorders the actual window stacking, so that it has the stacking
120 * order in the internal window stacking lists. It does the opposite
121 * of RemakeStackList().
124 * Windows may be restacked.
125 *----------------------------------------------------------------------
128 CommitStacking(WScreen
*scr
)
135 nwindows
= scr
->window_count
;
136 windows
= wmalloc(sizeof(Window
)*nwindows
);
138 for (level
=MAX_WINDOW_LEVELS
-1; level
>=0; level
--) {
139 tmp
= scr
->stacking_list
[level
];
143 puts("Internal inconsistency! window_count is incorrect!!!");
144 printf("window_count says %i windows\n", nwindows
);
149 windows
[i
++] = tmp
->window
;
150 tmp
= tmp
->stacking
->under
;
153 XRestackWindows(dpy
, windows
, i
);
157 wKWMBroadcastStacking(scr
);
162 *----------------------------------------------------------------------
164 * Reestacks windows so that "frame" is under "under".
170 * Changes the stacking order of frame.
171 *----------------------------------------------------------------------
174 moveFrameToUnder(WCoreWindow
*under
, WCoreWindow
*frame
)
178 wins
[0] = under
->window
;
179 wins
[1] = frame
->window
;
180 XRestackWindows(dpy
, wins
, 2);
183 wKWMBroadcastStacking(under
->screen_ptr
);
188 *----------------------------------------------------------------------
190 * Raises a frame taking the window level and the on_top flag
197 * Window stacking order and window list is changed.
199 *----------------------------------------------------------------------
202 wRaiseFrame(WCoreWindow
*frame
)
204 WCoreWindow
*wlist
= frame
, *wlist_above
;
205 int level
= frame
->stacking
->window_level
;
209 if (frame
->stacking
->above
== NULL
) {
213 /* insert on top of other windows */
216 if (wlist
== (wlist_above
= wlist
->stacking
->above
)) {
217 wwarning("You just found a bug in wmaker. Please try to figure what type of raising/lowering operations you did with which applications and report. Please give complete information about how to reproduce it.");
225 wlist
= wlist
->stacking
->above
;
227 /* window is inserted before the point found */
229 /* top most window (last on the list) */
230 if (frame
->stacking
->under
)
231 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
232 if (frame
->stacking
->above
)
233 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
235 frame
->stacking
->above
= NULL
;
236 frame
->stacking
->under
= frame
->screen_ptr
->stacking_list
[level
];
237 frame
->screen_ptr
->stacking_list
[level
]->stacking
->above
=frame
;
238 frame
->screen_ptr
->stacking_list
[level
] = frame
;
239 } else if (frame
!=wlist
) {
240 if (frame
->stacking
->under
)
241 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
242 if (frame
->stacking
->above
)
243 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
245 frame
->stacking
->above
= wlist
;
246 frame
->stacking
->under
= wlist
->stacking
->under
;
247 if (wlist
->stacking
->under
)
248 wlist
->stacking
->under
->stacking
->above
= frame
;
249 wlist
->stacking
->under
= frame
;
252 if (wPreferences
.on_top_transients
)
255 /* raise transients under us from bottom to top
256 * so that the order is kept */
258 wlist
= frame
->stacking
->under
;
259 while (wlist
&& wlist
->stacking
->under
)
260 wlist
= wlist
->stacking
->under
;
261 while (wlist
&& wlist
!=frame
) {
262 if (wlist
->stacking
->child_of
== frame
) {
266 wlist
= wlist
->stacking
->above
;
270 wlist
= frame
->stacking
->under
;
272 if (wlist
->stacking
->child_of
== frame
) {
273 /* transient for us */
275 goto again
; /* need this or we'll get in a loop */
277 wlist
= wlist
->stacking
->under
;
281 /* try to optimize things a little */
282 if (frame
->stacking
->above
== NULL
) {
283 WCoreWindow
*above
=NULL
;
285 for (i
=level
+1; i
<MAX_WINDOW_LEVELS
; i
++) {
286 if (frame
->screen_ptr
->stacking_list
[i
]!=NULL
) {
288 above
= frame
->screen_ptr
->stacking_list
[i
];
289 while (above
->stacking
->under
)
290 above
= above
->stacking
->under
;
295 XRaiseWindow(dpy
, frame
->window
);
297 moveFrameToUnder(above
, frame
);
300 moveFrameToUnder(frame
->stacking
->above
, frame
);
304 WWindow
*wwin
= wWindowFor(frame
->window
);
307 wKWMSendEventMessage(wwin
, WKWMRaiseWindow
);
314 wRaiseLowerFrame(WCoreWindow
*frame
)
316 if (!frame
->stacking
->above
317 ||(frame
->stacking
->window_level
318 !=frame
->stacking
->above
->stacking
->window_level
)) {
322 WCoreWindow
*scan
= frame
->stacking
->above
;
323 WWindow
*frame_wwin
= (WWindow
*) frame
->descriptor
.parent
;
327 if (scan
->descriptor
.parent_type
== WCLASS_WINDOW
) {
328 WWindow
*scan_wwin
= (WWindow
*) scan
->descriptor
.parent
;
330 if (wWindowObscuresWindow(scan_wwin
, frame_wwin
)
331 && scan_wwin
->flags
.mapped
) {
335 scan
= scan
->stacking
->above
;
348 wLowerFrame(WCoreWindow
*frame
)
350 WScreen
*scr
=frame
->screen_ptr
;
351 WCoreWindow
*prev
, *wlist
=frame
;
352 int level
= frame
->stacking
->window_level
;
355 /* already in bottom */
356 if (wlist
->stacking
->under
==NULL
) {
360 if (wPreferences
.on_top_transients
&&
361 wlist
->stacking
->under
==wlist
->stacking
->child_of
) {
365 if (wlist
->stacking
->under
==wlist
->stacking
->child_of
) {
370 /* remove from the list */
371 if (scr
->stacking_list
[level
] == frame
) {
372 /* it was the top window */
373 scr
->stacking_list
[level
] = frame
->stacking
->under
;
374 scr
->stacking_list
[level
]->stacking
->above
= NULL
;
376 if (frame
->stacking
->under
)
377 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
378 if (frame
->stacking
->above
)
379 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
381 wlist
= scr
->stacking_list
[level
];
382 /* look for place to put this window */
384 if (wPreferences
.on_top_transients
)
387 WCoreWindow
*owner
= frame
->stacking
->child_of
;
389 if (owner
!= wlist
) {
390 while (wlist
->stacking
->under
) {
391 /* if this is a transient, it should not be placed under
393 if (owner
== wlist
->stacking
->under
)
395 wlist
= wlist
->stacking
->under
;
401 while (wlist
->stacking
->under
) {
402 wlist
= wlist
->stacking
->under
;
406 /* insert under the place found */
407 frame
->stacking
->above
= wlist
;
408 frame
->stacking
->under
= wlist
->stacking
->under
;
409 if (wlist
->stacking
->under
)
410 wlist
->stacking
->under
->stacking
->above
= frame
;
411 wlist
->stacking
->under
= frame
;
413 /* try to optimize things a little */
414 if (frame
->stacking
->above
== NULL
) {
415 WCoreWindow
*above
= NULL
;
416 for (i
=level
-1; i
>=0; i
--) {
417 if (scr
->stacking_list
[i
]!=NULL
) {
419 above
= scr
->stacking_list
[i
];
420 while (above
->stacking
->under
)
421 above
= above
->stacking
->under
;
426 XLowerWindow(dpy
, frame
->window
);
428 moveFrameToUnder(above
, frame
);
431 moveFrameToUnder(frame
->stacking
->above
, frame
);
435 WWindow
*wwin
= wWindowFor(frame
->window
);
438 wKWMSendEventMessage(wwin
, WKWMLowerWindow
);
445 *----------------------------------------------------------------------
447 * Inserts the frame in the top of the stacking list. The
448 * stacking precedence is obeyed.
454 * The frame is added to it's screen's window list.
455 *----------------------------------------------------------------------
458 AddToStackList(WCoreWindow
*frame
)
460 WCoreWindow
*prev
, *tmpw
, *wlist
;
461 int index
= frame
->stacking
->window_level
;
463 frame
->screen_ptr
->window_count
++;
464 /* frame->screen_ptr->window_level_count[index]++;*/
465 XSaveContext(dpy
, frame
->window
, wStackContext
, (XPointer
)frame
);
466 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
468 frame
->screen_ptr
->stacking_list
[index
] = frame
;
469 frame
->stacking
->above
= NULL
;
470 frame
->stacking
->under
= NULL
;
471 CommitStacking(frame
->screen_ptr
);
475 /* check if this is a transient owner */
477 if (wPreferences
.on_top_transients
)
480 WCoreWindow
*trans
= NULL
;
482 wlist
= frame
->screen_ptr
->stacking_list
[index
];
484 if (wlist
->stacking
->child_of
== frame
)
486 wlist
= wlist
->stacking
->under
;
489 frame
->stacking
->above
= trans
;
491 frame
->stacking
->under
= trans
->stacking
->under
;
492 if (trans
->stacking
->under
) {
493 trans
->stacking
->under
->stacking
->above
= frame
;
495 trans
->stacking
->under
= frame
;
497 frame
->stacking
->under
= tmpw
;
498 tmpw
->stacking
->above
= frame
;
499 frame
->screen_ptr
->stacking_list
[index
] = frame
;
504 /* put on top of the stacking list */
505 frame
->stacking
->above
= NULL
;
506 frame
->stacking
->under
= tmpw
;
507 tmpw
->stacking
->above
= frame
;
508 frame
->screen_ptr
->stacking_list
[index
] = frame
;
511 CommitStacking(frame
->screen_ptr
);
516 *----------------------------------------------------------------------
517 * MoveInStackListAbove--
518 * Moves the frame above "next".
524 * Stacking order may be changed.
525 * Window level for frame may be changed.
526 *----------------------------------------------------------------------
529 MoveInStackListAbove(WCoreWindow
*next
, WCoreWindow
*frame
)
534 if (!next
|| frame
->stacking
->under
== next
)
537 if (frame
->stacking
->window_level
!= next
->stacking
->window_level
)
538 ChangeStackingLevel(frame
, next
->stacking
->window_level
);
540 index
= frame
->stacking
->window_level
;
542 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
544 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
545 if (frame
->stacking
->under
)
546 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
547 if (frame
->stacking
->above
)
548 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
549 if (next
->stacking
->above
)
550 next
->stacking
->above
->stacking
->under
= frame
;
551 frame
->stacking
->under
= next
;
552 frame
->stacking
->above
= next
->stacking
->above
;
553 next
->stacking
->above
= frame
;
555 frame
->screen_ptr
->stacking_list
[index
] = frame
;
557 /* try to optimize things a little */
558 if (frame
->stacking
->above
== NULL
) {
559 WCoreWindow
*above
=NULL
;
562 for (i
=index
+1; i
<MAX_WINDOW_LEVELS
; i
++) {
563 if (frame
->screen_ptr
->stacking_list
[i
]!=NULL
) {
565 above
= frame
->screen_ptr
->stacking_list
[i
];
566 while (above
->stacking
->under
)
567 above
= above
->stacking
->under
;
572 XRaiseWindow(dpy
, frame
->window
);
574 moveFrameToUnder(above
, frame
);
577 moveFrameToUnder(frame
->stacking
->above
, frame
);
583 *----------------------------------------------------------------------
584 * MoveInStackListUnder--
585 * Moves the frame to under "prev".
591 * Stacking order may be changed.
592 * Window level for frame may be changed.
593 *----------------------------------------------------------------------
596 MoveInStackListUnder(WCoreWindow
*prev
, WCoreWindow
*frame
)
601 if (!prev
|| frame
->stacking
->above
== prev
)
604 if (frame
->stacking
->window_level
!= prev
->stacking
->window_level
)
605 ChangeStackingLevel(frame
, prev
->stacking
->window_level
);
607 index
= frame
->stacking
->window_level
;
609 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
611 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
612 if (frame
->stacking
->under
)
613 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
614 if (frame
->stacking
->above
)
615 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
616 if (prev
->stacking
->under
)
617 prev
->stacking
->under
->stacking
->above
= frame
;
618 frame
->stacking
->above
= prev
;
619 frame
->stacking
->under
= prev
->stacking
->under
;
620 prev
->stacking
->under
= frame
;
621 moveFrameToUnder(prev
, frame
);
626 RemoveFromStackList(WCoreWindow
*frame
)
628 int index
= frame
->stacking
->window_level
;
630 if (XDeleteContext(dpy
, frame
->window
, wStackContext
)==XCNOENT
) {
632 wwarning("RemoveFromStackingList(): window not in list ");
636 /* remove from the window stack list */
637 if (frame
->stacking
->under
)
638 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
639 if (frame
->stacking
->above
)
640 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
641 else /* this was the first window on the list */
642 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
644 frame
->screen_ptr
->window_count
--;
645 /* frame->screen_ptr->window_level_count[index]--;*/
650 ChangeStackingLevel(WCoreWindow
*frame
, int new_level
)
653 if (frame
->stacking
->window_level
== new_level
)
655 old_level
= frame
->stacking
->window_level
;
657 RemoveFromStackList(frame
);
658 frame
->stacking
->window_level
= new_level
;
659 AddToStackList(frame
);
660 if (old_level
> new_level
) {