2 * Window Maker window manager
4 * Copyright (c) 1997, 1998 Alfredo K. Kojima
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 #include <X11/Xutil.h>
30 #include "WindowMaker.h"
35 #include "properties.h"
38 /*** Global Variables ***/
39 extern XContext wStackContext
;
41 extern WPreferences wPreferences
;
45 *----------------------------------------------------------------------
47 * Remakes the stacking_list for the screen, getting the real
48 * stacking order from the server and reordering windows that are not
49 * in the correct stacking.
52 * The stacking order list and the actual window stacking
53 * may be changed (corrected)
55 *----------------------------------------------------------------------
58 RemakeStackList(WScreen
*scr
)
61 unsigned int nwindows
;
64 WCoreWindow
*onbotw
[MAX_WINDOW_LEVELS
];
68 if (!XQueryTree(dpy
, scr
->root_win
, &junkr
, &junkp
, &windows
, &nwindows
)) {
69 wwarning(_("could not get window list!!"));
72 for (i
=0; i
<MAX_WINDOW_LEVELS
; i
++) {
73 scr
->stacking_list
[i
] = NULL
;
75 /* scr->window_level_count[i] = 0;*/
77 /* verify list integrity */
79 for (i
=0; i
<nwindows
; i
++) {
80 if (XFindContext(dpy
, windows
[i
], wStackContext
, (XPointer
*)&frame
)
86 level
= frame
->stacking
->window_level
;
88 onbotw
[level
]->stacking
->above
= frame
;
89 frame
->stacking
->under
= onbotw
[level
];
90 frame
->stacking
->above
= NULL
;
91 onbotw
[level
] = frame
;
92 /* scr->window_level_count[level]++;*/
96 if (c
!=scr
->window_count
) {
97 puts("Found different number of windows than in window lists!!!");
100 scr
->window_count
= c
;
102 /* now, just concatenate the lists */
103 for (i
=0; i
<MAX_WINDOW_LEVELS
; i
++) {
104 scr
->stacking_list
[i
] = onbotw
[i
];
106 onbotw
[i
]->stacking
->above
= NULL
;
113 *----------------------------------------------------------------------
115 * Reorders the actual window stacking, so that it has the stacking
116 * order in the internal window stacking lists. It does the opposite
117 * of RemakeStackList().
120 * Windows may be restacked.
121 *----------------------------------------------------------------------
124 CommitStacking(WScreen
*scr
)
131 nwindows
= scr
->window_count
;
132 windows
= wmalloc(sizeof(Window
)*nwindows
);
134 for (level
=MAX_WINDOW_LEVELS
-1; level
>=0; level
--) {
135 tmp
= scr
->stacking_list
[level
];
139 puts("Internal inconsistency! window_count is incorrect!!!");
140 printf("window_count says %i windows\n", nwindows
);
145 windows
[i
++] = tmp
->window
;
146 tmp
= tmp
->stacking
->under
;
149 XRestackWindows(dpy
, windows
, i
);
154 *----------------------------------------------------------------------
156 * Reestacks windows so that "frame" is under "under".
162 * Changes the stacking order of frame.
163 *----------------------------------------------------------------------
166 moveFrameToUnder(WCoreWindow
*under
, WCoreWindow
*frame
)
170 wins
[0] = under
->window
;
171 wins
[1] = frame
->window
;
172 XRestackWindows(dpy
, wins
, 2);
176 *----------------------------------------------------------------------
178 * Raises a frame taking the window level and the on_top flag
185 * Window stacking order and window list is changed.
187 *----------------------------------------------------------------------
190 wRaiseFrame(WCoreWindow
*frame
)
192 WCoreWindow
*wlist
=frame
;
193 int level
= frame
->stacking
->window_level
;
197 if (frame
->stacking
->above
== NULL
) {
201 /* insert on top of other windows */
203 wlist
= wlist
->stacking
->above
;
205 /* window is inserted before the point found */
207 /* top most window (last on the list) */
208 if (frame
->stacking
->under
)
209 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
210 if (frame
->stacking
->above
)
211 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
213 frame
->stacking
->above
= NULL
;
214 frame
->stacking
->under
= frame
->screen_ptr
->stacking_list
[level
];
215 frame
->screen_ptr
->stacking_list
[level
]->stacking
->above
=frame
;
216 frame
->screen_ptr
->stacking_list
[level
] = frame
;
217 } else if (frame
!=wlist
) {
218 if (frame
->stacking
->under
)
219 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
220 if (frame
->stacking
->above
)
221 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
223 frame
->stacking
->above
= wlist
;
224 frame
->stacking
->under
= wlist
->stacking
->under
;
225 if (wlist
->stacking
->under
)
226 wlist
->stacking
->under
->stacking
->above
= frame
;
227 wlist
->stacking
->under
= frame
;
229 if (wPreferences
.on_top_transients
) {
230 /* raise transients under us from bottom to top
231 * so that the order is kept */
233 wlist
= frame
->stacking
->under
;
234 while (wlist
&& wlist
->stacking
->under
)
235 wlist
= wlist
->stacking
->under
;
236 while (wlist
&& wlist
!=frame
) {
237 if (wlist
->stacking
->child_of
== frame
) {
241 wlist
= wlist
->stacking
->above
;
245 wlist
= frame
->stacking
->under
;
247 if (wlist
->stacking
->child_of
== frame
) {
248 /* transient for us */
250 goto again
; /* need this or we'll get in a loop */
252 wlist
= wlist
->stacking
->under
;
256 /* try to optimize things a little */
257 if (frame
->stacking
->above
== NULL
) {
258 WCoreWindow
*above
=NULL
;
260 for (i
=level
+1; i
<MAX_WINDOW_LEVELS
; i
++) {
261 if (frame
->screen_ptr
->stacking_list
[i
]!=NULL
) {
263 above
= frame
->screen_ptr
->stacking_list
[i
];
264 while (above
->stacking
->under
)
265 above
= above
->stacking
->under
;
270 XRaiseWindow(dpy
, frame
->window
);
272 moveFrameToUnder(above
, frame
);
275 moveFrameToUnder(frame
->stacking
->above
, frame
);
280 wRaiseLowerFrame(WCoreWindow
*frame
)
282 if (!frame
->stacking
->above
283 ||(frame
->stacking
->window_level
284 !=frame
->stacking
->above
->stacking
->window_level
))
292 wLowerFrame(WCoreWindow
*frame
)
294 WScreen
*scr
=frame
->screen_ptr
;
295 WCoreWindow
*prev
, *wlist
=frame
;
296 int level
= frame
->stacking
->window_level
;
299 /* already in bottom */
300 if (wlist
->stacking
->under
==NULL
) {
303 if (wPreferences
.on_top_transients
&&
304 wlist
->stacking
->under
==wlist
->stacking
->child_of
) {
308 /* remove from the list */
309 if (scr
->stacking_list
[level
] == frame
) {
310 /* it was the top window */
311 scr
->stacking_list
[level
] = frame
->stacking
->under
;
312 scr
->stacking_list
[level
]->stacking
->above
= NULL
;
314 if (frame
->stacking
->under
)
315 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
316 if (frame
->stacking
->above
)
317 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
319 wlist
= scr
->stacking_list
[level
];
320 /* look for place to put this window */
321 if (wPreferences
.on_top_transients
) {
322 WCoreWindow
*owner
= frame
->stacking
->child_of
;
324 if (owner
!= wlist
) {
325 while (wlist
->stacking
->under
) {
326 /* if this is a transient, it should not be placed under
328 if (owner
== wlist
->stacking
->under
)
330 wlist
= wlist
->stacking
->under
;
334 while (wlist
->stacking
->under
) {
335 wlist
= wlist
->stacking
->under
;
338 /* insert under the place found */
339 frame
->stacking
->above
= wlist
;
340 frame
->stacking
->under
= wlist
->stacking
->under
;
341 if (wlist
->stacking
->under
)
342 wlist
->stacking
->under
->stacking
->above
= frame
;
343 wlist
->stacking
->under
= frame
;
345 /* try to optimize things a little */
346 if (frame
->stacking
->above
== NULL
) {
347 WCoreWindow
*above
= NULL
;
348 for (i
=level
-1; i
>=0; i
--) {
349 if (scr
->stacking_list
[i
]!=NULL
) {
351 above
= scr
->stacking_list
[i
];
352 while (above
->stacking
->under
)
353 above
= above
->stacking
->under
;
358 XLowerWindow(dpy
, frame
->window
);
360 moveFrameToUnder(above
, frame
);
363 moveFrameToUnder(frame
->stacking
->above
, frame
);
369 *----------------------------------------------------------------------
371 * Inserts the frame in the top of the stacking list. The
372 * stacking precedence is obeyed.
378 * The frame is added to it's screen's window list.
379 *----------------------------------------------------------------------
382 AddToStackList(WCoreWindow
*frame
)
384 WCoreWindow
*prev
, *tmpw
, *wlist
;
385 int index
= frame
->stacking
->window_level
;
387 frame
->screen_ptr
->window_count
++;
388 /* frame->screen_ptr->window_level_count[index]++;*/
389 XSaveContext(dpy
, frame
->window
, wStackContext
, (XPointer
)frame
);
390 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
392 frame
->screen_ptr
->stacking_list
[index
] = frame
;
393 frame
->stacking
->above
= NULL
;
394 frame
->stacking
->under
= NULL
;
395 CommitStacking(frame
->screen_ptr
);
399 /* check if this is a transient owner */
400 if (wPreferences
.on_top_transients
) {
401 WCoreWindow
*trans
= NULL
;
403 wlist
= frame
->screen_ptr
->stacking_list
[index
];
405 if (wlist
->stacking
->child_of
== frame
)
407 wlist
= wlist
->stacking
->under
;
410 frame
->stacking
->above
= trans
;
412 frame
->stacking
->under
= trans
->stacking
->under
;
413 if (trans
->stacking
->under
) {
414 trans
->stacking
->under
->stacking
->above
= frame
;
416 trans
->stacking
->under
= frame
;
418 frame
->stacking
->under
= tmpw
;
419 tmpw
->stacking
->above
= frame
;
420 frame
->screen_ptr
->stacking_list
[index
] = frame
;
423 /* put on top of the stacking list */
424 frame
->stacking
->above
= NULL
;
425 frame
->stacking
->under
= tmpw
;
426 tmpw
->stacking
->above
= frame
;
427 frame
->screen_ptr
->stacking_list
[index
] = frame
;
429 CommitStacking(frame
->screen_ptr
);
434 *----------------------------------------------------------------------
435 * MoveInStackListAbove--
436 * Moves the frame above "next".
442 * Stacking order may be changed.
443 * Window level for frame may be changed.
444 *----------------------------------------------------------------------
447 MoveInStackListAbove(WCoreWindow
*next
, WCoreWindow
*frame
)
452 if (!next
|| frame
->stacking
->under
== next
)
455 if (frame
->stacking
->window_level
!= next
->stacking
->window_level
)
456 ChangeStackingLevel(frame
, next
->stacking
->window_level
);
458 index
= frame
->stacking
->window_level
;
460 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
462 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
463 if (frame
->stacking
->under
)
464 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
465 if (frame
->stacking
->above
)
466 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
467 if (next
->stacking
->above
)
468 next
->stacking
->above
->stacking
->under
= frame
;
469 frame
->stacking
->under
= next
;
470 frame
->stacking
->above
= next
->stacking
->above
;
471 next
->stacking
->above
= frame
;
473 frame
->screen_ptr
->stacking_list
[index
] = frame
;
475 /* try to optimize things a little */
476 if (frame
->stacking
->above
== NULL
) {
477 WCoreWindow
*above
=NULL
;
480 for (i
=index
+1; i
<MAX_WINDOW_LEVELS
; i
++) {
481 if (frame
->screen_ptr
->stacking_list
[i
]!=NULL
) {
483 above
= frame
->screen_ptr
->stacking_list
[i
];
484 while (above
->stacking
->under
)
485 above
= above
->stacking
->under
;
490 XRaiseWindow(dpy
, frame
->window
);
492 moveFrameToUnder(above
, frame
);
495 moveFrameToUnder(frame
->stacking
->above
, frame
);
501 *----------------------------------------------------------------------
502 * MoveInStackListUnder--
503 * Moves the frame under "prev".
509 * Stacking order may be changed.
510 * Window level for frame may be changed.
511 *----------------------------------------------------------------------
514 MoveInStackListUnder(WCoreWindow
*prev
, WCoreWindow
*frame
)
519 if (!prev
|| frame
->stacking
->above
== prev
)
522 if (frame
->stacking
->window_level
!= prev
->stacking
->window_level
)
523 ChangeStackingLevel(frame
, prev
->stacking
->window_level
);
525 index
= frame
->stacking
->window_level
;
527 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
529 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
530 if (frame
->stacking
->under
)
531 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
532 if (frame
->stacking
->above
)
533 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
534 if (prev
->stacking
->under
)
535 prev
->stacking
->under
->stacking
->above
= frame
;
536 frame
->stacking
->above
= prev
;
537 frame
->stacking
->under
= prev
->stacking
->under
;
538 prev
->stacking
->under
= frame
;
539 moveFrameToUnder(prev
, frame
);
544 RemoveFromStackList(WCoreWindow
*frame
)
546 int index
= frame
->stacking
->window_level
;
548 if (XDeleteContext(dpy
, frame
->window
, wStackContext
)==XCNOENT
) {
550 wwarning("RemoveFromStackingList(): window not in list ");
554 /* remove from the window stack list */
555 if (frame
->stacking
->under
)
556 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
557 if (frame
->stacking
->above
)
558 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
559 else /* this was the first window on the list */
560 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
562 frame
->screen_ptr
->window_count
--;
563 /* frame->screen_ptr->window_level_count[index]--;*/
568 ChangeStackingLevel(WCoreWindow
*frame
, int new_level
)
571 if (frame
->stacking
->window_level
== new_level
)
573 old_level
= frame
->stacking
->window_level
;
575 RemoveFromStackList(frame
);
576 frame
->stacking
->window_level
= new_level
;
577 AddToStackList(frame
);
578 if (old_level
> new_level
) {