1 /* $Id: windows.c,v 1.1 2004/08/28 19:25:46 dannybackx Exp $ */
2 /*****************************************************************************/
3 /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
4 /** Salt Lake City, Utah **/
5 /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
6 /** Cambridge, Massachusetts **/
7 /** **/
8 /** All Rights Reserved **/
9 /** **/
10 /** Permission to use, copy, modify, and distribute this software and **/
11 /** its documentation for any purpose and without fee is hereby **/
12 /** granted, provided that the above copyright notice appear in all **/
13 /** copies and that both that copyright notice and this permis- **/
14 /** sion notice appear in supporting documentation, and that the **/
15 /** names of Evans & Sutherland and M.I.T. not be used in advertising **/
16 /** in publicity pertaining to distribution of the software without **/
17 /** specific, written prior permission. **/
18 /** **/
19 /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
20 /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
21 /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
22 /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
23 /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
24 /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
25 /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
26 /** OR PERFORMANCE OF THIS SOFTWARE. **/
27 /*****************************************************************************/
28 /****************************************************************************
29 * THIS module is based on Twm, but has been siginificantly modified
30 * by Rob Nation
31 ****************************************************************************/
32 /****************************************************************************
33 * The placement code is by Rob Nation
34 *
35 * This code does smart-placement initial window placement stuff
36 *
37 * Copyright 1994 Robert Nation. No restrictions are placed on this code,
38 * as long as the copyright notice is preserved . No guarantees or
39 * warrantees of any sort whatsoever are given or implied or anything.
40 ****************************************************************************/
41 /***********************************************************************
42 * The rest of it is all my fault -- MLM
43 * mwm - "LessTif Window Manager"
44 ***********************************************************************/
45
46
47 #include <LTconfig.h>
48
49 #include <stdio.h>
50
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54
55 #include <X11/Intrinsic.h>
56 #include <X11/extensions/shape.h>
57
58 #include <Xm/Xm.h>
59 #include <Xm/MwmUtil.h>
60
61 #include "mwm.h"
62
63 /*
64 * some macros used by the constraint code
65 */
66 #define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
67 #define _min(a,b) (((a) < (b)) ? (a) : (b))
68 #define MaxAspectX(t) ((t)->hints.max_aspect.x)
69 #define MaxAspectY(t) ((t)->hints.max_aspect.y)
70 #define MinAspectX(t) ((t)->hints.min_aspect.x)
71 #define MinAspectY(t) ((t)->hints.min_aspect.y)
72
73 static Boolean PPosOverride = False;
74 static long isIconicState = 0;
75
76 char NoName[] = "Untitled"; /* name if no name is specified */
77
78 /*
79 * check to see if we should really put a mwm frame on the window
80 */
81 static Boolean
mapped_not_override(ScreenInfo * scr,Window w)82 mapped_not_override(ScreenInfo *scr, Window w)
83 {
84 XWindowAttributes wa;
85 Atom atype;
86 int aformat;
87 unsigned long nitems, bytes_remain;
88 unsigned char *prop;
89
90 isIconicState = DontCareState;
91
92 if (!XGetWindowAttributes(dpy, w, &wa))
93 return False;
94
95 if (XGetWindowProperty(dpy, w, XA_WM_STATE, 0L, 3L, False, XA_WM_STATE,
96 &atype, &aformat, &nitems, &bytes_remain, &prop) == Success)
97 {
98 if (prop != NULL)
99 {
100 isIconicState = *(long *)prop;
101 XFree(prop);
102 }
103 }
104
105 if (w == scr->pager_win)
106 return True;
107
108 if ((isIconicState == IconicState || wa.map_state != IsUnmapped) &&
109 wa.override_redirect != True)
110 return True;
111
112 return False;
113 }
114
115 /*
116 * map gravity to (x,y) offset signs for adding to x and y when window is
117 * mapped to get proper placement.
118 */
119 static void
get_gravity_offsets(MwmWindow * tmp,int * xp,int * yp)120 get_gravity_offsets(MwmWindow *tmp, int *xp, int *yp)
121 {
122 static struct _gravity_offset
123 {
124 int x, y;
125 }
126 gravity_offsets[11] =
127 {
128 {
129 0, 0
130 }
131 , /* ForgetGravity */
132 {
133 -1, -1
134 }
135 , /* NorthWestGravity */
136 {
137 0, -1
138 }
139 , /* NorthGravity */
140 {
141 1, -1
142 }
143 , /* NorthEastGravity */
144 {
145 -1, 0
146 }
147 , /* WestGravity */
148 {
149 0, 0
150 }
151 , /* CenterGravity */
152 {
153 1, 0
154 }
155 , /* EastGravity */
156 {
157 -1, 1
158 }
159 , /* SouthWestGravity */
160 {
161 0, 1
162 }
163 , /* SouthGravity */
164 {
165 1, 1
166 }
167 , /* SouthEastGravity */
168 {
169 0, 0
170 }
171 , /* StaticGravity */
172 };
173 register int g = ((tmp->hints.flags & PWinGravity)
174 ? tmp->hints.win_gravity : NorthWestGravity);
175
176 if (g < ForgetGravity || g > StaticGravity)
177 *xp = *yp = 0;
178 else
179 {
180 *xp = (int)gravity_offsets[g].x;
181 *yp = (int)gravity_offsets[g].y;
182 }
183 }
184
185 /*
186 * grab needed buttons for the window
187 */
188 static void
grab_buttons(ScreenInfo * scr,MwmWindow * tmp_win)189 grab_buttons(ScreenInfo *scr, MwmWindow *tmp_win)
190 {
191 MouseButton *MouseEntry;
192
193 MouseEntry = scr->buttons;
194 while (MouseEntry != (MouseButton *)0)
195 {
196 if ((MouseEntry->func != (int)0) && (MouseEntry->context & C_WINDOW))
197 {
198 if (MouseEntry->button > 0)
199 {
200 XGrabButton(dpy, MouseEntry->button, MouseEntry->modifier,
201 tmp_win->w,
202 True, ButtonPressMask | ButtonReleaseMask,
203 GrabModeAsync, GrabModeAsync, None,
204 scr->cursors[DEFAULT_CURS]);
205 if (MouseEntry->modifier != AnyModifier)
206 {
207 XGrabButton(dpy, MouseEntry->button,
208 (MouseEntry->modifier | LockMask),
209 tmp_win->w,
210 True, ButtonPressMask | ButtonReleaseMask,
211 GrabModeAsync, GrabModeAsync, None,
212 scr->cursors[DEFAULT_CURS]);
213 }
214 }
215 else
216 {
217 XGrabButton(dpy, 1, MouseEntry->modifier,
218 tmp_win->w,
219 True, ButtonPressMask | ButtonReleaseMask,
220 GrabModeAsync, GrabModeAsync, None,
221 scr->cursors[DEFAULT_CURS]);
222 XGrabButton(dpy, 2, MouseEntry->modifier,
223 tmp_win->w,
224 True, ButtonPressMask | ButtonReleaseMask,
225 GrabModeAsync, GrabModeAsync, None,
226 scr->cursors[DEFAULT_CURS]);
227 XGrabButton(dpy, 3, MouseEntry->modifier,
228 tmp_win->w,
229 True, ButtonPressMask | ButtonReleaseMask,
230 GrabModeAsync, GrabModeAsync, None,
231 scr->cursors[DEFAULT_CURS]);
232 if (MouseEntry->modifier != AnyModifier)
233 {
234 XGrabButton(dpy, 1,
235 (MouseEntry->modifier | LockMask),
236 tmp_win->w,
237 True, ButtonPressMask | ButtonReleaseMask,
238 GrabModeAsync, GrabModeAsync, None,
239 scr->cursors[DEFAULT_CURS]);
240 XGrabButton(dpy, 2,
241 (MouseEntry->modifier | LockMask),
242 tmp_win->w,
243 True, ButtonPressMask | ButtonReleaseMask,
244 GrabModeAsync, GrabModeAsync, None,
245 scr->cursors[DEFAULT_CURS]);
246 XGrabButton(dpy, 3,
247 (MouseEntry->modifier | LockMask),
248 tmp_win->w,
249 True, ButtonPressMask | ButtonReleaseMask,
250 GrabModeAsync, GrabModeAsync, None,
251 scr->cursors[DEFAULT_CURS]);
252 }
253 }
254 }
255 MouseEntry = MouseEntry->next;
256 }
257 }
258
259 /*
260 * grab needed keys for the window
261 */
262 static void
grab_keys(ScreenInfo * scr,MwmWindow * tmp_win)263 grab_keys(ScreenInfo *scr, MwmWindow *tmp_win)
264 {
265 FuncKey *tmp;
266
267 for (tmp = scr->keys; tmp != NULL; tmp = tmp->next)
268 {
269 if (tmp->cont & (C_WINDOW | C_TITLE | C_RALL | C_LALL | C_FRAME))
270 {
271 XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->frame, True,
272 GrabModeAsync, GrabModeAsync);
273 if (tmp->mods != AnyModifier)
274 {
275 XGrabKey(dpy, tmp->keycode, tmp->mods | LockMask,
276 tmp_win->frame, True,
277 GrabModeAsync, GrabModeAsync);
278 }
279 }
280 }
281 }
282
283 /*
284 * set the contexts for the various windows
285 */
286 static void
save_context(MwmWindow * tmp_win)287 save_context(MwmWindow *tmp_win)
288 {
289 int i;
290
291 XSaveContext(dpy, tmp_win->w, MwmContext, (XPointer)tmp_win);
292 XSaveContext(dpy, tmp_win->frame, MwmContext, (XPointer)tmp_win);
293 XSaveContext(dpy, tmp_win->parent, MwmContext, (XPointer)tmp_win);
294 if (tmp_win->decorations & MWM_DECOR_TITLE)
295 {
296 XSaveContext(dpy, tmp_win->title, MwmContext,
297 (XPointer)tmp_win);
298 if (tmp_win->menub != None)
299 XSaveContext(dpy, tmp_win->menub, MwmContext,
300 (XPointer)tmp_win);
301 if (tmp_win->minimizeb != None)
302 XSaveContext(dpy, tmp_win->minimizeb, MwmContext,
303 (XPointer)tmp_win);
304 if (tmp_win->maximizeb != None)
305 XSaveContext(dpy, tmp_win->maximizeb, MwmContext,
306 (XPointer)tmp_win);
307 }
308 if (tmp_win->decorations & MWM_DECOR_BORDER)
309 {
310 for (i = 0; i < 4; i++)
311 {
312 XSaveContext(dpy, tmp_win->sides[i],
313 MwmContext, (XPointer)tmp_win);
314 }
315 }
316 if (tmp_win->decorations & MWM_DECOR_RESIZEH)
317 {
318 for (i = 0; i < 4; i++)
319 {
320 XSaveContext(dpy, tmp_win->corners[i],
321 MwmContext, (XPointer)tmp_win);
322 }
323 }
324 }
325
326 /*
327 * The function below, in its previous life, tried to allocate a window
328 * such that it wouldn't overlap with others. I guess this comes from fvwm.
329 * If the result (x and y) are negative, our caller will prompt the user
330 * to let him interactively position the window.
331 *
332 * As far as I know mwm isn't supposed to behave like this so I really
333 * disabled that functionality.
334 *
335 * Danny 19/4/1997
336 *
337 * Converted this to a resource file setting. MLM (sometime in August 97).
338 */
339
340 #define INC 25
341 /*
342 * try to be smart about how to place the window
343 */
344 static void
smart_placement(ScreenInfo * scr,MwmWindow * t,int width,int height,int * x,int * y)345 smart_placement(ScreenInfo *scr, MwmWindow *t,
346 int width, int height, int *x, int *y)
347 {
348 int temp_h, temp_w;
349 int test_x = 0, test_y = 0;
350 int loc_ok = False, tw, tx, ty, th;
351 MwmWindow *test_window;
352 static int last_x = 0, last_y = 0, begin_x = INC, begin_y = INC;
353
354 temp_h = height;
355 temp_w = width;
356
357 if (!scr->smart_placement)
358 {
359 if (t == NULL)
360 {
361 test_x = test_y = -1;
362 }
363 else
364 {
365 test_x = t->frame_x;
366 test_y = t->frame_y;
367
368 /* If the user specified a position, grant it */
369 if (t->hints.flags & USPosition)
370 {
371 *x = test_x;
372 *y = test_y;
373 return;
374 }
375
376 /* Otherwise, we need to make up a position.
377
378 * Let's start near the top left of the screen, always move a bit
379 * to the lower right with each next window, until a window would
380 * fall of the screen either on the right or on the bottom edge.
381 * When that happens, start near the upper left again.
382 * The upper left starting point should change somewhat too.
383 */
384 #if 0
385 if (test_x == 0 && test_y == 0)
386 #endif
387 {
388 last_x += INC;
389 last_y += INC;
390
391 test_x = last_x;
392 test_y = last_y;
393
394 if (t->frame_width + last_x >= scr->d_width
395 || t->frame_height + last_y >= scr->d_height)
396 {
397 begin_x += INC;
398 begin_y = INC;
399
400 test_x = last_x = begin_x;
401 test_y = last_y = begin_y;
402
403 if (begin_x > scr->d_width / 2)
404 begin_x = begin_y = INC;
405 }
406
407 /* Is this window simply too big ? */
408 if (t->frame_width + last_x >= scr->d_width)
409 test_x = 0;
410 if (t->frame_height + last_y >= scr->d_height)
411 test_y = 0;
412
413 }
414 }
415 }
416 /* smart placement */
417 else
418 {
419 while (((test_y + temp_h) < (scr->d_height)) && (!loc_ok))
420 {
421 test_x = 0;
422 while (((test_x + temp_w) < (scr->d_width)) && (!loc_ok))
423 {
424 loc_ok = True;
425 test_window = scr->mwm_root.next;
426 while ((test_window != (MwmWindow *)0) && (loc_ok == True))
427 {
428 if (test_window->Desk == scr->current_desk)
429 {
430 if (scr->flags & StubbornPlacement)
431 {
432 if ((test_window->flags & ICONIFIED) &&
433 (!(test_window->flags & ICON_UNMAPPED)) &&
434 (test_window->icon_w) &&
435 (test_window != t))
436 {
437 tw = test_window->icon_p_width;
438 th = test_window->icon_p_height +
439 test_window->icon_w_height;
440 tx = test_window->icon_x_loc;
441 ty = test_window->icon_y_loc;
442
443 if ((tx < (test_x + width)) && ((tx + tw) > test_x) &&
444 (ty < (test_y + height)) && ((ty + th) > test_y))
445 {
446 loc_ok = False;
447 test_x = tx + tw;
448 }
449 }
450 }
451
452 if (!(test_window->flags & ICONIFIED) && (test_window != t))
453 {
454 tw = test_window->frame_width + 2 * test_window->bw;
455 th = test_window->frame_height + 2 * test_window->bw;
456 tx = test_window->frame_x;
457 ty = test_window->frame_y;
458 if ((tx <= (test_x + width)) && ((tx + tw) >= test_x) &&
459 (ty <= (test_y + height)) && ((ty + th) >= test_y))
460 {
461 loc_ok = False;
462 test_x = tx + tw;
463 }
464 }
465 }
466 test_window = test_window->next;
467 }
468 test_x += 1;
469 }
470 test_y += 1;
471 }
472 if (loc_ok == False)
473 {
474 *x = -1;
475 *y = -1;
476 return;
477 }
478 }
479 *x = test_x;
480 *y = test_y;
481 }
482
483 /*
484 * Handles initial placement and sizing of a new window. Returns False in
485 * the event of a lost window.
486 */
487 static Boolean
place_window(ScreenInfo * scr,MwmWindow * tmp_win)488 place_window(ScreenInfo *scr, MwmWindow *tmp_win)
489 {
490 MwmWindow *t;
491 int xl = -1, yt, DragWidth, DragHeight;
492 int gravx, gravy; /* gravity signs for positioning */
493 int show_feed;
494 Boolean usePPos;
495
496 get_gravity_offsets(tmp_win, &gravx, &gravy);
497
498
499 /* Select a desk to put the window on (in list of priority):
500 * 1. Sticky Windows stay on the current desk.
501 * 2. Windows specified with StartsOnDesk go where specified
502 * 3. Put it on the desk it was on before the restart.
503 * 4. Transients go on the same desk as their parents.
504 * 5. Window groups stay together (completely untested)
505 */
506 tmp_win->Desk = scr->current_desk;
507 if (tmp_win->flags & STICKY)
508 tmp_win->Desk = scr->current_desk;
509 else
510 {
511 Atom atype;
512 int aformat;
513 unsigned long nitems, bytes_remain;
514 unsigned char *prop;
515
516 if ((tmp_win->wmhints) && (tmp_win->wmhints->flags & WindowGroupHint) &&
517 (tmp_win->wmhints->window_group != None) &&
518 (tmp_win->wmhints->window_group != scr->root_win))
519 {
520 /* Try to find the group leader or another window
521 * in the group */
522 for (t = scr->mwm_root.next; t != NULL; t = t->next)
523 {
524 if ((t->w == tmp_win->wmhints->window_group) ||
525 ((t->wmhints) && (t->wmhints->flags & WindowGroupHint) &&
526 (t->wmhints->window_group == tmp_win->wmhints->window_group)))
527 tmp_win->Desk = t->Desk;
528 }
529 }
530 if ((tmp_win->flags & TRANSIENT) && (tmp_win->transientfor != None) &&
531 (tmp_win->transientfor != scr->root_win))
532 {
533 /* Try to find the parent's desktop */
534 for (t = scr->mwm_root.next; t != NULL; t = t->next)
535 {
536 if (t->w == tmp_win->transientfor)
537 tmp_win->Desk = t->Desk;
538 }
539 }
540
541 if ((XGetWindowProperty(dpy, tmp_win->w, XA_WM_DESKTOP, 0L, 1L, True,
542 XA_WM_DESKTOP, &atype, &aformat, &nitems,
543 &bytes_remain, &prop)) == Success)
544 {
545 if (prop != NULL)
546 {
547 tmp_win->Desk = *(unsigned long *)prop;
548 XFree(prop);
549 }
550 }
551 }
552 /* I think it would be good to switch to the selected desk
553 * whenever a new window pops up, except during initialization */
554 if (!PPosOverride)
555 DT_ChangeDesks(scr, 0, tmp_win->Desk);
556
557
558 /* Desk has been selected, now pick a location for the window */
559 /*
560 * If
561 * o the window is a transient, or
562 *
563 * o a USPosition was requested
564 *
565 * then put the window where requested.
566 *
567 */
568 #if 0
569 fprintf(stderr,
570 "PlaceWindow: UsePPosition = %s, Hints %s%s, attr x %d y %d\n",
571 (tmp_win->use_p_position == XmUSE_PPOSITION_ON) ? "XmUSE_PPOSITION_ON" :
572 (tmp_win->use_p_position == XmUSE_PPOSITION_NON_ZERO)
573 ? "XmUSE_PPOSITION_NON_ZERO" : "???",
574 (tmp_win->hints.flags & USPosition) ? "USPosition" : "",
575 (tmp_win->hints.flags & PPosition) ? "PPosition" : "",
576 tmp_win->attr.x, tmp_win->attr.y);
577 #endif
578
579 if (tmp_win->use_p_position == XmUSE_PPOSITION_ON &&
580 (tmp_win->hints.flags & USPosition ||
581 tmp_win->hints.flags & PPosition))
582 usePPos = True;
583 else if (tmp_win->use_p_position == XmUSE_PPOSITION_NON_ZERO &&
584 (tmp_win->hints.flags & USPosition ||
585 tmp_win->hints.flags & PPosition) &&
586 (tmp_win->attr.x != 0 || tmp_win->attr.y != 0))
587 usePPos = True;
588 else
589 usePPos = False;
590
591 if (!(tmp_win->flags & TRANSIENT) &&
592 !(PPosOverride) &&
593 !(usePPos) &&
594 !((tmp_win->wmhints) &&
595 (tmp_win->wmhints->flags & StateHint) &&
596 (tmp_win->wmhints->initial_state == IconicState)))
597 {
598 /* Get user's window placement */
599 xl = -1;
600 yt = -1;
601 if (Mwm.client_auto_place)
602 smart_placement(scr, tmp_win,
603 tmp_win->frame_width + 2 * tmp_win->bw,
604 tmp_win->frame_height + 2 * tmp_win->bw,
605 &xl, &yt);
606 if (xl < 0)
607 {
608
609 if (MISC_Grab(scr, POSITION_CURS))
610 {
611
612 /* Grabbed the pointer - continue */
613 XGrabServer(dpy);
614
615 if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
616 (unsigned int *)&DragWidth,
617 (unsigned int *)&DragHeight,
618 &JunkBW, &JunkDepth) == 0)
619 {
620 XtFree((char *)tmp_win);
621 XUngrabServer(dpy);
622 return False;
623 }
624
625 DragWidth += 2 * tmp_win->boundary_width +
626 2 * tmp_win->matte_width;
627 DragHeight +=
628 tmp_win->title_height +
629 2 * tmp_win->boundary_width +
630 2 * tmp_win->matte_width;
631
632 if (Mwm.show_feedback & MWM_FEEDBACK_PLACEMENT)
633 XMapRaised(dpy, scr->size_win);
634
635 show_feed = Mwm.show_feedback & MWM_FEEDBACK_MOVE;
636 if (!(Mwm.show_feedback & MWM_FEEDBACK_PLACEMENT))
637 Mwm.show_feedback &= ~MWM_FEEDBACK_MOVE;
638
639 MOVE_EventLoop(scr, tmp_win, 0, 0, DragWidth, DragHeight,
640 &xl, &yt, False, True);
641
642 if (Mwm.show_feedback & MWM_FEEDBACK_PLACEMENT)
643 XUnmapWindow(dpy, scr->size_win);
644
645 if (show_feed)
646 Mwm.show_feedback |= MWM_FEEDBACK_MOVE;
647
648 XUngrabServer(dpy);
649
650 MISC_Ungrab(scr);
651 }
652 else
653 {
654 /* couldn't grab the pointer - better do something */
655 XBell(dpy, scr->screen);
656 xl = 0;
657 yt = 0;
658 }
659 }
660 tmp_win->attr.y = yt - tmp_win->old_bw + tmp_win->bw;
661 tmp_win->attr.x = xl - tmp_win->old_bw + tmp_win->bw;
662 tmp_win->xdiff = xl;
663 tmp_win->ydiff = yt;
664 }
665 else
666 {
667 /* the USPosition was specified, or the window is a transient,
668 * or it starts iconic so place it automatically */
669
670 tmp_win->xdiff = tmp_win->attr.x;
671 tmp_win->ydiff = tmp_win->attr.y;
672 /* put it where asked, mod title bar */
673 /* if the gravity is towards the top, move it by the title height */
674 tmp_win->attr.y -= gravy * (tmp_win->bw - tmp_win->old_bw);
675 tmp_win->attr.x -= gravx * (tmp_win->bw - tmp_win->old_bw);
676 if (gravy > 0)
677 tmp_win->attr.y -= tmp_win->title_height +
678 2 * tmp_win->boundary_width +
679 2 * tmp_win->matte_width;
680 if (gravx > 0)
681 tmp_win->attr.x -= 2 * tmp_win->boundary_width +
682 2 * tmp_win->matte_width;
683 }
684 return True;
685 }
686
687 /*
688 * add a new window to the mwm list
689 */
690 static MwmWindow *
add_window(ScreenInfo * scr,Window w)691 add_window(ScreenInfo *scr, Window w)
692 {
693 MwmWindow *tmp_win; /* new mwm window structure */
694 int i, width, height, tx, ty;
695 int xws, yws, xbs, ybs;
696 unsigned wws, hws, wbs, hbs;
697 int boundingShaped, clipShaped;
698 XTextProperty text_prop;
699
700 NeedToResizeToo = False;
701
702 /* allocate space for the mwm window */
703 tmp_win = (MwmWindow *)XtCalloc(1, sizeof(MwmWindow));
704 if (tmp_win == NULL)
705 {
706 return NULL;
707 }
708
709 tmp_win->w = w;
710
711 tmp_win->classhint.res_name = NoName;
712 tmp_win->classhint.res_class = NoName;
713 XGetClassHint(dpy, tmp_win->w, &tmp_win->classhint);
714 if (tmp_win->classhint.res_name == NULL)
715 tmp_win->classhint.res_name = NoName;
716 if (tmp_win->classhint.res_class == NULL)
717 tmp_win->classhint.res_class = NoName;
718
719 RES_GetClientDefaults(scr, tmp_win, tmp_win->classhint.res_name, tmp_win->classhint.res_class);
720
721 if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
722 &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
723 {
724 XtFree((char *)tmp_win);
725 return (NULL);
726 }
727
728 PROP_GetWmProtocols(tmp_win);
729
730 PROP_GetWmColormapWindows(tmp_win);
731
732 if (!(XGetWindowAttributes(dpy, tmp_win->w, &(tmp_win->attr))))
733 tmp_win->attr.colormap = scr->mwm_root.attr.colormap;
734
735 if (XGetWMName(dpy, tmp_win->w, &text_prop) != 0)
736 tmp_win->name = (char *)text_prop.value;
737 else
738 tmp_win->name = NoName;
739
740 tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w);
741
742 if (XGetTransientForHint(dpy, tmp_win->w, &tmp_win->transientfor))
743 tmp_win->flags |= TRANSIENT;
744 else
745 tmp_win->flags &= ~TRANSIENT;
746
747 tmp_win->old_bw = tmp_win->attr.border_width;
748
749 XShapeSelectInput(dpy, tmp_win->w, ShapeNotifyMask);
750
751 XShapeQueryExtents(dpy, tmp_win->w,
752 &boundingShaped, &xws, &yws, &wws, &hws,
753 &clipShaped, &xbs, &ybs, &wbs, &hbs);
754 tmp_win->wShaped = boundingShaped;
755
756 tmp_win->title_height = scr->components[MWM_TITLE_A].f_height + 3 +
757 tmp_win->bw;
758
759 PROP_GetWmIconName(tmp_win);
760
761 PROP_GetMwmHints(tmp_win);
762
763 DEC_SelectDecorations(scr, tmp_win);
764
765 if ((tmp_win->wmhints)
766 && (tmp_win->wmhints->flags & (IconWindowHint | IconPixmapHint)))
767 {
768 /* window has its own icon */
769 tmp_win->icon_bitmap_file = NULL;
770 }
771 /* use default icon if nothing specified */
772 else if (tmp_win->icon_image == NULL)
773 tmp_win->icon_bitmap_file = scr->DefaultIcon;
774
775 PROP_GetWindowSizeHints(tmp_win);
776
777 /* Tentative size estimate */
778 tmp_win->frame_width = tmp_win->attr.width +
779 2 * tmp_win->boundary_width +
780 2 * tmp_win->matte_width;
781 tmp_win->frame_height = tmp_win->attr.height +
782 tmp_win->title_height +
783 2 * tmp_win->boundary_width +
784 2 * tmp_win->matte_width;
785
786 WIN_ConstrainWindow(scr, tmp_win,
787 &tmp_win->frame_width, &tmp_win->frame_height);
788
789 if (!place_window(scr, tmp_win))
790 return NULL;
791
792 /*
793 * Make sure the client window still exists. We don't want to leave an
794 * orphan frame window if it doesn't. Since we now have the server
795 * grabbed, the window can't disappear later without having been
796 * reparented, so we'll get a DestroyNotify for it. We won't have
797 * gotten one for anything up to here, however.
798 */
799 XGrabServer(dpy);
800
801 if (XGetGeometry(dpy, w, &JunkRoot, &JunkX, &JunkY,
802 &JunkWidth, &JunkHeight,
803 &JunkBW, &JunkDepth) == 0)
804 {
805 XtFree((char *)tmp_win);
806 XUngrabServer(dpy);
807 return (NULL);
808 }
809
810 XSetWindowBorderWidth(dpy, tmp_win->w, 0);
811
812 if (tmp_win->icon_label == NULL)
813 tmp_win->icon_label = tmp_win->classhint.res_name;
814 tmp_win->icon_active_label = tmp_win->name;
815
816 tmp_win->flags &= ~ICONIFIED;
817 tmp_win->flags &= ~ICON_UNMAPPED;
818 tmp_win->flags &= ~MAXIMIZED;
819
820 /* add the window into the mwm list */
821 MISC_AddToTree(scr, tmp_win);
822
823 DEC_CreateDecorations(scr, tmp_win);
824
825 if (XGetWMName(dpy, tmp_win->w, &text_prop) != 0)
826 tmp_win->name = (char *)text_prop.value;
827 else
828 tmp_win->name = NoName;
829
830 if (tmp_win->w != scr->pager_win && tmp_win->w != scr->restart_win &&
831 tmp_win->w != scr->quit_win && tmp_win->w != scr->toggle_win)
832 XAddToSaveSet(dpy, tmp_win->w);
833
834 /*
835 * Reparenting generates an UnmapNotify event, followed by a MapNotify.
836 * Set the map state to False to prevent a transition back to
837 * WithdrawnState in HandleUnmapNotify. Map state gets set correctly
838 * again in HandleMapNotify.
839 */
840 tmp_win->flags &= ~MAPPED;
841 width = tmp_win->frame_width;
842 tmp_win->frame_width = 0;
843 height = tmp_win->frame_height;
844 tmp_win->frame_height = 0;
845
846 DEC_ConfigureDecorations(scr, tmp_win, tmp_win->frame_x, tmp_win->frame_y,
847 width, height, True);
848
849 /* wait until the window is iconified and the icon window is mapped
850 * before creating the icon window
851 */
852 tmp_win->icon_w = None;
853
854 grab_buttons(scr, tmp_win);
855 grab_keys(scr, tmp_win);
856
857 save_context(tmp_win);
858
859 PROP_GetMwmMenu(tmp_win);
860
861 MENU_BuildWindowMenu(scr, tmp_win);
862
863 PROP_GetMwmMessages(tmp_win);
864
865 WIN_Raise(scr, tmp_win);
866
867 XUngrabServer(dpy);
868
869 XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
870 &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
871 XTranslateCoordinates(dpy, tmp_win->frame, scr->root_win, JunkX, JunkY,
872 &tx, &ty, &JunkChild);
873 tmp_win->xdiff -= tx;
874 tmp_win->ydiff -= ty;
875
876 if (Mwm.keyboard_focus_policy == XmEXPLICIT)
877 {
878 /* need to grab all buttons for window that we are about to
879 * unhighlight */
880 for (i = 0; i < 3; i++)
881 if (scr->buttons2grab & (1 << i))
882 {
883 XGrabButton(dpy, (i + 1), 0, tmp_win->frame, True,
884 ButtonPressMask, GrabModeSync, GrabModeAsync, None,
885 scr->cursors[SYS_CURS]);
886 XGrabButton(dpy, (i + 1), LockMask, tmp_win->frame, True,
887 ButtonPressMask, GrabModeSync, GrabModeAsync, None,
888 scr->cursors[SYS_CURS]);
889 }
890 }
891
892 PROP_GetWmProtocols(tmp_win);
893 PROP_GetWmColormapWindows(tmp_win);
894
895 if (!(XGetWindowAttributes(dpy, tmp_win->w, &(tmp_win->attr))))
896 tmp_win->attr.colormap = scr->mwm_root.attr.colormap;
897
898 if (NeedToResizeToo)
899 {
900 int show_feed;
901
902 XWarpPointer(dpy, scr->root_win, scr->root_win, 0, 0, scr->d_width,
903 scr->d_height,
904 tmp_win->frame_x + (tmp_win->frame_width >> 1),
905 tmp_win->frame_y + (tmp_win->frame_height >> 1));
906
907 show_feed = Mwm.show_feedback & MWM_FEEDBACK_RESIZE;
908
909 if (!(Mwm.show_feedback & MWM_FEEDBACK_PLACEMENT))
910 Mwm.show_feedback &= ~MWM_FEEDBACK_RESIZE;
911
912 RESIZE_EventLoop(scr, tmp_win->w, tmp_win, 0, 0, 0, 0);
913
914 if (show_feed)
915 Mwm.show_feedback |= MWM_FEEDBACK_RESIZE;
916 }
917
918 COLOR_InstallWindowColorMap(scr, scr->mwm_colormap);
919
920 return (tmp_win);
921 }
922
923 /*
924 * release a window and the subs
925 */
926 static void
release_window(ScreenInfo * scr,MwmWindow * win)927 release_window(ScreenInfo *scr, MwmWindow *win)
928 {
929 MwmWindow *tmp;
930
931 for (tmp = win->child; tmp != NULL; tmp = tmp->next)
932 release_window(scr, tmp);
933
934 XUnmapWindow(dpy, win->frame);
935 WIN_RestoreWithdrawn(scr, win, True);
936 XDestroyWindow(dpy, win->frame);
937 }
938
939 /*
940 * count the transient children of a window
941 */
942 static int
count_transients(ScreenInfo * scr,MwmWindow * win)943 count_transients(ScreenInfo *scr, MwmWindow *win)
944 {
945 MwmWindow *tmp;
946 int count = 0;
947
948 for (tmp = win->child; tmp != NULL; tmp = tmp->next)
949 {
950 count++;
951 count += count_transients(scr, tmp);
952 if ((scr->pager_win) && !(tmp->flags & STICKY))
953 XRaiseWindow(dpy, tmp->pager_view);
954 if ((tmp->flags & ICONIFIED))
955 {
956 count += 2;
957 }
958 }
959
960 return count;
961 }
962
963 /*
964 * gather up the transients
965 */
966 static void
gather_transients(MwmWindow * win,Window * wins,int * count)967 gather_transients(MwmWindow *win, Window *wins, int *count)
968 {
969 MwmWindow *tmp;
970
971 for (tmp = win->child; tmp != NULL; tmp = tmp->next)
972 gather_transients(tmp, wins, count);
973
974 for (tmp = win->child; tmp != NULL; tmp = tmp->next)
975 {
976 wins[(*count)++] = tmp->frame;
977 if ((tmp->flags & ICONIFIED))
978 {
979 wins[(*count)++] = tmp->icon_w;
980 wins[(*count)++] = tmp->icon_pixmap_w;
981 }
982 }
983 }
984
985 /*
986 * lower our children before ourselves
987 */
988 static void
lower_children(MwmWindow * win)989 lower_children(MwmWindow *win)
990 {
991 MwmWindow *tmp;
992
993 if (win == NULL)
994 return;
995
996 for (tmp = win; tmp != NULL; tmp = tmp->next)
997 {
998 if (tmp->child)
999 lower_children(tmp->child);
1000 XLowerWindow(dpy, tmp->w);
1001 }
1002 }
1003
1004 /*
1005 * Decorates all windows at start-up
1006 */
1007 void
WIN_CaptureWindows(ScreenInfo * scr)1008 WIN_CaptureWindows(ScreenInfo *scr)
1009 {
1010 unsigned int i, j;
1011 unsigned int nchildren;
1012 Window root, parent, *children;
1013
1014 PPosOverride = True;
1015
1016 if (!XQueryTree(dpy, scr->root_win, &root, &parent, &children, &nchildren))
1017 return;
1018
1019 /*
1020 * weed out icon windows
1021 */
1022 for (i = 0; i < nchildren; i++)
1023 {
1024 if (children[i])
1025 {
1026 XWMHints *wmhintsp = XGetWMHints(dpy, children[i]);
1027
1028 if (wmhintsp)
1029 {
1030 if (wmhintsp->flags & IconWindowHint)
1031 {
1032 for (j = 0; j < nchildren; j++)
1033 {
1034 if (children[j] == wmhintsp->icon_window)
1035 {
1036 children[j] = None;
1037 break;
1038 }
1039 }
1040 }
1041 XFree((char *)wmhintsp);
1042 }
1043 }
1044 }
1045
1046 /*
1047 * map all of the non-override windows
1048 */
1049 for (i = 0; i < nchildren; i++)
1050 {
1051 if (children[i] && mapped_not_override(scr, children[i]))
1052 {
1053 /* Why the unmap? MLM */
1054 /* Answering my own question: if the unmap isn't there, when
1055 * the window manager restarts, any transients lying around never
1056 * get they're MAPPED flag set (no map event, so they don't go
1057 * through normal channels. I'm not happy with this, but for now
1058 * I'm going to keep it. Actually, it should be ok as long as
1059 * any transient children aren't modal. If they are, we'll need
1060 * to fixup the window trees based on that modality after the
1061 * capture procedure.
1062 */
1063 XUnmapWindow(dpy, children[i]);
1064 WIN_MapWindow(scr, children[i]);
1065 }
1066 }
1067
1068 isIconicState = DontCareState;
1069
1070 if (nchildren > 0)
1071 XFree((char *)children);
1072
1073 /* after the windows already on the screen are in place,
1074 * don't use PPosition */
1075 PPosOverride = False;
1076 }
1077
1078 /*
1079 * release window decorations when exiting
1080 */
1081 void
WIN_ReleaseWindows(ScreenInfo * scr)1082 WIN_ReleaseWindows(ScreenInfo *scr)
1083 {
1084 MwmWindow *tmp; /* temp mwm window structure */
1085
1086 /*
1087 * remove the frame components from all the windows
1088 */
1089 XGrabServer(dpy);
1090
1091 if (scr->pager_win != None)
1092 XDestroyWindow(dpy, scr->pager_win);
1093
1094 COLOR_InstallWindowColorMap(scr, &scr->mwm_root); /* force reinstall */
1095 for (tmp = scr->mwm_root.next; tmp != NULL; tmp = tmp->next)
1096 release_window(scr, tmp);
1097
1098 MENU_DestroyMenus(scr);
1099
1100 XUngrabServer(dpy);
1101 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
1102 XSync(dpy, 0);
1103 }
1104
1105 /*
1106 * find the MwmWindow structure associated with a Window
1107 */
1108 MwmWindow *
WIN_WindowToStruct(ScreenInfo * scr,Window target)1109 WIN_WindowToStruct(ScreenInfo *scr, Window target)
1110 {
1111 MwmWindow *t, *tmp_win = 0;
1112
1113 tmp_win = NULL;
1114 for (t = scr->mwm_root.next; t != NULL; t = t->next)
1115 {
1116 if (t->pager_view == target)
1117 {
1118 tmp_win = t;
1119 }
1120 }
1121 return tmp_win;
1122 }
1123
1124 /*
1125 * set the focus window in a window tree
1126 */
1127 void
WIN_SetFocusInTree(MwmWindow * leaf)1128 WIN_SetFocusInTree(MwmWindow *leaf)
1129 {
1130 MwmWindow *root;
1131
1132 root = MISC_RootOfTree(leaf);
1133
1134 if (root)
1135 root->focus_in_tree = leaf;
1136 }
1137
1138 /*
1139 * Sets the input focus to the indicated window.
1140 */
1141 void
WIN_SetFocus(ScreenInfo * scr,Window w,MwmWindow * Fw)1142 WIN_SetFocus(ScreenInfo *scr, Window w, MwmWindow *Fw)
1143 {
1144 int i;
1145
1146 /* XmEXPLICIT keyboard focus policy queue manipulation */
1147 if (Fw && Fw != scr->mwm_focus && Fw != &scr->mwm_root)
1148 {
1149 MwmWindow *anc;
1150
1151 anc = Fw->ancestor;
1152
1153 MISC_RemoveFromTree(scr, Fw);
1154 MISC_AddToTree(scr, Fw);
1155
1156 anc = MISC_RootOfTree(Fw);
1157
1158 if (Fw != anc->focus_in_tree)
1159 {
1160 Fw = anc->focus_in_tree;
1161 /* Without the if statement below, we can crash here.
1162 * Danny 16/4/97 */
1163 if (Fw)
1164 {
1165 w = Fw->w;
1166 }
1167 }
1168 }
1169
1170 if (Mwm.number_of_screens > 1)
1171 {
1172 XQueryPointer(dpy, scr->root_win, &JunkRoot, &JunkChild,
1173 &JunkX, &JunkY, &JunkX, &JunkY, &JunkMask);
1174 if (JunkRoot != scr->root_win)
1175 {
1176 if ((Mwm.keyboard_focus_policy == XmEXPLICIT) &&
1177 (scr->mwm_grabbing != NULL))
1178 {
1179 /* Need to grab buttons for focus window */
1180 XSync(dpy, 0);
1181 for (i = 0; i < 3; i++)
1182 if (scr->buttons2grab & (1 << i))
1183 {
1184 XGrabButton(dpy, (i + 1), 0, scr->mwm_grabbing->frame, True,
1185 ButtonPressMask, GrabModeSync, GrabModeAsync,
1186 None, scr->cursors[SYS_CURS]);
1187 XGrabButton(dpy, (i + 1), LockMask, scr->mwm_grabbing->frame, True,
1188 ButtonPressMask, GrabModeSync, GrabModeAsync,
1189 None, scr->cursors[SYS_CURS]);
1190 }
1191 scr->mwm_focus = NULL;
1192 scr->mwm_grabbing = NULL;
1193 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, MISC_FetchEventTime());
1194 }
1195 return;
1196 }
1197 }
1198
1199 if ((Fw != NULL) && (Fw->Desk != scr->current_desk))
1200 {
1201 Fw = NULL;
1202 w = scr->no_focus_win;
1203 }
1204
1205 if ((Mwm.keyboard_focus_policy == XmEXPLICIT) && (scr->mwm_grabbing != Fw))
1206 {
1207 /* need to grab all buttons for window that we are about to
1208 * unfocus */
1209 if (scr->mwm_grabbing != NULL)
1210 {
1211 XSync(dpy, 0);
1212 for (i = 0; i < 3; i++)
1213 if (scr->buttons2grab & (1 << i))
1214 {
1215 XGrabButton(dpy, (i + 1), 0, scr->mwm_grabbing->frame, True,
1216 ButtonPressMask, GrabModeSync, GrabModeAsync, None,
1217 scr->cursors[SYS_CURS]);
1218 XGrabButton(dpy, (i + 1), LockMask, scr->mwm_grabbing->frame, True,
1219 ButtonPressMask, GrabModeSync, GrabModeAsync, None,
1220 scr->cursors[SYS_CURS]);
1221 }
1222 scr->mwm_grabbing = NULL;
1223 }
1224 /* if we do click to focus, remove the grab on mouse events that
1225 * was made to detect the focus change */
1226 if ((Mwm.keyboard_focus_policy == XmEXPLICIT) && (Fw != NULL))
1227 {
1228 for (i = 0; i < 3; i++)
1229 if (scr->buttons2grab & (1 << i))
1230 {
1231 XUngrabButton(dpy, (i + 1), 0, Fw->frame);
1232 XUngrabButton(dpy, (i + 1), LockMask, Fw->frame);
1233 }
1234 scr->mwm_grabbing = Fw;
1235 }
1236 }
1237 if ((Fw) && (Fw->flags & ICONIFIED) && (Fw->icon_w))
1238 {
1239 w = Fw->icon_w;
1240 ICON_UpdateWindow(scr, Fw, True);
1241 }
1242
1243 if (!((Fw) && (Fw->wmhints) && (Fw->wmhints->flags & InputHint) &&
1244 (Fw->wmhints->input == False)))
1245 {
1246 /* Window rw; */
1247 /* int rt; */
1248
1249 /* Window will accept input focus */
1250 /* MLM: 6/??/98. A very weird thing can happen here. We set
1251 * the focus, but if you add a call just below here to XGetInputFocus(),
1252 * you'll see that the focus has reverted to the old value. I *think*
1253 * this is due to the XSetInputFocus calls in the menu system -- I
1254 * think there is a race condition where a dying application with
1255 * a posted menu can reclaim the focus *after* their window manager
1256 * info is gone (matte and decor), but before the application
1257 * really terminates. This manifests itself as a "missing" FocusIn
1258 * event, but we receive the FocusOut event when the window finally
1259 * goes away. The (hack) fix for this is in events.c (see FocusOut
1260 * in the event handler).
1261 */
1262 XSetInputFocus(dpy, w, RevertToParent, MISC_FetchEventTime());
1263 scr->mwm_focus = Fw;
1264 }
1265 else if ((scr->mwm_focus) && (scr->mwm_focus->Desk == scr->current_desk))
1266 {
1267 /* Window doesn't want focus. Leave focus alone */
1268 /* XSetInputFocus (dpy,scr->mwm_highlight->w , RevertToParent, MISC_FetchEventTime()); */
1269 }
1270 else
1271 {
1272 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, MISC_FetchEventTime());
1273 scr->mwm_focus = NULL;
1274 }
1275
1276 if ((Fw) && (Fw->flags & WM_TAKES_FOCUS))
1277 PROP_SendClientMessage(w, XA_WM_TAKE_FOCUS, MISC_FetchEventTime());
1278
1279 XSync(dpy, 0);
1280 }
1281
1282 /*
1283 * Moves focus to specified window
1284 */
1285 void
WIN_ChangeFocus(ScreenInfo * scr,MwmWindow * t,int DeIconifyOnly)1286 WIN_ChangeFocus(ScreenInfo *scr, MwmWindow *t, int DeIconifyOnly)
1287 {
1288 int dx, dy;
1289 int cx, cy;
1290 int x, y;
1291
1292 if (t == (MwmWindow *)0)
1293 return;
1294
1295 if (t->Desk != scr->current_desk)
1296 DT_ChangeDesks(scr, 0, t->Desk);
1297
1298 if (t->flags & ICONIFIED)
1299 {
1300 cx = t->icon_xl_loc + t->icon_w_width / 2;
1301 cy = t->icon_y_loc + t->icon_p_height +
1302 (scr->components[MWM_ICON].f_height + 6) / 2;
1303 }
1304 else
1305 {
1306 cx = t->frame_x + t->frame_width / 2;
1307 cy = t->frame_y + t->frame_height / 2;
1308 }
1309
1310 dx = (cx + scr->virt_x) / scr->d_width * scr->d_width;
1311 dy = (cy + scr->virt_y) / scr->d_height * scr->d_height;
1312
1313 PAGER_MoveViewPort(scr, dx, dy, True);
1314
1315 if (t->flags & ICONIFIED)
1316 {
1317 x = t->icon_xl_loc + t->icon_w_width / 2;
1318 y = t->icon_y_loc + t->icon_p_height +
1319 (scr->components[MWM_ICON].f_height + 6) / 2;
1320 }
1321 else
1322 {
1323 x = t->frame_x;
1324 y = t->frame_y;
1325 }
1326 if (!(Mwm.keyboard_focus_policy == XmEXPLICIT))
1327 XWarpPointer(dpy, None, scr->root_win, 0, 0, 0, 0, x + 2, y + 2);
1328 WIN_Raise(scr, t);
1329
1330 /* If the window is still not visible, make it visible! */
1331 if (((t->frame_x + t->frame_height) < 0) || (t->frame_y + t->frame_width < 0) ||
1332 (t->frame_x > scr->d_width) || (t->frame_y > scr->d_height))
1333 {
1334 DEC_ConfigureDecorations(scr, t, 0, 0, t->frame_width, t->frame_height, False);
1335 if (!(Mwm.keyboard_focus_policy == XmEXPLICIT))
1336 XWarpPointer(dpy, None, scr->root_win, 0, 0, 0, 0, 2, 2);
1337 }
1338 MISC_Ungrab(scr);
1339 WIN_SetFocus(scr, t->w, t);
1340 }
1341
1342 /*
1343 * Puts windows back where they were before mwm took over
1344 */
1345 void
WIN_RestoreWithdrawn(ScreenInfo * scr,MwmWindow * tmp,Boolean restart)1346 WIN_RestoreWithdrawn(ScreenInfo *scr, MwmWindow *tmp, Boolean restart)
1347 {
1348 int a, b, w2, h2;
1349 unsigned int bw, mask;
1350 XWindowChanges xwc;
1351
1352 if (!tmp)
1353 return;
1354
1355 if (XGetGeometry(dpy, tmp->w, &JunkRoot, &xwc.x, &xwc.y,
1356 &JunkWidth, &JunkHeight, &bw, &JunkDepth))
1357 {
1358 XTranslateCoordinates(dpy, tmp->frame, scr->root_win, xwc.x, xwc.y,
1359 &a, &b, &JunkChild);
1360 xwc.x = a + tmp->xdiff;
1361 xwc.y = b + tmp->ydiff;
1362 xwc.border_width = tmp->old_bw;
1363 mask = (CWX | CWY | CWBorderWidth);
1364
1365 /* We can not assume that the window is currently on the screen.
1366 * Although this is normally the case, it is not always true. The
1367 * most common example is when the user does something in an
1368 * application which will, after some amount of computational delay,
1369 * cause the window to be unmapped, but then switches screens before
1370 * this happens. The XTranslateCoordinates call above will set the
1371 * window coordinates to either be larger than the screen, or negative.
1372 * This will result in the window being placed in odd, or even
1373 * unviewable locations when the window is remapped. The followin code
1374 * forces the "relative" location to be within the bounds of the display.
1375 *
1376 * gpw -- 11/11/93
1377 *
1378 * Unfortunately, this does horrendous things during re-starts,
1379 * hence the "if(restart) clause (RN)
1380 *
1381 * Also, fixed so that it only does this stuff if a window is more than
1382 * half off the screen. (RN)
1383 */
1384
1385 if (!restart)
1386 {
1387 /* Don't mess with it if its partially on the screen now */
1388 if ((tmp->frame_x < 0) || (tmp->frame_y < 0) ||
1389 (tmp->frame_x >= scr->d_width) ||
1390 (tmp->frame_y >= scr->d_height))
1391 {
1392 w2 = (tmp->frame_width >> 1);
1393 h2 = (tmp->frame_height >> 1);
1394 if ((xwc.x < -w2) || (xwc.x > (scr->d_width - w2)))
1395 {
1396 xwc.x = xwc.x % scr->d_width;
1397 if (xwc.x < -w2)
1398 xwc.x += scr->d_width;
1399 }
1400 if ((xwc.y < -h2) || (xwc.y > (scr->d_height - h2)))
1401 {
1402 xwc.y = xwc.y % scr->d_height;
1403 if (xwc.y < -h2)
1404 xwc.y += scr->d_height;
1405 }
1406 }
1407 }
1408 XReparentWindow(dpy, tmp->w, scr->root_win, xwc.x, xwc.y);
1409
1410 if ((tmp->flags & ICONIFIED))
1411 {
1412 if (tmp->icon_w)
1413 XUnmapWindow(dpy, tmp->icon_w);
1414 if (tmp->icon_pixmap_w)
1415 XUnmapWindow(dpy, tmp->icon_pixmap_w);
1416 }
1417
1418 XConfigureWindow(dpy, tmp->w, mask, &xwc);
1419 XSync(dpy, 0);
1420 }
1421 }
1422
1423 /*
1424 * raise a window
1425 */
1426 void
WIN_Raise(ScreenInfo * scr,MwmWindow * t)1427 WIN_Raise(ScreenInfo *scr, MwmWindow *t)
1428 {
1429 int count, i;
1430 Window *wins;
1431
1432 MISC_SetTimer(0);
1433
1434 /* raise the target, at least */
1435 count = 1;
1436
1437 count += count_transients(scr, t);
1438
1439 if ((t->flags & ICONIFIED))
1440 count += 2;
1441
1442 if ((scr->pager_win) && !(t->flags & STICKY))
1443 XRaiseWindow(dpy, t->pager_view);
1444
1445 wins = (Window *)XtMalloc(count * sizeof(Window));
1446
1447 i = 0;
1448
1449 /* now raise transients */
1450 gather_transients(t, wins, &i);
1451
1452 if ((t->flags & ICONIFIED))
1453 {
1454 wins[i++] = t->icon_w;
1455 wins[i++] = t->icon_pixmap_w;
1456 }
1457 wins[i++] = t->frame;
1458 scr->mwm_last_raised = t;
1459
1460 if (i > 0)
1461 XRaiseWindow(dpy, wins[0]);
1462
1463 XRestackWindows(dpy, wins, i);
1464 XtFree((char *)wins);
1465
1466 PAGER_Clear(scr);
1467
1468 PAN_Raise(scr);
1469 }
1470
1471 /*
1472 * lower a window
1473 */
1474 void
WIN_Lower(ScreenInfo * scr,MwmWindow * t)1475 WIN_Lower(ScreenInfo *scr, MwmWindow *t)
1476 {
1477 if (t->child)
1478 lower_children(t->child);
1479
1480 XLowerWindow(dpy, t->frame);
1481
1482 MISC_SetTimer(0);
1483
1484 if ((scr->pager_win) && !(t->flags & STICKY))
1485 XLowerWindow(dpy, t->pager_view);
1486
1487 if ((t->flags & ICONIFIED))
1488 {
1489 XLowerWindow(dpy, t->icon_w);
1490 XLowerWindow(dpy, t->icon_pixmap_w);
1491 }
1492 scr->mwm_last_raised = (MwmWindow *)0;
1493 if (scr->pager_child_win)
1494 XLowerWindow(dpy, scr->pager_child_win);
1495 PAGER_Clear(scr);
1496 }
1497
1498 /*
1499 * adjust the given width and height to account for the constraints imposed
1500 * by size hints
1501 * The general algorithm, especially the aspect ratio stuff, is borrowed from
1502 * uwm's CheckConsistency routine.
1503 */
1504 void
WIN_ConstrainWindow(ScreenInfo * scr,MwmWindow * tmp_win,int * widthp,int * heightp)1505 WIN_ConstrainWindow(ScreenInfo *scr, MwmWindow *tmp_win,
1506 int *widthp, int *heightp)
1507 {
1508 int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
1509 int baseWidth, baseHeight;
1510 int dwidth = *widthp, dheight = *heightp;
1511
1512 dwidth -= (2 * tmp_win->boundary_width + 2 * tmp_win->matte_width);
1513 dheight -= (tmp_win->title_height + 2 * tmp_win->boundary_width +
1514 2 * tmp_win->matte_width);
1515
1516 minWidth = tmp_win->hints.min_width;
1517 minHeight = tmp_win->hints.min_height;
1518
1519 baseWidth = tmp_win->hints.base_width;
1520 baseHeight = tmp_win->hints.base_height;
1521
1522 maxWidth = tmp_win->hints.max_width;
1523 maxHeight = tmp_win->hints.max_height;
1524
1525 /* maxWidth = scr->virt_x_max + scr->d_width;
1526 maxHeight = scr->virt_y_max + scr->d_height; */
1527
1528 xinc = tmp_win->hints.width_inc;
1529 yinc = tmp_win->hints.height_inc;
1530
1531 /*
1532 * First, clamp to min and max values
1533 */
1534 if (dwidth < minWidth)
1535 dwidth = minWidth;
1536 if (dheight < minHeight)
1537 dheight = minHeight;
1538
1539 if (dwidth > maxWidth)
1540 dwidth = maxWidth;
1541 if (dheight > maxHeight)
1542 dheight = maxHeight;
1543
1544 /*
1545 * Second, fit to base + N * inc
1546 */
1547 dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
1548 dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
1549
1550
1551 /*
1552 * Third, adjust for aspect ratio
1553 * The math looks like this:
1554 *
1555 * minAspectX dwidth maxAspectX
1556 * ---------- <= ------- <= ----------
1557 * minAspectY dheight maxAspectY
1558 *
1559 * If that is multiplied out, then the width and height are
1560 * invalid in the following situations:
1561 *
1562 * minAspectX * dheight > minAspectY * dwidth
1563 * maxAspectX * dheight < maxAspectY * dwidth
1564 *
1565 */
1566 if (tmp_win->hints.flags & PAspect)
1567 {
1568 if (MinAspectX(tmp_win) * dheight > MinAspectY(tmp_win) * dwidth)
1569 {
1570 delta = makemult(MinAspectX(tmp_win) * dheight /
1571 MinAspectY(tmp_win) - dwidth, xinc);
1572 if (dwidth + delta <= maxWidth)
1573 dwidth += delta;
1574 else
1575 {
1576 delta = makemult(dheight - dwidth * MinAspectY(tmp_win) /
1577 MinAspectX(tmp_win), yinc);
1578 if (dheight - delta >= minHeight)
1579 dheight -= delta;
1580 }
1581 }
1582
1583 if (MaxAspectX(tmp_win) * dheight < MaxAspectY(tmp_win) * dwidth)
1584 {
1585 delta = makemult(dwidth * MaxAspectY(tmp_win) /
1586 MaxAspectX(tmp_win) - dheight, yinc);
1587 if (dheight + delta <= maxHeight)
1588 dheight += delta;
1589 else
1590 {
1591 delta = makemult(dwidth - MaxAspectX(tmp_win) * dheight /
1592 MaxAspectY(tmp_win), xinc);
1593 if (dwidth - delta >= minWidth)
1594 dwidth -= delta;
1595 }
1596 }
1597 }
1598
1599
1600 /*
1601 * Fourth, account for border width and title height
1602 */
1603 *widthp = dwidth + 2 * tmp_win->boundary_width +
1604 2 * tmp_win->matte_width;
1605 *heightp = dheight + tmp_win->title_height +
1606 2 * tmp_win->boundary_width + 2 * tmp_win->matte_width;
1607 }
1608
1609 /*
1610 * move/draw a window outline
1611 */
1612 void
WIN_DrawOutline(ScreenInfo * scr,Window root,int x,int y,int width,int height)1613 WIN_DrawOutline(ScreenInfo *scr, Window root, int x, int y, int width, int height)
1614 {
1615 static int lastx = 0;
1616 static int lasty = 0;
1617 static int lastWidth = 0;
1618 static int lastHeight = 0;
1619 XRectangle rects[5];
1620
1621 if (x == lastx && y == lasty && width == lastWidth && height == lastHeight)
1622 return;
1623
1624 /* undraw the old one, if any */
1625 if (lastWidth || lastHeight)
1626 {
1627 rects[0].x = lastx;
1628 rects[0].y = lasty;
1629 rects[0].width = lastWidth;
1630 rects[0].height = lastHeight;
1631 rects[1].x = lastx + 1;
1632 rects[1].y = lasty + 1;
1633 rects[1].width = lastWidth - 2;
1634 rects[1].height = lastHeight - 2;
1635 rects[2].x = lastx + 2;
1636 rects[2].y = lasty + 2;
1637 rects[2].width = lastWidth - 4;
1638 rects[2].height = lastHeight - 4;
1639 rects[3].x = lastx + 3;
1640 rects[3].y = lasty + 3 + (lastHeight - 6) / 3;
1641 rects[3].width = lastWidth - 6;
1642 rects[3].height = (lastHeight - 6) / 3;
1643 rects[4].x = lastx + 3 + (lastWidth - 6) / 3;
1644 rects[4].y = lasty + 3;
1645 rects[4].width = (lastWidth - 6) / 3;
1646 rects[4].height = (lastHeight - 6);
1647 XDrawRectangles(dpy, scr->root_win, scr->resize_GC, rects, 5);
1648 }
1649
1650 lastx = x;
1651 lasty = y;
1652 lastWidth = width;
1653 lastHeight = height;
1654
1655 /* draw the new one, if any */
1656 if (lastWidth || lastHeight)
1657 {
1658 rects[0].x = lastx;
1659 rects[0].y = lasty;
1660 rects[0].width = lastWidth;
1661 rects[0].height = lastHeight;
1662 rects[1].x = lastx + 1;
1663 rects[1].y = lasty + 1;
1664 rects[1].width = lastWidth - 2;
1665 rects[1].height = lastHeight - 2;
1666 rects[2].x = lastx + 2;
1667 rects[2].y = lasty + 2;
1668 rects[2].width = lastWidth - 4;
1669 rects[2].height = lastHeight - 4;
1670 rects[3].x = lastx + 3;
1671 rects[3].y = lasty + 3 + (lastHeight - 6) / 3;
1672 rects[3].width = lastWidth - 6;
1673 rects[3].height = (lastHeight - 6) / 3;
1674 rects[4].x = lastx + 3 + (lastWidth - 6) / 3;
1675 rects[4].y = lasty + 3;
1676 rects[4].width = (lastWidth - 6) / 3;
1677 rects[4].height = (lastHeight - 6);
1678 XDrawRectangles(dpy, scr->root_win, scr->resize_GC, rects, 5);
1679 }
1680 }
1681
1682 /*
1683 * Releases dynamically allocated space used to store window/icon names
1684 */
1685 void
WIN_FreeNames(MwmWindow * tmp,Bool nukename,Bool nukeicon)1686 WIN_FreeNames(MwmWindow *tmp, Bool nukename, Bool nukeicon)
1687 {
1688 if (!tmp)
1689 return;
1690
1691 if (nukename && nukeicon)
1692 {
1693 if (tmp->name == tmp->icon_active_label)
1694 {
1695 if (tmp->name != NoName)
1696 XFree(tmp->name);
1697 tmp->name = NULL;
1698 tmp->icon_active_label = NULL;
1699 }
1700 else
1701 {
1702 if (tmp->name != NoName)
1703 XFree(tmp->name);
1704 tmp->name = NULL;
1705 if (tmp->icon_active_label != NoName)
1706 XFree(tmp->icon_active_label);
1707 tmp->icon_active_label = NULL;
1708 }
1709 }
1710 else if (nukename)
1711 {
1712 if (tmp->name != tmp->icon_active_label && tmp->name != NoName)
1713 XFree(tmp->name);
1714 tmp->name = NULL;
1715 }
1716 else
1717 { /* if (nukeicon) */
1718 if (tmp->icon_active_label != tmp->name && tmp->icon_active_label != NoName)
1719 XFree(tmp->icon_active_label);
1720 tmp->icon_active_label = NULL;
1721 }
1722 }
1723
1724 /*
1725 * map a window
1726 */
1727 void
WIN_MapWindow(ScreenInfo * scr,Window win)1728 WIN_MapWindow(ScreenInfo *scr, Window win)
1729 {
1730 MwmWindow *tmp;
1731
1732 if (XFindContext(dpy, win, MwmContext, (XPointer *)&tmp) == XCNOENT)
1733 tmp = NULL;
1734
1735 XFlush(dpy);
1736
1737 /* If the window has never been mapped before ... */
1738 if (!tmp)
1739 {
1740 /* Add decorations. */
1741 tmp = add_window(scr, win);
1742 if (tmp == NULL)
1743 return;
1744 }
1745
1746 /* If it's not merely iconified, and we have hints, use them. */
1747 if (!(tmp->flags & ICONIFIED))
1748 {
1749 int state;
1750
1751 if (tmp->wmhints && (tmp->wmhints->flags & StateHint))
1752 state = tmp->wmhints->initial_state;
1753 else
1754 state = NormalState;
1755
1756 if (tmp->flags & STARTICONIC)
1757 state = IconicState;
1758
1759 if (isIconicState != DontCareState)
1760 state = isIconicState;
1761
1762 XGrabServer(dpy);
1763 switch (state)
1764 {
1765 case DontCareState:
1766 case NormalState:
1767 case InactiveState:
1768 default:
1769 if (tmp->Desk == scr->current_desk)
1770 {
1771 XMapWindow(dpy, tmp->w);
1772 XMapWindow(dpy, tmp->frame);
1773 tmp->flags |= MAP_PENDING;
1774 PROP_SetState(tmp, NormalState);
1775 if (Mwm.keyboard_focus_policy == XmEXPLICIT &&
1776 Mwm.startup_key_focus)
1777 {
1778 WIN_SetFocusInTree(tmp);
1779 WIN_SetFocus(scr, tmp->w, tmp);
1780 MISC_SetFocusSequence(scr);
1781 }
1782 }
1783 else
1784 {
1785 XMapWindow(dpy, tmp->w);
1786 PROP_SetState(tmp, NormalState);
1787 }
1788 break;
1789
1790 case IconicState:
1791 ICON_Iconify(scr, tmp, 0, 0);
1792 break;
1793 }
1794 XSync(dpy, 0);
1795 XUngrabServer(dpy);
1796 }
1797 /* If no hints, or currently an icon, just "deiconify" */
1798 else
1799 ICON_DeIconify(scr, tmp);
1800 }
1801
1802 /*
1803 * Handles destruction of a window
1804 */
1805 void
WIN_DestroyWindow(ScreenInfo * scr,MwmWindow * tmp)1806 WIN_DestroyWindow(ScreenInfo *scr, MwmWindow *tmp)
1807 {
1808 int i;
1809
1810 /*
1811 * Warning, this is also called by HandleUnmapNotify; if it ever needs to
1812 * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
1813 * into a DestroyNotify.
1814 */
1815 if (!tmp)
1816 return;
1817
1818 MISC_DestroyChildren(scr, tmp);
1819
1820 MENU_DestroyWindowMenu(scr, tmp);
1821
1822 XUnmapWindow(dpy, tmp->frame);
1823 XSync(dpy, 0);
1824
1825 if (tmp == scr->mwm_highlight)
1826 {
1827 scr->mwm_highlight = NULL;
1828 }
1829
1830 if (scr->mwm_last_focus == tmp)
1831 {
1832 scr->mwm_last_focus = NULL;
1833 }
1834
1835 if (scr->mwm_event == tmp)
1836 {
1837 scr->mwm_event = NULL;
1838 }
1839
1840 if (tmp == scr->mwm_focus && Mwm.keyboard_focus_policy == XmEXPLICIT &&
1841 Mwm.auto_key_focus)
1842 {
1843 if (tmp->next != NULL)
1844 {
1845 WIN_SetFocusInTree(tmp->next);
1846 WIN_SetFocus(scr, tmp->next->w, tmp->next);
1847 }
1848 else if (tmp->ancestor)
1849 {
1850 WIN_SetFocusInTree(tmp->ancestor);
1851 WIN_SetFocus(scr, tmp->ancestor->w, tmp->ancestor);
1852 }
1853 else
1854 {
1855 WIN_SetFocus(scr, scr->no_focus_win, NULL);
1856 }
1857 }
1858
1859 MISC_RemoveFromTree(scr, tmp);
1860
1861 if (scr->mwm_focus == tmp)
1862 {
1863 WIN_SetFocus(scr, scr->no_focus_win, NULL);
1864 }
1865
1866 MISC_SetFocusSequence(scr);
1867
1868 if (tmp == scr->mwm_pushed)
1869 scr->mwm_pushed = NULL;
1870
1871 if (tmp == scr->mwm_colormap)
1872 scr->mwm_colormap = NULL;
1873
1874 XDestroyWindow(dpy, tmp->frame);
1875 XDeleteContext(dpy, tmp->frame, MwmContext);
1876
1877 XDestroyWindow(dpy, tmp->parent);
1878
1879 XDeleteContext(dpy, tmp->parent, MwmContext);
1880
1881 XDeleteContext(dpy, tmp->w, MwmContext);
1882
1883 if ((tmp->icon_w) && (tmp->flags & PIXMAP_OURS))
1884 XFreePixmap(dpy, tmp->icon_pixmap);
1885
1886 if ((scr->pager_win) && !(tmp->flags & STICKY))
1887 XDestroyWindow(dpy, tmp->pager_view);
1888
1889 if (tmp->icon_w)
1890 {
1891 XDestroyWindow(dpy, tmp->icon_w);
1892 XDeleteContext(dpy, tmp->icon_w, MwmContext);
1893 }
1894 if ((tmp->flags & ICON_OURS) && (tmp->icon_pixmap_w != None))
1895 XDestroyWindow(dpy, tmp->icon_pixmap_w);
1896 if (tmp->icon_pixmap_w != None)
1897 XDeleteContext(dpy, tmp->icon_pixmap_w, MwmContext);
1898
1899 for (i = 0; i < 4; i++)
1900 {
1901 if (tmp->icon_borders[i] != None)
1902 {
1903 XDestroyWindow(dpy, tmp->icon_borders[i]);
1904 XDeleteContext(dpy, tmp->icon_borders[i], MwmContext);
1905 }
1906 }
1907
1908 if (tmp->decorations & MWM_DECOR_TITLE)
1909 {
1910 XDeleteContext(dpy, tmp->title, MwmContext);
1911 if (tmp->menub != None)
1912 XDeleteContext(dpy, tmp->menub, MwmContext);
1913 if (tmp->menub != None)
1914 XDeleteContext(dpy, tmp->menub, MwmContext);
1915 }
1916 if (tmp->decorations & MWM_DECOR_BORDER)
1917 {
1918 for (i = 0; i < 4; i++)
1919 XDeleteContext(dpy, tmp->sides[i], MwmContext);
1920 }
1921 if (tmp->decorations & MWM_DECOR_RESIZEH)
1922 {
1923 for (i = 0; i < 4; i++)
1924 XDeleteContext(dpy, tmp->corners[i], MwmContext);
1925 }
1926
1927 WIN_FreeNames(tmp, True, True);
1928
1929 if (tmp->wmhints)
1930 XFree((char *)tmp->wmhints);
1931 if (tmp->classhint.res_name && tmp->classhint.res_name != NoName)
1932 XFree((char *)tmp->classhint.res_name);
1933 if (tmp->classhint.res_class && tmp->classhint.res_class != NoName)
1934 XFree((char *)tmp->classhint.res_class);
1935 if (tmp->mwm_hints)
1936 XFree((char *)tmp->mwm_hints);
1937 if (tmp->mwm_menu)
1938 XFree((char *)tmp->mwm_menu);
1939 if (tmp->mwm_messages)
1940 XFree((char *)tmp->mwm_messages);
1941
1942 if (tmp->cmap_windows != (Window *)NULL)
1943 XFree((void *)tmp->cmap_windows);
1944
1945 XtFree((char *)tmp);
1946
1947 PAGER_Clear(scr);
1948 XSync(dpy, 0);
1949 }
1950