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"
41 /*** Global Variables ***/
42 extern XContext wStackContext
;
44 extern WPreferences wPreferences
;
48 *----------------------------------------------------------------------
50 * Remakes the stacking_list for the screen, getting the real
51 * stacking order from the server and reordering windows that are not
52 * in the correct stacking.
55 * The stacking order list and the actual window stacking
56 * may be changed (corrected)
58 *----------------------------------------------------------------------
61 RemakeStackList(WScreen
*scr
)
64 unsigned int nwindows
;
67 WCoreWindow
*onbotw
[MAX_WINDOW_LEVELS
];
71 if (!XQueryTree(dpy
, scr
->root_win
, &junkr
, &junkp
, &windows
, &nwindows
)) {
72 wwarning(_("could not get window list!!"));
75 for (i
=0; i
<MAX_WINDOW_LEVELS
; i
++) {
76 scr
->stacking_list
[i
] = NULL
;
78 /* scr->window_level_count[i] = 0;*/
80 /* verify list integrity */
82 for (i
=0; i
<nwindows
; i
++) {
83 if (XFindContext(dpy
, windows
[i
], wStackContext
, (XPointer
*)&frame
)
89 level
= frame
->stacking
->window_level
;
91 onbotw
[level
]->stacking
->above
= frame
;
92 frame
->stacking
->under
= onbotw
[level
];
93 frame
->stacking
->above
= NULL
;
94 onbotw
[level
] = frame
;
95 /* scr->window_level_count[level]++;*/
99 if (c
!=scr
->window_count
) {
100 puts("Found different number of windows than in window lists!!!");
103 scr
->window_count
= c
;
105 /* now, just concatenate the lists */
106 for (i
=0; i
<MAX_WINDOW_LEVELS
; i
++) {
107 scr
->stacking_list
[i
] = onbotw
[i
];
109 onbotw
[i
]->stacking
->above
= NULL
;
116 *----------------------------------------------------------------------
118 * Reorders the actual window stacking, so that it has the stacking
119 * order in the internal window stacking lists. It does the opposite
120 * of RemakeStackList().
123 * Windows may be restacked.
124 *----------------------------------------------------------------------
127 CommitStacking(WScreen
*scr
)
134 nwindows
= scr
->window_count
;
135 windows
= wmalloc(sizeof(Window
)*nwindows
);
137 for (level
=MAX_WINDOW_LEVELS
-1; level
>=0; level
--) {
138 tmp
= scr
->stacking_list
[level
];
142 puts("Internal inconsistency! window_count is incorrect!!!");
143 printf("window_count says %i windows\n", nwindows
);
148 windows
[i
++] = tmp
->window
;
149 tmp
= tmp
->stacking
->under
;
152 XRestackWindows(dpy
, windows
, i
);
157 *----------------------------------------------------------------------
159 * Reestacks windows so that "frame" is under "under".
165 * Changes the stacking order of frame.
166 *----------------------------------------------------------------------
169 moveFrameToUnder(WCoreWindow
*under
, WCoreWindow
*frame
)
173 wins
[0] = under
->window
;
174 wins
[1] = frame
->window
;
175 XRestackWindows(dpy
, wins
, 2);
179 *----------------------------------------------------------------------
181 * Raises a frame taking the window level and the on_top flag
188 * Window stacking order and window list is changed.
190 *----------------------------------------------------------------------
193 wRaiseFrame(WCoreWindow
*frame
)
195 WCoreWindow
*wlist
=frame
;
196 int level
= frame
->stacking
->window_level
;
200 if (frame
->stacking
->above
== NULL
) {
204 /* insert on top of other windows */
206 wlist
= wlist
->stacking
->above
;
208 /* window is inserted before the point found */
210 /* top most window (last on the list) */
211 if (frame
->stacking
->under
)
212 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
213 if (frame
->stacking
->above
)
214 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
216 frame
->stacking
->above
= NULL
;
217 frame
->stacking
->under
= frame
->screen_ptr
->stacking_list
[level
];
218 frame
->screen_ptr
->stacking_list
[level
]->stacking
->above
=frame
;
219 frame
->screen_ptr
->stacking_list
[level
] = frame
;
220 } else if (frame
!=wlist
) {
221 if (frame
->stacking
->under
)
222 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
223 if (frame
->stacking
->above
)
224 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
226 frame
->stacking
->above
= wlist
;
227 frame
->stacking
->under
= wlist
->stacking
->under
;
228 if (wlist
->stacking
->under
)
229 wlist
->stacking
->under
->stacking
->above
= frame
;
230 wlist
->stacking
->under
= frame
;
232 if (wPreferences
.on_top_transients
) {
233 /* raise transients under us from bottom to top
234 * so that the order is kept */
236 wlist
= frame
->stacking
->under
;
237 while (wlist
&& wlist
->stacking
->under
)
238 wlist
= wlist
->stacking
->under
;
239 while (wlist
&& wlist
!=frame
) {
240 if (wlist
->stacking
->child_of
== frame
) {
244 wlist
= wlist
->stacking
->above
;
248 wlist
= frame
->stacking
->under
;
250 if (wlist
->stacking
->child_of
== frame
) {
251 /* transient for us */
253 goto again
; /* need this or we'll get in a loop */
255 wlist
= wlist
->stacking
->under
;
259 /* try to optimize things a little */
260 if (frame
->stacking
->above
== NULL
) {
261 WCoreWindow
*above
=NULL
;
263 for (i
=level
+1; i
<MAX_WINDOW_LEVELS
; i
++) {
264 if (frame
->screen_ptr
->stacking_list
[i
]!=NULL
) {
266 above
= frame
->screen_ptr
->stacking_list
[i
];
267 while (above
->stacking
->under
)
268 above
= above
->stacking
->under
;
273 XRaiseWindow(dpy
, frame
->window
);
275 moveFrameToUnder(above
, frame
);
278 moveFrameToUnder(frame
->stacking
->above
, frame
);
282 WWindow
*wwin
= wWindowFor(frame
->window
);
285 wKWMSendEventMessage(wwin
, WKWMRaiseWindow
);
291 wRaiseLowerFrame(WCoreWindow
*frame
)
293 if (!frame
->stacking
->above
294 ||(frame
->stacking
->window_level
295 !=frame
->stacking
->above
->stacking
->window_level
))
303 wLowerFrame(WCoreWindow
*frame
)
305 WScreen
*scr
=frame
->screen_ptr
;
306 WCoreWindow
*prev
, *wlist
=frame
;
307 int level
= frame
->stacking
->window_level
;
310 /* already in bottom */
311 if (wlist
->stacking
->under
==NULL
) {
314 if (wPreferences
.on_top_transients
&&
315 wlist
->stacking
->under
==wlist
->stacking
->child_of
) {
319 /* remove from the list */
320 if (scr
->stacking_list
[level
] == frame
) {
321 /* it was the top window */
322 scr
->stacking_list
[level
] = frame
->stacking
->under
;
323 scr
->stacking_list
[level
]->stacking
->above
= NULL
;
325 if (frame
->stacking
->under
)
326 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
327 if (frame
->stacking
->above
)
328 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
330 wlist
= scr
->stacking_list
[level
];
331 /* look for place to put this window */
332 if (wPreferences
.on_top_transients
) {
333 WCoreWindow
*owner
= frame
->stacking
->child_of
;
335 if (owner
!= wlist
) {
336 while (wlist
->stacking
->under
) {
337 /* if this is a transient, it should not be placed under
339 if (owner
== wlist
->stacking
->under
)
341 wlist
= wlist
->stacking
->under
;
345 while (wlist
->stacking
->under
) {
346 wlist
= wlist
->stacking
->under
;
349 /* insert under the place found */
350 frame
->stacking
->above
= wlist
;
351 frame
->stacking
->under
= wlist
->stacking
->under
;
352 if (wlist
->stacking
->under
)
353 wlist
->stacking
->under
->stacking
->above
= frame
;
354 wlist
->stacking
->under
= frame
;
356 /* try to optimize things a little */
357 if (frame
->stacking
->above
== NULL
) {
358 WCoreWindow
*above
= NULL
;
359 for (i
=level
-1; i
>=0; i
--) {
360 if (scr
->stacking_list
[i
]!=NULL
) {
362 above
= scr
->stacking_list
[i
];
363 while (above
->stacking
->under
)
364 above
= above
->stacking
->under
;
369 XLowerWindow(dpy
, frame
->window
);
371 moveFrameToUnder(above
, frame
);
374 moveFrameToUnder(frame
->stacking
->above
, frame
);
378 WWindow
*wwin
= wWindowFor(frame
->window
);
381 wKWMSendEventMessage(wwin
, WKWMLowerWindow
);
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
= 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
= 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 to 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
= 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
= 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
) {