add_window.c revision ffd25bca
1/*****************************************************************************/
2/*
3
4Copyright 1989,1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26*/
27/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
28/**                          Salt Lake City, Utah                           **/
29/**                        Cambridge, Massachusetts                         **/
30/**                                                                         **/
31/**                           All Rights Reserved                           **/
32/**                                                                         **/
33/**    Permission to use, copy, modify, and distribute this software and    **/
34/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
35/**    granted, provided that the above copyright notice appear  in  all    **/
36/**    copies and that both  that  copyright  notice  and  this  permis-    **/
37/**    sion  notice appear in supporting  documentation,  and  that  the    **/
38/**    name of Evans & Sutherland not be used in advertising    **/
39/**    in publicity pertaining to distribution of the  software  without    **/
40/**    specific, written prior permission.                                  **/
41/**                                                                         **/
42/**    EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD    **/
43/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
44/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND    **/
45/**    BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
46/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
47/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
48/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
49/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
50/*****************************************************************************/
51
52
53/**********************************************************************
54 *
55 * Add a new window, put the titlbar and other stuff around
56 * the window
57 *
58 * 31-Mar-88 Tom LaStrange        Initial Version.
59 *
60 **********************************************************************/
61
62#include <stdio.h>
63#include "twm.h"
64#include <X11/Xatom.h>
65#include "util.h"
66#include "resize.h"
67#include "parse.h"
68#include "list.h"
69#include "events.h"
70#include "menus.h"
71#include "screen.h"
72#include "iconmgr.h"
73#include "session.h"
74#include "add_window.h"
75
76#define gray_width 2
77#define gray_height 2
78static char gray_bits[] = {
79   0x02, 0x01};
80
81int AddingX;
82int AddingY;
83int AddingW;
84int AddingH;
85
86static int PlaceX = 50;
87static int PlaceY = 50;
88
89static void do_add_binding ( int button, int context, int modifier, int func );
90static Window CreateHighlightWindow ( TwmWindow *tmp_win );
91static void CreateWindowTitlebarButtons ( TwmWindow *tmp_win );
92
93
94char NoName[] = "Untitled"; /* name if no name is specified */
95
96
97/**
98 * map gravity to (x,y) offset signs for adding to x and y when window is
99 * mapped to get proper placement.
100 *
101 *  \param tmp    window from which to get gravity
102 *  \param xp,yp  return values
103 *
104 */
105void
106GetGravityOffsets (TwmWindow *tmp, int *xp, int *yp)
107{
108    static struct _gravity_offset {
109	int x, y;
110    } gravity_offsets[11] = {
111	{  0,  0 },			/* ForgetGravity */
112	{ -1, -1 },			/* NorthWestGravity */
113	{  0, -1 },			/* NorthGravity */
114	{  1, -1 },			/* NorthEastGravity */
115	{ -1,  0 },			/* WestGravity */
116	{  0,  0 },			/* CenterGravity */
117	{  1,  0 },			/* EastGravity */
118	{ -1,  1 },			/* SouthWestGravity */
119	{  0,  1 },			/* SouthGravity */
120	{  1,  1 },			/* SouthEastGravity */
121	{  0,  0 },			/* StaticGravity */
122    };
123    register int g = ((tmp->hints.flags & PWinGravity)
124		      ? tmp->hints.win_gravity : NorthWestGravity);
125
126    if (g < ForgetGravity || g > StaticGravity) {
127	*xp = *yp = 0;
128    } else {
129	*xp = gravity_offsets[g].x;
130	*yp = gravity_offsets[g].y;
131    }
132}
133
134
135
136
137/**
138 * add a new window to the twm list.
139 *
140 *  \return  pointer to the TwmWindow structure
141 *
142 *	\param w      the window id of the window to add
143 *	\param iconm  flag to tell if this is an icon manager window
144 *	\param iconp  pointer to icon manager struct
145 */
146TwmWindow *
147AddWindow(Window w, int iconm, IconMgr *iconp)
148{
149    TwmWindow *tmp_win;			/* new twm window structure */
150    int stat;
151    XEvent event;
152    unsigned long valuemask;		/* mask for create windows */
153    XSetWindowAttributes attributes;	/* attributes for create windows */
154    int width, height;			/* tmp variable */
155    int ask_user;		/* don't know where to put the window */
156    int gravx, gravy;			/* gravity signs for positioning */
157    int namelen;
158    int bw2;
159    short saved_x, saved_y, restore_icon_x, restore_icon_y;
160    unsigned short saved_width, saved_height;
161    Bool restore_iconified = 0;
162    Bool restore_icon_info_present = 0;
163    int restoredFromPrevSession;
164    Bool width_ever_changed_by_user;
165    Bool height_ever_changed_by_user;
166    char *name;
167
168#ifdef DEBUG
169    fprintf(stderr, "AddWindow: w = 0x%lx\n", (unsigned long)w);
170#endif
171
172    /* allocate space for the twm window */
173    tmp_win = (TwmWindow *)calloc(1, sizeof(TwmWindow));
174    if (tmp_win == 0)
175    {
176	fprintf (stderr, "%s: Unable to allocate memory to manage window ID %lx.\n",
177		 ProgramName, w);
178	return NULL;
179    }
180    tmp_win->w = w;
181    tmp_win->zoomed = ZOOM_NONE;
182    tmp_win->iconmgr = iconm;
183    tmp_win->iconmgrp = iconp;
184    tmp_win->cmaps.number_cwins = 0;
185
186    XSelectInput(dpy, tmp_win->w, PropertyChangeMask);
187
188    XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr);
189
190    if (!I18N_FetchName(dpy, tmp_win->w, &name))
191      name = NULL;
192    tmp_win->class = NoClass;
193    XGetClassHint(dpy, tmp_win->w, &tmp_win->class);
194    FetchWmProtocols (tmp_win);
195    FetchWmColormapWindows (tmp_win);
196
197    if (name == NULL)
198	tmp_win->name = strdup(NoName);
199    else {
200      tmp_win->name = strdup(name);
201      free(name);
202    }
203
204    if (GetWindowConfig (tmp_win,
205	&saved_x, &saved_y, &saved_width, &saved_height,
206	&restore_iconified, &restore_icon_info_present,
207	&restore_icon_x, &restore_icon_y,
208	&width_ever_changed_by_user, &height_ever_changed_by_user))
209    {
210	tmp_win->attr.x = saved_x;
211	tmp_win->attr.y = saved_y;
212
213	tmp_win->widthEverChangedByUser = width_ever_changed_by_user;
214	tmp_win->heightEverChangedByUser = height_ever_changed_by_user;
215
216	if (width_ever_changed_by_user)
217	    tmp_win->attr.width = saved_width;
218
219	if (height_ever_changed_by_user)
220	    tmp_win->attr.height = saved_height;
221
222	restoredFromPrevSession = 1;
223    }
224    else
225    {
226	tmp_win->widthEverChangedByUser = False;
227	tmp_win->heightEverChangedByUser = False;
228
229	restoredFromPrevSession = 0;
230    }
231
232
233    /*
234     * do initial clip; should look at window gravity
235     */
236    if (tmp_win->attr.width > Scr->MaxWindowWidth)
237      tmp_win->attr.width = Scr->MaxWindowWidth;
238    if (tmp_win->attr.height > Scr->MaxWindowHeight)
239      tmp_win->attr.height = Scr->MaxWindowHeight;
240
241    tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w);
242
243    if (tmp_win->wmhints)
244    {
245	if (restore_iconified)
246	{
247	    tmp_win->wmhints->initial_state = IconicState;
248	    tmp_win->wmhints->flags |= StateHint;
249	}
250
251	if (restore_icon_info_present)
252	{
253	    tmp_win->wmhints->icon_x = restore_icon_x;
254	    tmp_win->wmhints->icon_y = restore_icon_y;
255	    tmp_win->wmhints->flags |= IconPositionHint;
256	}
257    }
258
259    if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint))
260      tmp_win->group = tmp_win->wmhints->window_group;
261    else
262	tmp_win->group = tmp_win->w/* NULL */;
263
264    /*
265     * The July 27, 1988 draft of the ICCCM ignores the size and position
266     * fields in the WM_NORMAL_HINTS property.
267     */
268
269    tmp_win->transient = Transient(tmp_win->w, &tmp_win->transientfor);
270
271    tmp_win->nameChanged = 0;
272    if (tmp_win->class.res_name == NULL)
273    	tmp_win->class.res_name = NoName;
274    if (tmp_win->class.res_class == NULL)
275    	tmp_win->class.res_class = NoName;
276
277    tmp_win->full_name = strdup(tmp_win->name);
278    namelen = strlen (tmp_win->name);
279
280    tmp_win->highlight = Scr->Highlight &&
281	(!(short)(long) LookInList(Scr->NoHighlight, tmp_win->full_name,
282	    &tmp_win->class));
283
284    tmp_win->stackmode = Scr->StackMode &&
285	(!(short)(long) LookInList(Scr->NoStackModeL, tmp_win->full_name,
286	    &tmp_win->class));
287
288    tmp_win->titlehighlight = Scr->TitleHighlight &&
289	(!(short)(long) LookInList(Scr->NoTitleHighlight, tmp_win->full_name,
290	    &tmp_win->class));
291
292    tmp_win->auto_raise = (short)(long) LookInList(Scr->AutoRaise,
293						  tmp_win->full_name,
294					    &tmp_win->class);
295    if (tmp_win->auto_raise) Scr->NumAutoRaises++;
296    tmp_win->iconify_by_unmapping = Scr->IconifyByUnmapping;
297    if (Scr->IconifyByUnmapping)
298    {
299	tmp_win->iconify_by_unmapping = iconm ? FALSE :
300	    !(short)(long) LookInList(Scr->DontIconify, tmp_win->full_name,
301		&tmp_win->class);
302    }
303    tmp_win->iconify_by_unmapping |=
304	(short)(long) LookInList(Scr->IconifyByUn, tmp_win->full_name,
305	    &tmp_win->class);
306
307    if (LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->class)) {
308	if (Scr->Ring) {
309	    tmp_win->ring.next = Scr->Ring->ring.next;
310	    if (Scr->Ring->ring.next->ring.prev)
311	      Scr->Ring->ring.next->ring.prev = tmp_win;
312	    Scr->Ring->ring.next = tmp_win;
313	    tmp_win->ring.prev = Scr->Ring;
314	} else {
315	    tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
316	}
317    } else
318      tmp_win->ring.next = tmp_win->ring.prev = NULL;
319    tmp_win->ring.cursor_valid = False;
320
321    tmp_win->squeeze_info = NULL;
322    /*
323     * get the squeeze information; note that this does not have to be freed
324     * since it is coming from the screen list
325     */
326    if (HasShape) {
327	if (!LookInList (Scr->DontSqueezeTitleL, tmp_win->full_name,
328			 &tmp_win->class)) {
329	    tmp_win->squeeze_info = (SqueezeInfo *)
330	      LookInList (Scr->SqueezeTitleL, tmp_win->full_name,
331			  &tmp_win->class);
332	    if (!tmp_win->squeeze_info) {
333		static SqueezeInfo default_squeeze = { J_LEFT, 0, 0 };
334		if (Scr->SqueezeTitle)
335		  tmp_win->squeeze_info = &default_squeeze;
336	    }
337	}
338      }
339
340    tmp_win->old_bw = tmp_win->attr.border_width;
341
342    if (Scr->ClientBorderWidth) {
343    	tmp_win->frame_bw = tmp_win->old_bw;
344    } else {
345    	tmp_win->frame_bw = Scr->BorderWidth;
346    }
347    bw2 = tmp_win->frame_bw * 2;
348
349    tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
350    if (Scr->NoTitlebar)
351        tmp_win->title_height = 0;
352    if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->class))
353        tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
354    if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->class))
355        tmp_win->title_height = 0;
356
357    /* if it is a transient window, don't put a title on it */
358    if (tmp_win->transient && !Scr->DecorateTransients)
359	tmp_win->title_height = 0;
360
361    if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->class))
362    {
363	if (!tmp_win->wmhints)
364	{
365	    tmp_win->wmhints = (XWMHints *)malloc(sizeof(XWMHints));
366	    tmp_win->wmhints->flags = 0;
367	}
368	tmp_win->wmhints->initial_state = IconicState;
369	tmp_win->wmhints->flags |= StateHint;
370    }
371
372    GetWindowSizeHints (tmp_win);
373
374    if (restoredFromPrevSession)
375    {
376	/*
377	 * When restoring window positions from the previous session,
378	 * we always use NorthWest gravity.
379	 */
380
381	gravx = gravy = -1;
382    }
383    else
384    {
385	GetGravityOffsets (tmp_win, &gravx, &gravy);
386    }
387
388    /*
389     * Don't bother user if:
390     *
391     *     o  the window is a transient, or
392     *
393     *     o  a USPosition was requested, or
394     *
395     *     o  a PPosition was requested and UsePPosition is ON or
396     *        NON_ZERO if the window is at other than (0,0)
397     */
398    ask_user = TRUE;
399    if (tmp_win->transient ||
400	(tmp_win->hints.flags & USPosition) ||
401        ((tmp_win->hints.flags & PPosition) && Scr->UsePPosition &&
402	 (Scr->UsePPosition == PPOS_ON ||
403	  tmp_win->attr.x != 0 || tmp_win->attr.y != 0)))
404      ask_user = FALSE;
405
406    /*
407     * do any prompting for position
408     */
409    if (HandlingEvents && ask_user && !restoredFromPrevSession) {
410      if (Scr->RandomPlacement) {	/* just stick it somewhere */
411	if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth)
412	    PlaceX = 50;
413	if ((PlaceY + tmp_win->attr.height) > Scr->MyDisplayHeight)
414	    PlaceY = 50;
415
416	tmp_win->attr.x = PlaceX;
417	tmp_win->attr.y = PlaceY;
418	PlaceX += 30;
419	PlaceY += 30;
420      } else {				/* else prompt */
421	if (!(tmp_win->wmhints && tmp_win->wmhints->flags & StateHint &&
422	      tmp_win->wmhints->initial_state == IconicState))
423	{
424	    Bool firsttime = True;
425
426	    /* better wait until all the mouse buttons have been
427	     * released.
428	     */
429	    while (TRUE)
430	    {
431		XUngrabServer(dpy);
432		XSync(dpy, 0);
433		XGrabServer(dpy);
434
435		JunkMask = 0;
436		if (!XQueryPointer (dpy, Scr->Root, &JunkRoot,
437				    &JunkChild, &JunkX, &JunkY,
438				    &AddingX, &AddingY, &JunkMask))
439		  JunkMask = 0;
440
441		JunkMask &= (Button1Mask | Button2Mask | Button3Mask |
442			     Button4Mask | Button5Mask);
443
444		/*
445		 * watch out for changing screens
446		 */
447		if (firsttime) {
448		    if (JunkRoot != Scr->Root) {
449			register int scrnum;
450
451			for (scrnum = 0; scrnum < NumScreens; scrnum++) {
452			    if (JunkRoot == RootWindow (dpy, scrnum)) break;
453			}
454
455			if (scrnum != NumScreens) PreviousScreen = scrnum;
456		    }
457		    firsttime = False;
458		}
459
460		/*
461		 * wait for buttons to come up; yuck
462		 */
463		if (JunkMask != 0) continue;
464
465		/*
466		 * this will cause a warp to the indicated root
467		 */
468		stat = XGrabPointer(dpy, Scr->Root, False,
469		    ButtonPressMask | ButtonReleaseMask |
470		    PointerMotionMask | PointerMotionHintMask,
471		    GrabModeAsync, GrabModeAsync,
472		    Scr->Root, UpperLeftCursor, CurrentTime);
473
474		if (stat == GrabSuccess)
475		    break;
476	    }
477
478	    width = (SIZE_HINDENT + MyFont_TextWidth (&Scr->SizeFont,
479						tmp_win->name, namelen));
480	    height = Scr->SizeFont.height + SIZE_VINDENT * 2;
481
482	    XResizeWindow (dpy, Scr->SizeWindow, width + SIZE_HINDENT, height);
483	    XMapRaised(dpy, Scr->SizeWindow);
484	    InstallRootColormap();
485
486	    MyFont_ChangeGC(Scr->DefaultC.fore, Scr->DefaultC.back,
487			    &Scr->SizeFont);
488	    MyFont_DrawImageString (dpy, Scr->SizeWindow, &Scr->SizeFont,
489				    Scr->NormalGC,
490				    SIZE_HINDENT,
491				    SIZE_VINDENT + Scr->SizeFont.ascent,
492				    tmp_win->name, namelen);
493
494	    AddingW = tmp_win->attr.width + bw2;
495	    AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
496
497  	    if (Scr->DontMoveOff) {
498  		/*
499		 * Make sure the initial outline comes up on the screen.
500  		 */
501  		if (AddingX < 0)
502  		    AddingX = 0;
503  		if (AddingX > Scr->MyDisplayWidth - AddingW)
504  		    AddingX = Scr->MyDisplayWidth - AddingW;
505
506  		if (AddingY < 0)
507  		    AddingY = 0;
508  		if (AddingY > Scr->MyDisplayHeight - AddingH)
509  		    AddingY = Scr->MyDisplayHeight - AddingH;
510  	    }
511
512	    MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
513	      	        tmp_win->frame_bw, tmp_win->title_height);
514
515	    while (TRUE)
516		{
517		XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, &event);
518
519		if (Event.type == MotionNotify) {
520		    /* discard any extra motion events before a release */
521		    while(XCheckMaskEvent(dpy,
522			ButtonMotionMask | ButtonPressMask, &Event))
523			if (Event.type == ButtonPress)
524			    break;
525		}
526
527		if (event.type == ButtonPress) {
528		  AddingX = event.xbutton.x_root;
529		  AddingY = event.xbutton.y_root;
530
531		  /* DontMoveOff prohibits user form off-screen placement */
532		  if (Scr->DontMoveOff)
533  		    {
534		      int AddingR, AddingB;
535
536		      AddingR = AddingX + AddingW;
537		      AddingB = AddingY + AddingH;
538
539		      if (AddingX < 0)
540			AddingX = 0;
541		      if (AddingR > Scr->MyDisplayWidth)
542			AddingX = Scr->MyDisplayWidth - AddingW;
543
544		      if (AddingY < 0)
545			AddingY = 0;
546		      if (AddingB > Scr->MyDisplayHeight)
547			AddingY = Scr->MyDisplayHeight - AddingH;
548
549 		    }
550		  break;
551		}
552
553		if (event.type != MotionNotify) {
554		    continue;
555	    }
556
557		XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
558		    &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
559
560		if (Scr->DontMoveOff)
561		{
562		    int AddingR, AddingB;
563
564		    AddingR = AddingX + AddingW;
565		    AddingB = AddingY + AddingH;
566
567		    if (AddingX < 0)
568		        AddingX = 0;
569		    if (AddingR > Scr->MyDisplayWidth)
570		        AddingX = Scr->MyDisplayWidth - AddingW;
571
572		    if (AddingY < 0)
573			AddingY = 0;
574		    if (AddingB > Scr->MyDisplayHeight)
575			AddingY = Scr->MyDisplayHeight - AddingH;
576		}
577
578		MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
579			    tmp_win->frame_bw, tmp_win->title_height);
580
581	    }
582
583	    if (event.xbutton.button == Button2) {
584		int lastx, lasty;
585
586		Scr->SizeStringOffset = width +
587		  MyFont_TextWidth(&Scr->SizeFont, ": ", 2);
588		XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
589			       Scr->SizeStringWidth, height);
590		MyFont_DrawImageString (dpy, Scr->SizeWindow, &Scr->SizeFont,
591				  Scr->NormalGC, width,
592				  SIZE_VINDENT + Scr->SizeFont.ascent,
593				  ": ", 2);
594		if (0/*Scr->AutoRelativeResize*/) {
595		    int dx = (tmp_win->attr.width / 4);
596		    int dy = (tmp_win->attr.height / 4);
597
598#define HALF_AVE_CURSOR_SIZE 8		/* so that it is visible */
599		    if (dx < HALF_AVE_CURSOR_SIZE) dx = HALF_AVE_CURSOR_SIZE;
600		    if (dy < HALF_AVE_CURSOR_SIZE) dy = HALF_AVE_CURSOR_SIZE;
601#undef HALF_AVE_CURSOR_SIZE
602		    dx += (tmp_win->frame_bw + 1);
603		    dy += (bw2 + tmp_win->title_height + 1);
604		    if (AddingX + dx >= Scr->MyDisplayWidth)
605		      dx = Scr->MyDisplayWidth - AddingX - 1;
606		    if (AddingY + dy >= Scr->MyDisplayHeight)
607		      dy = Scr->MyDisplayHeight - AddingY - 1;
608		    if (dx > 0 && dy > 0)
609		      XWarpPointer (dpy, None, None, 0, 0, 0, 0, dx, dy);
610		} else {
611		    XWarpPointer (dpy, None, Scr->Root, 0, 0, 0, 0,
612				  AddingX + AddingW/2, AddingY + AddingH/2);
613		}
614		AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH);
615
616		lastx = -10000;
617		lasty = -10000;
618		while (TRUE)
619		{
620		    XMaskEvent(dpy,
621			       ButtonReleaseMask | ButtonMotionMask, &event);
622
623		    if (Event.type == MotionNotify) {
624			/* discard any extra motion events before a release */
625			while(XCheckMaskEvent(dpy,
626			    ButtonMotionMask | ButtonReleaseMask, &Event))
627			    if (Event.type == ButtonRelease)
628				break;
629		    }
630
631		    if (event.type == ButtonRelease)
632		    {
633			AddEndResize(tmp_win);
634			break;
635		    }
636
637		    if (event.type != MotionNotify) {
638			continue;
639		    }
640
641		    /*
642		     * XXX - if we are going to do a loop, we ought to consider
643		     * using multiple GXxor lines so that we don't need to
644		     * grab the server.
645		     */
646		    XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
647			&JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
648
649		    if (lastx != AddingX || lasty != AddingY)
650		    {
651			DoResize(AddingX, AddingY, tmp_win);
652
653			lastx = AddingX;
654			lasty = AddingY;
655		    }
656
657		}
658	    }
659	    else if (event.xbutton.button == Button3)
660	    {
661		int maxw = Scr->MyDisplayWidth - AddingX - bw2;
662		int maxh = Scr->MyDisplayHeight - AddingY - bw2;
663
664		/*
665		 * Make window go to bottom of screen, and clip to right edge.
666		 * This is useful when popping up large windows and fixed
667		 * column text windows.
668		 */
669		if (AddingW > maxw) AddingW = maxw;
670		AddingH = maxh;
671
672		ConstrainSize (tmp_win, &AddingW, &AddingH);  /* w/o borders */
673		AddingW += bw2;
674		AddingH += bw2;
675	    }
676	    else
677	    {
678		XMaskEvent(dpy, ButtonReleaseMask, &event);
679	    }
680
681	    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
682	    XUnmapWindow(dpy, Scr->SizeWindow);
683	    UninstallRootColormap();
684	    XUngrabPointer(dpy, CurrentTime);
685
686	    tmp_win->attr.x = AddingX;
687	    tmp_win->attr.y = AddingY + tmp_win->title_height;
688	    tmp_win->attr.width = AddingW - bw2;
689	    tmp_win->attr.height = AddingH - tmp_win->title_height - bw2;
690
691	    XUngrabServer(dpy);
692	}
693      }
694    } else {				/* put it where asked, mod title bar */
695	/* if the gravity is towards the top, move it by the title height */
696	if (gravy < 0) tmp_win->attr.y -= gravy * tmp_win->title_height;
697    }
698
699
700#ifdef DEBUG
701	fprintf(stderr, "  position window  %d, %d  %dx%d\n",
702	    tmp_win->attr.x,
703	    tmp_win->attr.y,
704	    tmp_win->attr.width,
705	    tmp_win->attr.height);
706#endif
707
708    if (!Scr->ClientBorderWidth) {	/* need to adjust for twm borders */
709	int delta = tmp_win->attr.border_width - tmp_win->frame_bw;
710	tmp_win->attr.x += gravx * delta;
711	tmp_win->attr.y += gravy * delta;
712    }
713
714    tmp_win->title_width = tmp_win->attr.width;
715
716    if (tmp_win->old_bw) XSetWindowBorderWidth (dpy, tmp_win->w, 0);
717
718    tmp_win->name_width = MyFont_TextWidth(&Scr->TitleBarFont, tmp_win->name,
719					    namelen);
720
721    if (!I18N_GetIconName(dpy, tmp_win->w, &name)) {
722	tmp_win->icon_name = strdup(tmp_win->name);
723    } else {
724	if (name == NULL) {
725	    tmp_win->icon_name = strdup(tmp_win->name);
726	} else {
727	    tmp_win->icon_name = strdup(name);
728	    free(name);
729	}
730    }
731
732    tmp_win->iconified = FALSE;
733    tmp_win->icon = FALSE;
734    tmp_win->icon_on = FALSE;
735
736    XGrabServer(dpy);
737
738    /*
739     * Make sure the client window still exists.  We don't want to leave an
740     * orphan frame window if it doesn't.  Since we now have the server
741     * grabbed, the window can't disappear later without having been
742     * reparented, so we'll get a DestroyNotify for it.  We won't have
743     * gotten one for anything up to here, however.
744     */
745    if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
746		     &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
747    {
748	free((char *)tmp_win);
749	XUngrabServer(dpy);
750	return(NULL);
751    }
752
753    /* add the window into the twm list */
754    tmp_win->next = Scr->TwmRoot.next;
755    if (Scr->TwmRoot.next != NULL)
756	Scr->TwmRoot.next->prev = tmp_win;
757    tmp_win->prev = &Scr->TwmRoot;
758    Scr->TwmRoot.next = tmp_win;
759
760    /* get all the colors for the window */
761
762    tmp_win->border = Scr->BorderColor;
763    tmp_win->icon_border = Scr->IconBorderColor;
764    tmp_win->border_tile.fore = Scr->BorderTileC.fore;
765    tmp_win->border_tile.back = Scr->BorderTileC.back;
766    tmp_win->title.fore = Scr->TitleC.fore;
767    tmp_win->title.back = Scr->TitleC.back;
768    tmp_win->iconc.fore = Scr->IconC.fore;
769    tmp_win->iconc.back = Scr->IconC.back;
770
771    GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class,
772	&tmp_win->border);
773    GetColorFromList(Scr->IconBorderColorL, tmp_win->full_name, &tmp_win->class,
774	&tmp_win->icon_border);
775    GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name,
776	&tmp_win->class, &tmp_win->border_tile.fore);
777    GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name,
778	&tmp_win->class, &tmp_win->border_tile.back);
779    GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, &tmp_win->class,
780	&tmp_win->title.fore);
781    GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, &tmp_win->class,
782	&tmp_win->title.back);
783    GetColorFromList(Scr->IconForegroundL, tmp_win->full_name, &tmp_win->class,
784	&tmp_win->iconc.fore);
785    GetColorFromList(Scr->IconBackgroundL, tmp_win->full_name, &tmp_win->class,
786	&tmp_win->iconc.back);
787
788
789    /* create windows */
790
791    tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw;
792    tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height +
793	tmp_win->old_bw - tmp_win->frame_bw;
794    tmp_win->frame_width = tmp_win->attr.width;
795    tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height;
796
797    valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask;
798    attributes.background_pixmap = None;
799    attributes.border_pixel = tmp_win->border;
800    attributes.cursor = Scr->FrameCursor;
801    attributes.event_mask = (SubstructureRedirectMask |
802			     ButtonPressMask | ButtonReleaseMask |
803			     EnterWindowMask | LeaveWindowMask);
804    if (tmp_win->attr.save_under) {
805	attributes.save_under = True;
806	valuemask |= CWSaveUnder;
807    }
808
809    tmp_win->frame = XCreateWindow (dpy, Scr->Root, tmp_win->frame_x,
810				    tmp_win->frame_y,
811				    (unsigned int) tmp_win->frame_width,
812				    (unsigned int) tmp_win->frame_height,
813				    (unsigned int) tmp_win->frame_bw,
814				    Scr->d_depth,
815				    (unsigned int) CopyFromParent,
816				    Scr->d_visual, valuemask, &attributes);
817
818    if (tmp_win->title_height)
819    {
820	valuemask = (CWEventMask | CWBorderPixel | CWBackPixel);
821	attributes.event_mask = (KeyPressMask | ButtonPressMask |
822				 ButtonReleaseMask | ExposureMask);
823	attributes.border_pixel = tmp_win->border;
824	attributes.background_pixel = tmp_win->title.back;
825	tmp_win->title_w = XCreateWindow (dpy, tmp_win->frame,
826					  -tmp_win->frame_bw,
827					  -tmp_win->frame_bw,
828					  (unsigned int) tmp_win->attr.width,
829					  (unsigned int) Scr->TitleHeight,
830					  (unsigned int) tmp_win->frame_bw,
831					  Scr->d_depth,
832					  (unsigned int) CopyFromParent,
833					  Scr->d_visual, valuemask,
834					  &attributes);
835    }
836    else {
837	tmp_win->title_w = 0;
838	tmp_win->squeeze_info = NULL;
839    }
840
841    if (tmp_win->highlight)
842    {
843	tmp_win->gray = XCreatePixmapFromBitmapData(dpy, Scr->Root,
844	    gray_bits, gray_width, gray_height,
845	    tmp_win->border_tile.fore, tmp_win->border_tile.back,
846	    Scr->d_depth);
847
848	SetBorder (tmp_win, False);
849    }
850    else
851	tmp_win->gray = None;
852
853
854    if (tmp_win->title_w) {
855	CreateWindowTitlebarButtons (tmp_win);
856	ComputeTitleLocation (tmp_win);
857	XMoveWindow (dpy, tmp_win->title_w,
858		     tmp_win->title_x, tmp_win->title_y);
859	XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor);
860    }
861
862    valuemask = (CWEventMask | CWDontPropagate);
863    attributes.event_mask = (StructureNotifyMask | PropertyChangeMask |
864			     ColormapChangeMask | VisibilityChangeMask |
865			     EnterWindowMask | LeaveWindowMask);
866    attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
867    XChangeWindowAttributes (dpy, tmp_win->w, valuemask, &attributes);
868
869    if (HasShape)
870	XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
871
872    if (tmp_win->title_w) {
873	XMapWindow (dpy, tmp_win->title_w);
874    }
875
876    if (HasShape) {
877	int xws, yws, xbs, ybs;
878	unsigned wws, hws, wbs, hbs;
879	int boundingShaped, clipShaped;
880
881	XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
882	XShapeQueryExtents (dpy, tmp_win->w,
883			    &boundingShaped, &xws, &yws, &wws, &hws,
884			    &clipShaped, &xbs, &ybs, &wbs, &hbs);
885	tmp_win->wShaped = boundingShaped;
886    }
887
888    if (!tmp_win->iconmgr)
889	XAddToSaveSet(dpy, tmp_win->w);
890
891    XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, tmp_win->title_height);
892    /*
893     * Reparenting generates an UnmapNotify event, followed by a MapNotify.
894     * Set the map state to FALSE to prevent a transition back to
895     * WithdrawnState in HandleUnmapNotify.  Map state gets set correctly
896     * again in HandleMapNotify.
897     */
898    tmp_win->mapped = FALSE;
899
900    SetupFrame (tmp_win, tmp_win->frame_x, tmp_win->frame_y,
901		tmp_win->frame_width, tmp_win->frame_height, -1, True);
902
903    /* wait until the window is iconified and the icon window is mapped
904     * before creating the icon window
905     */
906    tmp_win->icon_w = (Window) 0;
907
908    if (!tmp_win->iconmgr)
909    {
910	GrabButtons(tmp_win);
911	GrabKeys(tmp_win);
912    }
913
914    (void) AddIconManager(tmp_win);
915
916    XSaveContext(dpy, tmp_win->w, TwmContext, (caddr_t) tmp_win);
917    XSaveContext(dpy, tmp_win->w, ScreenContext, (caddr_t) Scr);
918    XSaveContext(dpy, tmp_win->frame, TwmContext, (caddr_t) tmp_win);
919    XSaveContext(dpy, tmp_win->frame, ScreenContext, (caddr_t) Scr);
920    if (tmp_win->title_height)
921    {
922	int i;
923	int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
924
925	XSaveContext(dpy, tmp_win->title_w, TwmContext, (caddr_t) tmp_win);
926	XSaveContext(dpy, tmp_win->title_w, ScreenContext, (caddr_t) Scr);
927	for (i = 0; i < nb; i++) {
928	    XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext,
929			 (caddr_t) tmp_win);
930	    XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext,
931			 (caddr_t) Scr);
932	}
933	if (tmp_win->hilite_w)
934	{
935	    XSaveContext(dpy, tmp_win->hilite_w, TwmContext, (caddr_t)tmp_win);
936	    XSaveContext(dpy, tmp_win->hilite_w, ScreenContext, (caddr_t)Scr);
937	}
938    }
939
940    XUngrabServer(dpy);
941
942    /* if we were in the middle of a menu activated function, regrab
943     * the pointer
944     */
945    if (RootFunction)
946	ReGrab();
947
948    return (tmp_win);
949}
950
951
952/**
953 * checks to see if we should really put a twm frame on the window
954 *
955 *  \return TRUE  - go ahead and place the window
956 *  \return FALSE - don't frame the window
957 *	\param w the window to check
958 */
959int
960MappedNotOverride(Window w)
961{
962    XWindowAttributes wa;
963
964    XGetWindowAttributes(dpy, w, &wa);
965    return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True));
966}
967
968
969/**
970 * attach default bindings so that naive users don't get messed up if they
971 * provide a minimal twmrc.
972 */
973static void do_add_binding (int button, int context, int modifier, int func)
974{
975    MouseButton *mb = &Scr->Mouse[button][context][modifier];
976
977    if (mb->func) return;		/* already defined */
978
979    mb->func = func;
980    mb->item = NULL;
981}
982
983void
984AddDefaultBindings ()
985{
986    /*
987     * The bindings are stored in Scr->Mouse, indexed by
988     * Mouse[button_number][C_context][modifier].
989     */
990
991#define NoModifierMask 0
992
993    do_add_binding (Button1, C_TITLE, NoModifierMask, F_MOVE);
994    do_add_binding (Button1, C_ICON, NoModifierMask, F_ICONIFY);
995    do_add_binding (Button1, C_ICONMGR, NoModifierMask, F_ICONIFY);
996
997    do_add_binding (Button2, C_TITLE, NoModifierMask, F_RAISELOWER);
998    do_add_binding (Button2, C_ICON, NoModifierMask, F_ICONIFY);
999    do_add_binding (Button2, C_ICONMGR, NoModifierMask, F_ICONIFY);
1000
1001#undef NoModifierMask
1002}
1003
1004
1005
1006
1007/**
1008 * grab needed buttons for the window
1009 *
1010 *  \param[in] tmp_win the twm window structure to use
1011 */
1012void
1013GrabButtons(TwmWindow *tmp_win)
1014{
1015    int i, j;
1016
1017    for (i = 0; i < MAX_BUTTONS+1; i++)
1018    {
1019	for (j = 0; j < MOD_SIZE; j++)
1020	{
1021	    if (Scr->Mouse[i][C_WINDOW][j].func != 0)
1022	    {
1023	        /* twm used to do this grab on the application main window,
1024                 * tmp_win->w . This was not ICCCM complient and was changed.
1025		 */
1026		XGrabButton(dpy, i, j, tmp_win->frame,
1027			    True, ButtonPressMask | ButtonReleaseMask,
1028			    GrabModeAsync, GrabModeAsync, None,
1029			    Scr->FrameCursor);
1030	    }
1031	}
1032    }
1033}
1034
1035/**
1036 * grab needed keys for the window
1037 *
1038 *  \param[in] tmp_win the twm window structure to use
1039 */
1040void
1041GrabKeys(TwmWindow *tmp_win)
1042{
1043    FuncKey *tmp;
1044    IconMgr *p;
1045
1046    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
1047    {
1048	switch (tmp->cont)
1049	{
1050	case C_WINDOW:
1051	    XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
1052		GrabModeAsync, GrabModeAsync);
1053	    break;
1054
1055	case C_ICON:
1056	    if (tmp_win->icon_w)
1057		XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True,
1058		    GrabModeAsync, GrabModeAsync);
1059
1060	case C_TITLE:
1061	    if (tmp_win->title_w)
1062		XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True,
1063		    GrabModeAsync, GrabModeAsync);
1064	    break;
1065
1066	case C_NAME:
1067	    XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
1068		GrabModeAsync, GrabModeAsync);
1069	    if (tmp_win->icon_w)
1070		XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True,
1071		    GrabModeAsync, GrabModeAsync);
1072	    if (tmp_win->title_w)
1073		XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True,
1074		    GrabModeAsync, GrabModeAsync);
1075	    break;
1076	/*
1077	case C_ROOT:
1078	    XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True,
1079		GrabModeAsync, GrabModeAsync);
1080	    break;
1081	*/
1082	}
1083    }
1084    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
1085    {
1086	if (tmp->cont == C_ICONMGR && !Scr->NoIconManagers)
1087	{
1088	    for (p = &Scr->iconmgr; p != NULL; p = p->next)
1089	    {
1090		XUngrabKey(dpy, tmp->keycode, tmp->mods, p->twm_win->w);
1091	    }
1092	}
1093    }
1094}
1095
1096static Window CreateHighlightWindow (TwmWindow *tmp_win)
1097{
1098    XSetWindowAttributes attributes;	/* attributes for create windows */
1099    Pixmap pm = None;
1100    GC gc;
1101    XGCValues gcv;
1102    unsigned long valuemask;
1103    int h = (Scr->TitleHeight - 2 * Scr->FramePadding);
1104    Window w;
1105
1106
1107    /*
1108     * If a special highlight pixmap was given, use that.  Otherwise,
1109     * use a nice, even gray pattern.  The old horizontal lines look really
1110     * awful on interlaced monitors (as well as resembling other looks a
1111     * little bit too closely), but can be used by putting
1112     *
1113     *                 Pixmaps { TitleHighlight "hline2" }
1114     *
1115     * (or whatever the horizontal line bitmap is named) in the startup
1116     * file.  If all else fails, use the foreground color to look like a
1117     * solid line.
1118     */
1119    if (!Scr->hilitePm) {
1120	Scr->hilitePm = XCreateBitmapFromData (dpy, tmp_win->title_w,
1121					       gray_bits, gray_width,
1122					       gray_height);
1123	Scr->hilite_pm_width = gray_width;
1124	Scr->hilite_pm_height = gray_height;
1125    }
1126    if (Scr->hilitePm) {
1127	pm = XCreatePixmap (dpy, tmp_win->title_w,
1128			    Scr->hilite_pm_width, Scr->hilite_pm_height,
1129			    Scr->d_depth);
1130	gcv.foreground = tmp_win->title.fore;
1131	gcv.background = tmp_win->title.back;
1132	gcv.graphics_exposures = False;
1133	gc = XCreateGC (dpy, pm,
1134			(GCForeground|GCBackground|GCGraphicsExposures),
1135			&gcv);
1136	if (gc) {
1137	    XCopyPlane (dpy, Scr->hilitePm, pm, gc, 0, 0,
1138			Scr->hilite_pm_width, Scr->hilite_pm_height,
1139			0, 0, 1);
1140	    XFreeGC (dpy, gc);
1141	} else {
1142	    XFreePixmap (dpy, pm);
1143	    pm = None;
1144	}
1145    }
1146    if (pm) {
1147	valuemask = CWBackPixmap;
1148	attributes.background_pixmap = pm;
1149    } else {
1150	valuemask = CWBackPixel;
1151	attributes.background_pixel = tmp_win->title.fore;
1152    }
1153
1154    w = XCreateWindow (dpy, tmp_win->title_w, 0, Scr->FramePadding,
1155		       (unsigned int) Scr->TBInfo.width, (unsigned int) h,
1156		       (unsigned int) 0,
1157		       Scr->d_depth, (unsigned int) CopyFromParent,
1158		       Scr->d_visual, valuemask, &attributes);
1159    if (pm) XFreePixmap (dpy, pm);
1160    return w;
1161}
1162
1163
1164void ComputeCommonTitleOffsets ()
1165{
1166    int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
1167
1168    Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding;
1169    if (Scr->TBInfo.nleft > 0)
1170      Scr->TBInfo.leftx += Scr->ButtonIndent;
1171    Scr->TBInfo.titlex = (Scr->TBInfo.leftx +
1172			  (Scr->TBInfo.nleft * buttonwidth) - Scr->TBInfo.pad +
1173			  Scr->TitlePadding);
1174    if (Scr->TBInfo.nright > 0)
1175      Scr->TBInfo.rightoff += (Scr->ButtonIndent +
1176			       ((Scr->TBInfo.nright * buttonwidth) -
1177				Scr->TBInfo.pad));
1178    return;
1179}
1180
1181void ComputeWindowTitleOffsets (TwmWindow *tmp_win, int width, Bool squeeze)
1182{
1183    tmp_win->highlightx = (Scr->TBInfo.titlex + tmp_win->name_width);
1184    if (tmp_win->hilite_w || Scr->TBInfo.nright > 0)
1185      tmp_win->highlightx += Scr->TitlePadding;
1186    tmp_win->rightx = width - Scr->TBInfo.rightoff;
1187    if (squeeze && tmp_win->squeeze_info) {
1188	int rx = (tmp_win->highlightx +
1189		  (tmp_win->hilite_w
1190		    ? Scr->TBInfo.width * 2 : 0) +
1191		  (Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) +
1192		  Scr->FramePadding);
1193	if (rx < tmp_win->rightx) tmp_win->rightx = rx;
1194    }
1195    return;
1196}
1197
1198
1199/**
1200 * calculate the position of the title window.  We need to take the frame_bw
1201 * into account since we want (0,0) of the title window to line up with (0,0)
1202 * of the frame window.
1203 */
1204void ComputeTitleLocation (register TwmWindow *tmp)
1205{
1206    tmp->title_x = -tmp->frame_bw;
1207    tmp->title_y = -tmp->frame_bw;
1208
1209    if (tmp->squeeze_info) {
1210	register SqueezeInfo *si = tmp->squeeze_info;
1211	int basex;
1212	int maxwidth = tmp->frame_width;
1213	int tw = tmp->title_width;
1214
1215	/*
1216	 * figure label base from squeeze info (justification fraction)
1217	 */
1218	if (si->denom == 0) {	/* num is pixel based */
1219	    if ((basex = si->num) == 0) {  /* look for special cases */
1220		switch (si->justify) {
1221		  case J_RIGHT:
1222		    basex = maxwidth;
1223		    break;
1224		  case J_CENTER:
1225		    basex = maxwidth / 2;
1226		break;
1227		}
1228	    }
1229	} else {			/* num/denom is fraction */
1230	    basex = ((si->num * maxwidth) / si->denom);
1231	    if (si->num < 0) basex += maxwidth;
1232	}
1233
1234	/*
1235	 * adjust for left (nop), center, right justify and clip
1236	 */
1237	switch (si->justify) {
1238	  case J_CENTER:
1239	    basex -= tw / 2;
1240	    break;
1241	  case J_RIGHT:
1242	    basex -= tw - 1;
1243	    break;
1244	}
1245	if (basex > maxwidth - tw + 1)
1246	  basex = maxwidth - tw + 1;
1247	if (basex < 0) basex = 0;
1248
1249	tmp->title_x = basex - tmp->frame_bw;
1250    }
1251}
1252
1253
1254static void CreateWindowTitlebarButtons (TwmWindow *tmp_win)
1255{
1256    unsigned long valuemask;		/* mask for create windows */
1257    XSetWindowAttributes attributes;	/* attributes for create windows */
1258    int leftx, rightx, y;
1259    TitleButton *tb;
1260    int nb;
1261
1262    if (tmp_win->title_height == 0)
1263    {
1264	tmp_win->hilite_w = 0;
1265	return;
1266    }
1267
1268
1269    /*
1270     * create the title bar windows; let the event handler deal with painting
1271     * so that we don't have to spend two pixmaps (or deal with hashing)
1272     */
1273    ComputeWindowTitleOffsets (tmp_win, tmp_win->attr.width, False);
1274
1275    leftx = y = Scr->TBInfo.leftx;
1276    rightx = tmp_win->rightx;
1277
1278    attributes.win_gravity = NorthWestGravity;
1279    attributes.background_pixel = tmp_win->title.back;
1280    attributes.border_pixel = tmp_win->title.fore;
1281    attributes.event_mask = (ButtonPressMask | ButtonReleaseMask |
1282			     ExposureMask);
1283    attributes.cursor = Scr->ButtonCursor;
1284    valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask |
1285		 CWCursor);
1286
1287    tmp_win->titlebuttons = NULL;
1288    nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1289    if (nb > 0) {
1290	tmp_win->titlebuttons = (TBWindow *) malloc (nb * sizeof(TBWindow));
1291	if (!tmp_win->titlebuttons) {
1292	    fprintf (stderr, "%s:  unable to allocate %d titlebuttons\n",
1293		     ProgramName, nb);
1294	} else {
1295	    TBWindow *tbw;
1296	    int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
1297	    unsigned int h = (Scr->TBInfo.width - Scr->TBInfo.border * 2);
1298
1299	    for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb;
1300		 tb = tb->next, tbw++) {
1301		int x;
1302		if (tb->rightside) {
1303		    x = rightx;
1304		    rightx += boxwidth;
1305		    attributes.win_gravity = NorthEastGravity;
1306		} else {
1307		    x = leftx;
1308		    leftx += boxwidth;
1309		    attributes.win_gravity = NorthWestGravity;
1310		}
1311		tbw->window = XCreateWindow (dpy, tmp_win->title_w, x, y, h, h,
1312					     (unsigned int) Scr->TBInfo.border,
1313					     0, (unsigned int) CopyFromParent,
1314					     (Visual *) CopyFromParent,
1315					     valuemask, &attributes);
1316		tbw->info = tb;
1317	    }
1318	}
1319    }
1320
1321    tmp_win->hilite_w = (tmp_win->titlehighlight
1322			 ? CreateHighlightWindow (tmp_win) : None);
1323
1324    XMapSubwindows(dpy, tmp_win->title_w);
1325    if (tmp_win->hilite_w)
1326      XUnmapWindow(dpy, tmp_win->hilite_w);
1327    return;
1328}
1329
1330
1331void
1332SetHighlightPixmap (char *filename)
1333{
1334    Pixmap pm = GetBitmap (filename);
1335
1336    if (pm) {
1337	if (Scr->hilitePm) {
1338	    XFreePixmap (dpy, Scr->hilitePm);
1339	}
1340	Scr->hilitePm = pm;
1341	Scr->hilite_pm_width = JunkWidth;
1342	Scr->hilite_pm_height = JunkHeight;
1343    }
1344}
1345
1346
1347void
1348FetchWmProtocols (TwmWindow *tmp)
1349{
1350    unsigned long flags = 0L;
1351    Atom *protocols = NULL;
1352    int n;
1353
1354    if (XGetWMProtocols (dpy, tmp->w, &protocols, &n)) {
1355	register int i;
1356	register Atom *ap;
1357
1358	for (i = 0, ap = protocols; i < n; i++, ap++) {
1359	    if (*ap == _XA_WM_TAKE_FOCUS) flags |= DoesWmTakeFocus;
1360	    if (*ap == _XA_WM_SAVE_YOURSELF) flags |= DoesWmSaveYourself;
1361	    if (*ap == _XA_WM_DELETE_WINDOW) flags |= DoesWmDeleteWindow;
1362	}
1363	if (protocols) XFree ((char *) protocols);
1364    }
1365    tmp->protocols = flags;
1366}
1367
1368TwmColormap *
1369CreateTwmColormap(Colormap c)
1370{
1371    TwmColormap *cmap;
1372    cmap = (TwmColormap *) malloc(sizeof(TwmColormap));
1373    if (!cmap ||
1374	XSaveContext(dpy, c, ColormapContext, (caddr_t) cmap)) {
1375	if (cmap) free((char *) cmap);
1376	return (NULL);
1377    }
1378    cmap->c = c;
1379    cmap->state = 0;
1380    cmap->install_req = 0;
1381    cmap->w = None;
1382    cmap->refcnt = 1;
1383    return (cmap);
1384}
1385
1386ColormapWindow *
1387CreateColormapWindow(Window w, Bool creating_parent, Bool property_window)
1388{
1389    ColormapWindow *cwin;
1390    TwmColormap *cmap;
1391    XWindowAttributes attributes;
1392
1393    cwin = (ColormapWindow *) malloc(sizeof(ColormapWindow));
1394    if (cwin) {
1395	if (!XGetWindowAttributes(dpy, w, &attributes) ||
1396	    XSaveContext(dpy, w, ColormapContext, (caddr_t) cwin)) {
1397	    free((char *) cwin);
1398	    return (NULL);
1399	}
1400
1401	if (XFindContext(dpy, attributes.colormap,  ColormapContext,
1402		(caddr_t *)&cwin->colormap) == XCNOENT) {
1403	    cwin->colormap = cmap = CreateTwmColormap(attributes.colormap);
1404	    if (!cmap) {
1405		XDeleteContext(dpy, w, ColormapContext);
1406		free((char *) cwin);
1407		return (NULL);
1408	    }
1409	} else {
1410	    cwin->colormap->refcnt++;
1411	}
1412
1413	cwin->w = w;
1414	/*
1415	 * Assume that windows in colormap list are
1416	 * obscured if we are creating the parent window.
1417	 * Otherwise, we assume they are unobscured.
1418	 */
1419	cwin->visibility = creating_parent ?
1420	    VisibilityPartiallyObscured : VisibilityUnobscured;
1421	cwin->refcnt = 1;
1422
1423	/*
1424	 * If this is a ColormapWindow property window and we
1425	 * are not monitoring ColormapNotify or VisibilityNotify
1426	 * events, we need to.
1427	 */
1428	if (property_window &&
1429	    (attributes.your_event_mask &
1430		(ColormapChangeMask|VisibilityChangeMask)) !=
1431		    (ColormapChangeMask|VisibilityChangeMask)) {
1432	    XSelectInput(dpy, w, attributes.your_event_mask |
1433		(ColormapChangeMask|VisibilityChangeMask));
1434	}
1435    }
1436
1437    return (cwin);
1438}
1439
1440void
1441FetchWmColormapWindows (TwmWindow *tmp)
1442{
1443    register int i, j;
1444    Window *cmap_windows = NULL;
1445    Bool can_free_cmap_windows = False;
1446    int number_cmap_windows = 0;
1447    ColormapWindow **cwins = NULL;
1448    int previously_installed;
1449
1450    number_cmap_windows = 0;
1451
1452    if (/* SUPPRESS 560 */(previously_installed =
1453       (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins))) {
1454	cwins = tmp->cmaps.cwins;
1455	for (i = 0; i < tmp->cmaps.number_cwins; i++)
1456	    cwins[i]->colormap->state = 0;
1457    }
1458
1459    if (XGetWMColormapWindows (dpy, tmp->w, &cmap_windows,
1460			       &number_cmap_windows) &&
1461	number_cmap_windows > 0) {
1462
1463	can_free_cmap_windows = False;
1464	/*
1465	 * check if the top level is in the list, add to front if not
1466	 */
1467	for (i = 0; i < number_cmap_windows; i++) {
1468	    if (cmap_windows[i] == tmp->w) break;
1469	}
1470	if (i == number_cmap_windows) {	 /* not in list */
1471	    Window *new_cmap_windows =
1472	      (Window *) malloc (sizeof(Window) * (number_cmap_windows + 1));
1473
1474	    if (!new_cmap_windows) {
1475		fprintf (stderr,
1476			 "%s:  unable to allocate %d element colormap window array\n",
1477			ProgramName, number_cmap_windows+1);
1478		goto done;
1479	    }
1480	    new_cmap_windows[0] = tmp->w;  /* add to front */
1481	    for (i = 0; i < number_cmap_windows; i++) {	 /* append rest */
1482		new_cmap_windows[i+1] = cmap_windows[i];
1483	    }
1484	    XFree ((char *) cmap_windows);
1485	    can_free_cmap_windows = True;  /* do not use XFree any more */
1486	    cmap_windows = new_cmap_windows;
1487	    number_cmap_windows++;
1488	}
1489
1490	cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *) *
1491		number_cmap_windows);
1492	if (cwins) {
1493	    for (i = 0; i < number_cmap_windows; i++) {
1494
1495		/*
1496		 * Copy any existing entries into new list.
1497		 */
1498		for (j = 0; j < tmp->cmaps.number_cwins; j++) {
1499		    if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) {
1500			cwins[i] = tmp->cmaps.cwins[j];
1501			cwins[i]->refcnt++;
1502			break;
1503		    }
1504		}
1505
1506		/*
1507		 * If the colormap window is not being pointed by
1508		 * some other applications colormap window list,
1509		 * create a new entry.
1510		 */
1511		if (j == tmp->cmaps.number_cwins) {
1512		    if (XFindContext(dpy, cmap_windows[i], ColormapContext,
1513				     (caddr_t *)&cwins[i]) == XCNOENT) {
1514			if ((cwins[i] = CreateColormapWindow(cmap_windows[i],
1515				    (Bool) tmp->cmaps.number_cwins == 0,
1516				    True)) == NULL) {
1517			    int k;
1518			    for (k = i + 1; k < number_cmap_windows; k++)
1519				cmap_windows[k-1] = cmap_windows[k];
1520			    i--;
1521			    number_cmap_windows--;
1522			}
1523		    } else
1524			cwins[i]->refcnt++;
1525		}
1526	    }
1527	}
1528    }
1529
1530    /* No else here, in case we bailed out of clause above.
1531     */
1532    if (number_cmap_windows == 0) {
1533
1534	number_cmap_windows = 1;
1535
1536	cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *));
1537	if (XFindContext(dpy, tmp->w, ColormapContext, (caddr_t *)&cwins[0]) ==
1538		XCNOENT)
1539	    cwins[0] = CreateColormapWindow(tmp->w,
1540			    (Bool) tmp->cmaps.number_cwins == 0, False);
1541	else
1542	    cwins[0]->refcnt++;
1543    }
1544
1545    if (tmp->cmaps.number_cwins)
1546	free_cwins(tmp);
1547
1548    tmp->cmaps.cwins = cwins;
1549    tmp->cmaps.number_cwins = number_cmap_windows;
1550    if (number_cmap_windows > 1)
1551	tmp->cmaps.scoreboard =
1552	  (char *) calloc(1, ColormapsScoreboardLength(&tmp->cmaps));
1553
1554    if (previously_installed)
1555	InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
1556
1557  done:
1558    if (cmap_windows) {
1559	if (can_free_cmap_windows)
1560	  free ((char *) cmap_windows);
1561	else
1562	  XFree ((char *) cmap_windows);
1563    }
1564
1565    return;
1566}
1567
1568
1569void GetWindowSizeHints (TwmWindow *tmp)
1570{
1571    long supplied = 0;
1572
1573    if (!XGetWMNormalHints (dpy, tmp->w, &tmp->hints, &supplied))
1574      tmp->hints.flags = 0;
1575
1576    if (tmp->hints.flags & PResizeInc) {
1577	if (tmp->hints.width_inc == 0) tmp->hints.width_inc = 1;
1578	if (tmp->hints.height_inc == 0) tmp->hints.height_inc = 1;
1579    }
1580
1581    if (!(supplied & PWinGravity) && (tmp->hints.flags & USPosition)) {
1582	static int gravs[] = { SouthEastGravity, SouthWestGravity,
1583			       NorthEastGravity, NorthWestGravity };
1584	int right =  tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
1585	int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
1586	tmp->hints.win_gravity =
1587	  gravs[((Scr->MyDisplayHeight - bottom < tmp->title_height) ? 0 : 2) |
1588		((Scr->MyDisplayWidth - right   < tmp->title_height) ? 0 : 1)];
1589	tmp->hints.flags |= PWinGravity;
1590    }
1591}
1592