add_window.c revision 645f5050
1/*****************************************************************************/
2/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
3/**                          Salt Lake City, Utah                           **/
4/**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
5/**                        Cambridge, Massachusetts                         **/
6/**                                                                         **/
7/**                           All Rights Reserved                           **/
8/**                                                                         **/
9/**    Permission to use, copy, modify, and distribute this software and    **/
10/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
11/**    granted, provided that the above copyright notice appear  in  all    **/
12/**    copies and that both  that  copyright  notice  and  this  permis-    **/
13/**    sion  notice appear in supporting  documentation,  and  that  the    **/
14/**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
15/**    in publicity pertaining to distribution of the  software  without    **/
16/**    specific, written prior permission.                                  **/
17/**                                                                         **/
18/**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
19/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
20/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
21/**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
22/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
23/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
24/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
25/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
26/*****************************************************************************/
27
28/*
29 *  [ ctwm ]
30 *
31 *  Copyright 1992 Claude Lecommandeur.
32 *
33 * Permission to use, copy, modify  and distribute this software  [ctwm] and
34 * its documentation for any purpose is hereby granted without fee, provided
35 * that the above  copyright notice appear  in all copies and that both that
36 * copyright notice and this permission notice appear in supporting documen-
37 * tation, and that the name of  Claude Lecommandeur not be used in adverti-
38 * sing or  publicity  pertaining to  distribution of  the software  without
39 * specific, written prior permission. Claude Lecommandeur make no represen-
40 * tations  about the suitability  of this software  for any purpose.  It is
41 * provided "as is" without express or implied warranty.
42 *
43 * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
44 * INCLUDING ALL  IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS.  IN NO
45 * EVENT SHALL  Claude Lecommandeur  BE LIABLE FOR ANY SPECIAL,  INDIRECT OR
46 * CONSEQUENTIAL  DAMAGES OR ANY  DAMAGES WHATSOEVER  RESULTING FROM LOSS OF
47 * USE, DATA  OR PROFITS,  WHETHER IN AN ACTION  OF CONTRACT,  NEGLIGENCE OR
48 * OTHER  TORTIOUS ACTION,  ARISING OUT OF OR IN  CONNECTION WITH THE USE OR
49 * PERFORMANCE OF THIS SOFTWARE.
50 *
51 * Author:  Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ]
52 */
53
54/**********************************************************************
55 *
56 * $XConsortium: add_window.c,v 1.153 91/07/10 13:17:26 dave Exp $
57 *
58 * Add a new window, put the titlbar and other stuff around
59 * the window
60 *
61 * 31-Mar-88 Tom LaStrange        Initial Version.
62 *
63 * Do the necessary modification to be integrated in ctwm.
64 * Can no longer be used for the standard twm.
65 *
66 * 22-April-92 Claude Lecommandeur.
67 *
68 **********************************************************************/
69
70#include <stdio.h>
71#include <string.h>
72#ifndef VMS
73#include <sys/time.h>
74#else
75#include <time.h>
76#endif
77#if defined(AIXV3) || defined(_SYSTYPE_SVR4) || defined(ibm) || defined __QNX__
78#include <sys/select.h>
79#endif
80#include "twm.h"
81#ifdef VMS
82#include <decw$include/Xatom.h>
83#else
84#include <X11/Xatom.h>
85#endif
86#include "add_window.h"
87#include "windowbox.h"
88#include "util.h"
89#include "resize.h"
90#include "parse.h"
91#include "list.h"
92#include "events.h"
93#include "menus.h"
94#include "screen.h"
95#include "icons.h"
96#include "iconmgr.h"
97#include "session.h"
98#include "mwmhints.h"
99
100#define gray_width 2
101#define gray_height 2
102static unsigned char gray_bits[] = {
103   0x02, 0x01};
104static unsigned char black_bits[] = {
105   0xFF, 0xFF};
106
107int AddingX;
108int AddingY;
109unsigned int AddingW;
110unsigned int AddingH;
111
112static int PlaceX = -1;
113static int PlaceY = -1;
114static void CreateWindowTitlebarButtons(TwmWindow *tmp_win);
115void DealWithNonSensicalGeometries(Display *dpy, Window vroot, TwmWindow *tmp_win);
116
117static void		splitWindowRegionEntry (WindowEntry	*we,
118						int grav1, int grav2,
119						int w, int h);
120static WindowEntry	*findWindowEntry (WorkSpace    *wl,
121					  TwmWindow    *tmp_win,
122					  WindowRegion **wrp);
123static WindowEntry	*prevWindowEntry (WindowEntry	*we,
124					  WindowRegion	*wr);
125static void		mergeWindowEntries (WindowEntry	*old, WindowEntry *we);
126
127char NoName[] = "Untitled"; /* name if no name is specified */
128int  resizeWhenAdd;
129
130extern Atom _OL_WIN_ATTR;
131
132#if defined(__hpux) && !defined(_XPG4_EXTENDED)
133#   define FDSET int*
134#else
135#   define FDSET fd_set*
136#endif
137/************************************************************************
138 *
139 *  Procedure:
140 *	GetGravityOffsets - map gravity to (x,y) offset signs for adding
141 *		to x and y when window is mapped to get proper placement.
142 *
143 ************************************************************************
144 */
145
146void GetGravityOffsets (TwmWindow *tmp,	/* window from which to get gravity */
147			int *xp, int *yp)	/* return values */
148{
149    static struct _gravity_offset {
150	int x, y;
151    } gravity_offsets[11] = {
152	{  0,  0 },			/* ForgetGravity */
153	{ -1, -1 },			/* NorthWestGravity */
154	{  0, -1 },			/* NorthGravity */
155	{  1, -1 },			/* NorthEastGravity */
156	{ -1,  0 },			/* WestGravity */
157	{  0,  0 },			/* CenterGravity */
158	{  1,  0 },			/* EastGravity */
159	{ -1,  1 },			/* SouthWestGravity */
160	{  0,  1 },			/* SouthGravity */
161	{  1,  1 },			/* SouthEastGravity */
162	{  0,  0 },			/* StaticGravity */
163    };
164    register int g = ((tmp->hints.flags & PWinGravity)
165		      ? tmp->hints.win_gravity : NorthWestGravity);
166
167    if (g < ForgetGravity || g > StaticGravity) {
168	*xp = *yp = 0;
169    } else {
170	*xp = gravity_offsets[g].x;
171	*yp = gravity_offsets[g].y;
172    }
173}
174
175
176
177
178/***********************************************************************
179 *
180 *  Procedure:
181 *	AddWindow - add a new window to the twm list
182 *
183 *  Returned Value:
184 *	(TwmWindow *) - pointer to the TwmWindow structure
185 *
186 *  Inputs:
187 *	w	- the window id of the window to add
188 *	iconm	- flag to tell if this is an icon manager window
189 *		0 --> normal window.
190 *		1 --> icon manager.
191 *		2 --> window box;
192 *		else --> iconmgr;
193 *
194 *	iconp	- pointer to icon manager struct
195 *
196 ***********************************************************************
197 */
198
199TwmWindow *AddWindow(Window w, int iconm, IconMgr *iconp)
200{
201    virtualScreen *vs;
202    TwmWindow *tmp_win;			/* new twm window structure */
203    int stat;
204    XEvent event;
205    unsigned long valuemask;		/* mask for create windows */
206    XSetWindowAttributes attributes;	/* attributes for create windows */
207    int width, height;			/* tmp variable */
208    int ask_user;		/* don't know where to put the window */
209    int gravx, gravy;			/* gravity signs for positioning */
210    int namelen;
211    int bw2;
212    short saved_x, saved_y, restore_icon_x, restore_icon_y;
213    unsigned short saved_width, saved_height;
214    Bool restore_iconified = 0;
215    Bool restore_icon_info_present = 0;
216    int restoredFromPrevSession;
217    Bool width_ever_changed_by_user;
218    Bool height_ever_changed_by_user;
219    int saved_occupation; /* <== [ Matthew McNeill Feb 1997 ] == */
220    Bool        random_placed = False;
221    int		found = 0;
222#ifndef VMS
223    fd_set	mask;
224    int		fd;
225    struct timeval timeout;
226#endif
227    XRectangle ink_rect;
228    XRectangle logical_rect;
229    WindowBox *winbox;
230    int iswinbox = 0;
231    int iswman = 0;
232    Window vroot;
233
234#ifdef DEBUG
235    fprintf(stderr, "AddWindow: w = 0x%x\n", w);
236#endif
237
238    if (!captive && RedirectToCaptive (w)) return (NULL);
239
240    /* allocate space for the twm window */
241    tmp_win = (TwmWindow *)calloc(1, sizeof(TwmWindow));
242    if (tmp_win == 0)
243    {
244	fprintf (stderr, "%s: Unable to allocate memory to manage window ID %lx.\n",
245		 ProgramName, w);
246	return NULL;
247    }
248    switch (iconm) {
249	case  0 : iswinbox = 0; break;
250	case  1 : iswinbox = 0; break;
251	case  2 : iswinbox = 1; iconm  = 0; break;
252	case  3 : iswman   = 1; iconm  = 0; break;
253	default : iswinbox = 0; iswman = 0; iconm = 1; break;
254    }
255    tmp_win->w = w;
256    tmp_win->zoomed = ZOOM_NONE;
257    tmp_win->iconmgr = iconm;
258    tmp_win->iconmgrp = iconp;
259    tmp_win->wspmgr = iswman;
260    tmp_win->iswinbox = iswinbox;
261    tmp_win->vs = NULL;
262    tmp_win->old_parent_vs = NULL;
263    tmp_win->savevs = NULL;
264    tmp_win->cmaps.number_cwins = 0;
265    tmp_win->savegeometry.width = -1;
266
267    XSelectInput(dpy, tmp_win->w, PropertyChangeMask);
268    XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr);
269    tmp_win->name = (char*) GetWMPropertyString(tmp_win->w, XA_WM_NAME);
270    tmp_win->class = NoClass;
271    XGetClassHint(dpy, tmp_win->w, &tmp_win->class);
272    FetchWmProtocols (tmp_win);
273    FetchWmColormapWindows (tmp_win);
274
275    if (GetWindowConfig (tmp_win,
276	&saved_x, &saved_y, &saved_width, &saved_height,
277	&restore_iconified, &restore_icon_info_present,
278	&restore_icon_x, &restore_icon_y,
279	&width_ever_changed_by_user, &height_ever_changed_by_user,
280	&saved_occupation)) /* <== [ Matthew McNeill Feb 1997 ] == */
281    {
282	tmp_win->attr.x = saved_x;
283	tmp_win->attr.y = saved_y;
284
285	tmp_win->widthEverChangedByUser = width_ever_changed_by_user;
286	tmp_win->heightEverChangedByUser = height_ever_changed_by_user;
287
288	if (width_ever_changed_by_user)
289	    tmp_win->attr.width = saved_width;
290
291	if (height_ever_changed_by_user)
292	    tmp_win->attr.height = saved_height;
293
294	restoredFromPrevSession = 1;
295    }
296    else
297    {
298	tmp_win->widthEverChangedByUser = False;
299	tmp_win->heightEverChangedByUser = False;
300
301	restoredFromPrevSession = 0;
302    }
303
304    /*
305     * do initial clip; should look at window gravity
306     */
307    if (tmp_win->attr.width > Scr->MaxWindowWidth)
308      tmp_win->attr.width = Scr->MaxWindowWidth;
309    if (tmp_win->attr.height > Scr->MaxWindowHeight)
310      tmp_win->attr.height = Scr->MaxWindowHeight;
311
312    tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w);
313
314    if (tmp_win->wmhints)
315    {
316	if (restore_iconified)
317	{
318	    tmp_win->wmhints->initial_state = IconicState;
319	    tmp_win->wmhints->flags |= StateHint;
320	}
321
322	if (restore_icon_info_present)
323	{
324	    tmp_win->wmhints->icon_x = restore_icon_x;
325	    tmp_win->wmhints->icon_y = restore_icon_y;
326	    tmp_win->wmhints->flags |= IconPositionHint;
327	}
328    }
329
330    if (tmp_win->wmhints) tmp_win->wmhints->input = True;
331				/* CL: Having with not willing focus
332				cause problems with AutoSqueeze and a few others
333				things. So I suppress it. And the whole focus thing
334				is buggy anyway */
335    if (tmp_win->wmhints && !(tmp_win->wmhints->flags & InputHint))
336	tmp_win->wmhints->input = True;
337    if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint)) {
338	tmp_win->group = tmp_win->wmhints->window_group;
339	if (tmp_win->group) {
340	    /*
341	     * GTK windows often have a spurious "group leader" window which is
342	     * never reported to us and therefore does not really exist.  This
343	     * is annoying because we treat group members a lot like transient
344	     * windows.  Look for that here. It is in fact a duplicate of the
345	     * WM_CLIENT_LEADER property.
346	     */
347	    if (tmp_win->group != w && !GetTwmWindow(tmp_win->group)) {
348		tmp_win->group = 0;
349	    }
350	}
351    } else
352	tmp_win->group = 0;
353
354    /*
355     * The July 27, 1988 draft of the ICCCM ignores the size and position
356     * fields in the WM_NORMAL_HINTS property.
357     */
358
359    tmp_win->transient = Transient(tmp_win->w, &tmp_win->transientfor);
360
361    tmp_win->nameChanged = 0;
362    if (tmp_win->name == NULL)
363	tmp_win->name = NoName;
364    if (tmp_win->class.res_name == NULL)
365    	tmp_win->class.res_name = NoName;
366    if (tmp_win->class.res_class == NULL)
367    	tmp_win->class.res_class = NoName;
368
369    /*
370     * full_name seems to exist only because in the conditional code below,
371     * name is sometimes changed. In all other cases, name and full_name
372     * seem to be identical. Is that worth it?
373     */
374    tmp_win->full_name = tmp_win->name;
375#ifdef CLAUDE
376    if (strstr (tmp_win->name, " - Mozilla")) {
377      char *moz = strstr (tmp_win->name, " - Mozilla");
378      *moz = '\0';
379    }
380#endif
381    namelen = strlen (tmp_win->name);
382
383    if (LookInList(Scr->IgnoreTransientL, tmp_win->full_name, &tmp_win->class))
384      tmp_win->transient = 0;
385
386    tmp_win->highlight = Scr->Highlight &&
387	(!LookInList(Scr->NoHighlight, tmp_win->full_name,
388	    &tmp_win->class));
389
390    tmp_win->stackmode = Scr->StackMode &&
391	(!LookInList(Scr->NoStackModeL, tmp_win->full_name,
392	    &tmp_win->class));
393
394    tmp_win->ontoppriority = (LookInList(Scr->AlwaysOnTopL,
395	tmp_win->full_name, &tmp_win->class)) ? ONTOP_MAX : ONTOP_DEFAULT;
396
397    tmp_win->titlehighlight = Scr->TitleHighlight &&
398	(!LookInList(Scr->NoTitleHighlight, tmp_win->full_name,
399	    &tmp_win->class));
400
401    tmp_win->auto_raise = Scr->AutoRaiseDefault ||
402	LookInList(Scr->AutoRaise, tmp_win->full_name,
403			      &tmp_win->class);
404    if (tmp_win->auto_raise) Scr->NumAutoRaises++;
405
406    tmp_win->auto_lower = Scr->AutoLowerDefault ||
407	LookInList(Scr->AutoLower, tmp_win->full_name,
408			      &tmp_win->class);
409    if (tmp_win->auto_lower) Scr->NumAutoLowers++;
410
411    tmp_win->iconify_by_unmapping = Scr->IconifyByUnmapping;
412    if (Scr->IconifyByUnmapping)
413    {
414	tmp_win->iconify_by_unmapping = iconm ? FALSE :
415	    !LookInList(Scr->DontIconify, tmp_win->full_name,
416		&tmp_win->class);
417    }
418    tmp_win->iconify_by_unmapping = tmp_win->iconify_by_unmapping ||
419	LookInList(Scr->IconifyByUn, tmp_win->full_name, &tmp_win->class);
420
421    if (LookInList (Scr->UnmapByMovingFarAway, tmp_win->full_name, &tmp_win->class))
422	tmp_win->UnmapByMovingFarAway = True;
423    else
424	tmp_win->UnmapByMovingFarAway = False;
425
426    if (LookInList (Scr->DontSetInactive, tmp_win->full_name, &tmp_win->class))
427	tmp_win->DontSetInactive = True;
428    else
429	tmp_win->DontSetInactive = False;
430
431    if (LookInList (Scr->AutoSqueeze, tmp_win->full_name, &tmp_win->class))
432	tmp_win->AutoSqueeze = True;
433    else
434	tmp_win->AutoSqueeze = False;
435
436    if (LookInList (Scr->StartSqueezed, tmp_win->full_name, &tmp_win->class))
437	tmp_win->StartSqueezed = True;
438    else
439	tmp_win->StartSqueezed = False;
440
441    if (Scr->AlwaysSqueezeToGravity
442	|| LookInList (Scr->AlwaysSqueezeToGravityL, tmp_win->full_name, &tmp_win->class))
443	tmp_win->AlwaysSqueezeToGravity = True;
444    else
445	tmp_win->AlwaysSqueezeToGravity = False;
446
447    if (tmp_win->transient || tmp_win->group) {
448	TwmWindow *t = NULL;
449	if (tmp_win->transient) t = GetTwmWindow(tmp_win->transientfor);
450	if (!t && tmp_win->group) t = GetTwmWindow(tmp_win->group);
451	if (t) tmp_win->UnmapByMovingFarAway = t->UnmapByMovingFarAway;
452    }
453    if ((Scr->WindowRingAll && !iswman &&
454	!LookInList(Scr->WindowRingExcludeL, tmp_win->full_name, &tmp_win->class)) ||
455	LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->class)) {
456	if (Scr->Ring) {
457	    tmp_win->ring.next = Scr->Ring->ring.next;
458	    if (Scr->Ring->ring.next->ring.prev)
459	      Scr->Ring->ring.next->ring.prev = tmp_win;
460	    Scr->Ring->ring.next = tmp_win;
461	    tmp_win->ring.prev = Scr->Ring;
462	} else {
463	    tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
464	}
465    } else
466      tmp_win->ring.next = tmp_win->ring.prev = NULL;
467    tmp_win->ring.cursor_valid = False;
468
469    tmp_win->squeeze_info = NULL;
470    tmp_win->squeeze_info_copied = 0;
471    /*
472     * get the squeeze information; note that this does not have to be freed
473     * since it is coming from the screen list
474     */
475    if (HasShape) {
476	if (!LookInList (Scr->DontSqueezeTitleL, tmp_win->full_name,
477			 &tmp_win->class)) {
478	    tmp_win->squeeze_info = (SqueezeInfo *)
479	      LookInList (Scr->SqueezeTitleL, tmp_win->full_name,
480			  &tmp_win->class);
481	    if (!tmp_win->squeeze_info) {
482		static SqueezeInfo default_squeeze = { J_LEFT, 0, 0 };
483		if (Scr->SqueezeTitle)
484		  tmp_win->squeeze_info = &default_squeeze;
485	    }
486	}
487      }
488
489    tmp_win->old_bw = tmp_win->attr.border_width;
490
491    {
492	MotifWmHints mwmHints;
493	Boolean have_title;
494
495	GetMWMHints(tmp_win->w, &mwmHints);
496
497	tmp_win->frame_bw3D = Scr->ThreeDBorderWidth;
498	if (((mwmHints.flags & MWM_HINTS_DECORATIONS) &&
499		 (mwmHints.decorations & MWM_DECOR_BORDER) == 0)
500	    || LookInList(Scr->NoBorder, tmp_win->full_name, &tmp_win->class)) {
501	    tmp_win->frame_bw = 0;
502	    tmp_win->frame_bw3D = 0;
503	} else if (tmp_win->frame_bw3D != 0) {
504	    tmp_win->frame_bw = 0;
505	    Scr->ClientBorderWidth = FALSE;
506	} else if (Scr->ClientBorderWidth) {
507	    tmp_win->frame_bw = tmp_win->old_bw;
508	} else {
509	    tmp_win->frame_bw = Scr->BorderWidth;
510	}
511	bw2 = tmp_win->frame_bw * 2;
512
513
514	have_title = True;
515	if (mwmHints.flags & MWM_HINTS_DECORATIONS)
516	    have_title = (mwmHints.decorations & MWM_DECOR_TITLE) != 0;
517	if (Scr->NoTitlebar)
518	    have_title = False;
519	if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->class))
520	    have_title = True;
521	if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->class))
522	    have_title = False;
523
524	if (have_title) {
525	    tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
526	} else {
527	    tmp_win->title_height = 0;
528	}
529    }
530
531    tmp_win->OpaqueMove = Scr->DoOpaqueMove;
532    if (LookInList(Scr->OpaqueMoveList, tmp_win->full_name, &tmp_win->class))
533	tmp_win->OpaqueMove = TRUE;
534    else
535    if (LookInList(Scr->NoOpaqueMoveList, tmp_win->full_name, &tmp_win->class))
536	tmp_win->OpaqueMove = FALSE;
537
538    tmp_win->OpaqueResize = Scr->DoOpaqueResize;
539    if (LookInList(Scr->OpaqueResizeList, tmp_win->full_name, &tmp_win->class))
540	tmp_win->OpaqueResize = TRUE;
541    else
542    if (LookInList(Scr->NoOpaqueResizeList, tmp_win->full_name, &tmp_win->class))
543	tmp_win->OpaqueResize = FALSE;
544
545    /* if it is a transient window, don't put a title on it */
546    if (tmp_win->transient && !Scr->DecorateTransients)
547	tmp_win->title_height = 0;
548
549    if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->class))
550    {
551	if (!tmp_win->wmhints)
552	{
553	    tmp_win->wmhints = (XWMHints *)malloc(sizeof(XWMHints));
554	    tmp_win->wmhints->flags = 0;
555	}
556	tmp_win->wmhints->initial_state = IconicState;
557	tmp_win->wmhints->flags |= StateHint;
558    }
559
560    GetWindowSizeHints (tmp_win);
561
562    if (restoredFromPrevSession)
563    {
564	/*
565	 * When restoring window positions from the previous session,
566	 * we always use NorthWest gravity.
567	 */
568
569	gravx = gravy = -1;
570    }
571    else
572    {
573	GetGravityOffsets (tmp_win, &gravx, &gravy);
574    }
575
576    /*
577     * Don't bother user if:
578     *
579     *     o  the window is a transient, or
580     *
581     *     o  a USPosition was requested, or
582     *
583     *     o  a PPosition was requested and UsePPosition is ON or
584     *        NON_ZERO if the window is at other than (0,0)
585     */
586    ask_user = TRUE;
587    if (tmp_win->transient ||
588	(tmp_win->hints.flags & USPosition) ||
589        ((tmp_win->hints.flags & PPosition) && Scr->UsePPosition &&
590	 (Scr->UsePPosition == PPOS_ON ||
591	  tmp_win->attr.x != 0 || tmp_win->attr.y != 0)))
592      ask_user = FALSE;
593
594    /*===============[ Matthew McNeill 1997 ]==========================*
595     * added the occupation parameter to this function call so that the
596     * occupation can be set up in a specific state if desired
597     * (restore session for example)
598     */
599
600    /* note, this is where tmp_win->vs get setup, among other things */
601
602    if (restoredFromPrevSession) {
603      SetupOccupation (tmp_win, saved_occupation);
604    } else
605      SetupOccupation (tmp_win, 0);
606    /*=================================================================*/
607
608    tmp_win->frame_width  = tmp_win->attr.width  + 2 * tmp_win->frame_bw3D;
609    tmp_win->frame_height = tmp_win->attr.height + 2 * tmp_win->frame_bw3D +
610			    tmp_win->title_height;
611    ConstrainSize (tmp_win, &tmp_win->frame_width, &tmp_win->frame_height);
612    winbox = findWindowBox (tmp_win);
613    if (PlaceWindowInRegion (tmp_win, &(tmp_win->attr.x), &(tmp_win->attr.y))) {
614	ask_user = False;
615    }
616    if (LookInList (Scr->WindowGeometries, tmp_win->full_name, &tmp_win->class)) {
617        char *geom;
618	int mask_;
619	geom = LookInList (Scr->WindowGeometries, tmp_win->full_name, &tmp_win->class);
620	mask_ = XParseGeometry (geom, &tmp_win->attr.x, &tmp_win->attr.y,
621				(unsigned int*) &tmp_win->attr.width,
622				(unsigned int*) &tmp_win->attr.height);
623
624	if (mask_ & XNegative) tmp_win->attr.x += Scr->rootw - tmp_win->attr.width;
625	if (mask_ & YNegative) tmp_win->attr.y += Scr->rooth - tmp_win->attr.height;
626	ask_user = False;
627    }
628
629    if (XFindContext (dpy, w, VirtScreenContext, (XPointer *)&vs) == XCSUCCESS)
630      vroot = vs->window;
631    else
632    if (tmp_win->vs)
633      vroot = tmp_win->vs->window;
634    else
635      vroot = Scr->Root;
636    if (winbox) vroot = winbox->window;
637
638    /*
639     * do any prompting for position
640     */
641
642    if (HandlingEvents && ask_user && !restoredFromPrevSession) {
643      if ((Scr->RandomPlacement == RP_ALL) ||
644          ((Scr->RandomPlacement == RP_UNMAPPED) &&
645	   ((tmp_win->wmhints && (tmp_win->wmhints->initial_state == IconicState)) ||
646	    (! visible (tmp_win))))) { /* just stick it somewhere */
647
648#ifdef DEBUG
649	fprintf(stderr,
650		"DEBUG[RandomPlacement]: win: %dx%d+%d+%d, screen: %dx%d, title height: %d, random: +%d+%d\n",
651		tmp_win->attr.width, tmp_win->attr.height,
652		tmp_win->attr.x, tmp_win->attr.y,
653		Scr->rootw, Scr->rooth,
654		tmp_win->title_height,
655		PlaceX, PlaceY);
656#endif
657
658	/* Initiallise PlaceX and PlaceY */
659	if (PlaceX < 0 && PlaceY < 0) {
660	  if (Scr->RandomDisplacementX >= 0)
661	    PlaceX = Scr->BorderLeft + 5;
662	  else
663	    PlaceX = Scr->rootw - tmp_win->attr.width - Scr->BorderRight - 5;
664	  if (Scr->RandomDisplacementY >= 0)
665	    PlaceY = Scr->BorderTop + 5;
666	  else
667	    PlaceY = Scr->rooth - tmp_win->attr.height - tmp_win->title_height
668	      - Scr->BorderBottom - 5;
669	}
670
671	/* For a positive horizontal displacement, if the right edge
672	   of the window would fall outside of the screen, start over
673	   by placing the left edge of the window 5 pixels inside
674	   the left edge of the screen.*/
675	if (Scr->RandomDisplacementX >= 0
676	    && (PlaceX + tmp_win->attr.width
677		> Scr->rootw - Scr->BorderRight - 5))
678	  PlaceX = Scr->BorderLeft + 5;
679
680	/* For a negative horizontal displacement, if the left edge
681	   of the window would fall outside of the screen, start over
682	   by placing the right edge of the window 5 pixels inside
683	   the right edge of the screen.*/
684	if (Scr->RandomDisplacementX < 0 && PlaceX < Scr->BorderLeft + 5)
685	  PlaceX = Scr->rootw - tmp_win->attr.width - Scr->BorderRight - 5;
686
687	/* For a positive vertical displacement, if the bottom edge
688	   of the window would fall outside of the screen, start over
689	   by placing the top edge of the window 5 pixels inside the
690	   top edge of the screen.  Because we add the title height
691	   further down, we need to count with it here as well.  */
692	if (Scr->RandomDisplacementY >= 0
693	    && (PlaceY + tmp_win->attr.height + tmp_win->title_height
694		> Scr->rooth - Scr->BorderBottom - 5))
695	  PlaceY = Scr->BorderTop + 5;
696
697	/* For a negative vertical displacement, if the top edge of
698	   the window would fall outside of the screen, start over by
699	   placing the bottom edge of the window 5 pixels inside the
700	   bottom edge of the screen.  Because we add the title height
701	   further down, we need to count with it here as well.  */
702	if (Scr->RandomDisplacementY < 0 && PlaceY < Scr->BorderTop + 5)
703	  PlaceY = Scr->rooth - tmp_win->attr.height - tmp_win->title_height
704	    - Scr->BorderBottom - 5;
705
706	/* Assign the current random placement to the new window, as
707	   a preliminary measure.  Add the title height so things will
708	   look right.  */
709	tmp_win->attr.x = PlaceX;
710	tmp_win->attr.y = PlaceY + tmp_win->title_height;
711
712	/* If the window is not supposed to move off the screen, check
713	   that it's still within the screen, and if not, attempt to
714	   correct the situation. */
715	if (Scr->DontMoveOff) {
716	    int available;
717
718#ifdef DEBUG
719	    fprintf(stderr,
720		    "DEBUG[DontMoveOff]: win: %dx%d+%d+%d, screen: %dx%d, bw2: %d, bw3D: %d\n",
721		    tmp_win->attr.width, tmp_win->attr.height,
722		    tmp_win->attr.x, tmp_win->attr.y,
723		    Scr->rootw, Scr->rooth,
724		    bw2, tmp_win->frame_bw3D);
725#endif
726
727	    /* If the right edge of the window is outside the right edge
728	       of the screen, we need to move the window left.  Note that
729	       this can only happen with windows that are less than 50
730	       pixels less wide than the screen. */
731	    if ((tmp_win->attr.x + tmp_win->attr.width)  > Scr->rootw) {
732	      available = Scr->rootw - tmp_win->attr.width
733		- 2 * (bw2 + tmp_win->frame_bw3D);
734
735#ifdef DEBUG
736	      fprintf(stderr, "DEBUG[DontMoveOff]: availableX: %d\n",
737		      available);
738#endif
739
740	      /* If the window is wider than the screen or exactly the width
741		 of the screen, the availability is exactly 0.  The result
742		 will be to have the window placed as much to the left as
743		 possible. */
744	      if (available <= 0) available = 0;
745
746	      /* Place the window exactly between the left and right edge of
747		 the screen when possible.  If available was originally less
748		 than zero, it means the window's left edge will be against
749		 the screen's left edge, and the window's right edge will be
750		 outside the screen.  */
751	      tmp_win->attr.x = available / 2;
752	    }
753
754	    /* If the bottom edge of the window is outside the bottom edge
755	       of the screen, we need to move the window up.  Note that
756	       this can only happen with windows that are less than 50
757	       pixels less tall than the screen.  Don't forget to count
758	       with the title height and the frame widths.  */
759	    if ((tmp_win->attr.y + tmp_win->attr.height)  > Scr->rooth) {
760	      available = Scr->rooth - tmp_win->attr.height
761		- tmp_win->title_height - 2 * (bw2 + tmp_win->frame_bw3D);
762
763#ifdef DEBUG
764	      fprintf(stderr, "DEBUG[DontMoveOff]: availableY: %d\n",
765		      available);
766#endif
767
768	      /* If the window is taller than the screen or exactly the
769		 height of the screen, the availability is exactly 0.
770		 The result will be to have the window placed as much to
771		 the top as possible. */
772	      if (available <= 0) available = 0;
773
774	      /* Place the window exactly between the top and bottom edge of
775		 the screen when possible.  If available was originally less
776		 than zero, it means the window's top edge will be against
777		 the screen's top edge, and the window's bottom edge will be
778		 outside the screen.  Again, don't forget to add the title
779		 height.  */
780	      tmp_win->attr.y = available / 2 + tmp_win->title_height;
781	    }
782
783#ifdef DEBUG
784	    fprintf(stderr,
785		    "DEBUG[DontMoveOff]: win: %dx%d+%d+%d, screen: %dx%d\n",
786		    tmp_win->attr.width, tmp_win->attr.height,
787		    tmp_win->attr.x, tmp_win->attr.y,
788		    Scr->rootw, Scr->rooth);
789#endif
790	}
791
792	/* We know that if the window's left edge has moved compared to
793	   PlaceX, it will have moved to the left.  If it was moved less
794	   than 15 pixel either way, change the next "random position"
795	   30 pixels down and right. */
796	if (PlaceX - tmp_win->attr.x < 15
797	    || PlaceY - (tmp_win->attr.y - tmp_win->title_height) < 15) {
798	  PlaceX += Scr->RandomDisplacementX;
799	  PlaceY += Scr->RandomDisplacementY;
800	}
801
802	random_placed = True;
803      } else {				/* else prompt */
804	if (!(tmp_win->wmhints && tmp_win->wmhints->flags & StateHint &&
805	      tmp_win->wmhints->initial_state == IconicState))
806	{
807	    Bool firsttime = True;
808
809	    /* better wait until all the mouse buttons have been
810	     * released.
811	     */
812	    while (TRUE)
813	    {
814		XUngrabServer(dpy);
815		XSync(dpy, 0);
816		XGrabServer(dpy);
817
818		JunkMask = 0;
819		if (!XQueryPointer (dpy, Scr->Root, &JunkRoot,
820				    &JunkChild, &JunkX, &JunkY,
821				    &AddingX, &AddingY, &JunkMask))
822		  JunkMask = 0;
823
824		JunkMask &= (Button1Mask | Button2Mask | Button3Mask |
825			     Button4Mask | Button5Mask);
826
827		/*
828		 * watch out for changing screens
829		 */
830		if (firsttime) {
831		    if (JunkRoot != Scr->Root) {
832			register int scrnum;
833			for (scrnum = 0; scrnum < NumScreens; scrnum++) {
834			    if (JunkRoot == RootWindow (dpy, scrnum)) break;
835			}
836			if (scrnum != NumScreens) PreviousScreen = scrnum;
837		    }
838		    if (Scr->currentvs) {
839			vroot = Scr->currentvs->window;
840		    }
841		    firsttime = False;
842		}
843		if (winbox) vroot = winbox->window;
844
845		/*
846		 * wait for buttons to come up; yuck
847		 */
848		if (JunkMask != 0) continue;
849
850		/*
851		 * this will cause a warp to the indicated root
852		 */
853		stat = XGrabPointer(dpy, vroot, False,
854		    ButtonPressMask | ButtonReleaseMask |
855		    PointerMotionMask | PointerMotionHintMask,
856		    GrabModeAsync, GrabModeAsync,
857		    vroot, UpperLeftCursor, CurrentTime);
858		if (stat == GrabSuccess) break;
859	    }
860
861	    XmbTextExtents(Scr->SizeFont.font_set,
862			   tmp_win->name, namelen,
863			   &ink_rect, &logical_rect);
864	    width = SIZE_HINDENT + ink_rect.width;
865	    height = logical_rect.height + SIZE_VINDENT * 2;
866	    XmbTextExtents(Scr->SizeFont.font_set,
867			   ": ", 2,  &logical_rect, &logical_rect);
868	    Scr->SizeStringOffset = width + logical_rect.width;
869
870	    XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
871				Scr->SizeStringWidth + SIZE_HINDENT, height);
872	    XMapRaised(dpy, Scr->SizeWindow);
873	    InstallRootColormap();
874	    FB(Scr->DefaultC.fore, Scr->DefaultC.back);
875	    XmbDrawImageString (dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
876				Scr->NormalGC, SIZE_HINDENT,
877				SIZE_VINDENT + Scr->SizeFont.ascent,
878				tmp_win->name, namelen);
879
880	    if (winbox) ConstrainedToWinBox (tmp_win, AddingX, AddingY, &AddingX, &AddingY);
881
882	    AddingW = tmp_win->attr.width + bw2 + 2 * tmp_win->frame_bw3D;
883	    AddingH = tmp_win->attr.height + tmp_win->title_height +
884				bw2 + 2 * tmp_win->frame_bw3D;
885	    MoveOutline(vroot,AddingX, AddingY, AddingW, AddingH,
886			tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D);
887
888	    XmbDrawImageString (dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
889				Scr->NormalGC, width,
890				SIZE_VINDENT + Scr->SizeFont.ascent, ": ", 2);
891	    DisplayPosition (tmp_win, AddingX, AddingY);
892
893	    tmp_win->frame_width  = AddingW;
894	    tmp_win->frame_height = AddingH;
895	    /*SetFocus ((TwmWindow *) NULL, CurrentTime);*/
896	    while (TRUE)
897		{
898#ifndef VMS			/* I'll try to implement this later.  RL */
899		if (Scr->OpenWindowTimeout) {
900		    fd = ConnectionNumber (dpy);
901		    while (!XCheckMaskEvent (dpy, ButtonMotionMask | ButtonPressMask, &event)) {
902			FD_ZERO (&mask);
903			FD_SET  (fd, &mask);
904			timeout.tv_sec  = Scr->OpenWindowTimeout;
905			timeout.tv_usec = 0;
906			found = select (fd + 1, (FDSET)&mask, (FDSET)0, (FDSET)0, &timeout);
907			if (found == 0) break;
908		    }
909		    if (found == 0) break;
910		} else {
911#else
912		{
913#endif
914		    found = 1;
915		    XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, &event);
916		}
917		if (event.type == MotionNotify) {
918		    /* discard any extra motion events before a release */
919		    while(XCheckMaskEvent(dpy,
920			ButtonMotionMask | ButtonPressMask, &event))
921			if (event.type == ButtonPress)
922			    break;
923		}
924		FixRootEvent (&event);
925		if (event.type == ButtonPress) {
926		  AddingX = event.xbutton.x_root;
927		  AddingY = event.xbutton.y_root;
928
929		  TryToGrid (tmp_win, &AddingX, &AddingY);
930		  if (Scr->PackNewWindows) TryToPack (tmp_win, &AddingX, &AddingY);
931
932		  /* DontMoveOff prohibits user form off-screen placement */
933		  if (Scr->DontMoveOff)
934                  {
935                      ConstrainByBorders (tmp_win, &AddingX, AddingW, &AddingY, AddingH);
936                  }
937		  break;
938		}
939
940		if (event.type != MotionNotify) {
941		    continue;
942		}
943
944		XQueryPointer(dpy, vroot, &JunkRoot, &JunkChild,
945		    &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
946
947		TryToGrid (tmp_win, &AddingX, &AddingY);
948		if (Scr->PackNewWindows) TryToPack (tmp_win, &AddingX, &AddingY);
949		if (Scr->DontMoveOff)
950		{
951		    ConstrainByBorders (tmp_win, &AddingX, AddingW, &AddingY, AddingH);
952		}
953		MoveOutline(vroot, AddingX, AddingY, AddingW, AddingH,
954			    tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D);
955
956		DisplayPosition (tmp_win, AddingX, AddingY);
957	    }
958
959	  if (found) {
960	    if (event.xbutton.button == Button2) {
961		int lastx, lasty;
962
963		XmbTextExtents(Scr->SizeFont.font_set,
964			       ": ", 2,  &logical_rect, &logical_rect);
965		Scr->SizeStringOffset = width + logical_rect.width;
966
967		XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
968			       Scr->SizeStringWidth + SIZE_HINDENT, height);
969
970		XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
971				   Scr->NormalGC, width,
972				   SIZE_VINDENT + Scr->SizeFont.ascent, ": ", 2);
973
974		if (0/*Scr->AutoRelativeResize*/) {
975		    int dx = (tmp_win->attr.width / 4);
976		    int dy = (tmp_win->attr.height / 4);
977
978#define HALF_AVE_CURSOR_SIZE 8		/* so that it is visible */
979		    if (dx < HALF_AVE_CURSOR_SIZE + Scr->BorderLeft)
980                        dx = HALF_AVE_CURSOR_SIZE + Scr->BorderLeft;
981		    if (dy < HALF_AVE_CURSOR_SIZE + Scr->BorderTop)
982                        dy = HALF_AVE_CURSOR_SIZE + Scr->BorderTop;
983#undef HALF_AVE_CURSOR_SIZE
984		    dx += (tmp_win->frame_bw + 1);
985		    dy += (bw2 + tmp_win->title_height + 1);
986		    if (AddingX + dx >= Scr->rootw - Scr->BorderRight)
987		      dx = Scr->rootw - Scr->BorderRight - AddingX - 1;
988		    if (AddingY + dy >= Scr->rooth - Scr->BorderBottom)
989		      dy = Scr->rooth - Scr->BorderBottom - AddingY - 1;
990		    if (dx > 0 && dy > 0)
991		      XWarpPointer (dpy, None, None, 0, 0, 0, 0, dx, dy);
992		} else {
993		    XWarpPointer (dpy, None, vroot, 0, 0, 0, 0,
994				  AddingX + AddingW/2, AddingY + AddingH/2);
995		}
996		AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH);
997
998		lastx = -10000;
999		lasty = -10000;
1000		while (TRUE)
1001		{
1002		    XMaskEvent(dpy,
1003			       ButtonReleaseMask | ButtonMotionMask, &event);
1004
1005		    if (event.type == MotionNotify) {
1006			/* discard any extra motion events before a release */
1007			while(XCheckMaskEvent(dpy,
1008			    ButtonMotionMask | ButtonReleaseMask, &event))
1009			    if (event.type == ButtonRelease)
1010				break;
1011		    }
1012		    FixRootEvent (&event);
1013
1014		    if (event.type == ButtonRelease)
1015		    {
1016			AddEndResize(tmp_win);
1017			break;
1018		    }
1019
1020		    if (event.type != MotionNotify) {
1021			continue;
1022		    }
1023
1024		    /*
1025		     * XXX - if we are going to do a loop, we ought to consider
1026		     * using multiple GXxor lines so that we don't need to
1027		     * grab the server.
1028		     */
1029		    XQueryPointer(dpy, vroot, &JunkRoot, &JunkChild,
1030				  &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
1031
1032		    if (lastx != AddingX || lasty != AddingY)
1033		    {
1034			resizeWhenAdd = TRUE;
1035			DoResize(AddingX, AddingY, tmp_win);
1036			resizeWhenAdd = FALSE;
1037
1038			lastx = AddingX;
1039			lasty = AddingY;
1040		    }
1041
1042		}
1043	    }
1044	    else if (event.xbutton.button == Button3)
1045	    {
1046		int maxw = Scr->rootw - Scr->BorderRight  - AddingX - bw2;
1047		int maxh = Scr->rooth - Scr->BorderBottom - AddingY - bw2;
1048
1049		/*
1050		 * Make window go to bottom of screen, and clip to right edge.
1051		 * This is useful when popping up large windows and fixed
1052		 * column text windows.
1053		 */
1054		if (AddingW > maxw) AddingW = maxw;
1055		AddingH = maxh;
1056
1057		ConstrainSize (tmp_win, &AddingW, &AddingH);  /* w/o borders */
1058		AddingW += bw2;
1059		AddingH += bw2;
1060		XMaskEvent(dpy, ButtonReleaseMask, &event);
1061	    }
1062	    else
1063	    {
1064		XMaskEvent(dpy, ButtonReleaseMask, &event);
1065	    }
1066	  }
1067	    MoveOutline(vroot, 0, 0, 0, 0, 0, 0);
1068	    XUnmapWindow(dpy, Scr->SizeWindow);
1069	    UninstallRootColormap();
1070	    XUngrabPointer(dpy, CurrentTime);
1071
1072	    tmp_win->attr.x = AddingX;
1073	    tmp_win->attr.y = AddingY + tmp_win->title_height;
1074	    tmp_win->attr.width = AddingW - bw2 - 2 * tmp_win->frame_bw3D;
1075	    tmp_win->attr.height = AddingH - tmp_win->title_height -
1076				bw2 - 2 * tmp_win->frame_bw3D;
1077
1078	    XUngrabServer(dpy);
1079	}
1080      }
1081    } else {				/* put it where asked, mod title bar */
1082	/* if the gravity is towards the top, move it by the title height */
1083	if (gravy < 0) tmp_win->attr.y -= gravy * tmp_win->title_height;
1084    }
1085
1086#ifdef DEBUG
1087	fprintf(stderr, "  position window  %d, %d  %dx%d\n",
1088	    tmp_win->attr.x,
1089	    tmp_win->attr.y,
1090	    tmp_win->attr.width,
1091	    tmp_win->attr.height);
1092#endif
1093
1094    if (!Scr->ClientBorderWidth) {	/* need to adjust for twm borders */
1095	int delta = tmp_win->attr.border_width - tmp_win->frame_bw - tmp_win->frame_bw3D;
1096	tmp_win->attr.x += gravx * delta;
1097	tmp_win->attr.y += gravy * delta;
1098    }
1099
1100    tmp_win->title_width = tmp_win->attr.width;
1101
1102    tmp_win->icon_name = (char*) GetWMPropertyString(tmp_win->w, XA_WM_ICON_NAME);
1103    if (!tmp_win->icon_name)
1104	tmp_win->icon_name = tmp_win->name;
1105
1106#ifdef CLAUDE
1107    if (strstr (tmp_win->icon_name, " - Mozilla")) {
1108      char *moz = strstr (tmp_win->icon_name, " - Mozilla");
1109      *moz = '\0';
1110    }
1111#endif
1112
1113    XmbTextExtents (Scr->TitleBarFont.font_set, tmp_win->name, namelen, &ink_rect, &logical_rect);
1114    tmp_win->name_width = logical_rect.width;
1115
1116    if (tmp_win->old_bw) XSetWindowBorderWidth (dpy, tmp_win->w, 0);
1117
1118    tmp_win->squeezed = FALSE;
1119    tmp_win->iconified = FALSE;
1120    tmp_win->isicon = FALSE;
1121    tmp_win->icon_on = FALSE;
1122
1123    XGrabServer(dpy);
1124
1125    /*
1126     * Make sure the client window still exists.  We don't want to leave an
1127     * orphan frame window if it doesn't.  Since we now have the server
1128     * grabbed, the window can't disappear later without having been
1129     * reparented, so we'll get a DestroyNotify for it.  We won't have
1130     * gotten one for anything up to here, however.
1131     */
1132    if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
1133		     &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
1134    {
1135	TwmWindow *prev = tmp_win->ring.prev, *next = tmp_win->ring.next;
1136
1137	if (prev) prev->ring.next = next;
1138	if (next) next->ring.prev = prev;
1139	if (Scr->Ring == tmp_win) Scr->Ring = (next != tmp_win ? next : (TwmWindow *) NULL);
1140	if (!Scr->Ring || Scr->RingLeader == tmp_win) Scr->RingLeader = Scr->Ring;
1141
1142	free((char *)tmp_win);
1143	XUngrabServer(dpy);
1144	return(NULL);
1145    }
1146
1147    /* add the window into the twm list */
1148    tmp_win->next = Scr->FirstWindow;
1149    if (Scr->FirstWindow != NULL)
1150	Scr->FirstWindow->prev = tmp_win;
1151    tmp_win->prev = NULL;
1152    Scr->FirstWindow = tmp_win;
1153
1154    /* get all the colors for the window */
1155
1156    tmp_win->borderC.fore     = Scr->BorderColorC.fore;
1157    tmp_win->borderC.back     = Scr->BorderColorC.back;
1158    tmp_win->border_tile.fore = Scr->BorderTileC.fore;
1159    tmp_win->border_tile.back = Scr->BorderTileC.back;
1160    tmp_win->title.fore       = Scr->TitleC.fore;
1161    tmp_win->title.back       = Scr->TitleC.back;
1162
1163    GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class,
1164	&tmp_win->borderC.fore);
1165    GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class,
1166	&tmp_win->borderC.back);
1167    GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name,
1168	&tmp_win->class, &tmp_win->border_tile.fore);
1169    GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name,
1170	&tmp_win->class, &tmp_win->border_tile.back);
1171    GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, &tmp_win->class,
1172	&tmp_win->title.fore);
1173    GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, &tmp_win->class,
1174	&tmp_win->title.back);
1175
1176    if (Scr->use3Dtitles  && !Scr->BeNiceToColormap) GetShadeColors (&tmp_win->title);
1177    if (Scr->use3Dborders && !Scr->BeNiceToColormap) {
1178	GetShadeColors (&tmp_win->borderC);
1179	GetShadeColors (&tmp_win->border_tile);
1180    }
1181    /* create windows */
1182
1183    tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw
1184			- tmp_win->frame_bw3D;
1185    tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height +
1186	tmp_win->old_bw - tmp_win->frame_bw - tmp_win->frame_bw3D;
1187    tmp_win->frame_width = tmp_win->attr.width + 2 * tmp_win->frame_bw3D;
1188    tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height +
1189				2 * tmp_win->frame_bw3D;
1190
1191    ConstrainSize (tmp_win, &tmp_win->frame_width, &tmp_win->frame_height);
1192    if (random_placed)
1193        ConstrainByBorders (tmp_win, &tmp_win->frame_x, tmp_win->frame_width,
1194                            &tmp_win->frame_y, tmp_win->frame_height);
1195
1196    valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask | CWBackPixel;
1197    attributes.background_pixmap = None;
1198    attributes.border_pixel = tmp_win->border_tile.back;
1199    attributes.background_pixel = tmp_win->border_tile.back;
1200    attributes.cursor = Scr->FrameCursor;
1201    attributes.event_mask = (SubstructureRedirectMask |
1202			     ButtonPressMask | ButtonReleaseMask |
1203			     EnterWindowMask | LeaveWindowMask | ExposureMask);
1204    if (Scr->BorderCursors) attributes.event_mask |= PointerMotionMask;
1205    if (tmp_win->attr.save_under) {
1206	attributes.save_under = True;
1207	valuemask |= CWSaveUnder;
1208    }
1209    if (tmp_win->hints.flags & PWinGravity) {
1210	attributes.win_gravity = tmp_win->hints.win_gravity;
1211	valuemask |= CWWinGravity;
1212    }
1213
1214    if ((tmp_win->frame_x > Scr->rootw) ||
1215	(tmp_win->frame_y > Scr->rooth) ||
1216	((int)(tmp_win->frame_x + tmp_win->frame_width)  < 0) ||
1217	((int)(tmp_win->frame_y + tmp_win->frame_height) < 0)) {
1218      tmp_win->frame_x = 0;
1219      tmp_win->frame_y = 0;
1220    }
1221
1222    DealWithNonSensicalGeometries(dpy, vroot, tmp_win);
1223
1224    tmp_win->frame = XCreateWindow (dpy, vroot, tmp_win->frame_x, tmp_win->frame_y,
1225				    (unsigned int) tmp_win->frame_width,
1226				    (unsigned int) tmp_win->frame_height,
1227				    (unsigned int) tmp_win->frame_bw,
1228				    Scr->d_depth,
1229				    (unsigned int) CopyFromParent,
1230				    Scr->d_visual, valuemask, &attributes);
1231
1232    if (tmp_win->title_height)
1233    {
1234	valuemask = (CWEventMask | CWDontPropagate | CWBorderPixel | CWBackPixel);
1235	attributes.event_mask = (KeyPressMask | ButtonPressMask |
1236				 ButtonReleaseMask | ExposureMask);
1237	attributes.do_not_propagate_mask = PointerMotionMask;
1238	attributes.border_pixel = tmp_win->borderC.back;
1239	attributes.background_pixel = tmp_win->title.back;
1240	tmp_win->title_w = XCreateWindow (dpy, tmp_win->frame,
1241					  tmp_win->frame_bw3D - tmp_win->frame_bw,
1242					  tmp_win->frame_bw3D - tmp_win->frame_bw,
1243					  (unsigned int) tmp_win->attr.width,
1244					  (unsigned int) Scr->TitleHeight,
1245					  (unsigned int) tmp_win->frame_bw,
1246					  Scr->d_depth,
1247					  (unsigned int) CopyFromParent,
1248					  Scr->d_visual, valuemask,
1249					  &attributes);
1250    }
1251    else {
1252	tmp_win->title_w = 0;
1253	tmp_win->squeeze_info = NULL;
1254    }
1255
1256    if (tmp_win->highlight)
1257    {
1258	if (Scr->use3Dtitles && (Scr->Monochrome != COLOR))
1259	    tmp_win->gray = XCreatePixmapFromBitmapData(dpy, vroot,
1260		(char*)black_bits, gray_width, gray_height,
1261		tmp_win->border_tile.fore, tmp_win->border_tile.back,
1262		Scr->d_depth);
1263	else
1264	    tmp_win->gray = XCreatePixmapFromBitmapData(dpy, vroot,
1265		(char*)gray_bits, gray_width, gray_height,
1266		tmp_win->border_tile.fore, tmp_win->border_tile.back,
1267		Scr->d_depth);
1268
1269	tmp_win->hasfocusvisible = True;
1270	SetFocusVisualAttributes (tmp_win, False);
1271    }
1272    else
1273	tmp_win->gray = None;
1274
1275    RaiseWindow(tmp_win);
1276
1277    if (tmp_win->title_w) {
1278	ComputeTitleLocation (tmp_win);
1279	CreateWindowTitlebarButtons (tmp_win);
1280	XMoveWindow (dpy, tmp_win->title_w,
1281		     tmp_win->title_x, tmp_win->title_y);
1282	XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor);
1283    }
1284    else {
1285	tmp_win->title_x = tmp_win->frame_bw3D - tmp_win->frame_bw;
1286	tmp_win->title_y = tmp_win->frame_bw3D - tmp_win->frame_bw;
1287    }
1288
1289    valuemask = (CWEventMask | CWDontPropagate);
1290    attributes.event_mask = (StructureNotifyMask | PropertyChangeMask |
1291			     ColormapChangeMask | VisibilityChangeMask |
1292			     FocusChangeMask |
1293			     EnterWindowMask | LeaveWindowMask);
1294    attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
1295    XChangeWindowAttributes (dpy, tmp_win->w, valuemask, &attributes);
1296
1297    if (HasShape)
1298	XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
1299
1300    if (tmp_win->title_w) {
1301	XMapWindow (dpy, tmp_win->title_w);
1302    }
1303
1304    if (HasShape) {
1305	int xws, yws, xbs, ybs;
1306	unsigned wws, hws, wbs, hbs;
1307	int boundingShaped, clipShaped;
1308
1309	XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
1310	XShapeQueryExtents (dpy, tmp_win->w,
1311			    &boundingShaped, &xws, &yws, &wws, &hws,
1312			    &clipShaped, &xbs, &ybs, &wbs, &hbs);
1313	tmp_win->wShaped = boundingShaped;
1314    }
1315
1316    if (!tmp_win->iconmgr &&! iswman &&
1317	(tmp_win->w != Scr->workSpaceMgr.occupyWindow->w))
1318	XAddToSaveSet(dpy, tmp_win->w);
1319
1320    XReparentWindow(dpy, tmp_win->w, tmp_win->frame, tmp_win->frame_bw3D,
1321		tmp_win->title_height + tmp_win->frame_bw3D);
1322    /*
1323     * Reparenting generates an UnmapNotify event, followed by a MapNotify.
1324     * Set the map state to FALSE to prevent a transition back to
1325     * WithdrawnState in HandleUnmapNotify.  Map state gets set correctly
1326     * again in HandleMapNotify.
1327     */
1328    tmp_win->mapped = FALSE;
1329
1330    SetupFrame (tmp_win, tmp_win->frame_x, tmp_win->frame_y,
1331		tmp_win->frame_width, tmp_win->frame_height, -1, True);
1332
1333    /* wait until the window is iconified and the icon window is mapped
1334     * before creating the icon window
1335     */
1336    tmp_win->icon = (Icon*) 0;
1337    tmp_win->iconslist = (name_list*) 0;
1338
1339    if (!tmp_win->iconmgr)
1340    {
1341	GrabButtons(tmp_win);
1342	GrabKeys(tmp_win);
1343    }
1344
1345    (void) AddIconManager(tmp_win);
1346
1347    XSaveContext(dpy, tmp_win->w, TwmContext, (XPointer) tmp_win);
1348    XSaveContext(dpy, tmp_win->w, ScreenContext, (XPointer) Scr);
1349    XSaveContext(dpy, tmp_win->frame, TwmContext, (XPointer) tmp_win);
1350    XSaveContext(dpy, tmp_win->frame, ScreenContext, (XPointer) Scr);
1351
1352    if (tmp_win->title_height)
1353    {
1354	int i;
1355	int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1356
1357	XSaveContext(dpy, tmp_win->title_w, TwmContext, (XPointer) tmp_win);
1358	XSaveContext(dpy, tmp_win->title_w, ScreenContext, (XPointer) Scr);
1359	for (i = 0; i < nb; i++) {
1360	    XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext,
1361			 (XPointer) tmp_win);
1362	    XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext,
1363			 (XPointer) Scr);
1364	}
1365	if (tmp_win->hilite_wl)
1366	{
1367	    XSaveContext(dpy, tmp_win->hilite_wl, TwmContext, (XPointer)tmp_win);
1368	    XSaveContext(dpy, tmp_win->hilite_wl, ScreenContext, (XPointer)Scr);
1369	}
1370	if (tmp_win->hilite_wr)
1371	{
1372	    XSaveContext(dpy, tmp_win->hilite_wr, TwmContext, (XPointer)tmp_win);
1373	    XSaveContext(dpy, tmp_win->hilite_wr, ScreenContext, (XPointer)Scr);
1374	}
1375	if (tmp_win->lolite_wl)
1376	{
1377	    XSaveContext(dpy, tmp_win->lolite_wl, TwmContext, (XPointer)tmp_win);
1378	    XSaveContext(dpy, tmp_win->lolite_wl, ScreenContext, (XPointer)Scr);
1379	}
1380	if (tmp_win->lolite_wr)
1381	{
1382	    XSaveContext(dpy, tmp_win->lolite_wr, TwmContext, (XPointer)tmp_win);
1383	    XSaveContext(dpy, tmp_win->lolite_wr, ScreenContext, (XPointer)Scr);
1384	}
1385    }
1386
1387    XUngrabServer(dpy);
1388
1389    /* if we were in the middle of a menu activated function, regrab
1390     * the pointer
1391     */
1392    if (RootFunction) ReGrab();
1393    if (!iswman) WMapAddWindow (tmp_win);
1394    SetPropsIfCaptiveCtwm (tmp_win);
1395    savegeometry (tmp_win);
1396    return (tmp_win);
1397}
1398
1399/***********************************************************************
1400 *
1401 *  Procedure:
1402 *	GetTwmWindow - finds the TwmWindow structure associated with
1403 *		a Window (if any), or NULL.
1404 *
1405 *  Returned Value:
1406 *	NULL	- it is not a Window we know about
1407 *	otherwise- the TwmWindow *
1408 *
1409 *  Inputs:
1410 *	w	- the window to check
1411 *
1412 *  Note:
1413 *  	This is a relatively cheap function since it does not involve
1414 *  	communication with the server. Probably faster than walking
1415 *  	the list of TwmWindows, since the lookup is by a hash table.
1416 *
1417 ***********************************************************************
1418 */
1419TwmWindow *GetTwmWindow(Window w)
1420{
1421    TwmWindow *twmwin;
1422    int stat;
1423
1424    stat = XFindContext(dpy, w, TwmContext, (XPointer *)&twmwin);
1425    if (stat == XCNOENT)
1426	twmwin = NULL;
1427
1428    return twmwin;
1429}
1430
1431/***********************************************************************
1432 *
1433 *  Procedure:
1434 *	MappedNotOverride - checks to see if we should really
1435 *		put a twm frame on the window
1436 *
1437 *  Returned Value:
1438 *	TRUE	- go ahead and frame the window
1439 *	FALSE	- don't frame the window
1440 *
1441 *  Inputs:
1442 *	w	- the window to check
1443 *
1444 ***********************************************************************
1445 */
1446
1447int MappedNotOverride(Window w)
1448{
1449    XWindowAttributes wa;
1450
1451    XGetWindowAttributes(dpy, w, &wa);
1452    return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True));
1453}
1454
1455
1456/***********************************************************************
1457 *
1458 *  Procedure:
1459 *      AddDefaultBindings - attach default bindings so that naive users
1460 *      don't get messed up if they provide a minimal twmrc.
1461 */
1462static void do_add_binding (int button, int context, int modifier, int func)
1463{
1464    AddFuncButton (button, context, modifier, func, NULL, NULL);
1465}
1466
1467void AddDefaultBindings (void)
1468{
1469#define NoModifierMask 0
1470
1471    do_add_binding (Button1, C_TITLE, NoModifierMask, F_MOVE);
1472    do_add_binding (Button1, C_ICON, NoModifierMask, F_ICONIFY);
1473    do_add_binding (Button1, C_ICONMGR, NoModifierMask, F_ICONIFY);
1474
1475    do_add_binding (Button2, C_TITLE, NoModifierMask, F_RAISELOWER);
1476    do_add_binding (Button2, C_ICON, NoModifierMask, F_ICONIFY);
1477    do_add_binding (Button2, C_ICONMGR, NoModifierMask, F_ICONIFY);
1478
1479#undef NoModifierMask
1480}
1481
1482
1483
1484
1485/***********************************************************************
1486 *
1487 *  Procedure:
1488 *	GrabButtons - grab needed buttons for the window
1489 *
1490 *  Inputs:
1491 *	tmp_win - the twm window structure to use
1492 *
1493 ***********************************************************************
1494 */
1495
1496#define AltMask (Alt1Mask | Alt2Mask | Alt3Mask | Alt4Mask | Alt5Mask)
1497#define grabbutton(button, modifier, window, pointer_mode) \
1498	XGrabButton (dpy, button, modifier, window,  \
1499		True, ButtonPressMask | ButtonReleaseMask, \
1500		pointer_mode, GrabModeAsync, None,  \
1501		Scr->FrameCursor);
1502
1503void GrabButtons(TwmWindow *tmp_win)
1504{
1505    FuncButton *tmp;
1506    int i;
1507    unsigned int ModifierMask[8] = { ShiftMask, ControlMask, LockMask,
1508				     Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask,
1509				     Mod5Mask };
1510
1511    for (tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) {
1512	if ((tmp->cont != C_WINDOW) || (tmp->func == 0)) continue;
1513	grabbutton (tmp->num, tmp->mods, tmp_win->frame, GrabModeAsync);
1514
1515	if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) {
1516	    grabbutton (tmp->num, tmp->mods | LockMask, tmp_win->frame, GrabModeAsync);
1517	}
1518	for (i = 0 ; i < 8 ; i++) {
1519	    if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i]))
1520		grabbutton (tmp->num, tmp->mods | ModifierMask [i],
1521			  tmp_win->frame, GrabModeAsync);
1522	}
1523    }
1524    if (Scr->ClickToFocus) {
1525	grabbutton (AnyButton, None, tmp_win->w, GrabModeSync);
1526	for (i = 0 ; i < 8 ; i++) {
1527	    grabbutton (AnyButton, ModifierMask [i], tmp_win->w, GrabModeSync);
1528	}
1529    } else
1530    if (Scr->RaiseOnClick) {
1531	grabbutton (Scr->RaiseOnClickButton, None, tmp_win->w, GrabModeSync);
1532	for (i = 0 ; i < 8 ; i++) {
1533	    grabbutton (Scr->RaiseOnClickButton,
1534			ModifierMask [i], tmp_win->w, GrabModeSync);
1535	}
1536    }
1537}
1538
1539/***********************************************************************
1540 *
1541 *  Procedure:
1542 *	GrabKeys - grab needed keys for the window
1543 *
1544 *  Inputs:
1545 *	tmp_win - the twm window structure to use
1546 *
1547 ***********************************************************************
1548 */
1549
1550#define MAX_KEYCODE 256
1551#define grabkey(funckey, modifier, window) \
1552	XGrabKey(dpy, funckey->keycode, funckey->mods | modifier, window, True, \
1553		GrabModeAsync, GrabModeAsync);
1554#define ungrabkey(funckey, modifier, window) \
1555	XUngrabKey (dpy, funckey->keycode, funckey->mods | modifier, window);
1556
1557void GrabKeys(TwmWindow *tmp_win)
1558{
1559    FuncKey *tmp;
1560    IconMgr *p;
1561    int i;
1562    unsigned int ModifierMask[8] = { ShiftMask, ControlMask, LockMask,
1563				     Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask,
1564				     Mod5Mask };
1565
1566    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
1567    {
1568	switch (tmp->cont)
1569	{
1570	case C_WINDOW:
1571	/* case C_WORKSPACE: */
1572	    if (tmp->mods & AltMask) break;
1573	    grabkey (tmp, 0, tmp_win->w);
1574	    if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask))
1575		grabkey (tmp, LockMask, tmp_win->w);
1576	    for (i = 0 ; i < 8 ; i++) {
1577		if ((Scr->IgnoreModifier & ModifierMask [i]) &&
1578		    !(tmp->mods & ModifierMask [i]))
1579		  grabkey (tmp, ModifierMask [i], tmp_win->w);
1580	    }
1581	    break;
1582
1583	case C_ICON:
1584	    if (!tmp_win->icon || tmp_win->icon->w) break;
1585	    grabkey (tmp, 0, tmp_win->icon->w);
1586	    if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask))
1587		grabkey (tmp, LockMask, tmp_win->icon->w);
1588	    for (i = 0 ; i < 8 ; i++) {
1589		if ((Scr->IgnoreModifier & ModifierMask [i]) &&
1590		    !(tmp->mods & ModifierMask [i]))
1591		    grabkey (tmp, ModifierMask [i], tmp_win->icon->w);
1592	    }
1593	    break;
1594
1595	case C_TITLE:
1596	    if (!tmp_win->title_w) break;
1597	    grabkey (tmp, 0, tmp_win->title_w);
1598	    if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask))
1599		grabkey (tmp, LockMask, tmp_win->title_w);
1600	    for (i = 0 ; i < 8 ; i++) {
1601		if ((Scr->IgnoreModifier & ModifierMask [i]) &&
1602		    !(tmp->mods & ModifierMask [i]))
1603		    grabkey (tmp, ModifierMask [i], tmp_win->title_w);
1604	    }
1605	    break;
1606
1607	case C_NAME:
1608	    grabkey (tmp, 0, tmp_win->w);
1609	    if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) {
1610		grabkey (tmp, LockMask, tmp_win->w);
1611	    }
1612	    for (i = 0 ; i < 8 ; i++) {
1613		if ((Scr->IgnoreModifier & ModifierMask [i]) &&
1614		    !(tmp->mods & ModifierMask [i]))
1615		    grabkey (tmp, ModifierMask [i], tmp_win->w);
1616	    }
1617	    if (tmp_win->icon && tmp_win->icon->w) {
1618		grabkey (tmp, 0, tmp_win->icon->w);
1619		if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask))
1620		    grabkey (tmp, LockMask, tmp_win->icon->w);
1621		for (i = 0 ; i < 8 ; i++) {
1622		    if ((Scr->IgnoreModifier & ModifierMask [i]) &&
1623			!(tmp->mods & ModifierMask [i]))
1624			grabkey (tmp, ModifierMask [i], tmp_win->icon->w);
1625		}
1626	    }
1627	    if (tmp_win->title_w) {
1628		grabkey (tmp, 0, tmp_win->title_w);
1629		if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask))
1630		    grabkey (tmp, LockMask, tmp_win->title_w);
1631		for (i = 0 ; i < 8 ; i++) {
1632		    if ((Scr->IgnoreModifier & ModifierMask [i]) &&
1633			!(tmp->mods & ModifierMask [i]))
1634			grabkey (tmp, ModifierMask [i], tmp_win->title_w);
1635		}
1636	    }
1637	    break;
1638	/*
1639	case C_ROOT:
1640	    XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True,
1641		GrabModeAsync, GrabModeAsync);
1642	    break;
1643	*/
1644	}
1645    }
1646    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
1647    {
1648	if (tmp->cont == C_ICONMGR && !Scr->NoIconManagers)
1649	{
1650	    for (p = Scr->iconmgr; p != NULL; p = p->next) {
1651		ungrabkey (tmp, 0, p->twm_win->w);
1652		if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask))
1653		    ungrabkey (tmp, LockMask, p->twm_win->w);
1654		for (i = 0 ; i < 8 ; i++) {
1655		    if ((Scr->IgnoreModifier & ModifierMask [i]) &&
1656			!(tmp->mods & ModifierMask [i]))
1657			ungrabkey (tmp, ModifierMask [i], p->twm_win->w);
1658		}
1659	    }
1660	}
1661    }
1662}
1663
1664void ComputeCommonTitleOffsets (void)
1665{
1666    int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
1667
1668    Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding;
1669    if (Scr->TBInfo.nleft  > 0) Scr->TBInfo.leftx    += Scr->ButtonIndent;
1670    if (Scr->TBInfo.nright > 0) Scr->TBInfo.rightoff += (Scr->ButtonIndent +
1671			       (Scr->TBInfo.nright * buttonwidth) -
1672				Scr->TBInfo.pad);
1673
1674    Scr->TBInfo.titlex = (Scr->TBInfo.leftx +
1675				(Scr->TBInfo.nleft * buttonwidth) -
1676				Scr->TBInfo.pad +
1677				Scr->TitlePadding);
1678}
1679
1680static void CreateHighlightWindows (TwmWindow *tmp_win)
1681{
1682    XSetWindowAttributes attributes;	/* attributes for create windows */
1683    GC gc;
1684    XGCValues gcv;
1685    unsigned long valuemask;
1686    int h = (Scr->TitleHeight - 2 * Scr->FramePadding);
1687    int y = Scr->FramePadding;
1688
1689    if (! tmp_win->titlehighlight) {
1690	tmp_win->hilite_wl = (Window) 0;
1691	tmp_win->hilite_wr = (Window) 0;
1692	return;
1693    }
1694    /*
1695     * If a special highlight pixmap was given, use that.  Otherwise,
1696     * use a nice, even gray pattern.  The old horizontal lines look really
1697     * awful on interlaced monitors (as well as resembling other looks a
1698     * little bit too closely), but can be used by putting
1699     *
1700     *                 Pixmaps { TitleHighlight "hline2" }
1701     *
1702     * (or whatever the horizontal line bitmap is named) in the startup
1703     * file.  If all else fails, use the foreground color to look like a
1704     * solid line.
1705     */
1706
1707    if (! tmp_win->HiliteImage) {
1708	if (Scr->HighlightPixmapName) {
1709	    tmp_win->HiliteImage = GetImage (Scr->HighlightPixmapName, tmp_win->title);
1710	}
1711    }
1712    if (! tmp_win->HiliteImage) {
1713	Pixmap pm = None;
1714	Pixmap bm = None;
1715
1716	if (Scr->use3Dtitles && (Scr->Monochrome != COLOR))
1717	    bm = XCreateBitmapFromData (dpy, tmp_win->title_w,
1718					(char*)black_bits, gray_width, gray_height);
1719	else
1720	    bm = XCreateBitmapFromData (dpy, tmp_win->title_w,
1721					(char*)gray_bits, gray_width, gray_height);
1722
1723	pm = XCreatePixmap (dpy, tmp_win->title_w, gray_width, gray_height, Scr->d_depth);
1724	gcv.foreground = tmp_win->title.fore;
1725	gcv.background = tmp_win->title.back;
1726	gcv.graphics_exposures = False;
1727	gc = XCreateGC (dpy, pm, (GCForeground|GCBackground|GCGraphicsExposures), &gcv);
1728	if (gc) {
1729	    XCopyPlane (dpy, bm, pm, gc, 0, 0, gray_width, gray_height, 0, 0, 1);
1730	    tmp_win->HiliteImage = (Image*) malloc (sizeof (struct _Image));
1731	    tmp_win->HiliteImage->pixmap = pm;
1732	    tmp_win->HiliteImage->width  = gray_width;
1733	    tmp_win->HiliteImage->height = gray_height;
1734	    tmp_win->HiliteImage->mask   = None;
1735	    tmp_win->HiliteImage->next   = None;
1736	    XFreeGC (dpy, gc);
1737	} else {
1738	    XFreePixmap (dpy, pm);
1739	    pm = None;
1740	}
1741	XFreePixmap (dpy, bm);
1742    }
1743    if (tmp_win->HiliteImage) {
1744	valuemask = CWBackPixmap;
1745	attributes.background_pixmap = tmp_win->HiliteImage->pixmap;
1746    } else {
1747	valuemask = CWBackPixel;
1748	attributes.background_pixel = tmp_win->title.fore;
1749    }
1750
1751    if (Scr->use3Dtitles) {
1752	y += Scr->TitleShadowDepth;
1753	h -= 2 * Scr->TitleShadowDepth;
1754    }
1755    if (Scr->TitleJustification == J_LEFT)
1756	tmp_win->hilite_wl = (Window) 0;
1757    else
1758	tmp_win->hilite_wl = XCreateWindow (dpy, tmp_win->title_w, 0, y,
1759		       (unsigned int) Scr->TBInfo.width, (unsigned int) h,
1760		       (unsigned int) 0, Scr->d_depth, (unsigned int) CopyFromParent,
1761		       Scr->d_visual, valuemask, &attributes);
1762
1763    if (Scr->TitleJustification == J_RIGHT)
1764	tmp_win->hilite_wr = (Window) 0;
1765    else
1766	tmp_win->hilite_wr = XCreateWindow (dpy, tmp_win->title_w, 0, y,
1767		       (unsigned int) Scr->TBInfo.width, (unsigned int) h,
1768		       (unsigned int) 0,  Scr->d_depth, (unsigned int) CopyFromParent,
1769		       Scr->d_visual, valuemask, &attributes);
1770}
1771
1772void DeleteHighlightWindows(TwmWindow *tmp_win)
1773{
1774    if (tmp_win->HiliteImage) {
1775	if (Scr->HighlightPixmapName) {
1776	    /*
1777	     * Image obtained from GetImage(): it is in a cache
1778	     * so we don't need to free it. There will not be multiple
1779	     * copies if the same xpm:foo image is requested again.
1780	     */
1781	} else {
1782	    XFreePixmap (dpy, tmp_win->HiliteImage->pixmap);
1783	    free(tmp_win->HiliteImage);
1784	}
1785	tmp_win->HiliteImage = NULL;
1786    }
1787}
1788
1789static void CreateLowlightWindows (TwmWindow *tmp_win)
1790{
1791    XSetWindowAttributes attributes;    /* attributes for create windows */
1792    unsigned long valuemask;
1793    int h = (Scr->TitleHeight - 2 * Scr->FramePadding);
1794    int y = Scr->FramePadding;
1795    ColorPair cp;
1796
1797    if (!Scr->UseSunkTitlePixmap || ! tmp_win->titlehighlight) {
1798	tmp_win->lolite_wl = (Window) 0;
1799	tmp_win->lolite_wr = (Window) 0;
1800	return;
1801    }
1802    /*
1803     * If a special highlight pixmap was given, use that.  Otherwise,
1804     * use a nice, even gray pattern.  The old horizontal lines look really
1805     * awful on interlaced monitors (as well as resembling other looks a
1806     * little bit too closely), but can be used by putting
1807     *
1808     *                 Pixmaps { TitleHighlight "hline2" }
1809     *
1810     * (or whatever the horizontal line bitmap is named) in the startup
1811     * file.  If all else fails, use the foreground color to look like a
1812     * solid line.
1813     */
1814
1815    if (! tmp_win->LoliteImage) {
1816        if (Scr->HighlightPixmapName) {
1817            cp = tmp_win->title;
1818            cp.shadc = tmp_win->title.shadd;
1819            cp.shadd = tmp_win->title.shadc;
1820            tmp_win->LoliteImage = GetImage (Scr->HighlightPixmapName, cp);
1821        }
1822    }
1823    if (tmp_win->LoliteImage) {
1824        valuemask = CWBackPixmap;
1825        attributes.background_pixmap = tmp_win->LoliteImage->pixmap;
1826    } else {
1827        valuemask = CWBackPixel;
1828        attributes.background_pixel = tmp_win->title.fore;
1829    }
1830
1831    if (Scr->use3Dtitles) {
1832        y += 2;
1833        h -= 4;
1834    }
1835    if (Scr->TitleJustification == J_LEFT)
1836        tmp_win->lolite_wl = (Window) 0;
1837    else
1838        tmp_win->lolite_wl = XCreateWindow (dpy, tmp_win->title_w, 0, y,
1839                       (unsigned int) Scr->TBInfo.width, (unsigned int) h,
1840                       (unsigned int) 0, Scr->d_depth, (unsigned int) CopyFromParent,
1841                       Scr->d_visual, valuemask, &attributes);
1842
1843    if (Scr->TitleJustification == J_RIGHT)
1844        tmp_win->lolite_wr = (Window) 0;
1845    else
1846        tmp_win->lolite_wr = XCreateWindow (dpy, tmp_win->title_w, 0, y,
1847                       (unsigned int) Scr->TBInfo.width, (unsigned int) h,
1848                       (unsigned int) 0,  Scr->d_depth, (unsigned int) CopyFromParent,
1849                       Scr->d_visual, valuemask, &attributes);
1850}
1851
1852
1853void ComputeWindowTitleOffsets (TwmWindow *tmp_win, unsigned int width,
1854				Bool squeeze)
1855{
1856    int titlew = width - Scr->TBInfo.titlex - Scr->TBInfo.rightoff;
1857
1858    switch (Scr->TitleJustification) {
1859	case J_LEFT :
1860	    tmp_win->name_x = Scr->TBInfo.titlex;
1861	    if (Scr->use3Dtitles) tmp_win->name_x += Scr->TitleShadowDepth + 2;
1862	    break;
1863	case J_CENTER :
1864	    tmp_win->name_x = Scr->TBInfo.titlex + (titlew - tmp_win->name_width) / 2;
1865	    break;
1866	case J_RIGHT :
1867	    tmp_win->name_x = Scr->TBInfo.titlex + titlew - tmp_win->name_width;
1868	    if (Scr->use3Dtitles) tmp_win->name_x -= Scr->TitleShadowDepth - 2;
1869	    break;
1870    }
1871    if (Scr->use3Dtitles) {
1872	if (tmp_win->name_x < (Scr->TBInfo.titlex + 2 * Scr->TitleShadowDepth))
1873		tmp_win->name_x = Scr->TBInfo.titlex + 2 * Scr->TitleShadowDepth;
1874    }
1875    else
1876    if (tmp_win->name_x < Scr->TBInfo.titlex) {
1877	tmp_win->name_x = Scr->TBInfo.titlex;
1878    }
1879    tmp_win->highlightxl = Scr->TBInfo.titlex;
1880    tmp_win->highlightxr = tmp_win->name_x + tmp_win->name_width + 2;
1881
1882    if (Scr->use3Dtitles) {
1883	tmp_win->highlightxl += Scr->TitleShadowDepth;
1884    }
1885    if (tmp_win->hilite_wr || Scr->TBInfo.nright > 0)
1886      tmp_win->highlightxr += Scr->TitlePadding;
1887    tmp_win->rightx = width - Scr->TBInfo.rightoff;
1888    if (squeeze && tmp_win->squeeze_info && !tmp_win->squeezed) {
1889	int rx = (tmp_win->highlightxr +
1890		  (tmp_win->hilite_wr
1891		    ? Scr->TBInfo.width * 2 : 0) +
1892		  (Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) +
1893		  Scr->FramePadding);
1894	if (rx < tmp_win->rightx) tmp_win->rightx = rx;
1895    }
1896    return;
1897}
1898
1899
1900/*
1901 * ComputeTitleLocation - calculate the position of the title window; we need
1902 * to take the frame_bw into account since we want (0,0) of the title window
1903 * to line up with (0,0) of the frame window.
1904 */
1905void ComputeTitleLocation (register TwmWindow *tmp)
1906{
1907    tmp->title_x = tmp->frame_bw3D - tmp->frame_bw;
1908    tmp->title_y = tmp->frame_bw3D - tmp->frame_bw;
1909
1910    if (tmp->squeeze_info && !tmp->squeezed) {
1911	register SqueezeInfo *si = tmp->squeeze_info;
1912	int basex;
1913	int maxwidth = tmp->frame_width;
1914	int tw = tmp->title_width + 2 * tmp->frame_bw3D;
1915
1916	/*
1917	 * figure label base from squeeze info (justification fraction)
1918	 */
1919	if (si->denom == 0) {		/* num is pixel based */
1920	    basex = si->num;
1921	} else {			/* num/denom is fraction */
1922	    basex = ((si->num * maxwidth) / si->denom);
1923	}
1924	if (si->num < 0)
1925	    basex += maxwidth;
1926
1927	/*
1928	 * adjust for left (nop), center, right justify and clip
1929	 */
1930	switch (si->justify) {
1931	  case J_CENTER:
1932	    basex -= tw / 2;
1933	    break;
1934	  case J_RIGHT:
1935	    basex -= tw - 1;
1936	    break;
1937	}
1938	if (basex > maxwidth - tw)
1939	  basex = maxwidth - tw;
1940	if (basex < 0) basex = 0;
1941
1942	tmp->title_x = basex - tmp->frame_bw + tmp->frame_bw3D;
1943    }
1944}
1945
1946
1947static void CreateWindowTitlebarButtons (TwmWindow *tmp_win)
1948{
1949    unsigned long valuemask;		/* mask for create windows */
1950    XSetWindowAttributes attributes;	/* attributes for create windows */
1951    int leftx, rightx, y;
1952    TitleButton *tb;
1953    int nb;
1954
1955    if (tmp_win->title_height == 0)
1956    {
1957	tmp_win->hilite_wl = (Window) 0;
1958	tmp_win->hilite_wr = (Window) 0;
1959	tmp_win->lolite_wl = (Window) 0;
1960	tmp_win->lolite_wr = (Window) 0;
1961	return;
1962    }
1963
1964
1965    /*
1966     * create the title bar windows; let the event handler deal with painting
1967     * so that we don't have to spend two pixmaps (or deal with hashing)
1968     */
1969    ComputeWindowTitleOffsets (tmp_win, tmp_win->attr.width, False);
1970
1971    leftx = y = Scr->TBInfo.leftx;
1972    rightx = tmp_win->rightx;
1973
1974    attributes.win_gravity = NorthWestGravity;
1975    attributes.background_pixel = tmp_win->title.back;
1976    attributes.border_pixel = tmp_win->title.fore;
1977    attributes.event_mask = (ButtonPressMask | ButtonReleaseMask |
1978			     ExposureMask);
1979    attributes.cursor = Scr->ButtonCursor;
1980    valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask |
1981		 CWCursor);
1982
1983    tmp_win->titlebuttons = NULL;
1984    nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1985    if (nb > 0) {
1986	tmp_win->titlebuttons = (TBWindow *) malloc (nb * sizeof(TBWindow));
1987	if (!tmp_win->titlebuttons) {
1988	    fprintf (stderr, "%s:  unable to allocate %d titlebuttons\n",
1989		     ProgramName, nb);
1990	} else {
1991	    TBWindow *tbw;
1992	    int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
1993	    unsigned int h = (Scr->TBInfo.width - Scr->TBInfo.border * 2);
1994
1995	    for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb;
1996		 tb = tb->next, tbw++) {
1997		int x;
1998		if (tb->rightside) {
1999		    x = rightx;
2000		    rightx += boxwidth;
2001		    attributes.win_gravity = NorthEastGravity;
2002		} else {
2003		    x = leftx;
2004		    leftx += boxwidth;
2005		    attributes.win_gravity = NorthWestGravity;
2006		}
2007		tbw->window = XCreateWindow (dpy, tmp_win->title_w, x, y, h, h,
2008					     (unsigned int) Scr->TBInfo.border,
2009					     0, (unsigned int) CopyFromParent,
2010					     (Visual *) CopyFromParent,
2011					     valuemask, &attributes);
2012		tbw->image = GetImage (tb->name, tmp_win->title);
2013		if (! tbw->image) {
2014		    tbw->image = GetImage (TBPM_QUESTION, tmp_win->title);
2015		    if (! tbw->image) {		/* cannot happen (see util.c) */
2016			fprintf (stderr, "%s:  unable to add titlebar button \"%s\"\n",
2017				 ProgramName, tb->name);
2018		    }
2019		}
2020		tbw->info = tb;
2021	    }
2022	}
2023    }
2024
2025    CreateHighlightWindows (tmp_win);
2026    CreateLowlightWindows  (tmp_win);
2027    XMapSubwindows(dpy, tmp_win->title_w);
2028    if (tmp_win->hilite_wl) XUnmapWindow(dpy, tmp_win->hilite_wl);
2029    if (tmp_win->hilite_wr) XUnmapWindow(dpy, tmp_win->hilite_wr);
2030    if (tmp_win->lolite_wl) XMapWindow(dpy, tmp_win->lolite_wl);
2031    if (tmp_win->lolite_wr) XMapWindow(dpy, tmp_win->lolite_wr);
2032    return;
2033}
2034
2035void SetHighlightPixmap (char *filename)
2036{
2037#ifdef VMS
2038    char *ftemp;
2039    ftemp = (char *) malloc((strlen(filename)+1)*sizeof(char));
2040    Scr->HighlightPixmapName = strcpy (ftemp,filename);
2041#else
2042    Scr->HighlightPixmapName = (char*) strdup (filename);
2043#endif
2044}
2045
2046
2047void FetchWmProtocols (TwmWindow *tmp)
2048{
2049    unsigned long flags = 0L;
2050    Atom *protocols = NULL;
2051    int n;
2052
2053    if (XGetWMProtocols (dpy, tmp->w, &protocols, &n)) {
2054	register int i;
2055	register Atom *ap;
2056
2057	for (i = 0, ap = protocols; i < n; i++, ap++) {
2058	    if (*ap == _XA_WM_TAKE_FOCUS) flags |= DoesWmTakeFocus;
2059	    if (*ap == _XA_WM_SAVE_YOURSELF) flags |= DoesWmSaveYourself;
2060	    if (*ap == _XA_WM_DELETE_WINDOW) flags |= DoesWmDeleteWindow;
2061	}
2062	if (protocols) XFree ((char *) protocols);
2063    }
2064    tmp->protocols = flags;
2065}
2066
2067TwmColormap *CreateTwmColormap(Colormap c)
2068{
2069    TwmColormap *cmap;
2070    cmap = (TwmColormap *) malloc(sizeof(TwmColormap));
2071    if (!cmap ||
2072	XSaveContext(dpy, c, ColormapContext, (XPointer) cmap)) {
2073	if (cmap) free((char *) cmap);
2074	return (NULL);
2075    }
2076    cmap->c = c;
2077    cmap->state = 0;
2078    cmap->install_req = 0;
2079    cmap->w = None;
2080    cmap->refcnt = 1;
2081    return (cmap);
2082}
2083
2084ColormapWindow *CreateColormapWindow(Window w,
2085				     Bool creating_parent,
2086				     Bool property_window)
2087{
2088    ColormapWindow *cwin;
2089    TwmColormap *cmap;
2090    XWindowAttributes attributes;
2091
2092    cwin = (ColormapWindow *) malloc(sizeof(ColormapWindow));
2093    if (cwin) {
2094	if (!XGetWindowAttributes(dpy, w, &attributes) ||
2095	    XSaveContext(dpy, w, ColormapContext, (XPointer) cwin)) {
2096	    free((char *) cwin);
2097	    return (NULL);
2098	}
2099
2100	if (XFindContext(dpy, attributes.colormap,  ColormapContext,
2101		(XPointer *)&cwin->colormap) == XCNOENT) {
2102	    cwin->colormap = cmap = CreateTwmColormap(attributes.colormap);
2103	    if (!cmap) {
2104		XDeleteContext(dpy, w, ColormapContext);
2105		free((char *) cwin);
2106		return (NULL);
2107	    }
2108	} else {
2109	    cwin->colormap->refcnt++;
2110	}
2111
2112	cwin->w = w;
2113	/*
2114	 * Assume that windows in colormap list are
2115	 * obscured if we are creating the parent window.
2116	 * Otherwise, we assume they are unobscured.
2117	 */
2118	cwin->visibility = creating_parent ?
2119	    VisibilityPartiallyObscured : VisibilityUnobscured;
2120	cwin->refcnt = 1;
2121
2122	/*
2123	 * If this is a ColormapWindow property window and we
2124	 * are not monitoring ColormapNotify or VisibilityNotify
2125	 * events, we need to.
2126	 */
2127	if (property_window &&
2128	    (attributes.your_event_mask &
2129		(ColormapChangeMask|VisibilityChangeMask)) !=
2130		    (ColormapChangeMask|VisibilityChangeMask)) {
2131	    XSelectInput(dpy, w, attributes.your_event_mask |
2132		(ColormapChangeMask|VisibilityChangeMask));
2133	}
2134    }
2135
2136    return (cwin);
2137}
2138
2139int FetchWmColormapWindows (TwmWindow *tmp)
2140{
2141    register int i, j;
2142    Window *cmap_windows = NULL;
2143    Bool can_free_cmap_windows = False;
2144    int number_cmap_windows = 0;
2145    ColormapWindow **cwins = NULL;
2146    int previously_installed;
2147
2148    number_cmap_windows = 0;
2149
2150    if (/* SUPPRESS 560 */
2151	(previously_installed =
2152	 (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins))) {
2153	cwins = tmp->cmaps.cwins;
2154	for (i = 0; i < tmp->cmaps.number_cwins; i++)
2155	    cwins[i]->colormap->state = 0;
2156    }
2157
2158    if (XGetWMColormapWindows (dpy, tmp->w, &cmap_windows,
2159			       &number_cmap_windows) &&
2160	number_cmap_windows > 0) {
2161
2162	can_free_cmap_windows = False;
2163	/*
2164	 * check if the top level is in the list, add to front if not
2165	 */
2166	for (i = 0; i < number_cmap_windows; i++) {
2167	    if (cmap_windows[i] == tmp->w) break;
2168	}
2169	if (i == number_cmap_windows) {	 /* not in list */
2170	    Window *new_cmap_windows =
2171	      (Window *) malloc (sizeof(Window) * (number_cmap_windows + 1));
2172
2173	    if (!new_cmap_windows) {
2174		fprintf (stderr,
2175			 "%s:  unable to allocate %d element colormap window array\n",
2176			ProgramName, number_cmap_windows+1);
2177		goto done;
2178	    }
2179	    new_cmap_windows[0] = tmp->w;  /* add to front */
2180	    for (i = 0; i < number_cmap_windows; i++) {	 /* append rest */
2181		new_cmap_windows[i+1] = cmap_windows[i];
2182	    }
2183	    XFree ((char *) cmap_windows);
2184	    can_free_cmap_windows = True;  /* do not use XFree any more */
2185	    cmap_windows = new_cmap_windows;
2186	    number_cmap_windows++;
2187	}
2188
2189	cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *) *
2190		number_cmap_windows);
2191	if (cwins) {
2192	    for (i = 0; i < number_cmap_windows; i++) {
2193
2194		/*
2195		 * Copy any existing entries into new list.
2196		 */
2197		for (j = 0; j < tmp->cmaps.number_cwins; j++) {
2198		    if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) {
2199			cwins[i] = tmp->cmaps.cwins[j];
2200			cwins[i]->refcnt++;
2201			break;
2202		    }
2203		}
2204
2205		/*
2206		 * If the colormap window is not being pointed by
2207		 * some other applications colormap window list,
2208		 * create a new entry.
2209		 */
2210		if (j == tmp->cmaps.number_cwins) {
2211		    if (XFindContext(dpy, cmap_windows[i], ColormapContext,
2212				     (XPointer *)&cwins[i]) == XCNOENT) {
2213			if ((cwins[i] = CreateColormapWindow(cmap_windows[i],
2214				    (Bool) tmp->cmaps.number_cwins == 0,
2215				    True)) == NULL) {
2216			    int k;
2217			    for (k = i + 1; k < number_cmap_windows; k++)
2218				cmap_windows[k-1] = cmap_windows[k];
2219			    i--;
2220			    number_cmap_windows--;
2221			}
2222		    } else
2223			cwins[i]->refcnt++;
2224		}
2225	    }
2226	}
2227    }
2228
2229    /* No else here, in case we bailed out of clause above.
2230     */
2231    if (number_cmap_windows == 0) {
2232
2233	number_cmap_windows = 1;
2234
2235	cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *));
2236	if (XFindContext(dpy, tmp->w, ColormapContext, (XPointer *)&cwins[0]) ==
2237		XCNOENT)
2238	    cwins[0] = CreateColormapWindow(tmp->w,
2239			    (Bool) tmp->cmaps.number_cwins == 0, False);
2240	else
2241	    cwins[0]->refcnt++;
2242    }
2243
2244    if (tmp->cmaps.number_cwins)
2245	free_cwins(tmp);
2246
2247    tmp->cmaps.cwins = cwins;
2248    tmp->cmaps.number_cwins = number_cmap_windows;
2249    if (number_cmap_windows > 1)
2250	tmp->cmaps.scoreboard =
2251	  (char *) calloc(1, ColormapsScoreboardLength(&tmp->cmaps));
2252
2253    if (previously_installed) {
2254	InstallColormaps(PropertyNotify, NULL);
2255    }
2256
2257  done:
2258    if (cmap_windows) {
2259	if (can_free_cmap_windows)
2260	  free ((char *) cmap_windows);
2261	else
2262	  XFree ((char *) cmap_windows);
2263    }
2264
2265    return (0);
2266}
2267
2268
2269void GetWindowSizeHints (TwmWindow *tmp)
2270{
2271    long supplied = 0;
2272    XSizeHints *hints = &tmp->hints;
2273
2274    if (!XGetWMNormalHints (dpy, tmp->w, hints, &supplied))
2275      hints->flags = 0;
2276
2277    if (hints->flags & PResizeInc) {
2278	if (hints->width_inc == 0) hints->width_inc = 1;
2279	if (hints->height_inc == 0) hints->height_inc = 1;
2280    }
2281
2282    if (!(supplied & PWinGravity) && (hints->flags & USPosition)) {
2283	static int gravs[] = { SouthEastGravity, SouthWestGravity,
2284			       NorthEastGravity, NorthWestGravity };
2285	int right =  tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
2286	int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
2287	hints->win_gravity =
2288	  gravs[((Scr->rooth - bottom <
2289		tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 2) |
2290		((Scr->rootw - right   <
2291		tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 1)];
2292	hints->flags |= PWinGravity;
2293    }
2294
2295    /* Check for min size < max size */
2296    if ((hints->flags & (PMinSize|PMaxSize)) == (PMinSize|PMaxSize)) {
2297	if (hints->max_width < hints->min_width) {
2298	    if (hints->max_width > 0) {
2299		hints->min_width = hints->max_width;
2300	    } else if (hints->min_width > 0) {
2301		hints->max_width = hints->min_width;
2302	    } else {
2303		hints->max_width = hints->min_width = 1;
2304	    }
2305	}
2306
2307	if (hints->max_height < hints->min_height) {
2308	    if (hints->max_height > 0) {
2309		hints->min_height = hints->max_height;
2310	    } else if (hints->min_height > 0) {
2311		hints->max_height = hints->min_height;
2312	    } else {
2313		hints->max_height = hints->min_height = 1;
2314	    }
2315	}
2316    }
2317}
2318
2319void AnimateButton (TBWindow *tbw)
2320{
2321    Image	*image;
2322    XSetWindowAttributes attr;
2323
2324    image = tbw->image;
2325    attr.background_pixmap = image->pixmap;
2326    XChangeWindowAttributes (dpy, tbw->window, CWBackPixmap, &attr);
2327    XClearWindow (dpy, tbw->window);
2328    tbw->image = image->next;
2329}
2330
2331void AnimateHighlight (TwmWindow *t)
2332{
2333    Image	*image;
2334    XSetWindowAttributes attr;
2335
2336    image = t->HiliteImage;
2337    attr.background_pixmap = image->pixmap;
2338    if (t->hilite_wl) {
2339	XChangeWindowAttributes (dpy, t->hilite_wl, CWBackPixmap, &attr);
2340	XClearWindow (dpy, t->hilite_wl);
2341    }
2342    if (t->hilite_wr) {
2343	XChangeWindowAttributes (dpy, t->hilite_wr, CWBackPixmap, &attr);
2344	XClearWindow (dpy, t->hilite_wr);
2345    }
2346    t->HiliteImage = image->next;
2347}
2348
2349name_list **AddWindowRegion (char *geom, int grav1, int grav2)
2350{
2351    WindowRegion *wr;
2352    int mask;
2353
2354    wr = (WindowRegion*) malloc (sizeof (WindowRegion));
2355    wr->next = NULL;
2356
2357    if (!Scr->FirstWindowRegion) Scr->FirstWindowRegion = wr;
2358
2359    wr->entries    = NULL;
2360    wr->clientlist = NULL;
2361    wr->grav1      = grav1;
2362    wr->grav2      = grav2;
2363    wr->x = wr->y = wr->w = wr->h = 0;
2364
2365    mask = XParseGeometry (geom, &wr->x, &wr->y, (unsigned int*) &wr->w,
2366						 (unsigned int*) &wr->h);
2367
2368    if (mask & XNegative) wr->x += Scr->rootw - wr->w;
2369    if (mask & YNegative) wr->y += Scr->rooth - wr->h;
2370
2371    return (&(wr->clientlist));
2372}
2373
2374void CreateWindowRegions (void) {
2375    WindowRegion  *wr, *wr1 = NULL, *wr2 = NULL;
2376    WorkSpace *wl;
2377
2378    for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) {
2379	wl->FirstWindowRegion = NULL;
2380	wr2 = NULL;
2381	for (wr = Scr->FirstWindowRegion; wr != NULL; wr = wr->next) {
2382	    wr1  = (WindowRegion*) malloc (sizeof (WindowRegion));
2383	    *wr1 = *wr;
2384	    wr1->entries = (WindowEntry*) malloc (sizeof (WindowEntry));
2385	    wr1->entries->next = 0;
2386	    wr1->entries->x = wr1->x;
2387	    wr1->entries->y = wr1->y;
2388	    wr1->entries->w = wr1->w;
2389	    wr1->entries->h = wr1->h;
2390	    wr1->entries->twm_win = (TwmWindow*) 0;
2391	    wr1->entries->used = 0;
2392	    if (wr2) wr2->next = wr1; else wl->FirstWindowRegion = wr1;
2393	    wr2 = wr1;
2394	}
2395	if (wr1) wr1->next = NULL;
2396    }
2397}
2398
2399
2400Bool PlaceWindowInRegion (TwmWindow *tmp_win, int *final_x, int *final_y)
2401{
2402    WindowRegion  *wr;
2403    WindowEntry	  *we;
2404    int		  w, h;
2405    WorkSpace     *wl;
2406
2407    if (!Scr->FirstWindowRegion) return (False);
2408    for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) {
2409	if (OCCUPY (tmp_win, wl)) break;
2410    }
2411    if (!wl) return (False);
2412    w = tmp_win->frame_width;
2413    h = tmp_win->frame_height;
2414    we = (WindowEntry*) 0;
2415    for (wr = wl->FirstWindowRegion; wr; wr = wr->next) {
2416	if (LookInList (wr->clientlist, tmp_win->full_name, &tmp_win->class)) {
2417	    for (we = wr->entries; we; we=we->next) {
2418	        if (we->used) continue;
2419	        if (we->w >= w && we->h >= h) break;
2420	    }
2421	    if (we) break;
2422	}
2423    }
2424    tmp_win->wr = (WindowRegion*) 0;
2425    if (!we) return (False);
2426
2427    splitWindowRegionEntry (we, wr->grav1, wr->grav2, w, h);
2428    we->used = 1;
2429    we->twm_win = tmp_win;
2430    *final_x = we->x;
2431    *final_y = we->y;
2432    tmp_win->wr = wr;
2433    return (True);
2434}
2435
2436static void splitWindowRegionEntry (WindowEntry *we, int grav1, int grav2,
2437				    int w, int h)
2438{
2439    WindowEntry	*new;
2440
2441    switch (grav1) {
2442	case D_NORTH:
2443	case D_SOUTH:
2444	    if (w != we->w) splitWindowRegionEntry (we, grav2, grav1, w, we->h);
2445	    if (h != we->h) {
2446		new = (WindowEntry *) malloc (sizeof (WindowEntry));
2447		new->twm_win = 0;
2448		new->used = 0;
2449		new->next = we->next;
2450		we->next  = new;
2451		new->x    = we->x;
2452		new->h    = (we->h - h);
2453		new->w    = we->w;
2454		we->h     = h;
2455		if (grav1 == D_SOUTH) {
2456		    new->y = we->y;
2457		    we->y  = new->y + new->h;
2458		} else
2459		    new->y = we->y + we->h;
2460		}
2461	    break;
2462	case D_EAST:
2463	case D_WEST:
2464	    if (h != we->h) splitWindowRegionEntry (we, grav2, grav1, we->w, h);
2465	    if (w != we->w) {
2466		new = (WindowEntry *) malloc (sizeof (WindowEntry));
2467		new->twm_win = 0;
2468		new->used = 0;
2469		new->next = we->next;
2470		we->next  = new;
2471		new->y    = we->y;
2472		new->w    = (we->w - w);
2473		new->h    = we->h;
2474		we->w = w;
2475		if (grav1 == D_EAST) {
2476		    new->x = we->x;
2477		    we->x  = new->x + new->w;
2478		} else
2479		    new->x = we->x + we->w;
2480		}
2481	    break;
2482    }
2483}
2484
2485static WindowEntry *findWindowEntry (WorkSpace *wl, TwmWindow *tmp_win,
2486				     WindowRegion **wrp)
2487{
2488    WindowRegion *wr;
2489    WindowEntry	 *we;
2490
2491    for (wr = wl->FirstWindowRegion; wr; wr = wr->next) {
2492	for (we = wr->entries; we; we=we->next) {
2493	    if (we->twm_win == tmp_win) {
2494		if (wrp) *wrp = wr;
2495		return we;
2496	    }
2497	}
2498    }
2499    return (WindowEntry*) 0;
2500}
2501
2502static WindowEntry *prevWindowEntry (WindowEntry *we, WindowRegion *wr)
2503{
2504    WindowEntry	*wp;
2505
2506    if (we == wr->entries) return 0;
2507    for (wp = wr->entries; wp->next != we; wp=wp->next);
2508    return wp;
2509}
2510
2511static void mergeWindowEntries (WindowEntry *old, WindowEntry *we)
2512{
2513    if (old->y == we->y) {
2514	we->w = old->w + we->w;
2515	if (old->x < we->x) we->x = old->x;
2516    } else {
2517	we->h = old->h + we->h;
2518	if (old->y < we->y) we->y = old->y;
2519    }
2520}
2521
2522void RemoveWindowFromRegion (TwmWindow *tmp_win)
2523{
2524    WindowEntry  *we, *wp, *wn;
2525    WindowRegion *wr;
2526    WorkSpace    *wl;
2527
2528    if (!Scr->FirstWindowRegion) return;
2529    we = (WindowEntry*) 0;
2530    for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) {
2531	we = findWindowEntry (wl, tmp_win, &wr);
2532	if (we) break;
2533    }
2534    if (!we) return;
2535
2536    we->twm_win = 0;
2537    we->used = 0;
2538    wp = prevWindowEntry (we, wr);
2539    wn = we->next;
2540    for (;;) {
2541	if (wp && wp->used == 0 &&
2542	       ((wp->x == we->x && wp->w == we->w) ||
2543	        (wp->y == we->y && wp->h == we->h))) {
2544	    wp->next = we->next;
2545	    mergeWindowEntries (we, wp);
2546	    free ((char *) we);
2547	    we = wp;
2548	    wp = prevWindowEntry (wp, wr);
2549	} else
2550	if (wn && wn->used == 0 &&
2551	       ((wn->x == we->x && wn->w == we->w) ||
2552	        (wn->y == we->y && wn->h == we->h))) {
2553	    we->next = wn->next;
2554	    mergeWindowEntries (wn, we);
2555	    free ((char *) wn);
2556	    wn = we->next;
2557	} else break;
2558    }
2559}
2560
2561/*
2562 * This is largely for Xinerama support with VirtualScreens.
2563 * In this case, windows may be on something other then the main screen
2564 * on startup, or the mapping may be relative to the right side of the
2565 * screen, which is on a different monitor, which will cause issues with
2566 * the virtual screens.
2567 *
2568 * It probably needs to be congnizant of windows that are actually owned by
2569 * other workspaces, and ignore them (this needs to be revisited), or perhaps
2570 * that functionality is appropriate in AddWindow().  This needs to be dug into
2571 * more deply.
2572 *
2573 * this approach assumes screens that are next to each other horizontally,
2574 * Other possibilities need to be investigated and accounted for.
2575 */
2576void DealWithNonSensicalGeometries(Display *mydpy, Window vroot, TwmWindow *tmp_win)
2577{
2578    Window		vvroot;
2579    int			x,y;
2580    unsigned int	w,h;
2581    unsigned int	j;
2582    virtualScreen	*myvs, *vs;
2583    int			dropx = 0;
2584
2585    if(! vroot)
2586	return;
2587
2588    if(!(XGetGeometry(mydpy, vroot, &vvroot, &x, &y, &w, &h, &j, &j)))
2589	return;
2590
2591    myvs = findIfVScreenOf(x, y);
2592
2593    /*
2594     * probably need to rethink this  for unmapped vs's.  ugh.
2595     */
2596    if(!myvs)
2597	return;
2598
2599    for(vs = myvs->next; vs; vs = vs->next) {
2600	dropx += vs->w;
2601    }
2602
2603    for(vs = Scr->vScreenList; vs && vs != myvs; vs = vs->next) {
2604	dropx -= vs->w;
2605    }
2606
2607    if(tmp_win->frame_x > 0 && tmp_win->frame_x >= w) {
2608	tmp_win->frame_x -= abs(dropx);
2609    } else {
2610}
2611
2612}
2613