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