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
);
310 #ifdef VIRTUAL_DESKTOP
311 wWorkspaceRaiseEdge(frame
->screen_ptr
);
317 wRaiseLowerFrame(WCoreWindow
*frame
)
319 if (!frame
->stacking
->above
320 ||(frame
->stacking
->window_level
321 !=frame
->stacking
->above
->stacking
->window_level
)) {
325 WCoreWindow
*scan
= frame
->stacking
->above
;
326 WWindow
*frame_wwin
= (WWindow
*) frame
->descriptor
.parent
;
330 if (scan
->descriptor
.parent_type
== WCLASS_WINDOW
) {
331 WWindow
*scan_wwin
= (WWindow
*) scan
->descriptor
.parent
;
333 if (wWindowObscuresWindow(scan_wwin
, frame_wwin
)
334 && scan_wwin
->flags
.mapped
) {
338 scan
= scan
->stacking
->above
;
351 wLowerFrame(WCoreWindow
*frame
)
353 WScreen
*scr
=frame
->screen_ptr
;
354 WCoreWindow
*prev
, *wlist
=frame
;
355 int level
= frame
->stacking
->window_level
;
358 /* already in bottom */
359 if (wlist
->stacking
->under
==NULL
) {
363 if (wPreferences
.on_top_transients
&&
364 wlist
->stacking
->under
==wlist
->stacking
->child_of
) {
368 if (wlist
->stacking
->under
==wlist
->stacking
->child_of
) {
373 /* remove from the list */
374 if (scr
->stacking_list
[level
] == frame
) {
375 /* it was the top window */
376 scr
->stacking_list
[level
] = frame
->stacking
->under
;
377 scr
->stacking_list
[level
]->stacking
->above
= NULL
;
379 if (frame
->stacking
->under
)
380 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
381 if (frame
->stacking
->above
)
382 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
384 wlist
= scr
->stacking_list
[level
];
385 /* look for place to put this window */
387 if (wPreferences
.on_top_transients
)
390 WCoreWindow
*owner
= frame
->stacking
->child_of
;
392 if (owner
!= wlist
) {
393 while (wlist
->stacking
->under
) {
394 /* if this is a transient, it should not be placed under
396 if (owner
== wlist
->stacking
->under
)
398 wlist
= wlist
->stacking
->under
;
404 while (wlist
->stacking
->under
) {
405 wlist
= wlist
->stacking
->under
;
409 /* insert under the place found */
410 frame
->stacking
->above
= wlist
;
411 frame
->stacking
->under
= wlist
->stacking
->under
;
412 if (wlist
->stacking
->under
)
413 wlist
->stacking
->under
->stacking
->above
= frame
;
414 wlist
->stacking
->under
= frame
;
416 /* try to optimize things a little */
417 if (frame
->stacking
->above
== NULL
) {
418 WCoreWindow
*above
= NULL
;
419 for (i
=level
-1; i
>=0; i
--) {
420 if (scr
->stacking_list
[i
]!=NULL
) {
422 above
= scr
->stacking_list
[i
];
423 while (above
->stacking
->under
)
424 above
= above
->stacking
->under
;
429 XLowerWindow(dpy
, frame
->window
);
431 moveFrameToUnder(above
, frame
);
434 moveFrameToUnder(frame
->stacking
->above
, frame
);
438 WWindow
*wwin
= wWindowFor(frame
->window
);
441 wKWMSendEventMessage(wwin
, WKWMLowerWindow
);
448 *----------------------------------------------------------------------
450 * Inserts the frame in the top of the stacking list. The
451 * stacking precedence is obeyed.
457 * The frame is added to it's screen's window list.
458 *----------------------------------------------------------------------
461 AddToStackList(WCoreWindow
*frame
)
463 WCoreWindow
*prev
, *tmpw
, *wlist
;
464 int index
= frame
->stacking
->window_level
;
466 frame
->screen_ptr
->window_count
++;
467 /* frame->screen_ptr->window_level_count[index]++;*/
468 XSaveContext(dpy
, frame
->window
, wStackContext
, (XPointer
)frame
);
469 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
471 frame
->screen_ptr
->stacking_list
[index
] = frame
;
472 frame
->stacking
->above
= NULL
;
473 frame
->stacking
->under
= NULL
;
474 CommitStacking(frame
->screen_ptr
);
478 /* check if this is a transient owner */
480 if (wPreferences
.on_top_transients
)
483 WCoreWindow
*trans
= NULL
;
485 wlist
= frame
->screen_ptr
->stacking_list
[index
];
487 if (wlist
->stacking
->child_of
== frame
)
489 wlist
= wlist
->stacking
->under
;
492 frame
->stacking
->above
= trans
;
494 frame
->stacking
->under
= trans
->stacking
->under
;
495 if (trans
->stacking
->under
) {
496 trans
->stacking
->under
->stacking
->above
= frame
;
498 trans
->stacking
->under
= frame
;
500 frame
->stacking
->under
= tmpw
;
501 tmpw
->stacking
->above
= frame
;
502 frame
->screen_ptr
->stacking_list
[index
] = frame
;
507 /* put on top of the stacking list */
508 frame
->stacking
->above
= NULL
;
509 frame
->stacking
->under
= tmpw
;
510 tmpw
->stacking
->above
= frame
;
511 frame
->screen_ptr
->stacking_list
[index
] = frame
;
514 CommitStacking(frame
->screen_ptr
);
519 *----------------------------------------------------------------------
520 * MoveInStackListAbove--
521 * Moves the frame above "next".
527 * Stacking order may be changed.
528 * Window level for frame may be changed.
529 *----------------------------------------------------------------------
532 MoveInStackListAbove(WCoreWindow
*next
, WCoreWindow
*frame
)
537 if (!next
|| frame
->stacking
->under
== next
)
540 if (frame
->stacking
->window_level
!= next
->stacking
->window_level
)
541 ChangeStackingLevel(frame
, next
->stacking
->window_level
);
543 index
= frame
->stacking
->window_level
;
545 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
547 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
548 if (frame
->stacking
->under
)
549 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
550 if (frame
->stacking
->above
)
551 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
552 if (next
->stacking
->above
)
553 next
->stacking
->above
->stacking
->under
= frame
;
554 frame
->stacking
->under
= next
;
555 frame
->stacking
->above
= next
->stacking
->above
;
556 next
->stacking
->above
= frame
;
558 frame
->screen_ptr
->stacking_list
[index
] = frame
;
560 /* try to optimize things a little */
561 if (frame
->stacking
->above
== NULL
) {
562 WCoreWindow
*above
=NULL
;
565 for (i
=index
+1; i
<MAX_WINDOW_LEVELS
; i
++) {
566 if (frame
->screen_ptr
->stacking_list
[i
]!=NULL
) {
568 above
= frame
->screen_ptr
->stacking_list
[i
];
569 while (above
->stacking
->under
)
570 above
= above
->stacking
->under
;
575 XRaiseWindow(dpy
, frame
->window
);
577 moveFrameToUnder(above
, frame
);
580 moveFrameToUnder(frame
->stacking
->above
, frame
);
586 *----------------------------------------------------------------------
587 * MoveInStackListUnder--
588 * Moves the frame to under "prev".
594 * Stacking order may be changed.
595 * Window level for frame may be changed.
596 *----------------------------------------------------------------------
599 MoveInStackListUnder(WCoreWindow
*prev
, WCoreWindow
*frame
)
604 if (!prev
|| frame
->stacking
->above
== prev
)
607 if (frame
->stacking
->window_level
!= prev
->stacking
->window_level
)
608 ChangeStackingLevel(frame
, prev
->stacking
->window_level
);
610 index
= frame
->stacking
->window_level
;
612 tmpw
= frame
->screen_ptr
->stacking_list
[index
];
614 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
615 if (frame
->stacking
->under
)
616 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
617 if (frame
->stacking
->above
)
618 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
619 if (prev
->stacking
->under
)
620 prev
->stacking
->under
->stacking
->above
= frame
;
621 frame
->stacking
->above
= prev
;
622 frame
->stacking
->under
= prev
->stacking
->under
;
623 prev
->stacking
->under
= frame
;
624 moveFrameToUnder(prev
, frame
);
629 RemoveFromStackList(WCoreWindow
*frame
)
631 int index
= frame
->stacking
->window_level
;
633 if (XDeleteContext(dpy
, frame
->window
, wStackContext
)==XCNOENT
) {
635 wwarning("RemoveFromStackingList(): window not in list ");
639 /* remove from the window stack list */
640 if (frame
->stacking
->under
)
641 frame
->stacking
->under
->stacking
->above
= frame
->stacking
->above
;
642 if (frame
->stacking
->above
)
643 frame
->stacking
->above
->stacking
->under
= frame
->stacking
->under
;
644 else /* this was the first window on the list */
645 frame
->screen_ptr
->stacking_list
[index
] = frame
->stacking
->under
;
647 frame
->screen_ptr
->window_count
--;
648 /* frame->screen_ptr->window_level_count[index]--;*/
653 ChangeStackingLevel(WCoreWindow
*frame
, int new_level
)
656 if (frame
->stacking
->window_level
== new_level
)
658 old_level
= frame
->stacking
->window_level
;
660 RemoveFromStackList(frame
);
661 frame
->stacking
->window_level
= new_level
;
662 AddToStackList(frame
);
663 if (old_level
> new_level
) {