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 levelToIndex(int level
)
48 case WMNormalWindowLevel
:
50 case WMFloatingWindowLevel
:
52 case WMDockWindowLevel
:
54 case WMSubmenuWindowLevel
:
56 case WMMainMenuWindowLevel
:
64 *----------------------------------------------------------------------
66 * Remakes the stacking_list for the screen, getting the real
67 * stacking order from the server and reordering windows that are not
68 * in the correct stacking.
71 * The stacking order list and the actual window stacking
72 * may be changed (corrected)
74 *----------------------------------------------------------------------
77 RemakeStackList(WScreen
*scr
)
80 unsigned int nwindows
;
83 WCoreWindow
*onbotw
[MAX_WINDOW_LEVELS
];
87 if (!XQueryTree(dpy
, scr
->root_win
, &junkr
, &junkp
, &windows
, &nwindows
)) {
88 wwarning(_("could not get window list!!"));
91 for (i
=0; i
<MAX_WINDOW_LEVELS
; i
++) {
92 scr
->stacking_list
[i
] = NULL
;
94 scr
->window_level_count
[i
] = 0;
96 /* verify list integrity */
98 for (i
=0; i
<nwindows
; i
++) {
99 if (XFindContext(dpy
, windows
[i
], wStackContext
, (XPointer
*)&frame
)
103 if (!frame
) continue;
105 level
= levelToIndex(frame
->stacking
->window_level
);
107 onbotw
[level
]->stacking
->above
= frame
;
108 frame
->stacking
->under
= onbotw
[level
];
109 frame
->stacking
->above
= NULL
;
110 onbotw
[level
] = frame
;
111 scr
->window_level_count
[level
]++;
115 if (c
!=scr
->window_count
) {
116 puts("Found different number of windows than in window lists!!!");
119 scr
->window_count
= c
;
121 /* now, just concatenate the lists */
122 for (i
=0; i
<MAX_WINDOW_LEVELS
; i
++) {
123 scr
->stacking_list
[i
] = onbotw
[i
];
125 onbotw
[i
]->stacking
->above
= NULL
;
132 *----------------------------------------------------------------------
134 * Reorders the actual window stacking, so that it has the stacking
135 * order in the internal window stacking lists. It does the opposite
136 * of RemakeStackList().
139 * Windows may be restacked.
140 *----------------------------------------------------------------------
143 CommitStacking(WScreen
*scr
)
150 nwindows
= scr
->window_count
;
151 windows
= wmalloc(sizeof(Window
)*nwindows
);
153 for (level
=MAX_WINDOW_LEVELS
-1; level
>=0; level
--) {
154 tmp
= scr
->stacking_list
[level
];
158 puts("Internal inconsistency! window_count is incorrect!!!");
159 printf("window_count says %i windows\n", nwindows
);
164 windows
[i
++] = tmp
->window
;
165 tmp
= tmp
->stacking
->under
;
168 XRestackWindows(dpy
, windows
, i
);
173 *----------------------------------------------------------------------
175 * Reestacks windows so that "frame" is under "under".
181 * Changes the stacking order of frame.
182 *----------------------------------------------------------------------
185 moveFrameToUnder(WCoreWindow
*under
, WCoreWindow
*frame
)
189 wins
[0] = under
->window
;
190 wins
[1] = frame
->window
;
191 XRestackWindows(dpy
, wins
, 2);
195 *----------------------------------------------------------------------
197 * Raises a frame taking the window level and the on_top flag
204 * Window stacking order and window list is changed.
206 *----------------------------------------------------------------------
209 wRaiseFrame(WCoreWindow
*frame
)
211 WCoreWindow
*wlist
=frame
;
212 int level
= levelToIndex(frame
->stacking
->window_level
);
216 if (frame
->stacking
->above
== NULL
) {
220 /* insert on top of other windows */
222 wlist
= wlist
->stacking
->above
;
224 /* window is inserted before the point found */
226 /* top most window (last on the list) */
227 if (frame
->stacking
->under
)
228 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
229 if (frame
->stacking
->above
)
230 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
232 frame
->stacking
->above
= NULL
;
233 frame
->stacking
->under
= frame
->screen_ptr
->stacking_list
[level
];
234 frame
->screen_ptr
->stacking_list
[level
]->stacking
->above
=frame
;
235 frame
->screen_ptr
->stacking_list
[level
] = frame
;
236 } else if (frame
!=wlist
) {
237 if (frame
->stacking
->under
)
238 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
239 if (frame
->stacking
->above
)
240 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
242 frame
->stacking
->above
= wlist
;
243 frame
->stacking
->under
= wlist
->stacking
->under
;
244 if (wlist
->stacking
->under
)
245 wlist
->stacking
->under
->stacking
->above
= frame
;
246 wlist
->stacking
->under
= frame
;
248 if (wPreferences
.on_top_transients
) {
249 /* raise transients under us from bottom to top
250 * so that the order is kept */
252 wlist
= frame
->stacking
->under
;
253 while (wlist
&& wlist
->stacking
->under
)
254 wlist
= wlist
->stacking
->under
;
255 while (wlist
&& wlist
!=frame
) {
256 if (wlist
->stacking
->child_of
== frame
) {
260 wlist
= wlist
->stacking
->above
;
264 wlist
= frame
->stacking
->under
;
266 if (wlist
->stacking
->child_of
== frame
) {
267 /* transient for us */
269 goto again
; /* need this or we'll get in a loop */
271 wlist
= wlist
->stacking
->under
;
275 /* try to optimize things a little */
276 if (frame
->stacking
->above
== NULL
) {
277 WCoreWindow
*above
=NULL
;
279 for (i
=level
+1; i
<MAX_WINDOW_LEVELS
; i
++) {
280 if (frame
->screen_ptr
->stacking_list
[i
]!=NULL
) {
282 above
= frame
->screen_ptr
->stacking_list
[i
];
283 while (above
->stacking
->under
)
284 above
= above
->stacking
->under
;
289 XRaiseWindow(dpy
, frame
->window
);
291 moveFrameToUnder(above
, frame
);
294 moveFrameToUnder(frame
->stacking
->above
, frame
);
299 wRaiseLowerFrame(WCoreWindow
*frame
)
301 if (!frame
->stacking
->above
302 ||(frame
->stacking
->window_level
303 !=frame
->stacking
->above
->stacking
->window_level
))
311 wLowerFrame(WCoreWindow
*frame
)
313 WScreen
*scr
=frame
->screen_ptr
;
314 WCoreWindow
*prev
, *wlist
=frame
;
315 int level
= levelToIndex(frame
->stacking
->window_level
);
318 /* already in bottom */
319 if (wlist
->stacking
->under
==NULL
) {
322 if (wPreferences
.on_top_transients
&&
323 wlist
->stacking
->under
==wlist
->stacking
->child_of
) {
327 /* remove from the list */
328 if (scr
->stacking_list
[level
] == frame
) {
329 /* it was the top window */
330 scr
->stacking_list
[level
] = frame
->stacking
->under
;
331 scr
->stacking_list
[level
]->stacking
->above
= NULL
;
333 if (frame
->stacking
->under
)
334 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
335 if (frame
->stacking
->above
)
336 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
338 wlist
= scr
->stacking_list
[level
];
339 /* look for place to put this window */
340 if (wPreferences
.on_top_transients
) {
341 WCoreWindow
*owner
= frame
->stacking
->child_of
;
343 if (owner
!= wlist
) {
344 while (wlist
->stacking
->under
) {
345 /* if this is a transient, it should not be placed under
347 if (owner
== wlist
->stacking
->under
)
349 wlist
= wlist
->stacking
->under
;
353 while (wlist
->stacking
->under
) {
354 wlist
= wlist
->stacking
->under
;
357 /* insert under the place found */
358 frame
->stacking
->above
= wlist
;
359 frame
->stacking
->under
= wlist
->stacking
->under
;
360 if (wlist
->stacking
->under
)
361 wlist
->stacking
->under
->stacking
->above
= frame
;
362 wlist
->stacking
->under
= frame
;
364 /* try to optimize things a little */
365 if (frame
->stacking
->above
== NULL
) {
366 WCoreWindow
*above
= NULL
;
367 for (i
=level
-1; i
>=0; i
--) {
368 if (scr
->stacking_list
[i
]!=NULL
) {
370 above
= scr
->stacking_list
[i
];
371 while (above
->stacking
->under
)
372 above
= above
->stacking
->under
;
377 XLowerWindow(dpy
, frame
->window
);
379 moveFrameToUnder(above
, frame
);
382 moveFrameToUnder(frame
->stacking
->above
, frame
);
388 *----------------------------------------------------------------------
390 * Inserts the frame in the top of the stacking list. The
391 * stacking precedence is obeyed.
397 * The frame is added to it's screen's window list.
398 *----------------------------------------------------------------------
401 AddToStackList(WCoreWindow
*frame
)
403 WCoreWindow
*prev
, *tmpw
, *wlist
;
404 int index
= levelToIndex(frame
->stacking
->window_level
);
406 frame
->screen_ptr
->window_count
++;
407 frame
->screen_ptr
->window_level_count
[index
]++;
408 XSaveContext(dpy
, frame
->window
, wStackContext
, (XPointer
)frame
);
409 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
411 frame
->screen_ptr
->stacking_list
[index
] = frame
;
412 frame
->stacking
->above
= NULL
;
413 frame
->stacking
->under
= NULL
;
414 CommitStacking(frame
->screen_ptr
);
418 /* check if this is a transient owner */
419 if (wPreferences
.on_top_transients
) {
420 WCoreWindow
*trans
= NULL
;
422 wlist
= frame
->screen_ptr
->stacking_list
[index
];
424 if (wlist
->stacking
->child_of
== frame
)
426 wlist
= wlist
->stacking
->under
;
429 frame
->stacking
->above
= trans
;
431 frame
->stacking
->under
= trans
->stacking
->under
;
432 if (trans
->stacking
->under
) {
433 trans
->stacking
->under
->stacking
->above
= frame
;
435 trans
->stacking
->under
= frame
;
437 frame
->stacking
->under
= tmpw
;
438 tmpw
->stacking
->above
= frame
;
439 frame
->screen_ptr
->stacking_list
[index
] = frame
;
442 /* put on top of the stacking list */
443 frame
->stacking
->above
= NULL
;
444 frame
->stacking
->under
= tmpw
;
445 tmpw
->stacking
->above
= frame
;
446 frame
->screen_ptr
->stacking_list
[index
] = frame
;
448 CommitStacking(frame
->screen_ptr
);
453 *----------------------------------------------------------------------
454 * MoveInStackListAbove--
455 * Moves the frame above "next".
461 * Stacking order may be changed.
462 * Window level for frame may be changed.
463 *----------------------------------------------------------------------
466 MoveInStackListAbove(WCoreWindow
*next
, WCoreWindow
*frame
)
471 if (!next
|| frame
->stacking
->under
== next
)
474 if (frame
->stacking
->window_level
!= next
->stacking
->window_level
)
475 ChangeStackingLevel(frame
, next
->stacking
->window_level
);
477 index
= levelToIndex(frame
->stacking
->window_level
);
479 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
481 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
482 if (frame
->stacking
->under
)
483 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
484 if (frame
->stacking
->above
)
485 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
486 if (next
->stacking
->above
)
487 next
->stacking
->above
->stacking
->under
= frame
;
488 frame
->stacking
->under
= next
;
489 frame
->stacking
->above
= next
->stacking
->above
;
490 next
->stacking
->above
= frame
;
492 frame
->screen_ptr
->stacking_list
[index
] = frame
;
494 /* try to optimize things a little */
495 if (frame
->stacking
->above
== NULL
) {
496 WCoreWindow
*above
=NULL
;
499 for (i
=index
+1; i
<MAX_WINDOW_LEVELS
; i
++) {
500 if (frame
->screen_ptr
->stacking_list
[i
]!=NULL
) {
502 above
= frame
->screen_ptr
->stacking_list
[i
];
503 while (above
->stacking
->under
)
504 above
= above
->stacking
->under
;
509 XRaiseWindow(dpy
, frame
->window
);
511 moveFrameToUnder(above
, frame
);
514 moveFrameToUnder(frame
->stacking
->above
, frame
);
520 *----------------------------------------------------------------------
521 * MoveInStackListUnder--
522 * Moves the frame under "prev".
528 * Stacking order may be changed.
529 * Window level for frame may be changed.
530 *----------------------------------------------------------------------
533 MoveInStackListUnder(WCoreWindow
*prev
, WCoreWindow
*frame
)
538 if (!prev
|| frame
->stacking
->above
== prev
)
541 if (frame
->stacking
->window_level
!= prev
->stacking
->window_level
)
542 ChangeStackingLevel(frame
, prev
->stacking
->window_level
);
544 index
= levelToIndex(frame
->stacking
->window_level
);
546 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
548 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
549 if (frame
->stacking
->under
)
550 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
551 if (frame
->stacking
->above
)
552 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
553 if (prev
->stacking
->under
)
554 prev
->stacking
->under
->stacking
->above
= frame
;
555 frame
->stacking
->above
= prev
;
556 frame
->stacking
->under
= prev
->stacking
->under
;
557 prev
->stacking
->under
= frame
;
558 moveFrameToUnder(prev
, frame
);
563 RemoveFromStackList(WCoreWindow
*frame
)
565 int index
= levelToIndex(frame
->stacking
->window_level
);
567 if (XDeleteContext(dpy
, frame
->window
, wStackContext
)==XCNOENT
) {
569 wwarning("RemoveFromStackingList(): window not in list ");
573 /* remove from the window stack list */
574 if (frame
->stacking
->under
)
575 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
576 if (frame
->stacking
->above
)
577 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
578 else /* this was the first window on the list */
579 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
581 frame
->screen_ptr
->window_count
--;
582 frame
->screen_ptr
->window_level_count
[index
]--;
587 ChangeStackingLevel(WCoreWindow
*frame
, int new_level
)
590 if (frame
->stacking
->window_level
== new_level
)
592 old_level
= frame
->stacking
->window_level
;
594 RemoveFromStackList(frame
);
595 frame
->stacking
->window_level
= new_level
;
596 AddToStackList(frame
);
597 if (old_level
> new_level
) {