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 /***********************************************************************
30  *
31  * $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $
32  *
33  * twm menu code
34  *
35  * $Log: menus.c,v $
36  * Revision 1.25  1995/02/09  20:08:59  cross
37  * Document a lack of a feature...
38  *
39  * Revision 1.24  1995/02/03  00:13:17  cross
40  * Use XmuCompareISOLatin1(), not FIXED_XmuCompareISOLatin1(), since it
41  * seems to be free of the original bug in R5 and greater (and,
42  * FIXED_XmuCompareISOLatin1() had a bug in it that XmuCompareISOLatin1()
43  * doesn't...)
44  *
45  * Revision 1.23  1994/10/17  20:06:20  cross
46  * Fixed relative resize buglet, and changed around to the X11R6 code
47  * for warping...
48  *
49  * Revision 1.22  1994/03/14  17:33:08  cross
50  * Doesn't SEGV (doesn't do anything at all, now) if you call relativemove
51  * when there's not a window for it to act upon.
52  *
53  * Revision 1.21  1993/12/01  22:58:42  cross
54  * Added f.relativemove...
55  *
56  * Revision 1.20  1993/05/20  15:40:06  cross
57  * pl9b5.  Mostly double-headed machine stuff
58  * XPM fixes to such.
59  *
60  * Revision 1.18  1993/01/20  23:14:34  cross
61  * RJC changes
62  *
63  * Revision 1.17  1992/11/04  01:17:22  cross
64  * Added code from rjc, with filtering.
65  * See text in CHANGES for details.
66  *
67  * Revision 1.16  1992/08/17  15:04:24  cross
68  * Added a needed include of sys/types.h
69  *
70  * Revision 1.15  1992/05/09  02:48:56  cross
71  * Minor modification that should be more correct, but doesn't seem
72  * to change much...
73  *
74  * Revision 1.14  1992/05/02  19:46:35  cross
75  * Added changes by RJC.  A few bug fixes, reorganization of lots of
76  * code, and many new features
77  *
78  * Revision 1.13  1992/02/09  21:50:03  cross
79  * First attempt to make StayUpMenus work again...  There should be
80  * more work done on this...
81  *
82  * Revision 1.12  1992/01/20  20:27:39  cross
83  * Fixed a bug that caused incorect colors on titlebar pixmaps
84  *
85  * Revision 1.11  1992/01/08  18:55:49  cross
86  * rewrote all the color/pixmap code
87  * fixes from Bob Mende (mende@piecomputer.rutgers.edu)
88  *   - f.menufunc works
89  *   - SIGUSR1 implementation
90  *   - ListRings works
91  * don't use m4 by default; added -m/-M flag
92  * DontInterpolateTitles
93  * icon stuff.  IconWindow doesn't get a bad mask.
94  * colors passed to xloadimage
95  *
96  * Revision 1.10  1991/10/29  22:28:11  cross
97  * Updated to be a strict superset of X11R5's twm, not X11R4's.
98  *
99  * Revision 1.9  1991/10/05  08:39:16  cross
100  * Changed to the new version of Xpm (v3.0, released a whole day before
101  * the contrib deadline.  Ugh.)
102  *
103  * Revision 1.8  1991/10/04  22:44:03  cross
104  * Changed the pixmap definition for the pullright pixmap.
105  * Now R5'ized.
106  *
107  * Revision 1.7  1991/10/03  00:09:23  cross
108  * Fixed some bogus uses of the NULL symbol.  Also, had to cast menu12_data
109  * to type char*.  It's unsigned char * in the R5 dist, but XCrPFBData()
110  * still wants a char*.  gcc caught it.
111  *
112  * Revision 1.6  1991/10/02  23:20:05  cross
113  * Spacing changes
114  *
115  * Revision 1.5  1991/10/02  22:36:23  cross
116  * Made some minor adjustements to text in the info window
117  *
118  * Revision 1.4  1991/10/01  20:12:10  cross
119  * Fixed a typo.  Had a "<" where I meant ">="
120  *
121  * Revision 1.3  1991/09/26  00:41:59  cross
122  * Changed old-style call to XCreatePixmapFromData to new-style (Xpm
123  * v3.0 +)
124  * Also, included X11/xpm.h
125  *
126  * Revision 1.2  1991/09/26  00:19:00  cross
127  * Changed all calls to FindBitmap() to FindPixmap().
128  * also, changed ispixmap stuff to isxpm
129  *
130  * Revision 1.1  1991/09/26  00:14:58  cross
131  * Initial revision
132  *
133  * Revision 10.0  91/06/12  09:05:38  toml
134  * Revision bump
135  *
136  * Revision 9.1  91/05/14  11:27:44  toml
137  * Fixed crash problem and removed #include "malloc.h"
138  *
139  * Revision 9.0  91/04/23  07:40:40  toml
140  * Revision bump
141  *
142  * Revision 8.3  91/04/15  09:13:24  toml
143  * Remove version comment
144  *
145  * Revision 8.2  90/12/29  16:39:35  toml
146  * RJC patches
147  *
148  * Revision 8.1  90/12/29  10:13:12  toml
149  * StayUpMenus
150  *
151  * Revision 8.0  90/11/15  20:02:43  toml
152  * Revision bump
153  *
154  * Revision 7.4  90/11/15  19:59:42  toml
155  * removed a printf from a patch
156  *
157  * Revision 7.3  90/11/12  22:05:00  toml
158  * Applied opaque move patches
159  *
160  * Revision 7.2  90/11/12  21:34:54  toml
161  * Implemented Scr->StickyAbove
162  *
163  * Revision 7.1  90/11/12  19:57:25  toml
164  * Patches to allow sticky windows to lower
165  *
166  * Revision 1.2  90/11/04  18:38:22  brossard
167  * Sticky windows are now child of the virtual root.
168  * This has the advantage that they can now be raised and lowered like
169  * any other window.  They no longuer are above everything else.
170  * It has the disadvantage that when you move the desktop, the
171  * sticky windows have to be moved back after scrolling the desktop.
172  *
173  *
174  * 17-Nov-87 Thomas E. LaStrange		File created
175  *
176  ***********************************************************************/
177 
178 #include <stdio.h>
179 #include <signal.h>
180 #include <sys/types.h>
181 #include <sys/stat.h>
182 #include <X11/Xos.h>
183 #include <X11/Xatom.h>
184 #include "twm.h"
185 #include "gc.h"
186 #include "menus.h"
187 #include "resize.h"
188 #include "events.h"
189 #include "util.h"
190 #include "parse.h"
191 #include "gram.h"
192 #include "screen.h"
193 #include <X11/Xmu/CharSet.h>		/* for XmuCompareISOLatin1() */
194 #include "version.h"
195 #include "vdt.h"
196 #include "add_window.h"
197 #include "patchlevel.h"
198 
199 extern XEvent Event;
200 
201 int RootFunction = 0;
202 char *RootAction = NULL;
203 
204 MenuRoot *ActiveMenu = NULL;		/* the active menu */
205 MenuItem *ActiveItem = NULL;		/* the active menu item */
206 int MoveFunction;			/* either F_MOVE or F_FORCEMOVE */
207 int WindowMoved = FALSE;
208 int menuFromFrameOrWindowOrTitlebar = FALSE;
209 
210 int ConstMove = FALSE;		/* constrained move variables */
211 int ConstMoveDir;
212 int ConstMoveX;
213 int ConstMoveY;
214 int ConstMoveXL;
215 int ConstMoveXR;
216 int ConstMoveYT;
217 int ConstMoveYB;
218 
219 /* Globals used to keep track of whether the mouse has moved during
220    a resize function. */
221 int ResizeOrigX;
222 int ResizeOrigY;
223 
224 int MenuDepth = 0;		/* number of menus up */
225 static struct {
226     int x;
227     int y;
228 } MenuOrigins[MAXMENUDEPTH];
229 static Cursor LastCursor;
230 
231 void WarpAlongRing(), WarpToWindow();
232 
233 extern char *Action;
234 extern int Context;
235 extern TwmWindow *ButtonWindow, *Tmp_win;
236 extern XEvent Event, ButtonEvent;
237 extern char *InitFile;
238 static void Identify();
239 
240 #define MAX(x,y) ((x)>(y)?(x):(y))
241 
242 
243 
244 /***********************************************************************
245  *
246  *  Procedure:
247  *	InitMenus - initialize menu roots
248  *
249  ***********************************************************************
250  */
251 
252 void
InitMenus()253 InitMenus()
254 {
255     int i, j, k;
256     FuncKey *key, *tmp;
257 
258     for (i = 0; i < MAX_BUTTONS+1; i++)
259 	for (j = 0; j < NUM_CONTEXTS; j++)
260 	    for (k = 0; k < MOD_SIZE; k++)
261 	    {
262 		Scr->Mouse[i][j][k].func = 0;
263 		Scr->Mouse[i][j][k].item = NULL;
264 	    }
265 
266     Scr->DefaultFunction.func = 0;
267     Scr->WindowFunction.func = 0;
268 
269     if (FirstScreen)
270     {
271 	for (key = Scr->FuncKeyRoot.next; key != NULL;)
272 	{
273 	    free(key->name);
274 	    tmp = key;
275 	    key = key->next;
276 	    free((char *) tmp);
277 	}
278 	Scr->FuncKeyRoot.next = NULL;
279     }
280 
281 }
282 
283 
284 
285 /***********************************************************************
286  *
287  *  Procedure:
288  *	AddFuncKey - add a function key to the list
289  *
290  *  Inputs:
291  *	name	- the name of the key
292  *	cont	- the context to look for the key press in
293  *	mods	- modifier keys that need to be pressed
294  *	func	- the function to perform
295  *	win_name- the window name (if any)
296  *	action	- the action string associated with the function (if any)
297  *
298  ***********************************************************************
299  */
300 
AddFuncKey(name,cont,mods,func,win_name,action)301 Bool AddFuncKey (name, cont, mods, func, win_name, action)
302     char *name;
303     int cont, mods, func;
304     char *win_name;
305     char *action;
306 {
307     FuncKey *tmp;
308     KeySym keysym;
309     KeyCode keycode;
310 
311     /*
312      * Don't let a 0 keycode go through, since that means AnyKey to the
313      * XGrabKey call in GrabKeys().
314      */
315     if ((keysym = XStringToKeysym(name)) == NoSymbol ||
316 	(keycode = XKeysymToKeycode(dpy, keysym)) == 0)
317     {
318 	return False;
319     }
320 
321     /* see if there already is a key defined for this context */
322     for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
323     {
324 	if (tmp->keysym == keysym &&
325 	    tmp->cont == cont &&
326 	    tmp->mods == mods)
327 	    break;
328     }
329 
330     if (tmp == NULL)
331     {
332 	tmp = (FuncKey *) malloc(sizeof(FuncKey));
333 	tmp->next = Scr->FuncKeyRoot.next;
334 	Scr->FuncKeyRoot.next = tmp;
335     }
336 
337     tmp->name = name;
338     tmp->keysym = keysym;
339     tmp->keycode = keycode;
340     tmp->cont = cont;
341     tmp->mods = mods;
342     tmp->func = func;
343     tmp->win_name = win_name;
344     tmp->action = action;
345 
346     return True;
347 }
348 
349 
350 
CreateTitleButton(name,func,action,menuroot,rightside,append)351 int CreateTitleButton (name, func, action, menuroot, rightside, append)
352     char *name;
353     int func;
354     char *action;
355     MenuRoot *menuroot;
356     Bool rightside;
357     Bool append;
358 {
359     TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton));
360 
361     if (!tb) {
362 	fprintf (stderr,
363 		 "%s:  unable to allocate %d bytes for title button\n",
364 		 ProgramName, sizeof(TitleButton));
365 	return 0;
366     }
367 
368 
369     tb->next = NULL;
370     tb->name = name;			/* note that we are not copying */
371     tb->bitmap = None;			/* WARNING, values not set yet */
372 #ifdef XPM
373     tb->isXpm = False;		 /* assume a bitmap */
374 #endif  /* XPM */
375     tb->width = 0;			/* see InitTitlebarButtons */
376     tb->height = 0;			/* ditto */
377     tb->func = func;
378     tb->action = action;
379     tb->menuroot = menuroot;
380     tb->rightside = rightside;
381     if (rightside) {
382 	Scr->TBInfo.nright++;
383     } else {
384 	Scr->TBInfo.nleft++;
385     }
386 
387     /*
388      * Cases for list:
389      *
390      *     1.  empty list, prepend left       put at head of list
391      *     2.  append left, prepend right     put in between left and right
392      *     3.  append right                   put at tail of list
393      *
394      * Do not refer to widths and heights yet since buttons not created
395      * (since fonts not loaded and heights not known).
396      */
397     if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) {	/* 1 */
398 	tb->next = Scr->TBInfo.head;
399 	Scr->TBInfo.head = tb;
400     } else if (append && rightside) {	/* 3 */
401 	register TitleButton *t;
402 	for /* SUPPRESS 530 */
403 	  (t = Scr->TBInfo.head; t->next; t = t->next) ;
404 	t->next = tb;
405 	tb->next = NULL;
406     } else {				/* 2 */
407 	register TitleButton *t, *prev = NULL;
408 	for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
409 	    prev = t;
410 	}
411 	if (prev) {
412 	    tb->next = prev->next;
413 	    prev->next = tb;
414 	} else {
415 	    tb->next = Scr->TBInfo.head;
416 	    Scr->TBInfo.head = tb;
417 	}
418     }
419 
420     return 1;
421 }
422 
423 
424 
425 /*
426  * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
427  * button.  If we can't find the button, then put in a question; if we can't
428  * find the question mark, something is wrong and we are probably going to be
429  * in trouble later on.
430  */
InitTitlebarButtons()431 void InitTitlebarButtons ()
432 {
433     TitleButton *tb;
434     int h;
435     Pixel bg_color;
436 
437     /*
438      * initialize dimensions
439      */
440     Scr->TBInfo.width = (Scr->TitleHeight -
441 			 2 * (Scr->FramePadding + Scr->ButtonIndent));
442     Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
443 		       ? ((Scr->TitlePadding + 1) / 2) : 1);
444     h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
445 
446     /*
447      * add in some useful buttons and bindings so that novices can still
448      * use the system.
449      */
450     if (!Scr->NoDefaults) {
451 	/* insert extra buttons */
452 	if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
453 				False, False)) {
454 	    fprintf (stderr, "%s:  unable to add iconify button\n",
455 		     ProgramName);
456 	}
457 	if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
458 				True, True)) {
459 	    fprintf (stderr, "%s:  unable to add resize button\n",
460 		     ProgramName);
461 	}
462 	AddDefaultBindings ();
463     }
464     ComputeCommonTitleOffsets ();
465 
466     /*
467      * load in images and do appropriate centering
468      */
469 
470     for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
471 	tb->bitmap = FindPixmap (tb->name, &tb->width, &tb->height,
472 		&tb->isXpm, &bg_color, NULL, 0, NULL);
473 	if (!tb->bitmap) {
474 	    tb->bitmap = FindPixmap (TBPM_QUESTION, &tb->width, &tb->height,
475 					&tb->isXpm, &bg_color, NULL, 0, NULL);
476 	    if (!tb->bitmap) {		/* cannot happen (see util.c) */
477 		fprintf (stderr,
478 			 "%s:  unable to add titlebar button \"%s\"\n",
479 			 ProgramName, tb->name);
480 	    }
481 	} else if ((tb->name[0] != ':') && (tb->name[0] != '#') &&
482 			(tb->isXpm == False))
483 	    tb->bitmap = XmuLocateBitmapFile(ScreenOfDisplay(dpy, Scr->screen),
484 				tb->name, NULL, 0, &tb->width, &tb->height,
485 				&JunkX, &JunkY);
486 
487 	tb->dstx = (h - tb->width + 1) / 2;
488 	if (tb->dstx < 0) {		/* clip to minimize copying */
489 	    tb->srcx = -(tb->dstx);
490 	    tb->width = h;
491 	    tb->dstx = 0;
492 	} else {
493 	    tb->srcx = 0;
494 	}
495 	tb->dsty = (h - tb->height + 1) / 2;
496 	if (tb->dsty < 0) {
497 	    tb->srcy = -(tb->dsty);
498 	    tb->height = h;
499 	    tb->dsty = 0;
500 	} else {
501 	    tb->srcy = 0;
502 	}
503 
504 	if (tb->isXpm == True) {
505 	    Pixmap new_btn;
506 	    GC gc;
507 	    XGCValues vals;
508 
509 	    new_btn = XCreatePixmap(dpy, Scr->Root, h, h,
510 			DefaultDepth(dpy, Scr->screen));
511 	    vals.foreground = bg_color;
512 	    gc = XCreateGC(dpy, new_btn, GCForeground, &vals);
513 	    XFillRectangle(dpy, new_btn, gc, 0, 0, h, h);
514 	    XCopyArea(dpy, tb->bitmap, new_btn, gc, tb->srcx, tb->srcy,
515 			tb->width, tb->height, tb->dstx, tb->dsty);
516 	    XFreeGC(dpy, gc);
517 	    XFreePixmap(dpy, tb->bitmap);
518 	    tb->bitmap = new_btn;
519 /* A completely new pixmap has been generated, so tvtwm must be
520  * told that it is the same size as the window, and therefore the
521  * coords for src and dst should all be 0. 				*/
522 	    tb->width = tb->height = h;
523 	    tb->dstx = tb->dsty = tb->srcx = tb->srcy = 0;
524 	}
525     }
526 }
527 
528 
529 
PaintEntry(mr,mi,exposure)530 PaintEntry(mr, mi, exposure)
531 MenuRoot *mr;
532 MenuItem *mi;
533 int exposure;
534 {
535     int y_offset;
536     int text_y;
537     GC gc;
538     MyFont *font;
539 
540     XSynchronize(dpy, True);
541 
542 #ifdef DEBUG_MENUS
543     fprintf(stderr, "Paint entry\n");
544 #endif
545     y_offset = mi->item_num * Scr->EntryHeight;
546 
547     if (mi->func != F_TITLE)
548     {
549 	int x, y;
550 
551 	font = &(Scr->MenuFont);
552 
553 	text_y = y_offset + font->y;
554 
555 	if (mi->state)
556 	{
557 	    XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
558 
559 	    XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
560 		mr->width, Scr->EntryHeight);
561 
562 	    FBF(mi->hi_fore, mi->hi_back, font->font->fid);
563 
564 	    XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
565 		text_y, mi->item, mi->strlen);
566 
567 	    gc = Scr->NormalGC;
568 	}
569 	else
570 	{
571 	    if (mi->user_colors || !exposure)
572 	    {
573 		XSetForeground(dpy, Scr->NormalGC, mi->back);
574 
575 		XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
576 		    mr->width, Scr->EntryHeight);
577 
578 		FBF(mi->fore, mi->back, font->font->fid);
579 		gc = Scr->NormalGC;
580 	    }
581 	    else
582 		gc = Scr->MenuGC;
583 
584 	    XDrawString(dpy, mr->w, gc, mi->x,
585 		text_y, mi->item, mi->strlen);
586 	}
587 
588 	if (mi->func == F_MENU || mi->func == F_MENUFUNC)
589 	{
590 	    /* Get or create the pull right menu icon */
591 	    if (Scr->pullrightPm.pm == None) {
592 		if (Scr->pullrightPm.name) {
593 #ifdef XPM
594 		    XpmColorSymbol ctrans[2];
595 
596 		    ctrans[0].name = "foreground";
597 		    ctrans[0].value = NULL;
598 		    ctrans[0].pixel = Scr->MenuC.fore;
599 		    ctrans[1].name = "background";
600 		    ctrans[1].value = NULL;
601 		    ctrans[1].pixel = Scr->MenuC.back;
602 #endif
603 
604 		    Scr->pullrightPm.pm = FindPixmap(Scr->pullrightPm.name,
605 						&Scr->pullrightPm.width,
606 						&Scr->pullrightPm.height,
607 						&Scr->pullrightPm.isXpm,
608 						NULL,
609 #ifdef XPM
610 						ctrans, 2,
611 #else
612 						NULL, 0,
613 #endif
614 						&Scr->pullrightPm.mask);
615 		} else {
616 		    Scr->pullrightPm.pm = CreateMenuIcon(Scr->MenuFont.height,
617 						&Scr->pullrightPm.width,
618 						&Scr->pullrightPm.height);
619 		    Scr->pullrightPm.isXpm = FALSE;
620 		    Scr->pullrightPm.mask = None;
621 		}
622 	    }
623 	    x = mr->width - Scr->pullrightPm.width - 5;
624 	    y = y_offset + ((font->height - Scr->pullrightPm.height) / 2);
625 	    if (Scr->pullrightPm.name && (Scr->pullrightPm.name[0] != '#'))
626 		XCopyArea(dpy, Scr->pullrightPm.pm, mr->w, gc, 0, 0,
627 			Scr->pullrightPm.width, Scr->pullrightPm.height, x, y);
628 	    else
629 		XCopyPlane(dpy, Scr->pullrightPm.pm, mr->w, gc, 0, 0,
630 			Scr->pullrightPm.width, Scr->pullrightPm.height,
631 			x, y, 1);
632 	}
633 	if (abs(mr->def) == (mi->item_num+1))
634 	    XDrawRectangle(dpy, mr->w, gc, 0, text_y-2, 2, 2);
635     }
636     else
637     {
638 	int y;
639 
640 	if (Scr->MenuTitleFont.name != NULL )
641 	    font = &(Scr->MenuTitleFont);
642 	else
643 	    font = &(Scr->MenuFont);
644 
645 	text_y = y_offset + font->y;
646 
647 	XSetForeground(dpy, Scr->NormalGC, mi->back);
648 
649 	/* fill the rectangle with the title background color */
650 	XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
651 	    mr->width, Scr->EntryHeight);
652 
653 	if ( Scr->MenuLineWidth > 0 ) /* note we loose the high efficiancy `0' line width */
654 	{
655 	    XSetForeground(dpy, Scr->NormalGC, mi->fore);
656 	    XSetLineAttributes(dpy,Scr->NormalGC,
657 			       Scr->MenuLineWidth,
658 			       LineSolid,
659 			       CapButt,
660 			       JoinMiter);
661 
662 	    /* now draw the dividing lines */
663 	    if (y_offset)
664 	      XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
665 			 mr->width, y_offset);
666 	    y = ((mi->item_num+1) * Scr->EntryHeight)-1;
667 	    XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
668 	    XSetLineAttributes(dpy,Scr->NormalGC,
669 			       0,
670 			       LineSolid,
671 			       CapButt,
672 			       JoinMiter);
673 	}
674 
675 	FBF(mi->fore, mi->back, font->font->fid);
676 	/* finally render the title */
677 	XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
678 	    text_y, mi->item, mi->strlen);
679 
680 	if (abs(mr->def) == (mi->item_num+1))
681 	    XDrawRectangle(dpy, mr->w, Scr->NormalGC, 0, text_y-2, 2, 2);
682     }
683 }
684 
685 
686 
PaintMenu(mr,e)687 PaintMenu(mr, e)
688 MenuRoot *mr;
689 XEvent *e;
690 {
691     MenuItem *mi;
692 
693     for (mi = mr->first; mi != NULL; mi = mi->next)
694     {
695 	int y_offset = mi->item_num * Scr->EntryHeight;
696 
697 	/* be smart about handling the expose, redraw only the entries
698 	 * that we need to
699 	 */
700 	if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
701 	    (e->xexpose.y + e->xexpose.height) > y_offset)
702 	{
703 	    PaintEntry(mr, mi, True);
704 	}
705     }
706     XSync(dpy, 0);
707 }
708 
709 
710 
711 static Bool fromMenu;
712 
713 #if 1
UpdateMenu()714 UpdateMenu()
715 {
716     MenuItem *mi;
717     int i, x, y, x_root, y_root, entry;
718     int done;
719     MenuItem *badItem = NULL;
720     Window aJunkRoot,aJunkChild;
721     unsigned int aJunkMask;
722     static int firstTime = True;
723 
724     fromMenu = TRUE;
725 
726     while (TRUE)
727     {
728       /* block until there is an event */
729 	if (!menuFromFrameOrWindowOrTitlebar) {
730 	    XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
731 		       EnterWindowMask | ExposureMask |
732 		       VisibilityChangeMask | LeaveWindowMask |
733 		       PointerMotionMask, &Event);
734 	}
735 
736 	if (Event.type == MotionNotify) {
737 	    /* discard any extra motion events before a release */
738 	    while(XCheckMaskEvent(dpy,
739 				ButtonMotionMask | ButtonReleaseMask, &Event))
740 		if (Event.type == ButtonRelease)
741 		    break;
742 	}
743 
744 	if (!DispatchEvent ())
745 	    continue;
746 
747 	if (Event.type == ButtonRelease)
748 	{
749 	    menuFromFrameOrWindowOrTitlebar = FALSE;
750 	    fromMenu = FALSE;
751 	    if (Scr->StayUpMenus)
752 	    {
753 		if (firstTime == True)
754 		{
755 		    /* it was the first release of the button */
756 		    firstTime = False;
757 		} /* end if  */
758 		else
759 		{
760 		    /* thats the second we need to return now */
761 		    firstTime = True;
762 		    return;
763 		} /* end else  */
764 	    } /* end if  */
765 	    else
766 	    {
767 		return;
768 	    } /* end else  */
769 	}
770 
771 	if (Event.type ==  Cancel || !ActiveMenu) {
772 	    menuFromFrameOrWindowOrTitlebar = FALSE;
773 	    fromMenu = FALSE;
774 	    return;
775 	}
776 
777 	if (Event.type == LeaveNotify
778 	    && ((XCrossingEvent *)&Event)->window == ActiveMenu->w) {
779 	    if (ActiveItem && ActiveItem->func != F_TITLE) {
780 		ActiveItem->state = 0;
781 		PaintEntry(ActiveMenu, ActiveItem, False);
782 	    }
783 	    ActiveItem = NULL;
784 	    continue;
785 	}
786 
787 	if (Event.type != MotionNotify)
788 	    continue;
789 
790 #if 1
791 	XQueryPointer( dpy, ActiveMenu->w, &aJunkRoot, &aJunkChild,
792 	    &x_root, &y_root, &x, &y, &aJunkMask);
793 #else
794 	x = ((XMotionEvent *)&Event)->x;
795 	y = ((XMotionEvent *)&Event)->y;
796 #endif
797 
798 	/* if we are in the parent, pop back down, this should prevent
799 	 * menus that are slow to pop up from hanging around too long.
800 	 */
801 	if (ActiveMenu->prev &&
802 	    ActiveMenu->prev->w == ((XMotionEvent *)&Event)->window) {
803 	    if (Scr->Shadow)
804 		XUnmapWindow(dpy, ActiveMenu->shadow);
805 	    XUnmapWindow(dpy, ActiveMenu->w);
806 	    ActiveMenu->mapped = UNMAPPED;
807 	    UninstallRootColormap();
808 	    if (ActiveItem) {
809 		ActiveItem->state = 0;
810 		PaintEntry(ActiveMenu, ActiveItem, False);
811 	    }
812 	    ActiveItem = NULL;
813 	    ActiveMenu = ActiveMenu->prev;
814 	    MenuDepth--;
815 	    continue;
816 	}
817 
818 	if (((XMotionEvent *)&Event)->window != ActiveMenu->w)
819 	    continue;
820 
821 	done = FALSE;
822 
823 	/* if we haven't recieved the enter notify yet, wait */
824 	if (ActiveMenu && !ActiveMenu->entered)
825 	    continue;
826 
827 	XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *)&Scr);
828 
829 	if (x < 0 || y < 0 ||
830 	    x >= ActiveMenu->width || y >= ActiveMenu->height)
831 	{
832 	    if (ActiveItem && ActiveItem->func != F_TITLE)
833 	    {
834 		ActiveItem->state = 0;
835 		PaintEntry(ActiveMenu, ActiveItem, False);
836 	    }
837 	    ActiveItem = NULL;
838 	    continue;
839 	}
840 
841 	/* look for the entry that the mouse is in */
842 	entry = y / Scr->EntryHeight;
843 	for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
844 	{
845 	    if (i == entry)
846 		break;
847 	}
848 
849 	/* if there is an active item, we might have to turn it off */
850 	if (ActiveItem)
851 	{
852 	    /* is the active item the one we are on ? */
853 	    if (ActiveItem->item_num == entry && ActiveItem->state)
854 		done = TRUE;
855 
856 	    /* if we weren't on the active entry, let's turn the old
857 	     * active one off
858 	     */
859 	    if (!done && ActiveItem->func != F_TITLE)
860 	    {
861 		ActiveItem->state = 0;
862 		PaintEntry(ActiveMenu, ActiveItem, False);
863 	    }
864 	}
865 
866 	/* if we weren't on the active item, change the active item and turn
867 	 * it on
868 	 */
869 	if (!done)
870 	{
871 	    ActiveItem = mi;
872 	    if (ActiveItem->func != F_TITLE && !ActiveItem->state)
873 	    {
874 		ActiveItem->state = 1;
875 		PaintEntry(ActiveMenu, ActiveItem, False);
876 	    }
877 	}
878 
879 	/* now check to see if we were over the arrow of a pull right entry */
880 	if ((ActiveItem->func == F_MENU || ActiveItem->func == F_MENUFUNC) &&
881 	    (((ActiveMenu->width - x) * 100) <
882 	    (ActiveMenu->width * Scr->PopupSensitivity)))
883 	{
884 	    MenuRoot *save = ActiveMenu;
885 	    int savex = MenuOrigins[MenuDepth - 1].x;
886 	    int savey = MenuOrigins[MenuDepth - 1].y;
887 
888 	    if (MenuDepth < MAXMENUDEPTH) {
889 		PopUpMenu (ActiveItem->sub,
890 			   (savex + (int)(ActiveMenu->width *
891 					(100-Scr->PopupSensitivity) / 100.0)),
892 			   (savey + ActiveItem->item_num * Scr->EntryHeight)
893 			   /*(savey + ActiveItem->item_num * Scr->EntryHeight +
894 			    (Scr->EntryHeight >> 1))*/, False);
895 	    } else if (!badItem) {
896 		XBell (dpy, 0);
897 		badItem = ActiveItem;
898 	    }
899 
900 	    /* if the menu did get popped up, unhighlight the active item */
901 	    if (save != ActiveMenu && ActiveItem->state)
902 	    {
903 		ActiveItem->state = 0;
904 		PaintEntry(save, ActiveItem, False);
905 		ActiveItem = NULL;
906 	    }
907 	}
908 	if (badItem != ActiveItem) badItem = NULL;
909 	XFlush(dpy);
910     }
911 
912 }
913 #else
UpdateMenu()914 UpdateMenu()
915 {
916     MenuItem       *mi;
917     int             i, x, y, x_root, y_root, entry;
918     int             done;
919     MenuItem       *badItem = NULL;
920     Window          aJunkRoot, aJunkChild;
921     unsigned int    aJunkMask;
922     static int      firstTime = True;
923 
924     fromMenu = TRUE;
925 
926     while (TRUE) {
927 	while (XCheckMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
928 			       EnterWindowMask | ExposureMask, &Event)) {
929 	    if (!DispatchEvent())
930 		continue;
931 
932 	    if (Event.type == ButtonRelease || ActiveMenu == NULL) {
933 		menuFromFrameOrWindowOrTitlebar = FALSE;
934 		fromMenu = FALSE;
935 		if (Scr->StayUpMenus) {
936 		    if (firstTime == True) {
937 			/* it was the first release of the button */
938 			firstTime = False;
939 		    }
940 		    /* end if  */
941 		    else {
942 			/* thats the second we need to return now */
943 			firstTime = True;
944 			return;
945 		    }				 /* end else  */
946 		}
947 		/* end if  */
948 		else {
949 		    return;
950 		}				 /* end else  */
951 	    }
952 	    if (Event.type == Cancel) {
953 		menuFromFrameOrWindowOrTitlebar = FALSE;
954 		fromMenu = FALSE;
955 		return;
956 	    }
957 	}
958 
959 	done = FALSE;
960 	XQueryPointer(dpy, ActiveMenu->w, &aJunkRoot, &aJunkChild,
961 		      &x_root, &y_root, &x, &y, &aJunkMask);
962 
963 	/* if we haven't received the enter notify yet, wait */
964 	if (!ActiveMenu || !ActiveMenu->entered)
965 	    continue;
966 
967 	XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *) & Scr);
968 
969 	if (x < 0 || y < 0 ||
970 	    x >= ActiveMenu->width || y >= ActiveMenu->height) {
971 	    if (ActiveItem && ActiveItem->func != F_TITLE) {
972 		ActiveItem->state = 0;
973 		PaintEntry(ActiveMenu, ActiveItem, False);
974 	    }
975 	    ActiveItem = NULL;
976 	    continue;
977 	}
978 	/* look for the entry that the mouse is in */
979 	entry = y / Scr->EntryHeight;
980 	for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi = mi->next) {
981 	    if (i == entry)
982 		break;
983 	}
984 
985 	/* if there is an active item, we might have to turn it off */
986 	if (ActiveItem) {
987 	    /* is the active item the one we are on ? */
988 	    if (ActiveItem->item_num == entry && ActiveItem->state)
989 		done = TRUE;
990 
991 	    /*
992 	     * if we weren't on the active entry, let's turn the old active
993 	     * one off
994 	     */
995 	    if (!done && ActiveItem->func != F_TITLE) {
996 		ActiveItem->state = 0;
997 		PaintEntry(ActiveMenu, ActiveItem, False);
998 	    }
999 	}
1000 	/*
1001 	 * if we weren't on the active item, change the active item and turn
1002 	 * it on
1003 	 */
1004 	if (!done) {
1005 	    ActiveItem = mi;
1006 	    if (ActiveItem->func != F_TITLE && !ActiveItem->state) {
1007 		ActiveItem->state = 1;
1008 		PaintEntry(ActiveMenu, ActiveItem, False);
1009 	    }
1010 	}
1011 	/* now check to see if we were over the arrow of a pull right entry */
1012 	if ((ActiveItem->func == F_MENU || ActiveItem->func == F_MENUFUNC) &&
1013 	    ((ActiveMenu->width - x) * 100 <
1014 	    (ActiveMenu->width * Scr->PopupSensitivity))) {
1015 	    MenuRoot       *save = ActiveMenu;
1016 	    int             savex = MenuOrigins[MenuDepth - 1].x;
1017 	    int             savey = MenuOrigins[MenuDepth - 1].y;
1018 	    if (MenuDepth < MAXMENUDEPTH) {
1019 		PopUpMenu(ActiveItem->sub,
1020 			  (savex + (int)(ActiveMenu->width
1021 					* (100-Scr->PopupSensitivity) / 100.0)),
1022 			  (savey + ActiveItem->item_num * Scr->EntryHeight)
1023 		/*
1024 		 * (savey + ActiveItem->item_num * Scr->EntryHeight +
1025 		 * (Scr->EntryHeight >> 1))
1026 			  */ , False);
1027 	    } else if (!badItem) {
1028 		XBell(dpy, 0);
1029 		badItem = ActiveItem;
1030 	    }
1031 	    /* if the menu did get popped up, unhighlight the active item */
1032 	    if (save != ActiveMenu && ActiveItem->state) {
1033 		ActiveItem->state = 0;
1034 		PaintEntry(save, ActiveItem, False);
1035 		ActiveItem = NULL;
1036 	    }
1037 	}
1038 	if (badItem != ActiveItem)
1039 	    badItem = NULL;
1040 	XFlush(dpy);
1041     }
1042 }
1043 #endif
1044 
1045 
1046 
1047 /***********************************************************************
1048  *
1049  *  Procedure:
1050  *	NewMenuRoot - create a new menu root
1051  *
1052  *  Returned Value:
1053  *	(MenuRoot *)
1054  *
1055  *  Inputs:
1056  *	name	- the name of the menu root
1057  *
1058  ***********************************************************************
1059  */
1060 
1061 MenuRoot *
NewMenuRoot(name)1062 NewMenuRoot(name)
1063     char *name;
1064 {
1065     MenuRoot *tmp;
1066 
1067 #define UNUSED_PIXEL ((unsigned long) (~0))   /* more than 24 bits */
1068 
1069     tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
1070     tmp->hi_fore = UNUSED_PIXEL;
1071     tmp->hi_back = UNUSED_PIXEL;
1072     tmp->name = name;
1073     tmp->file = NULL;
1074     tmp->mtime = 0;
1075     tmp->prev = NULL;
1076     tmp->first = NULL;
1077     tmp->last = NULL;
1078     tmp->items = 0;
1079     tmp->width = 0;
1080     tmp->mapped = NEVER_MAPPED;
1081     tmp->pull = FALSE;
1082     tmp->w = None;
1083     tmp->shadow = None;
1084     tmp->real_menu = FALSE;
1085 
1086     if (Scr->MenuList == NULL)
1087     {
1088 	Scr->MenuList = tmp;
1089 	Scr->MenuList->next = NULL;
1090     }
1091 
1092     if (Scr->LastMenu == NULL)
1093     {
1094 	Scr->LastMenu = tmp;
1095 	Scr->LastMenu->next = NULL;
1096     }
1097     else
1098     {
1099 	Scr->LastMenu->next = tmp;
1100 	Scr->LastMenu = tmp;
1101 	Scr->LastMenu->next = NULL;
1102     }
1103 
1104     if (strcmp(name, TWM_WINDOWS) == 0)
1105 	Scr->Windows = tmp;
1106 
1107     return (tmp);
1108 }
1109 
1110 
1111 
1112 /***********************************************************************
1113  *
1114  *  Procedure:
1115  *	AddToMenu - add an item to a root menu
1116  *
1117  *  Returned Value:
1118  *	(MenuItem *)
1119  *
1120  *  Inputs:
1121  *	menu	- pointer to the root menu to add the item
1122  *	item	- the text to appear in the menu
1123  *	action	- the string to possibly execute
1124  *	sub	- the menu root if it is a pull-right entry
1125  *	func	- the numeric function
1126  *	fore	- foreground color string
1127  *	back	- background color string
1128  *
1129  ***********************************************************************
1130  */
1131 
1132 MenuItem *
AddToMenu(menu,item,action,sub,func,fore,back)1133 AddToMenu(menu, item, action, sub, func, fore, back)
1134     MenuRoot *menu;
1135     char *item, *action;
1136     MenuRoot *sub;
1137     int func;
1138     char *fore, *back;
1139 {
1140     MenuItem *tmp;
1141     int width;
1142     MyFont *font;
1143 
1144 #ifdef DEBUG_MENUS
1145     fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
1146 	item, action, sub, func);
1147 #endif
1148 
1149     tmp = (MenuItem *) malloc(sizeof(MenuItem));
1150     tmp->root = menu;
1151 
1152     if (menu->first == NULL)
1153     {
1154 	menu->first = tmp;
1155 	tmp->prev = NULL;
1156     }
1157     else
1158     {
1159 	menu->last->next = tmp;
1160 	tmp->prev = menu->last;
1161     }
1162     menu->last = tmp;
1163 
1164     tmp->item = item;
1165     tmp->strlen = strlen(item);
1166     tmp->action = action;
1167     tmp->next = NULL;
1168     tmp->sub = NULL;
1169     tmp->state = 0;
1170     tmp->func = func;
1171 
1172     if ( func == F_TITLE && Scr->MenuTitleFont.name != NULL)
1173 	font= &(Scr->MenuTitleFont);
1174     else
1175 	font= &(Scr->MenuFont);
1176 
1177     if (!Scr->HaveFonts) CreateFonts();
1178     width = XTextWidth(font->font, item, tmp->strlen);
1179     if (width <= 0)
1180 	width = 1;
1181     if (width > menu->width)
1182 	menu->width = width;
1183 
1184     tmp->user_colors = FALSE;
1185     if (Scr->Monochrome == COLOR && fore != NULL)
1186     {
1187 	int save;
1188 
1189 	save = Scr->FirstTime;
1190 	Scr->FirstTime = TRUE;
1191 	GetColor(COLOR, &tmp->fore, fore);
1192 	GetColor(COLOR, &tmp->back, back);
1193 	Scr->FirstTime = save;
1194 	tmp->user_colors = TRUE;
1195     }
1196     if (sub != NULL)
1197     {
1198 	tmp->sub = sub;
1199 	menu->pull = TRUE;
1200     }
1201     tmp->item_num = menu->items++;
1202 
1203     return (tmp);
1204 }
1205 
1206 
1207 
MakeMenus()1208 MakeMenus()
1209 {
1210     MenuRoot *mr;
1211 
1212     for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
1213     {
1214 	if (mr->real_menu == FALSE)
1215 	    continue;
1216 
1217 	MakeMenu(mr);
1218     }
1219 }
1220 
1221 
1222 
MakeMenu(mr)1223 MakeMenu(mr)
1224 MenuRoot *mr;
1225 {
1226     MenuItem *start, *end, *cur, *tmp;
1227     XColor f1, f2, f3;
1228     XColor b1, b2, b3;
1229     XColor save_fore, save_back;
1230     int num, i;
1231     int fred, fgreen, fblue;
1232     int bred, bgreen, bblue;
1233     int width;
1234     unsigned long valuemask;
1235     XSetWindowAttributes attributes;
1236     Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
1237     MyFont *titleFont;
1238 
1239     if ( Scr->MenuTitleFont.name != NULL )
1240     {
1241  	Scr->EntryHeight = MAX(Scr->MenuFont.height,
1242  			       Scr->MenuTitleFont.height) + 4;
1243  	titleFont= &(Scr->MenuTitleFont);
1244     }
1245     else
1246     {
1247   	Scr->EntryHeight = Scr->MenuFont.height + 4;
1248 	titleFont= &(Scr->MenuFont);
1249     }
1250 
1251     /* lets first size the window accordingly */
1252     if (mr->mapped == NEVER_MAPPED)
1253     {
1254 	if (mr->items == 0)
1255 	    AddToMenu(mr, "Empty", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
1256 
1257 	if (mr->pull == TRUE)
1258 	    mr->width += 16 + 10;
1259 
1260 	width = mr->width + 10;
1261 
1262 	for (cur = mr->first; cur != NULL; cur = cur->next)
1263 	{
1264 	    if (cur->func != F_TITLE)
1265 		cur->x = 5;
1266 	    else
1267 	    {
1268 		cur->x = width - XTextWidth(titleFont->font, cur->item,
1269 		    cur->strlen);
1270 		cur->x /= 2;
1271 	    }
1272 	}
1273 	mr->height = mr->items * Scr->EntryHeight;
1274 	mr->width += 10;
1275 
1276 	if (Scr->Shadow)
1277 	{
1278 	    /*
1279 	     * Make sure that you don't draw into the shadow window or else
1280 	     * the background bits there will get saved
1281 	     */
1282 	    valuemask = CWBorderPixel;
1283 	    attributes.border_pixel = Scr->MenuShadowColor;
1284 	    if (Scr->SaveUnder) {
1285 		valuemask |= CWSaveUnder;
1286 		attributes.save_under = True;
1287 	    }
1288 	    if (Scr->shadowPm.name && ! Scr->shadowPm.pm) {
1289 #ifdef XPM
1290 		XpmColorSymbol ctrans[2];
1291 
1292 		ctrans[0].name = "foreground";
1293 		ctrans[0].value = NULL;
1294 		ctrans[0].pixel = Scr->MenuShadowColor;
1295 		ctrans[1].name = "background";
1296 		ctrans[1].value = NULL;
1297 		ctrans[1].pixel = Scr->MenuC.back;
1298 #endif
1299 
1300 		Scr->shadowPm.pm = FindPixmap(Scr->shadowPm.name,
1301 						&Scr->shadowPm.width,
1302 						&Scr->shadowPm.height,
1303 						&(Scr->shadowPm.isXpm),
1304 						NULL,
1305 #ifdef XPM
1306 						ctrans, 2,
1307 #else
1308 						NULL, 0,
1309 #endif
1310 						&Scr->shadowPm.mask);
1311 		if (! Scr->shadowPm.pm)
1312 		    Scr->shadowPm.name=None;
1313 	    }
1314 
1315 	    if (Scr->shadowPm.pm) {
1316 		valuemask |= CWBackPixmap;
1317 		attributes.background_pixmap = Scr->shadowPm.pm;
1318 	    } else {
1319 		valuemask |= CWBackPixel;
1320 		attributes.background_pixel = Scr->MenuShadowColor;
1321 	    }
1322 
1323 	    mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
1324 					(unsigned int) mr->width,
1325 					(unsigned int) mr->height,
1326 					Scr->shadowPm.pm ? (unsigned int)1 :
1327 							(unsigned int)0,
1328 					CopyFromParent,
1329 					(unsigned int) CopyFromParent,
1330 					(Visual *) CopyFromParent,
1331 					valuemask, &attributes);
1332 	}
1333 
1334 	valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
1335 	attributes.background_pixel = Scr->MenuC.back;
1336 	attributes.border_pixel = Scr->MenuC.fore;
1337 	attributes.event_mask = (ExposureMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask);
1338 	if (Scr->SaveUnder) {
1339 	    valuemask |= CWSaveUnder;
1340 	    attributes.save_under = True;
1341 	}
1342 	if (Scr->BackingStore) {
1343 	    valuemask |= CWBackingStore;
1344 	    attributes.backing_store = Always;
1345 	}
1346 	mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
1347 			       (unsigned int) mr->height, (unsigned int) 1,
1348 			       CopyFromParent, (unsigned int) CopyFromParent,
1349 			       (Visual *) CopyFromParent,
1350 			       valuemask, &attributes);
1351 
1352 
1353 	XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
1354 	XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
1355 
1356 	mr->mapped = UNMAPPED;
1357     }
1358 
1359     /* get the default colors into the menus */
1360     for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
1361     {
1362 	if (!tmp->user_colors) {
1363 	    if (tmp->func != F_TITLE) {
1364 		tmp->fore = Scr->MenuC.fore;
1365 		tmp->back = Scr->MenuC.back;
1366 	    } else {
1367 		tmp->fore = Scr->MenuTitleC.fore;
1368 		tmp->back = Scr->MenuTitleC.back;
1369 	    }
1370 	}
1371 
1372 	if (mr->hi_fore != UNUSED_PIXEL)
1373 	{
1374 	    tmp->hi_fore = mr->hi_fore;
1375 	    tmp->hi_back = mr->hi_back;
1376 	}
1377 	else
1378 	{
1379 	    tmp->hi_fore = tmp->back;
1380 	    tmp->hi_back = tmp->fore;
1381 	}
1382     }
1383 
1384     if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
1385 	return;
1386 
1387     start = mr->first;
1388     while (TRUE)
1389     {
1390 	for (; start != NULL; start = start->next)
1391 	{
1392 	    if (start->user_colors)
1393 		break;
1394 	}
1395 	if (start == NULL)
1396 	    break;
1397 
1398 	for (end = start->next; end != NULL; end = end->next)
1399 	{
1400 	    if (end->user_colors)
1401 		break;
1402 	}
1403 	if (end == NULL)
1404 	    break;
1405 
1406 	/* we have a start and end to interpolate between */
1407 	num = end->item_num - start->item_num;
1408 
1409 	f1.pixel = start->fore;
1410 	XQueryColor(dpy, cmap, &f1);
1411 	f2.pixel = end->fore;
1412 	XQueryColor(dpy, cmap, &f2);
1413 
1414 	b1.pixel = start->back;
1415 	XQueryColor(dpy, cmap, &b1);
1416 	b2.pixel = end->back;
1417 	XQueryColor(dpy, cmap, &b2);
1418 
1419 	fred = ((int)f2.red - (int)f1.red) / num;
1420 	fgreen = ((int)f2.green - (int)f1.green) / num;
1421 	fblue = ((int)f2.blue - (int)f1.blue) / num;
1422 
1423 	bred = ((int)b2.red - (int)b1.red) / num;
1424 	bgreen = ((int)b2.green - (int)b1.green) / num;
1425 	bblue = ((int)b2.blue - (int)b1.blue) / num;
1426 
1427 	f3 = f1;
1428 	f3.flags = DoRed | DoGreen | DoBlue;
1429 
1430 	b3 = b1;
1431 	b3.flags = DoRed | DoGreen | DoBlue;
1432 
1433 	num -= 1;
1434 	for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
1435 	{
1436 	    f3.red += fred;
1437 	    f3.green += fgreen;
1438 	    f3.blue += fblue;
1439 
1440 	    b3.red += bred;
1441 	    b3.green += bgreen;
1442 	    b3.blue += bblue;
1443 
1444 	    if (Scr->DontInterpolateTitles && (cur->func == F_TITLE))
1445 		continue;
1446 
1447 	    save_fore = f3;
1448 	    save_back = b3;
1449 
1450 	    XAllocColor(dpy, cmap, &f3);
1451 	    XAllocColor(dpy, cmap, &b3);
1452 	    cur->hi_back = cur->fore = f3.pixel;
1453 	    cur->hi_fore = cur->back = b3.pixel;
1454 	    cur->user_colors = True;
1455 
1456 	    f3 = save_fore;
1457 	    b3 = save_back;
1458 	}
1459 	start = end;
1460     }
1461 }
1462 
1463 
1464 
1465  /********************************************************************\
1466  *                                                                    *
1467  * HandleChangingMenus -- check if the contents of a menu should be   *
1468  *                         changed and if so, do so.                  *
1469  *                                                                    *
1470  * Used to be part of PopUpMenu, but it is needed by the code to do   *
1471  * default menu actions too.                                          *
1472  *                                                                    *
1473  \********************************************************************/
1474 
HandleChangingMenus(menu)1475 HandleChangingMenus(menu)
1476 MenuRoot *menu;
1477 {
1478     int WindowNameOffset, WindowNameCount;
1479     TwmWindow **WindowNames;
1480     TwmWindow *tmp_win2, *tmp_win3;
1481     TwmWindow **sortlist, *bakwin;
1482     int i, loop, curpos, count;
1483 
1484     int (*compar)() = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
1485 
1486     if (menu == Scr->Windows) {
1487 	TwmWindow *tmp_win;
1488 
1489 	/* this is the twm windows menu,  let's go ahead and build it */
1490 
1491 	DestroyMenu(menu);
1492 
1493 	menu->first = NULL;
1494 	menu->last = NULL;
1495 	menu->items = 0;
1496 	menu->width = 0;
1497 	menu->mapped = NEVER_MAPPED;
1498 	AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
1499 
1500 	/* CODE to SORT THE MENU @@@@@@@@@@@@@@ */
1501 	if (Scr->SortIconMgr) {
1502 	    for(count=0,tmp_win=Scr->TwmRoot.next; tmp_win != NULL;
1503 		tmp_win = tmp_win->next,count++) ;
1504 	    sortlist = (TwmWindow **)malloc(sizeof(TwmWindow *) * count);
1505 	    for(loop=0,tmp_win=Scr->TwmRoot.next; tmp_win != NULL;
1506 		tmp_win = tmp_win->next,loop++)
1507 	    	sortlist[loop]=tmp_win;
1508 
1509 	    /* Now that we have them in the list, just do an insertion sort. */
1510 	    for (curpos=1;curpos<count;curpos++) {
1511 		/*Everything from 0 to curpos-1 is sorted.*/
1512 		bakwin = sortlist[curpos];
1513 		for (loop=curpos;(loop>0);loop--)
1514 		    /*Everything from loop to curpos is sorted*/
1515 		    /* Sort order is [0] = min, [n]=max */
1516 		    if (((*compar)(sortlist[loop-1]->name,bakwin->name))>0)
1517 			sortlist[loop]=sortlist[loop-1];
1518 		    else
1519 			break;
1520 		sortlist[loop]=bakwin;
1521 	    }
1522 
1523 	    for(loop=0;loop<count;loop++)
1524 		AddToMenu(menu,sortlist[loop]->name, (char *)sortlist[loop],
1525 			NULL, F_POPUP, NULLSTR, NULLSTR);
1526 	} else {
1527 	    WindowNameOffset=(char *)Scr->TwmRoot.next->name -
1528 				(char *)Scr->TwmRoot.next;
1529 	    for(tmp_win = Scr->TwmRoot.next , WindowNameCount=0;
1530 		tmp_win != NULL;
1531 		tmp_win = tmp_win->next)
1532 		WindowNameCount++;
1533 	    WindowNames =
1534 		    (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
1535 	    WindowNames[0] = Scr->TwmRoot.next;
1536 	    for(tmp_win = Scr->TwmRoot.next->next , WindowNameCount=1;
1537 		tmp_win != NULL; tmp_win = tmp_win->next,WindowNameCount++) {
1538 		tmp_win2 = tmp_win;
1539 		for (i=0;i<WindowNameCount;i++) {
1540 		    if ((*compar)(tmp_win2->name,WindowNames[i]->name) < 0)
1541 		    {
1542 			tmp_win3 = tmp_win2;
1543 			tmp_win2 = WindowNames[i];
1544 			WindowNames[i] = tmp_win3;
1545 		    }
1546 		}
1547 		WindowNames[WindowNameCount] = tmp_win2;
1548 	    }
1549 	    for (i=0; i<WindowNameCount; i++) {
1550 		AddToMenu(menu, WindowNames[i]->name, (char *)WindowNames[i],
1551 			  NULL, F_POPUP,NULL,NULL);
1552 	    }
1553 	    free(WindowNames);
1554 	  }
1555       MakeMenu(menu);
1556     }
1557     else if (menu->file != NULL) {
1558 	struct stat buf;
1559 
1560 	if ( stat(menu->file, &buf) == 0 && buf.st_mtime > menu->mtime ) {
1561 	    menu->mtime=buf.st_mtime;
1562 
1563 	    menu->real_menu = FALSE;
1564 	    ParseMenuFile(menu->file, menu->name);
1565 	    if (menu->real_menu == FALSE)
1566 		fprintf(stderr,"%s: Menu %s not defined in %s\n",
1567 			ProgramName, menu->name, menu->file);
1568 	}
1569     }
1570 }
1571 
1572 /***********************************************************************
1573  *
1574  *  Procedure:
1575  *	PopUpMenu - pop up a pull down menu
1576  *
1577  *  Inputs:
1578  *	menu	- the root pointer of the menu to pop up
1579  *	x, y	- location of upper left of menu
1580  *      center	- whether or not to center horizontally over position
1581  *
1582  ***********************************************************************
1583  */
1584 
PopUpMenu(menu,x,y,center)1585 Bool PopUpMenu (menu, x, y, center)
1586     MenuRoot *menu;
1587     int x, y;
1588     Bool center;
1589 {
1590   if (!menu) return False;
1591 
1592   InstallRootColormap();
1593 
1594   /* Prevent recursively bringing up menus. */
1595   if (menu->mapped == MAPPED) return False;
1596 
1597   HandleChangingMenus(menu);
1598 
1599   if (menu->w == None || menu->items == 0) return False;
1600 
1601   /*
1602    * Dynamically set the parent;  this allows pull-ups to also be main
1603    * menus, or to be brought up from more than one place.
1604    */
1605   menu->prev = ActiveMenu;
1606 
1607   XGrabPointer(dpy, Scr->Root, True,
1608 	       ButtonPressMask | ButtonReleaseMask |
1609 	       ButtonMotionMask | PointerMotionHintMask,
1610 	       GrabModeAsync, GrabModeAsync,
1611 	       Scr->Root, Scr->MenuCursor, CurrentTime);
1612 
1613   ActiveMenu = menu;
1614   menu->mapped = MAPPED;
1615   menu->entered = FALSE;
1616 
1617   if (center) {
1618     x -= (menu->width / 2);
1619     y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */
1620   }
1621 
1622   /* if the menu has a default entry, put it under the cursor */
1623   if (menu->def)
1624     y -= (abs(menu->def) - 1) * Scr->EntryHeight;
1625 
1626   /*
1627    * clip to screen
1628    */
1629   if (x + menu->width > Scr->MyDisplayWidth) {
1630     x = Scr->MyDisplayWidth - menu->width;
1631   }
1632   if (x < 0) x = 0;
1633   if (y + menu->height > Scr->MyDisplayHeight) {
1634     y = Scr->MyDisplayHeight - menu->height;
1635   }
1636   if (y < 0) y = 0;
1637 
1638   MenuOrigins[MenuDepth].x = x;
1639   MenuOrigins[MenuDepth].y = y;
1640   MenuDepth++;
1641 
1642   XMoveWindow(dpy, menu->w, x, y);
1643   if (Scr->Shadow) {
1644     XMoveWindow (dpy, menu->shadow, x + Scr->ShadowWidth, y + Scr->ShadowWidth);
1645   }
1646   if (Scr->Shadow) {
1647     XRaiseWindow (dpy, menu->shadow);
1648   }
1649   XMapRaised(dpy, menu->w);
1650   if (Scr->Shadow) {
1651     XMapWindow (dpy, menu->shadow);
1652   }
1653   XSync(dpy, 0);
1654   return True;
1655 }
1656 
1657 
1658 
1659 /***********************************************************************
1660  *
1661  *  Procedure:
1662  *	PopDownMenu - unhighlight the current menu selection and
1663  *		take down the menus
1664  *
1665  ***********************************************************************
1666  */
1667 
PopDownMenu()1668 PopDownMenu()
1669 {
1670     MenuRoot *tmp;
1671 
1672     if (ActiveMenu == NULL)
1673 	return;
1674 
1675     if (ActiveItem)
1676     {
1677 	ActiveItem->state = 0;
1678 	PaintEntry(ActiveMenu, ActiveItem, False);
1679     }
1680 
1681     for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
1682     {
1683 	if (Scr->Shadow) {
1684 	    XUnmapWindow (dpy, tmp->shadow);
1685 	}
1686 	XUnmapWindow(dpy, tmp->w);
1687 	tmp->mapped = UNMAPPED;
1688 	UninstallRootColormap();
1689     }
1690 
1691     XFlush(dpy);
1692     ActiveMenu = NULL;
1693     ActiveItem = NULL;
1694     MenuDepth = 0;
1695     if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE)
1696 	menuFromFrameOrWindowOrTitlebar = TRUE;
1697 }
1698 
1699 
1700 
1701 /***********************************************************************
1702  *
1703  *  Procedure:
1704  *	FindMenuRoot - look for a menu root
1705  *
1706  *  Returned Value:
1707  *	(MenuRoot *)  - a pointer to the menu root structure
1708  *
1709  *  Inputs:
1710  *	name	- the name of the menu root
1711  *
1712  ***********************************************************************
1713  */
1714 
1715 MenuRoot *
FindMenuRoot(name)1716 FindMenuRoot(name)
1717     char *name;
1718 {
1719     MenuRoot *tmp;
1720 
1721     for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
1722     {
1723 	if (strcmp(name, tmp->name) == 0)
1724 	    return (tmp);
1725     }
1726     return NULL;
1727 }
1728 
1729 
1730 
belongs_to_twm_window(t,w)1731 static Bool belongs_to_twm_window (t, w)
1732     register TwmWindow *t;
1733     register Window w;
1734 {
1735     if (!t) return False;
1736 
1737     if (w == t->frame || w == t->title_w || w == t->hilite_w ||
1738 	w == t->icon.w
1739 	|| w == t->icon.image_w
1740 	|| w == t->icon.text_w) return True;
1741 
1742     if (t && t->titlebuttons) {
1743 	register TBWindow *tbw;
1744 	register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1745 	for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
1746 	    if (tbw->window == w) return True;
1747 	}
1748     }
1749     return False;
1750 }
1751 
1752 
1753 
1754 
1755 /***********************************************************************
1756  *
1757  *  Procedure:
1758  *	resizeFromCenter -
1759  *
1760  ***********************************************************************
1761  */
1762 
1763 
1764 extern int AddingX;
1765 extern int AddingY;
1766 extern int AddingW;
1767 extern int AddingH;
1768 
resizeFromCenter(w,tmp_win)1769 void resizeFromCenter(w, tmp_win)
1770     Window w;
1771     TwmWindow *tmp_win;
1772 {
1773   int lastx, lasty, width, height, bw2;
1774   int namelen;
1775   int stat;
1776   XEvent event;
1777   Window junk;
1778 
1779   namelen = strlen (tmp_win->name);
1780   bw2 = tmp_win->frame_bw * 2;
1781   AddingW = tmp_win->attr.width + bw2;
1782   AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
1783   width = (SIZE_HINDENT + XTextWidth (Scr->SizeFont.font,
1784 				      tmp_win->name, namelen));
1785   height = Scr->SizeFont.height + SIZE_VINDENT * 2;
1786   XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
1787 	       (unsigned int *)&DragWidth, (unsigned int *)&DragHeight,
1788 	       &JunkBW, &JunkDepth);
1789   XWarpPointer(dpy, None, w,
1790 	       0, 0, 0, 0, DragWidth/2, DragHeight/2);
1791   XQueryPointer(dpy, Scr->Root, &JunkRoot,
1792 		&JunkChild, &JunkX, &JunkY,
1793 		&AddingX, &AddingY, &JunkMask);
1794 /*****
1795   Scr->SizeStringOffset = width +
1796     XTextWidth(Scr->SizeFont.font, ": ", 2);
1797   XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
1798 		 Scr->SizeStringWidth, height);
1799   XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC, width,
1800 		    SIZE_VINDENT + Scr->SizeFont.font->ascent,
1801 		    ": ", 2);
1802 *****/
1803   lastx = -10000;
1804   lasty = -10000;
1805 /*****
1806   MoveOutline(Scr->Root,
1807 	      origDragX - JunkBW, origDragY - JunkBW,
1808 	      DragWidth * JunkBW, DragHeight * JunkBW,
1809 	      tmp_win->frame_bw,
1810 	      tmp_win->title_height);
1811 *****/
1812   MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
1813   while (TRUE)
1814     {
1815       XMaskEvent(dpy,
1816 		 ButtonPressMask | PointerMotionMask, &event);
1817 
1818       if (event.type == MotionNotify) {
1819 	/* discard any extra motion events before a release */
1820 	while(XCheckMaskEvent(dpy,
1821 			      ButtonMotionMask | ButtonPressMask, &event))
1822 	  if (event.type == ButtonPress)
1823 	    break;
1824       }
1825 
1826       if (event.type == ButtonPress)
1827       {
1828 	MenuEndResize(tmp_win);
1829 	XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
1830 	break;
1831       }
1832 
1833 /*    if (!DispatchEvent ()) continue; */
1834 
1835       if (event.type != MotionNotify) {
1836 	continue;
1837       }
1838 
1839       /*
1840        * XXX - if we are going to do a loop, we ought to consider
1841        * using multiple GXxor lines so that we don't need to
1842        * grab the server.
1843        */
1844       XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
1845 		    &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
1846 
1847       if (lastx != AddingX || lasty != AddingY)
1848       {
1849 	MenuDoResize(AddingX, AddingY, tmp_win);
1850 
1851 	lastx = AddingX;
1852 	lasty = AddingY;
1853       }
1854 
1855     }
1856 }
1857 
1858 
1859 
1860 /***********************************************************************
1861  *
1862  *  Procedure:
1863  *	RestartTwm - Restart Twm
1864  ***********************************************************************
1865  */
1866 
1867 void
RestartTwm(time)1868 RestartTwm(time)
1869     Time time;
1870 {
1871     XSync (dpy, 0);
1872     Reborder (time);
1873     XSync (dpy, 0);
1874     execvp(*Argv, Argv);
1875     fprintf (stderr, "%s:  unable to restart:  %s\n", ProgramName, *Argv);
1876 }
1877 
1878 
1879 /***********************************************************************
1880  *
1881  *  Procedure:
1882  *	ExecuteFunction - execute a twm root function
1883  *
1884  *  Inputs:
1885  *	func	- the function to execute
1886  *	action	- the menu action to execute
1887  *	sub	- pullright menu, if any
1888  *	w	- the window to execute this function on
1889  *	tmp_win	- the twm window structure
1890  *	event	- the event that caused the function
1891  *	context - the context in which the button was pressed
1892  *	pulldown- flag indicating execution from pull down menu
1893  *
1894  *  Returns:
1895  *	TRUE if should continue with remaining actions else FALSE to abort
1896  *
1897  ***********************************************************************
1898  */
1899 
1900 /* for F_WARPTO */
1901 int
1902 #ifdef __STDC__
WarpThere(TwmWindow * t)1903 WarpThere(TwmWindow *t)
1904 #else
1905 WarpThere(t)
1906 TwmWindow	*t;
1907 #endif
1908 {
1909     if (Scr->WarpUnmapped || t->mapped) {
1910 	if (!t->mapped)
1911 	    DeIconify(t);
1912 	if (!Scr->NoRaiseWarp)
1913 	    RaiseFrame(t);
1914 	WarpToWindow(t);
1915 	return TRUE;
1916     }
1917     return FALSE;
1918 }
1919 
1920 static struct MenuItem *
GetDefaultAction(menu)1921 GetDefaultAction(menu)
1922 struct MenuRoot *menu;
1923 {
1924     struct MenuItem *item;
1925     int i;
1926 
1927     if (!menu)
1928 	return NULL;
1929 
1930     HandleChangingMenus(menu);
1931 
1932     if (!menu->def)
1933 	return NULL;
1934 
1935     for(item = menu->first, i=abs(menu->def) ; (--i > 0) && (item) ;
1936 			item=item->next)
1937 	;
1938 
1939     if (item->func == F_MENU)
1940 	return GetDefaultAction(item->sub);
1941     else
1942 	return item;
1943 }
1944 
1945 int
ExecuteFunction(func,action,sub,w,tmp_win,eventp,context,pulldown)1946 ExecuteFunction(func, action, sub, w, tmp_win, eventp, context, pulldown)
1947     int func;
1948     char *action;
1949     struct MenuRoot *sub;
1950     Window w;
1951     TwmWindow *tmp_win;
1952     XEvent *eventp;
1953     int context;
1954     int pulldown;
1955 {
1956     static Time last_time = 0;
1957     short Real_OpaqueMove;                  /* holder for F_OPAQUEMOVE */
1958     char tmp[200];
1959     char *ptr;
1960     char buff[MAX_FILE_SIZE];
1961     int count, fd;
1962     Window rootw;
1963     int origX, origY;
1964     int do_next_action = TRUE;
1965     int moving_icon = FALSE;
1966     Bool fromtitlebar = False;
1967     extern int ConstrainedMoveTime;
1968     struct MenuItem *item;
1969 
1970     RootFunction = 0;
1971     if (Cancel)
1972 	return TRUE;			/* XXX should this be FALSE? */
1973 
1974     switch (func)
1975     {
1976     case F_UPICONMGR:
1977     case F_LEFTICONMGR:
1978     case F_RIGHTICONMGR:
1979     case F_DOWNICONMGR:
1980     case F_FORWICONMGR:
1981     case F_BACKICONMGR:
1982     case F_NEXTICONMGR:
1983     case F_PREVICONMGR:
1984     case F_NOP:
1985     case F_TITLE:
1986     case F_DELTASTOP:
1987     case F_RAISELOWER:
1988     case F_WARPTOSCREEN:
1989     case F_WARPTO:
1990     case F_WARPRING:
1991     case F_WARPTOICONMGR:
1992     case F_COLORMAP:
1993 	break;
1994     default:
1995         XGrabPointer(dpy, Scr->Root, True,
1996             ButtonPressMask | ButtonReleaseMask,
1997             GrabModeAsync, GrabModeAsync,
1998             Scr->Root, Scr->WaitCursor, CurrentTime);
1999 	break;
2000     }
2001 
2002     switch (func)
2003     {
2004     case F_NOP:
2005     case F_TITLE:
2006 	break;
2007 
2008     case F_MENU:
2009 	item = GetDefaultAction(sub);
2010 
2011 	if (item == NULL) {
2012 	    XBell(dpy, 0);
2013 	    return FALSE;
2014 	}
2015 
2016 	if (Deferrable(item->func) && DeferExecution(context, item->func,
2017 					item->action, Scr->SelectCursor))
2018 	    return TRUE;
2019 
2020 	return ExecuteFunction(item->func,
2021 				item->action,
2022 				item->sub,
2023 				w, tmp_win,
2024 				eventp, context, pulldown);
2025 	break;
2026 
2027     case F_PANNER:
2028 	if (Scr->Panner) {
2029 	    if (XFindContext (dpy, Scr->Panner, TwmContext, (caddr_t *)&tmp_win) != XCSUCCESS)
2030 		tmp_win = AddWindow(Scr->Panner, FALSE, NULL);
2031 	    if (tmp_win->mapped) {
2032 		UnmapFrame(tmp_win);
2033 		tmp_win->mapped = FALSE;
2034 	    }
2035 	    else {
2036 		if (tmp_win->isicon)
2037 		    DeIconify(tmp_win);
2038 		else
2039 		    MapFrame(tmp_win);
2040 		tmp_win->mapped = TRUE;
2041 	    }
2042 	}
2043 	break;
2044 
2045     case F_SCROLL:
2046     case F_SCROLLHOME:
2047     case F_SCROLLLEFT:
2048     case F_SCROLLRIGHT:
2049     case F_SCROLLUP:
2050     case F_SCROLLDOWN:
2051     case F_SCROLLBACK:
2052 	ScrollDesktop(func, action);
2053 	break;
2054 
2055     case F_DELTASTOP:
2056 	if (WindowMoved) do_next_action = FALSE;
2057 	break;
2058 
2059     case F_RESTART:
2060 	RestartTwm(eventp->xbutton.time);
2061 	break;
2062 
2063     case F_UPICONMGR:
2064     case F_DOWNICONMGR:
2065     case F_LEFTICONMGR:
2066     case F_RIGHTICONMGR:
2067     case F_FORWICONMGR:
2068     case F_BACKICONMGR:
2069 	MoveIconManager(func);
2070         break;
2071 
2072     case F_NEXTICONMGR:
2073     case F_PREVICONMGR:
2074 	JumpIconManager(func);
2075         break;
2076 
2077     case F_SHOWLIST:
2078 	if (Scr->NoIconManagers)
2079 	    break;
2080 	DeIconify(Scr->iconmgr.twm_win);
2081 	RaiseFrame(Scr->iconmgr.twm_win);
2082 	break;
2083 
2084     case F_HIDELIST:
2085 	if (Scr->NoIconManagers)
2086 	    break;
2087 	HideIconManager ();
2088 	break;
2089 
2090     case F_STICK:
2091 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2092 	    return TRUE;
2093 
2094 	if (Scr->VirtualDesktop) {
2095 	    int x, y;
2096 
2097 	    if (tmp_win->sticky) {
2098 		if (Scr->StickyAbove) {
2099 		    XReparentWindow(dpy, tmp_win->frame, Scr->VirtualDesktop,
2100 			tmp_win->frame_x + Scr->vdtPositionX,
2101 			tmp_win->frame_y + Scr->vdtPositionY);
2102 		    tmp_win->frame_x += Scr->vdtPositionX;
2103 		    tmp_win->frame_y += Scr->vdtPositionY;
2104 		    XMoveWindow(dpy, tmp_win->virtualWindow,
2105 			tmp_win->frame_x / Scr->PannerScale,
2106 			tmp_win->frame_y / Scr->PannerScale);
2107 		    if (tmp_win->icon.w) {
2108 			XReparentWindow(dpy, tmp_win->icon.w, Scr->VirtualDesktop,
2109 			    tmp_win->icon_loc_x + Scr->vdtPositionX,
2110 			    tmp_win->icon_loc_y + Scr->vdtPositionY);
2111 			tmp_win->icon_loc_x += Scr->vdtPositionX;
2112 			tmp_win->icon_loc_y += Scr->vdtPositionY;
2113 			XMoveWindow(dpy, tmp_win->virtualIcon,
2114 			    tmp_win->icon_loc_x / Scr->PannerScale,
2115 			    tmp_win->icon_loc_y / Scr->PannerScale);
2116 		    }
2117 		    tmp_win->root = Scr->VirtualDesktop;
2118 		}
2119 		if (!tmp_win->isicon)
2120 		    XMapRaised(dpy, tmp_win->virtualWindow);
2121 		else if (tmp_win->virtualIcon)
2122 		    XMapRaised(dpy, tmp_win->virtualIcon);
2123 		tmp_win->sticky = False;
2124 		SetSWM_ROOT(tmp_win);
2125 		SetTWM_FLAGS(tmp_win);
2126 	    }
2127 	    else {
2128 		if (Scr->StickyAbove) {
2129 		    XReparentWindow(dpy, tmp_win->frame, Scr->Root,
2130 			tmp_win->frame_x - Scr->vdtPositionX,
2131 			tmp_win->frame_y - Scr->vdtPositionY);
2132 		    tmp_win->frame_x -= Scr->vdtPositionX;
2133 		    tmp_win->frame_y -= Scr->vdtPositionY;
2134 		    if (tmp_win->icon.w) {
2135 			XReparentWindow(dpy, tmp_win->icon.w, Scr->Root,
2136 			    tmp_win->icon_loc_x - Scr->vdtPositionX,
2137 			    tmp_win->icon_loc_y - Scr->vdtPositionY);
2138 			tmp_win->icon_loc_x -= Scr->vdtPositionX;
2139 			tmp_win->icon_loc_y -= Scr->vdtPositionY;
2140 		    }
2141 		    tmp_win->root = Scr->Root;
2142 		}
2143 		XUnmapWindow(dpy, tmp_win->virtualWindow);
2144 		if (tmp_win->virtualIcon)
2145 		    XUnmapWindow(dpy, tmp_win->virtualIcon);
2146 		tmp_win->sticky = True;
2147 		SetSWM_ROOT(tmp_win);
2148 		SetTWM_FLAGS(tmp_win);
2149 	    }
2150 	}
2151 	break;
2152 
2153     case F_SORTICONMGR:
2154 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2155 	    return TRUE;
2156 
2157 	{
2158 	    int save_sort;
2159 
2160 	    save_sort = Scr->SortIconMgr;
2161 	    Scr->SortIconMgr = TRUE;
2162 
2163 	    if (context == C_ICONMGR)
2164 		SortIconManager((IconMgr *) NULL);
2165 	    else if (tmp_win->iconmgr)
2166 		SortIconManager(tmp_win->iconmgrp);
2167 	    else
2168 		XBell(dpy, 0);
2169 
2170 	    Scr->SortIconMgr = save_sort;
2171 	}
2172 	break;
2173 
2174     case F_IDENTIFY:
2175 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2176 	    return TRUE;
2177 
2178 	Identify(tmp_win);
2179 	break;
2180 
2181     case F_VERSION:
2182 	Identify ((TwmWindow *) NULL);
2183 	break;
2184 
2185     case F_AUTORAISE:
2186 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2187 	    return TRUE;
2188 
2189 	tmp_win->auto_raise = !tmp_win->auto_raise;
2190 	if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
2191 	else --(Scr->NumAutoRaises);
2192 	break;
2193 
2194     case F_BEEP:
2195 	XBell(dpy, 0);
2196 	break;
2197 
2198     case F_POPUP:
2199 	tmp_win = (TwmWindow *)action;
2200 	if (Scr->WindowFunction.func != 0)
2201 	{
2202 	   ExecuteFunction(Scr->WindowFunction.func,
2203 			   Scr->WindowFunction.item->action,
2204 			   NULL,
2205 			   w, tmp_win, eventp, C_FRAME, FALSE);
2206 	}
2207 	else
2208 	{
2209 	    DeIconify(tmp_win);
2210 	    if (Scr->VirtualDesktop)
2211 		ScrollToQuadrant(tmp_win);
2212 	    RaiseFrame (tmp_win);
2213 	}
2214 	break;
2215 
2216     case F_RELATIVERESIZE:
2217     case F_RESIZE:
2218 	EventHandler[EnterNotify] = HandleUnknown;
2219 	EventHandler[LeaveNotify] = HandleUnknown;
2220 	if (DeferExecution(context, func, action, Scr->MoveCursor))
2221 	    return TRUE;
2222 
2223 	PopDownMenu();
2224 	if (pulldown)
2225 	    XWarpPointer(dpy, None, Scr->Root,
2226 		0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
2227 
2228 	if (w != tmp_win->icon.w) {	/* can't resize icons */
2229 
2230 	  if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE)
2231 	       && fromMenu)
2232 	    resizeFromCenter(w, tmp_win);
2233 	  else {
2234 	    /*
2235 	     * see if this is being done from the titlebar
2236 	     */
2237 	    fromtitlebar =
2238 	      belongs_to_twm_window (tmp_win, eventp->xbutton.window);
2239 
2240 	    /* Save pointer position so we can tell if it was moved or
2241 	       not during the resize. */
2242 	    ResizeOrigX = eventp->xbutton.x_root;
2243 	    ResizeOrigY = eventp->xbutton.y_root;
2244 
2245 	    if (func == F_RELATIVERESIZE) {
2246 		short Real_AutoRelativeResize = Scr->AutoRelativeResize;
2247 		Scr->AutoRelativeResize = TRUE;
2248 		StartResize (eventp, tmp_win, fromtitlebar);
2249 		Scr->AutoRelativeResize = Real_AutoRelativeResize;
2250 	    } else {
2251 		StartResize (eventp, tmp_win, fromtitlebar);
2252 	    }
2253 
2254 	    do {
2255 	      XMaskEvent(dpy,
2256 			 ButtonPressMask | ButtonReleaseMask |
2257 			 EnterWindowMask | LeaveWindowMask |
2258 			 ButtonMotionMask, &Event);
2259 
2260 		if (fromtitlebar && Event.type == ButtonPress) {
2261 		  fromtitlebar = False;
2262 		  continue;
2263 		}
2264 
2265 		if (Event.type == MotionNotify) {
2266 		  /* discard any extra motion events before a release */
2267 		  while
2268 		    (XCheckMaskEvent
2269 		     (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
2270 		      if (Event.type == ButtonRelease)
2271 			break;
2272 		}
2273 
2274 	      if (!DispatchEvent ()) continue;
2275 
2276 	    } while (!(Event.type == ButtonRelease || Cancel));
2277 	    return TRUE;
2278 	}
2279 	}
2280 	break;
2281 
2282 
2283     case F_ZOOM:
2284     case F_HORIZOOM:
2285     case F_FULLZOOM:
2286     case F_LEFTZOOM:
2287     case F_RIGHTZOOM:
2288     case F_TOPZOOM:
2289     case F_BOTTOMZOOM:
2290 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2291 	    return TRUE;
2292 	fullzoom(tmp_win, func);
2293 	break;
2294 
2295     case F_MOVE:
2296     case F_FORCEMOVE:
2297     case F_CONSTRAINEDMOVE:
2298     case F_OPAQUEMOVE:
2299 	if (DeferExecution(context, func, action, Scr->MoveCursor))
2300 	    return TRUE;
2301 
2302 	PopDownMenu();
2303 	rootw = eventp->xbutton.root;
2304 	MoveFunction = func;
2305 	if (MoveFunction == F_OPAQUEMOVE) {
2306 	    Real_OpaqueMove = Scr->OpaqueMove;
2307 	    Scr->OpaqueMove = TRUE;
2308 	}
2309 
2310 	if (pulldown)
2311 	    XWarpPointer(dpy, None, Scr->Root,
2312 		0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
2313 
2314 	if (context == C_ICON && tmp_win->icon.w)
2315 	{
2316 	    DragIcon(tmp_win, eventp, pulldown);
2317 	}
2318 	else if (w != tmp_win->icon.w)
2319 	{
2320 	    DragFrame(tmp_win, eventp, pulldown);
2321 	}
2322 #ifdef OLD_MOVE
2323 	if (DeferExecution(context, func, action, Scr->MoveCursor))
2324 	    return TRUE;
2325 
2326 	PopDownMenu();
2327 	rootw = eventp->xbutton.root;
2328 	MoveFunction = func;
2329 
2330 	if (pulldown)
2331 	    XWarpPointer(dpy, None, Scr->Root,
2332 		0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
2333 
2334 	EventHandler[EnterNotify] = HandleUnknown;
2335 	EventHandler[LeaveNotify] = HandleUnknown;
2336 
2337 	if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
2338 	    XGrabServer(dpy);
2339 	}
2340 	XGrabPointer(dpy, eventp->xbutton.root, True,
2341 	    ButtonPressMask | ButtonReleaseMask |
2342 	    ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
2343 	    GrabModeAsync, GrabModeAsync,
2344 	    Scr->Root, Scr->MoveCursor, CurrentTime);
2345 
2346 	if (context == C_ICON && tmp_win->icon.w)
2347 	{
2348 	    w = tmp_win->icon.w;
2349 	    DragVirtual = tmp_win->virtualIcon;
2350 	    DragX = eventp->xbutton.x;
2351 	    DragY = eventp->xbutton.y;
2352 	    moving_icon = TRUE;
2353 	}
2354 	else if (w != tmp_win->icon.w)
2355 	{
2356 	    XTranslateCoordinates(dpy, w, tmp_win->frame,
2357 		eventp->xbutton.x,
2358 		eventp->xbutton.y,
2359 		&DragX, &DragY, &JunkChild);
2360 
2361 	    w = tmp_win->frame;
2362 	    DragVirtual = tmp_win->virtualWindow;
2363 	}
2364 
2365 	DragWindow = None;
2366 
2367 	XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
2368 	    (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW,
2369 	    &JunkDepth);
2370 
2371 	origX = eventp->xbutton.x_root;
2372 	origY = eventp->xbutton.y_root;
2373 	CurrentDragX = origDragX;
2374 	CurrentDragY = origDragY;
2375 
2376 	/*
2377 	 * only do the constrained move if timer is set; need to check it
2378 	 * in case of stupid or wicked fast servers
2379 	 */
2380 	if ((ConstrainedMoveTime &&
2381 	     (eventp->xbutton.time - last_time) < ConstrainedMoveTime) ||
2382 	    (MoveFunction == F_CONSTRAINEDMOVE))
2383 
2384 	{
2385 	    int width, height;
2386 
2387 	    ConstMove = TRUE;
2388 	    ConstMoveDir = MOVE_NONE;
2389 	    ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
2390 	    ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
2391 	    width = DragWidth + 2 * JunkBW;
2392 	    height = DragHeight + 2 * JunkBW;
2393 	    ConstMoveXL = ConstMoveX + width/3;
2394 	    ConstMoveXR = ConstMoveX + 2*(width/3);
2395 	    ConstMoveYT = ConstMoveY + height/3;
2396 	    ConstMoveYB = ConstMoveY + 2*(height/3);
2397 
2398 	    XWarpPointer(dpy, None, w,
2399 		0, 0, 0, 0, DragWidth/2, DragHeight/2);
2400 
2401 	    XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
2402 		&JunkX, &JunkY, &DragX, &DragY, &JunkMask);
2403 	}
2404 	last_time = eventp->xbutton.time;
2405 
2406 	if (!Scr->OpaqueMove)
2407 	{
2408 	    InstallRootColormap();
2409 	    if (!Scr->MoveDelta)
2410 	    {
2411 		/*
2412 		 * Draw initial outline.  This was previously done the
2413 		 * first time though the outer loop by dropping out of
2414 		 * the XCheckMaskEvent inner loop down to one of the
2415 		 * MoveOutline's below.
2416 		 */
2417 		MoveOutline(rootw,
2418 			    origDragX - JunkBW, origDragY - JunkBW,
2419 			    DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
2420 			    tmp_win->frame_bw,
2421 			    moving_icon ? 0 : tmp_win->title_height);
2422 	 	/*
2423 		 * This next line causes HandleReleaseNotify to call
2424 		 * XRaiseWindow().  This is solely to preserve the
2425 		 * previous behaviour that raises a window being moved
2426 		 * on button release even if you never actually moved
2427 		 * any distance (unless you move less than MoveDelta or
2428 		 * NoRaiseMove is set or OpaqueMove is set).
2429 		 */
2430 		DragWindow = w;
2431 	    }
2432 	}
2433 
2434 	/*
2435 	 * see if this is being done from the titlebar
2436 	 */
2437 	fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window);
2438 
2439 	if (menuFromFrameOrWindowOrTitlebar) {
2440 	    /* warp the pointer to the middle of the window */
2441 	    XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
2442 			 origDragX + DragWidth / 2,
2443 			 origDragY + DragHeight / 2);
2444 	    XFlush(dpy);
2445 	}
2446 
2447 	while (TRUE)
2448 	{
2449 	    long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
2450 					ButtonPress : ButtonRelease;
2451 	    long movementMask = menuFromFrameOrWindowOrTitlebar ?
2452 					PointerMotionMask : ButtonMotionMask;
2453 
2454 	    /* block until there is an interesting event */
2455 	    XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
2456 					EnterWindowMask | LeaveWindowMask |
2457 				        ExposureMask | movementMask |
2458 					VisibilityChangeMask, &Event))
2459 
2460 		/* throw away enter and leave events until release */
2461 		if (Event.xany.type == EnterNotify ||
2462 		    Event.xany.type == LeaveNotify) continue;
2463 
2464 		if (Event.type == MotionNotify) {
2465 		    /* discard any extra motion events before a logical release */
2466 		    while(XCheckMaskEvent(dpy,
2467 				movementMask | releaseEvent, &Event))
2468 			if (Event.type == releaseEvent)
2469 			    break;
2470 		}
2471 
2472 		/* test to see if we have a second button press to abort move */
2473 		if (!menuFromFrameOrWindowOrTitlebar)
2474 		  if (Event.type == ButtonPress && DragWindow != None) {
2475 		    if (Scr->OpaqueMove)
2476 		      XMoveWindow (dpy, DragWindow, origDragX, origDragY);
2477 		    else
2478 		      MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
2479 		    DragWindow = None;
2480 		  }
2481 
2482 		if (fromtitlebar && Event.type == ButtonPress) {
2483 		    fromtitlebar = False;
2484 		    CurrentDragX = origX = Event.xbutton.x_root;
2485 		    CurrentDragY = origY = Event.xbutton.y_root;
2486 		    XTranslateCoordinates (dpy, rootw, tmp_win->frame,
2487 					   origX, origY,
2488 					   &DragX, &DragY, &JunkChild);
2489 		    continue;
2490 		}
2491 
2492 		if (!DispatchEvent2 ()) continue;
2493 
2494 		if (Cancel)
2495 		{
2496 		    WindowMoved = FALSE;
2497 		    if (!Scr->OpaqueMove)
2498 			UninstallRootColormap();
2499 		    return TRUE;	/* XXX should this be FALSE? */
2500 		}
2501 		if (Event.type == releaseEvent)
2502 		{
2503 		    MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
2504 		    if (moving_icon &&
2505 			((CurrentDragX != origDragX ||
2506 			  CurrentDragY != origDragY)))
2507 		      tmp_win->icon_moved = TRUE;
2508 		      if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar)
2509 			XMoveWindow(dpy, DragWindow,
2510 				    Event.xbutton.x_root - DragWidth / 2,
2511 				    Event.xbutton.y_root - DragHeight / 2);
2512 		    break;
2513 		}
2514 
2515 	    /* something left to do only if the pointer moved */
2516 	    if (Event.type != MotionNotify)
2517 		continue;
2518 
2519 	    XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
2520 		&(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
2521 		&JunkX, &JunkY, &JunkMask);
2522 
2523 	    if (DragWindow == None &&
2524 		abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
2525 	        abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
2526 		continue;
2527 
2528 	    WindowMoved = TRUE;
2529 	    DragWindow = w;
2530 
2531 	    if (!Scr->NoRaiseMove && Scr->OpaqueMove)	/* can't restore... */
2532 	      XRaiseWindow(dpy, DragWindow);
2533 
2534 	    if (ConstMove)
2535 	    {
2536 		switch (ConstMoveDir)
2537 		{
2538 		    case MOVE_NONE:
2539 			if (eventp->xmotion.x_root < ConstMoveXL ||
2540 			    eventp->xmotion.x_root > ConstMoveXR)
2541 			    ConstMoveDir = MOVE_HORIZ;
2542 
2543 			if (eventp->xmotion.y_root < ConstMoveYT ||
2544 			    eventp->xmotion.y_root > ConstMoveYB)
2545 			    ConstMoveDir = MOVE_VERT;
2546 
2547 			XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
2548 			    &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
2549 			break;
2550 
2551 		    case MOVE_VERT:
2552 			ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
2553 			break;
2554 
2555 		    case MOVE_HORIZ:
2556 			ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
2557 			break;
2558 		}
2559 
2560 		if (ConstMoveDir != MOVE_NONE)
2561 		{
2562 		    int xl, yt, xr, yb, w, h;
2563 
2564 		    xl = ConstMoveX;
2565 		    yt = ConstMoveY;
2566 		    w = DragWidth + 2 * JunkBW;
2567 		    h = DragHeight + 2 * JunkBW;
2568 
2569 		    if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2570 		    {
2571 			xr = xl + w;
2572 			yb = yt + h;
2573 
2574 			if (xl < 0)
2575 			    xl = 0;
2576 			if (xr > Scr->MyDisplayWidth)
2577 			    xl = Scr->MyDisplayWidth - w;
2578 
2579 			if (yt < 0)
2580 			    yt = 0;
2581 			if (yb > Scr->MyDisplayHeight)
2582 			    yt = Scr->MyDisplayHeight - h;
2583 		    }
2584 		    CurrentDragX = xl;
2585 		    CurrentDragY = yt;
2586 		    if (Scr->OpaqueMove)
2587 			XMoveWindow(dpy, DragWindow, xl, yt);
2588 		    else
2589 			MoveOutline(eventp->xmotion.root, xl, yt, w, h,
2590 			    tmp_win->frame_bw,
2591 			    moving_icon ? 0 : tmp_win->title_height);
2592 		}
2593 	    }
2594 	    else if (DragWindow != None)
2595 	    {
2596 		int xl, yt, xr, yb, w, h;
2597 		if (!menuFromFrameOrWindowOrTitlebar) {
2598 		  xl = eventp->xmotion.x_root - DragX - JunkBW;
2599 		  yt = eventp->xmotion.y_root - DragY - JunkBW;
2600 		}
2601 		else {
2602 		  xl = eventp->xmotion.x_root - (DragWidth / 2);
2603 		  yt = eventp->xmotion.y_root - (DragHeight / 2);
2604 		}
2605 		w = DragWidth + 2 * JunkBW;
2606 		h = DragHeight + 2 * JunkBW;
2607 
2608 		if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2609 		{
2610 		    xr = xl + w;
2611 		    yb = yt + h;
2612 
2613 		    if (xl < 0)
2614 			xl = 0;
2615 		    if (xr > Scr->MyDisplayWidth)
2616 			xl = Scr->MyDisplayWidth - w;
2617 
2618 		    if (yt < 0)
2619 			yt = 0;
2620 		    if (yb > Scr->MyDisplayHeight)
2621 			yt = Scr->MyDisplayHeight - h;
2622 		}
2623 
2624 		CurrentDragX = xl;
2625 		CurrentDragY = yt;
2626 		if (Scr->OpaqueMove)
2627 		    XMoveWindow(dpy, DragWindow, xl, yt);
2628 		else
2629 		    MoveOutline(eventp->xmotion.root, xl, yt, w, h,
2630 			tmp_win->frame_bw,
2631 			moving_icon ? 0 : tmp_win->title_height);
2632 	    }
2633 
2634 	}
2635 
2636 	if (!Scr->OpaqueMove && DragWindow == None)
2637 	    UninstallRootColormap();
2638 #endif /* OLD_MOVE */
2639 
2640 	if (MoveFunction == F_OPAQUEMOVE)
2641 	  Scr->OpaqueMove = Real_OpaqueMove ;
2642 
2643         break;
2644 
2645     case F_FUNCTION:
2646     case F_MENUFUNC:
2647 	{
2648 	    MenuRoot *mroot;
2649 	    MenuItem *mitem;
2650 
2651 	    if ((mroot = FindMenuRoot(action)) == NULL)
2652 	    {
2653 		fprintf (stderr, "%s: couldn't find function \"%s\"\n",
2654 			 ProgramName, action);
2655 		return TRUE;
2656 	    }
2657 
2658 	    if (NeedToDefer(mroot) && DeferExecution(context, func, action, Scr->SelectCursor))
2659 		return TRUE;
2660 	    else
2661 	    {
2662 		for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
2663 		{
2664 		    if (!ExecuteFunction (mitem->func, mitem->action, NULL, w,
2665 					  tmp_win, eventp, context, pulldown))
2666 		      break;
2667 		}
2668 	    }
2669 	}
2670 	break;
2671 
2672     case F_DEICONIFY:
2673     case F_ICONIFY:
2674 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2675 	    return TRUE;
2676 
2677 	if (tmp_win->isicon || !tmp_win->mapped ) {
2678 	    DeIconify(tmp_win);
2679 	}
2680         else if (func == F_ICONIFY) {
2681 	    if ( tmp_win->root == Scr->VirtualDesktop ) {
2682 		Iconify (tmp_win,
2683 		    eventp->xbutton.x_root - 5 + Scr->vdtPositionX,
2684 		    eventp->xbutton.y_root - 5 + Scr->vdtPositionY
2685 		);
2686 	    }
2687 	    else {
2688 		Iconify (tmp_win, eventp->xbutton.x_root - 5,
2689 		    eventp->xbutton.y_root - 5);
2690 	    }
2691 	}
2692 	break;
2693 
2694     case F_RAISELOWER:
2695 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2696 	    return TRUE;
2697 
2698 	if (!WindowMoved) {
2699 	    Window virtual;
2700 	    XWindowChanges xwc;
2701 
2702 	    xwc.stack_mode = Opposite;
2703 	    virtual = tmp_win->virtualIcon;
2704 	    if (w != tmp_win->icon.w) {
2705 		w = tmp_win->frame;
2706 		virtual = tmp_win->virtualWindow;
2707 	    }
2708 	    XConfigureWindow (dpy, w, CWStackMode, &xwc);
2709 	    if (tmp_win->sticky && Scr->VirtualDesktop)
2710 		XLowerWindow(dpy, Scr->VirtualDesktop);
2711 	    if (virtual)
2712 		XConfigureWindow (dpy, virtual, CWStackMode, &xwc);
2713 	}
2714 	break;
2715 
2716     case F_RAISE:
2717 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2718 	    return TRUE;
2719 
2720 	/* check to make sure raise is not from the WindowFunction */
2721 	if (w == tmp_win->icon.w && Context != C_ROOT)
2722 	    RaiseIcon(tmp_win);
2723 	else
2724 	    RaiseFrame(tmp_win);
2725 
2726 	break;
2727 
2728     case F_LOWER:
2729 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2730 	    return TRUE;
2731 
2732 	if (w == tmp_win->icon.w)
2733 	    LowerIcon(tmp_win);
2734 	else
2735 	    LowerFrame(tmp_win);
2736 
2737 	break;
2738 
2739     case F_FOCUS:
2740 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2741 	    return TRUE;
2742 
2743 	if (tmp_win->isicon == FALSE)
2744 	{
2745 	    if (!Scr->FocusRoot && Scr->Focus == tmp_win)
2746 	    {
2747 		FocusOnRoot();
2748 	    }
2749 	    else
2750 	    {
2751 		if (Scr->Focus != NULL) {
2752 		    SetBorder (Scr->Focus, False);
2753 		    if (Scr->Focus->hilite_w)
2754 		      XUnmapWindow (dpy, Scr->Focus->hilite_w);
2755 		}
2756 
2757 		InstallWindowColormaps (0, tmp_win);
2758 		if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w);
2759 		SetBorder (tmp_win, True);
2760 		SetFocus (tmp_win, eventp->xbutton.time);
2761 		Scr->FocusRoot = FALSE;
2762 		Scr->Focus = tmp_win;
2763 	    }
2764 	}
2765 	break;
2766 
2767     case F_DESTROY:
2768 	if (DeferExecution(context, func, action, Scr->DestroyCursor))
2769 	    return TRUE;
2770 
2771 	if (tmp_win->iconmgr)
2772 	    XBell(dpy, 0);
2773 	else if (tmp_win->w == Scr->Panner) {
2774 	    UnmapFrame(tmp_win);
2775 	    tmp_win->mapped = FALSE;
2776 	}
2777 	else
2778 	    XKillClient(dpy, tmp_win->w);
2779 	break;
2780 
2781     case F_DELETE:
2782 	if (DeferExecution(context, func, action, Scr->DestroyCursor))
2783 	    return TRUE;
2784 
2785 	if (tmp_win->iconmgr)		/* don't send ourself a message */
2786 	  HideIconManager ();
2787 	else if (tmp_win->protocols & DoesWmDeleteWindow)
2788 	  SendDeleteWindowMessage (tmp_win, LastTimestamp());
2789 	else
2790 	  XBell (dpy, 0);
2791 	break;
2792 
2793     case F_DELETEORDESTROY:
2794 	if (DeferExecution(context, func, action, Scr->DestroyCursor))
2795 	    return TRUE;
2796 
2797 	if (tmp_win->iconmgr)		/* don't send ourself a message */
2798 	    HideIconManager();
2799 	else if (tmp_win->w == Scr->Panner) {
2800 	    UnmapFrame(tmp_win);
2801 	    tmp_win->mapped = FALSE;
2802 	} else if (tmp_win->protocols & DoesWmDeleteWindow)
2803 	    SendDeleteWindowMessage (tmp_win, LastTimestamp());
2804 	else
2805 	    XKillClient(dpy, tmp_win->w);
2806 	break;
2807 
2808     case F_SAVEYOURSELF:
2809 	if (DeferExecution (context, func, action, Scr->SelectCursor))
2810 	  return TRUE;
2811 
2812 	if (tmp_win->protocols & DoesWmSaveYourself)
2813 	  SendSaveYourselfMessage (tmp_win, LastTimestamp());
2814 	else
2815 	  XBell (dpy, 0);
2816 	break;
2817 
2818     case F_CIRCLEUP:
2819 	if (Scr->VirtualDesktop) {
2820 	    XCirculateSubwindowsUp(dpy, Scr->VirtualDesktop);
2821 	    XCirculateSubwindowsUp(dpy, Scr->Panner);
2822 	}
2823 	else
2824 	    XCirculateSubwindowsUp(dpy, Scr->Root);
2825 	break;
2826 
2827     case F_CIRCLEDOWN:
2828 	if (Scr->VirtualDesktop) {
2829 	    XCirculateSubwindowsDown(dpy, Scr->VirtualDesktop);
2830 	    XCirculateSubwindowsDown(dpy, Scr->Panner);
2831 	}
2832 	else
2833 	    XCirculateSubwindowsDown(dpy, Scr->Root);
2834 	break;
2835 
2836     case F_EXEC:
2837 	PopDownMenu();
2838 	if (!Scr->NoGrabServer) {
2839 	    XUngrabServer (dpy);
2840 	    XSync (dpy, 0);
2841 	}
2842 	(void)Execute(action, tmp_win);
2843 	break;
2844 
2845     case F_WINEXEC:
2846 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2847 	    return TRUE;
2848 
2849 	PopDownMenu();
2850 	if (!Scr->NoGrabServer)
2851 	    XUngrabServer(dpy);
2852 	XUngrabPointer(dpy, CurrentTime);
2853 	XSync(dpy, 0);
2854 	(void)Execute(action, tmp_win);
2855 	break;
2856 
2857     case F_TESTEXEC:
2858 	PopDownMenu();
2859 	if (!Scr->NoGrabServer) {
2860 	    XUngrabServer (dpy);
2861 	    XSync (dpy, 0);
2862 	}
2863 	do_next_action= (Execute(action, tmp_win)==0);
2864 	if ( !do_next_action )
2865 	    XBell(dpy,0);
2866 	break;
2867 
2868     case F_TESTWINEXEC:
2869 	if (DeferExecution(context, func, action, Scr->SelectCursor))
2870 	    return TRUE;
2871 
2872 	PopDownMenu();
2873 	if (!Scr->NoGrabServer)
2874 	    XUngrabServer(dpy);
2875 	XUngrabPointer(dpy, CurrentTime);
2876 	XSync(dpy, 0);
2877 	do_next_action = (Execute(action, tmp_win) == 0);
2878 	if (!do_next_action)
2879 	    XBell(dpy, 0);
2880 	break;
2881 
2882     case F_UNFOCUS:
2883 	FocusOnRoot();
2884 	break;
2885 
2886     case F_CUT:
2887 	strcpy(tmp, action);
2888 	strcat(tmp, "\n");
2889 	XStoreBytes(dpy, tmp, strlen(tmp));
2890 	break;
2891 
2892     case F_CUTFILE:
2893 	ptr = XFetchBytes(dpy, &count);
2894 	if (ptr) {
2895 	    if (sscanf (ptr, "%s", tmp) == 1) {
2896 		XFree (ptr);
2897 		ptr = ExpandFilename(tmp);
2898 		if (ptr) {
2899 		    fd = open (ptr, 0);
2900 		    if (fd >= 0) {
2901 			count = read (fd, buff, MAX_FILE_SIZE - 1);
2902 			if (count > 0) XStoreBytes (dpy, buff, count);
2903 			close(fd);
2904 		    } else {
2905 			fprintf (stderr,
2906 				 "%s:  unable to open cut file \"%s\"\n",
2907 				 ProgramName, tmp);
2908 		    }
2909 		    if (ptr != tmp) free (ptr);
2910 		}
2911 	    } else {
2912 		XFree(ptr);
2913 	    }
2914 	} else {
2915 	    fprintf(stderr, "%s:  cut buffer is empty\n", ProgramName);
2916 	}
2917 	break;
2918 
2919     case F_WARPTOSCREEN:
2920 	{
2921 	    if (strcmp (action, WARPSCREEN_NEXT) == 0) {
2922 		WarpToScreen (Scr->screen + 1, 1);
2923 	    } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
2924 		WarpToScreen (Scr->screen - 1, -1);
2925 	    } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
2926 		WarpToScreen (PreviousScreen, 0);
2927 	    } else {
2928 		WarpToScreen (atoi (action), 0);
2929 	    }
2930 	}
2931 	break;
2932 
2933     case F_COLORMAP:
2934 	{
2935 	    if (strcmp (action, COLORMAP_NEXT) == 0) {
2936 		BumpWindowColormap (tmp_win, 1);
2937 	    } else if (strcmp (action, COLORMAP_PREV) == 0) {
2938 		BumpWindowColormap (tmp_win, -1);
2939 	    } else {
2940 		BumpWindowColormap (tmp_win, 0);
2941 	    }
2942 	}
2943 	break;
2944 
2945     case F_WARPTO:
2946 	{
2947 	    register TwmWindow *t;
2948 	    int len;
2949 
2950 	    len = strlen(action);
2951 
2952 	    if (len == 0) {
2953 		if (!tmp_win)
2954 		    XBell (dpy,0);
2955 		else
2956 		    WarpThere(tmp_win);
2957 	    } else {
2958 		for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2959 		    if (!strncmp(action, t->name, len))
2960 			if (WarpThere(t))
2961 			    break;
2962 		}
2963 		if (!t) {
2964 		    for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2965 			if (!strncmp(action, t->class.res_name, len))
2966 			    if (WarpThere(t))
2967 			    	break;
2968 		    }
2969 		    if (!t) {
2970 			for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2971 			    if (!strncmp(action, t->class.res_class, len))
2972 				if (WarpThere(t))
2973 				    break;
2974 			}
2975 		    }
2976 		}
2977 
2978 		if (!t)
2979 		    XBell (dpy, 0);
2980 	    }
2981 	}
2982 	break;
2983 
2984     case F_WARPTOICONMGR:
2985 	{
2986 	    TwmWindow *t;
2987 	    int len;
2988 	    Window raisewin = None, iconwin = None;
2989 	    TwmWindow *raiseFrame;
2990 
2991 	    len = strlen(action);
2992 	    if (len == 0) {
2993 		if (tmp_win && tmp_win->list) {
2994 		    raisewin = tmp_win->list->iconmgr->twm_win->frame;
2995 		    raiseFrame = tmp_win->list->iconmgr->twm_win;
2996 		    iconwin = tmp_win->list->icon;
2997 		} else if (Scr->iconmgr.active) {
2998 		    raisewin = Scr->iconmgr.twm_win->frame;
2999 		    raiseFrame = Scr->iconmgr.twm_win;
3000 		    iconwin = Scr->iconmgr.active->w;
3001 		}
3002 	    } else {
3003 		for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
3004 		    if (strncmp (action, t->icon_name, len) == 0) {
3005 			if (t->list && t->list->iconmgr->twm_win->mapped) {
3006 			    raisewin = t->list->iconmgr->twm_win->frame;
3007 			    raiseFrame = t->list->iconmgr->twm_win;
3008 			    iconwin = t->list->icon;
3009 			    break;
3010 			}
3011 		    }
3012 		}
3013 	    }
3014 
3015 	    if (raisewin) {
3016 		RaiseFrame (raiseFrame);
3017 		ScrollToQuadrant(raiseFrame);
3018 		XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
3019 	    } else {
3020 		XBell (dpy, 0);
3021 	    }
3022 	}
3023 	break;
3024 
3025     case F_WARPRING:
3026 	switch (action[0]) {
3027 	  case 'n':
3028 	    WarpAlongRing (&eventp->xbutton, True);
3029 	    break;
3030 	  case 'p':
3031 	    WarpAlongRing (&eventp->xbutton, False);
3032 	    break;
3033 	  default:
3034 	    XBell (dpy, 0);
3035 	    break;
3036 	}
3037 	break;
3038 
3039     case F_FILE:
3040 	action = ExpandFilename(action);
3041 	fd = open(action, 0);
3042 	if (fd >= 0)
3043 	{
3044 	    count = read(fd, buff, MAX_FILE_SIZE - 1);
3045 	    if (count > 0)
3046 		XStoreBytes(dpy, buff, count);
3047 
3048 	    close(fd);
3049 	}
3050 	else
3051 	{
3052 	    fprintf (stderr, "%s:  unable to open file \"%s\"\n",
3053 		     ProgramName, action);
3054 	}
3055 	break;
3056 
3057     case F_REFRESH:
3058 	{
3059 	    XSetWindowAttributes attributes;
3060 	    unsigned long valuemask;
3061 
3062 	    valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
3063 	    attributes.background_pixel = Scr->Black;
3064 	    attributes.backing_store = NotUseful;
3065 	    attributes.save_under = False;
3066 	    w = XCreateWindow (dpy, Scr->Root, 0, 0,
3067 			       (unsigned int) Scr->MyDisplayWidth,
3068 			       (unsigned int) Scr->MyDisplayHeight,
3069 			       (unsigned int) 0,
3070 			       CopyFromParent, (unsigned int) CopyFromParent,
3071 			       (Visual *) CopyFromParent, valuemask,
3072 			       &attributes);
3073 	    XMapWindow (dpy, w);
3074 	    XDestroyWindow (dpy, w);
3075 	    XFlush (dpy);
3076 	}
3077 	break;
3078 
3079     case F_WINREFRESH:
3080 	if (DeferExecution(context, func, action, Scr->SelectCursor))
3081 	    return TRUE;
3082 
3083 	if (context == C_ICON && tmp_win->icon.w)
3084 	    w = XCreateSimpleWindow(dpy, tmp_win->icon.w,
3085 		0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
3086 	else
3087 	    w = XCreateSimpleWindow(dpy, tmp_win->frame,
3088 		0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
3089 
3090 	XMapWindow(dpy, w);
3091 	XDestroyWindow(dpy, w);
3092 	XFlush(dpy);
3093 	break;
3094 
3095     case F_RELATIVEMOVE:
3096 	if (tmp_win && !tmp_win->isicon && tmp_win->mapped)
3097 	    RelativeMove(tmp_win, action);
3098 	break;
3099 
3100     case F_DUMPSTATE:
3101 	printf("doing dumpstate\n");
3102 	{
3103 	    Window RootW;
3104 	    Window root, parent, *children;
3105 	    unsigned int nchildren;
3106 	    unsigned int numscr;
3107 	    unsigned int i;
3108 	    unsigned int scr;
3109 
3110 	    numscr = ScreenCount(dpy);
3111 	    printf("# of screens: %d\n",numscr);
3112 	    for(scr = 0; scr <= (numscr-1); scr++) {
3113 		RootW = RootWindow(dpy, scr);
3114 		printf("rootw: 0x%x\n",RootW);
3115 		XGrabServer(dpy);
3116 		XSync(dpy, 0);
3117 		XQueryTree(dpy, RootW, &root, &parent, &children, &nchildren);
3118 		for (i = 0; i < nchildren; i++) {
3119 		    if (children[i]) {
3120 			XWMHints *wmhintsp = XGetWMHints (dpy, children[i]);
3121 			if (wmhintsp) {
3122 			    if (wmhintsp->flags) {
3123 				printf("i: %d wmhints w: 0x%x flags: %d ",
3124 				    i,children[i], wmhintsp->flags
3125 				);
3126 			        if ( wmhintsp->flags & StateHint ) {
3127 				    printf("state: %d ",
3128 					wmhintsp->initial_state);
3129 				}
3130 				printf("\n");
3131 			    }
3132 			}
3133 		    }
3134 		    else {
3135 			printf(" NOT DEFINED\n");
3136 		    }
3137 		}
3138 	    }
3139 	    XUngrabServer(dpy);
3140 	    XFree(children);
3141 	}
3142 	break;
3143 
3144     case F_QUIT:
3145 	Done();
3146 	break;
3147     }
3148 
3149     if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
3150     return do_next_action;
3151 }
3152 
3153 
3154 
3155 /***********************************************************************
3156  *
3157  *  Procedure:
3158  *	DeferExecution - defer the execution of a function to the
3159  *	    next button press if the context is C_ROOT
3160  *
3161  *  Inputs:
3162  *	context	- the context in which the mouse button was pressed
3163  *	func	- the function to defer
3164  *	cursor	- the cursor to display while waiting
3165  *
3166  ***********************************************************************
3167  */
3168 
3169 int
DeferExecution(context,func,action,cursor)3170 DeferExecution(context, func, action, cursor)
3171 int context, func;
3172 char *action;
3173 Cursor cursor;
3174 {
3175     if (context == C_ROOT)
3176     {
3177 	LastCursor = cursor;
3178 	XGrabPointer(dpy, Scr->Root, True,
3179 	    ButtonPressMask | ButtonReleaseMask,
3180 	    GrabModeAsync, GrabModeAsync,
3181 	    Scr->Root, cursor, CurrentTime);
3182 
3183 	RootAction = action;
3184 	RootFunction = func;
3185 
3186 	return (TRUE);
3187     }
3188 
3189     return (FALSE);
3190 }
3191 
3192 
3193 
3194 /***********************************************************************
3195  *
3196  *  Procedure:
3197  *	ReGrab - regrab the pointer with the LastCursor;
3198  *
3199  ***********************************************************************
3200  */
3201 
ReGrab()3202 ReGrab()
3203 {
3204     XGrabPointer(dpy, Scr->Root, True,
3205 	ButtonPressMask | ButtonReleaseMask,
3206 	GrabModeAsync, GrabModeAsync,
3207 	Scr->Root, LastCursor, CurrentTime);
3208 }
3209 
3210 
3211 
3212 /***********************************************************************
3213  *
3214  *  Procedure:
3215  *	NeedToDefer - checks each function in the list to see if it
3216  *		is one that needs to be defered.
3217  *
3218  *  Inputs:
3219  *	root	- the menu root to check
3220  *
3221  ***********************************************************************
3222  */
3223 
Deferrable(func)3224 Deferrable(func)
3225 int func;
3226 {
3227     switch (func) {
3228 	case F_IDENTIFY:
3229 	case F_RESIZE:
3230 	case F_MOVE:
3231 	case F_FORCEMOVE:
3232 	case F_DEICONIFY:
3233 	case F_ICONIFY:
3234 	case F_RAISELOWER:
3235 	case F_RAISE:
3236 	case F_LOWER:
3237 	case F_FOCUS:
3238 	case F_DESTROY:
3239 	case F_DELETE:
3240 	case F_DELETEORDESTROY:
3241 	case F_DUMPSTATE:
3242 	case F_WINREFRESH:
3243 	case F_ZOOM:
3244 	case F_FULLZOOM:
3245 	case F_HORIZOOM:
3246         case F_RIGHTZOOM:
3247         case F_LEFTZOOM:
3248         case F_TOPZOOM:
3249         case F_BOTTOMZOOM:
3250 	case F_AUTORAISE:
3251 	case F_WINEXEC:
3252 	case F_TESTWINEXEC:
3253 	    return TRUE;
3254 	default:
3255 	    return FALSE;
3256     }
3257 }
3258 
NeedToDefer(root)3259 NeedToDefer(root)
3260 MenuRoot *root;
3261 {
3262     MenuItem *mitem;
3263 
3264     for (mitem = root->first; mitem != NULL; mitem = mitem->next)
3265 	if (Deferrable(mitem->func))
3266 	    return TRUE;
3267     return FALSE;
3268 }
3269 
3270 
3271 
3272 /***********************************************************************
3273  *
3274  *  Procedure:
3275  *	Execute - execute the string by /bin/sh
3276  *
3277  *  Inputs:
3278  *	s	- the string containing the command
3279  *
3280  ***********************************************************************
3281  */
3282 
3283 int
Execute(s,tmp_win)3284 Execute(s, tmp_win)
3285     char *s;
3286     TwmWindow *tmp_win;
3287 {
3288     static char buf1[256];
3289     static char buf2[256];
3290     static char buf3[256];
3291     static char buf4[256];
3292     static char buf5[256];
3293     static char buf6[256];
3294     char *ds = DisplayString (dpy);
3295     char *colon, *dot1;
3296     char oldDisplay[256];
3297     char *doisplay;
3298     int restorevar = 0;
3299     int status;
3300 
3301     oldDisplay[0] = '\0';
3302     doisplay=getenv("DISPLAY");
3303     if (doisplay)
3304 	strcpy (oldDisplay, doisplay);
3305 
3306     /*
3307      * Build a display string using the current screen number, so that
3308      * X programs which get fired up from a menu come up on the screen
3309      * that they were invoked from, unless specifically overridden on
3310      * their command line.
3311      */
3312     colon = rindex (ds, ':');
3313     if (colon) {			/* if host[:]:dpy */
3314 	strcpy (buf1, "DISPLAY=");
3315 	strcat (buf1, ds);
3316 	colon = buf1 + 8 + (colon - ds);	/* use version in buf */
3317 	dot1 = index (colon, '.');	/* first period after colon */
3318 	if (!dot1) dot1 = colon + strlen (colon);  /* if not there, append */
3319 	(void) sprintf (dot1, ".%d", Scr->screen);
3320 	putenv (buf1);
3321 	restorevar = 1;
3322     }
3323 
3324     if (tmp_win != NULL ) {
3325 	sprintf(buf2, "TWM_WIN=0x%lx", tmp_win->w);
3326 	putenv(buf2);
3327 	sprintf(buf3, "TWM_WIN_NAME=%s", tmp_win->full_name);
3328 	putenv(buf3);
3329 	sprintf(buf4, "TWM_ICON_NAME=%s", tmp_win->icon_name);
3330 	putenv(buf4);
3331 	sprintf(buf5, "TWM_RES_NAME=%s", tmp_win->class.res_name);
3332 	putenv(buf5);
3333 	sprintf(buf6, "TWM_RES_CLASS=%s", tmp_win->class.res_class);
3334 	putenv(buf6);
3335     }
3336 
3337     status=system (s);
3338 
3339     /* this next bit may be horribly BSD specific. */
3340     if ( (status&0xff) == 0 )
3341 	status = (status &0xff00) >> 8;
3342 
3343     if (restorevar) {		/* why bother? */
3344 	(void) sprintf (buf1, "DISPLAY=%s", oldDisplay);
3345 	putenv (buf1);
3346     }
3347 
3348     return status;
3349 }
3350 
3351 
3352 
3353 /***********************************************************************
3354  *
3355  *  Procedure:
3356  *	FocusOnRoot - put input focus on the root window
3357  *
3358  ***********************************************************************
3359  */
3360 
3361 void
FocusOnRoot()3362 FocusOnRoot()
3363 {
3364     SetFocus ((TwmWindow *) NULL, LastTimestamp());
3365     if (Scr->Focus != NULL)
3366     {
3367 	SetBorder (Scr->Focus, False);
3368 	if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w);
3369     }
3370     InstallWindowColormaps(0, &Scr->TwmRoot);
3371     Scr->Focus = NULL;
3372     Scr->FocusRoot = TRUE;
3373 }
3374 
DeIconify(tmp_win)3375 DeIconify(tmp_win)
3376 TwmWindow *tmp_win;
3377 {
3378     TwmWindow *t;
3379 
3380     /* de-iconify the main window */
3381     if (tmp_win->isicon)
3382     {
3383 	if (tmp_win->icon_on)
3384 	    Zoom(tmp_win->icon.w, tmp_win->frame);
3385 	else if (tmp_win->group != 0)
3386 	{
3387 	    for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
3388 	    {
3389 		if (tmp_win->group == t->w && t->icon_on)
3390 		{
3391 		    Zoom(t->icon.w, tmp_win->frame);
3392 		    break;
3393 		}
3394 	    }
3395 	}
3396     }
3397 
3398 
3399     tmp_win->mapped = TRUE;
3400     if (!Scr->NoRaiseDeicon)
3401 	RaiseFrame(tmp_win);
3402     MapFrame(tmp_win);
3403     SetMapStateProp(tmp_win, NormalState);
3404 
3405     if (tmp_win->icon.w) {
3406 	UnmapIcon(tmp_win);
3407 	IconDown (tmp_win);
3408     }
3409     if (tmp_win->list)
3410 	XUnmapWindow(dpy, tmp_win->list->icon);
3411     if ((Scr->WarpCursor ||
3412 	 LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)) &&
3413 	tmp_win->isicon)
3414       WarpToWindow (tmp_win);
3415     tmp_win->isicon = FALSE;
3416     tmp_win->icon_on = FALSE;
3417 
3418 
3419     /* now de-iconify transients */
3420       for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
3421       {
3422 	if (t->transient && t->transientfor == tmp_win->w)
3423 	  {
3424 	    if (t->icon_on)
3425 	      Zoom(t->icon.w, t->frame);
3426 	    else
3427 	      Zoom(tmp_win->icon.w, t->frame);
3428 
3429 	    t->mapped = TRUE;
3430 	    if (!Scr->NoRaiseDeicon)
3431 	      RaiseFrame(t);
3432 	    MapFrame(t);
3433 	    SetMapStateProp(t, NormalState);
3434 
3435 	    if (t->icon.w) {
3436 	      UnmapIcon(t);
3437 	      IconDown (t);
3438 	    }
3439 	    if (t->list) XUnmapWindow(dpy, t->list->icon);
3440 	    t->isicon = FALSE;
3441 	    t->icon_on = FALSE;
3442 	  }
3443 	}
3444 
3445     XSync (dpy, 0);
3446 }
3447 
3448 
3449 
Iconify(tmp_win,def_x,def_y)3450 Iconify(tmp_win, def_x, def_y)
3451 TwmWindow *tmp_win;
3452 int def_x, def_y;
3453 {
3454     TwmWindow *t;
3455     int iconify;
3456     XWindowAttributes winattrs;
3457     unsigned long eventMask;
3458 
3459     iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
3460     if (iconify)
3461     {
3462 	if (tmp_win->icon.w == None)
3463 	    CreateIconWindow(tmp_win, def_x, def_y);
3464 	else
3465 	    IconUp(tmp_win);
3466 	MapIcon(tmp_win);
3467     }
3468     if (tmp_win->list)
3469 	XMapWindow(dpy, tmp_win->list->icon);
3470 
3471     XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
3472     eventMask = winattrs.your_event_mask;
3473 
3474     /* iconify transients first */
3475 	for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
3476 	{
3477 	    if (t->transient && t->transientfor == tmp_win->w)
3478 	    {
3479 		if (iconify)
3480 		{
3481 		    if (t->icon_on)
3482 			Zoom(t->icon.w, tmp_win->icon.w);
3483 		    else
3484 			Zoom(t->frame, tmp_win->icon.w);
3485 		}
3486 
3487 		/*
3488 		 * Prevent the receipt of an UnmapNotify, since that would
3489 		 * cause a transition to the Withdrawn state.
3490 		 */
3491 		t->mapped = FALSE;
3492 		XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
3493 		UnmapFrame(t);
3494 		XSelectInput(dpy, t->w, eventMask);
3495 		if (t->icon.w)
3496 		    UnmapIcon(t);
3497 		SetMapStateProp(t, IconicState);
3498 		SetBorder (t, False);
3499 		if (t == Scr->Focus)
3500 		{
3501 		    SetFocus ((TwmWindow *) NULL, LastTimestamp());
3502 		    Scr->Focus = NULL;
3503 		    Scr->FocusRoot = TRUE;
3504 		}
3505 		if (t->list) XMapWindow(dpy, t->list->icon);
3506 		t->isicon = TRUE;
3507 		t->icon_on = FALSE;
3508 	    }
3509 	}
3510 
3511     if (iconify)
3512 	Zoom(tmp_win->frame, tmp_win->icon.w);
3513 
3514     /*
3515      * Prevent the receipt of an UnmapNotify, since that would
3516      * cause a transition to the Withdrawn state.
3517      */
3518     tmp_win->mapped = FALSE;
3519     XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
3520     UnmapFrame(tmp_win);
3521     XSelectInput(dpy, tmp_win->w, eventMask);
3522     SetMapStateProp(tmp_win, IconicState);
3523 
3524     SetBorder (tmp_win, False);
3525     if (tmp_win == Scr->Focus)
3526     {
3527 	SetFocus ((TwmWindow *) NULL, LastTimestamp());
3528 	Scr->Focus = NULL;
3529 	Scr->FocusRoot = TRUE;
3530     }
3531     tmp_win->isicon = TRUE;
3532     if (iconify)
3533 	tmp_win->icon_on = TRUE;
3534     else
3535 	tmp_win->icon_on = FALSE;
3536     XSync (dpy, 0);
3537 }
3538 
3539 
3540 
Identify(t)3541 static void Identify (t)
3542 TwmWindow *t;
3543 {
3544     int i, n, twidth, width, height;
3545     int x, y;
3546     unsigned int wwidth, wheight, bw, depth;
3547     Window junk;
3548     int px, py, dummy;
3549     unsigned udummy;
3550     char *s;
3551 
3552     n = 0;
3553 
3554     if (Scr->Identification) {
3555 	(void) sprintf(Info[n++], "%s", Scr->Identification);
3556 	Info[n++][0] = '\0';
3557     }
3558 
3559     (void) sprintf(Info[n++], "tvtwm version:  %s", Version);
3560 #ifdef BETA
3561     (void) sprintf(Info[n++], "tvtwm Patchlevel %d%s", PATCHLEVEL, BETA);
3562 #else
3563     (void) sprintf(Info[n++], "tvtwm Patchlevel %d", PATCHLEVEL);
3564 #endif
3565 
3566     Info[n++][0] = '\0';
3567 
3568     if (t) {
3569 	XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
3570 		      &wwidth, &wheight, &bw, &depth);
3571 	(void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
3572 				      &x, &y, &junk);
3573 	(void) sprintf(Info[n++], "Name             = \"%s\"", t->full_name);
3574 	(void) sprintf(Info[n++], "Class.res_name   = \"%s\"", t->class.res_name);
3575 	(void) sprintf(Info[n++], "Class.res_class  = \"%s\"", t->class.res_class);
3576 	if ((s = GetPropertyString(t->w, XA_WM_CLIENT_MACHINE)) != NULL)
3577 	    (void) sprintf(Info[n++], "Host             = \"%s\"", s);
3578 	else
3579 	    (void) sprintf(Info[n++], "Host             = <empty>");
3580 	Info[n++][0] = '\0';
3581 	(void) sprintf(Info[n++], "Geometry/root    = %dx%d+%d+%d", wwidth, wheight,
3582 		x, y);
3583 	(void) sprintf(Info[n++], "Border width     = %d", bw);
3584 	(void) sprintf(Info[n++], "Depth            = %d", depth);
3585     }
3586 
3587     Info[n++][0] = '\0';
3588     (void) sprintf(Info[n++], "Click to dismiss...");
3589 
3590     /* figure out the width and height of the info window */
3591     height = n * (Scr->DefaultFont.height+2);
3592     width = 1;
3593     for (i = 0; i < n; i++)
3594     {
3595 	twidth = XTextWidth(Scr->DefaultFont.font, Info[i],
3596 	    strlen(Info[i]));
3597 	if (twidth > width)
3598 	    width = twidth;
3599     }
3600     if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
3601 
3602     width += 10;		/* some padding */
3603     if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py,
3604 		       &dummy, &dummy, &udummy)) {
3605 	px -= (width / 2);
3606 	py -= (height / 3);
3607 	if (px + width + BW2 >= Scr->MyDisplayWidth)
3608 	  px = Scr->MyDisplayWidth - width - BW2;
3609 	if (py + height + BW2 >= Scr->MyDisplayHeight)
3610 	  py = Scr->MyDisplayHeight - height - BW2;
3611 	if (px < 0) px = 0;
3612 	if (py < 0) py = 0;
3613     } else {
3614 	px = py = 0;
3615     }
3616     XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
3617     XMapRaised(dpy, Scr->InfoWindow);
3618 #ifdef XPM
3619     if (!t) {
3620 # include "emblem.h"
3621 /* XXX - need to support the None color, at some point here. */
3622 /* currently, the automatic masking stuff in XPM doesn't work */
3623 /* for this image.        - cross  */
3624 	Pixmap pixmap;
3625 	int XPMret;
3626 	XpmColorSymbol bgcolor;
3627 	XpmAttributes attribs;
3628 
3629 	bgcolor.name = "background";
3630 	bgcolor.value = NULL;
3631 	bgcolor.pixel = Scr->DefaultC.back;
3632 
3633 	attribs.valuemask = XpmColorSymbols | XpmVisual |
3634 				XpmColormap | XpmDepth;
3635 	attribs.colorsymbols = &bgcolor;
3636 	attribs.numsymbols = 1;
3637 	attribs.visual = Scr->d_visual;
3638 	attribs.colormap = DefaultColormap(dpy, Scr->screen);
3639 	attribs.depth = Scr->d_depth;
3640 
3641 	if ((XPMret = XpmCreatePixmapFromData(dpy, RootWindow(dpy, Scr->screen),
3642 			emblem, &pixmap, NULL, &attribs)) >= 0) {
3643 
3644 		XCopyArea(dpy, pixmap, Scr->InfoWindow,
3645 			DefaultGC(dpy, Scr->screen), 0, 0,
3646 			attribs.width, attribs.height,
3647 			(width-attribs.width), (height-attribs.height));
3648 			XFlush(dpy);
3649 	} else fprintf(stderr, "tvtwm: Error creating info-box pixmap (Error code: %d)\n", XPMret);
3650     }
3651 #endif
3652     InfoLines = n;
3653 }
3654 
3655 
3656 
SetMapStateProp(tmp_win,state)3657 SetMapStateProp(tmp_win, state)
3658 TwmWindow *tmp_win;
3659 int state;
3660 {
3661     unsigned long data[2];		/* "suggested" by ICCCM version 1 */
3662 
3663     data[0] = (unsigned long) state;
3664     data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
3665 			   tmp_win->icon.w);
3666 
3667     XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
3668 		 PropModeReplace, (unsigned char *) data, 2);
3669 }
3670 
3671 
3672 
GetWMState(w,statep,iwp)3673 Bool GetWMState (w, statep, iwp)
3674     Window w;
3675     int *statep;
3676     Window *iwp;
3677 {
3678     Atom actual_type;
3679     int actual_format;
3680     unsigned long nitems, bytesafter;
3681     unsigned long *datap = NULL;
3682     Bool retval = False;
3683 
3684     if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
3685 			    &actual_type, &actual_format, &nitems, &bytesafter,
3686 			    (unsigned char **) &datap) != Success || !datap)
3687       return False;
3688 
3689     if (nitems <= 2) {			/* "suggested" by ICCCM version 1 */
3690 	*statep = (int) datap[0];
3691 	*iwp = (Window) datap[1];
3692 	retval = True;
3693     }
3694 
3695     XFree ((char *) datap);
3696     return retval;
3697 }
3698 
3699 
3700 
WarpToScreen(n,inc)3701 WarpToScreen (n, inc)
3702     int n, inc;
3703 {
3704     Window dumwin;
3705     int x, y, dumint;
3706     unsigned int dummask;
3707     ScreenInfo *newscr = NULL;
3708 
3709     while (!newscr) {
3710 					/* wrap around */
3711 	if (n < 0)
3712 	  n = NumScreens - 1;
3713 	else if (n >= NumScreens)
3714 	  n = 0;
3715 
3716 	newscr = ScreenList[n];
3717 	if (!newscr) {			/* make sure screen is managed */
3718 	    if (inc) {			/* walk around the list */
3719 		n += inc;
3720 		continue;
3721 	    }
3722 	    fprintf (stderr, "%s:  unable to warp to unmanaged screen %d\n",
3723 		     ProgramName, n);
3724 	    XBell (dpy, 0);
3725 	    return;
3726 	}
3727     }
3728 
3729     if (Scr->screen == n) return;	/* already on that screen */
3730 
3731     PreviousScreen = Scr->screen;
3732     XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
3733 		   &dumint, &dumint, &dummask);
3734 
3735     XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
3736     return;
3737 }
3738 
3739 
3740 
3741 /*
3742  * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
3743  */
3744 
BumpWindowColormap(tmp,inc)3745 BumpWindowColormap (tmp, inc)
3746     TwmWindow *tmp;
3747     int inc;
3748 {
3749     int i, j, previously_installed;
3750     ColormapWindow **cwins;
3751 
3752     if (!tmp) return;
3753 
3754     if (inc && tmp->cmaps.number_cwins > 0) {
3755 	cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
3756 					   tmp->cmaps.number_cwins);
3757 	if (cwins) {
3758 	    if (previously_installed =
3759 		/* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps &&
3760 		tmp->cmaps.number_cwins)) {
3761 		for (i = tmp->cmaps.number_cwins; i-- > 0; )
3762 		    tmp->cmaps.cwins[i]->colormap->state = 0;
3763 	    }
3764 
3765 	    for (i = 0; i < tmp->cmaps.number_cwins; i++) {
3766 		j = i - inc;
3767 		if (j >= tmp->cmaps.number_cwins)
3768 		    j -= tmp->cmaps.number_cwins;
3769 		else if (j < 0)
3770 		    j += tmp->cmaps.number_cwins;
3771 		cwins[j] = tmp->cmaps.cwins[i];
3772 	    }
3773 
3774 	    free((char *) tmp->cmaps.cwins);
3775 
3776 	    tmp->cmaps.cwins = cwins;
3777 
3778 	    if (tmp->cmaps.number_cwins > 1)
3779 		bzero (tmp->cmaps.scoreboard,
3780 		       ColormapsScoreboardLength(&tmp->cmaps));
3781 
3782 	    if (previously_installed)
3783 		InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
3784 	}
3785     } else
3786 	FetchWmColormapWindows (tmp);
3787 }
3788 
3789 
3790 
HideIconManager()3791 HideIconManager ()
3792 {
3793     SetMapStateProp (Scr->iconmgr.twm_win, WithdrawnState);
3794     UnmapFrame(Scr->iconmgr.twm_win);
3795     if (Scr->iconmgr.twm_win->icon.w)
3796       UnmapIcon(Scr->iconmgr.twm_win);
3797     Scr->iconmgr.twm_win->mapped = FALSE;
3798     Scr->iconmgr.twm_win->isicon = TRUE;
3799 }
3800 
3801 
3802 
SetBorder(tmp,onoroff)3803 SetBorder (tmp, onoroff)
3804     TwmWindow *tmp;
3805     Bool onoroff;
3806 {
3807     if (tmp->highlight) {
3808 	if (onoroff) {
3809 	    XSetWindowBorder (dpy, tmp->frame, tmp->border);
3810 	    if (tmp->title_w)
3811 	      XSetWindowBorder (dpy, tmp->title_w, tmp->border);
3812 	} else {
3813 	    XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray);
3814 	    if (tmp->title_w)
3815 	      XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray);
3816 	}
3817     }
3818 }
3819 
3820 
3821 
DestroyMenu(menu)3822 DestroyMenu (menu)
3823     MenuRoot *menu;
3824 {
3825     MenuItem *item;
3826 
3827     if (menu->w) {
3828 	XDeleteContext (dpy, menu->w, MenuContext);
3829 	XDeleteContext (dpy, menu->w, ScreenContext);
3830 	if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
3831 	XDestroyWindow(dpy, menu->w);
3832     }
3833 
3834     for (item = menu->first; item; ) {
3835 	MenuItem *tmp = item;
3836 	item = item->next;
3837 	free ((char *) tmp);
3838     }
3839 }
3840 
3841 
3842 
3843 /*
3844  * warping routines
3845  */
WarpAlongRing(ev,forward)3846 void WarpAlongRing (ev, forward)
3847     XButtonEvent *ev;
3848     Bool forward;
3849 {
3850     TwmWindow *r, *head;
3851 
3852     if (Scr->RingLeader)
3853       head = Scr->RingLeader;
3854     else if (!(head = Scr->Ring))
3855       return;
3856 
3857     if (forward) {
3858 	for (r = head->ring.next; r != head; r = r->ring.next) {
3859 	    if (!r || r->mapped) break;
3860 	}
3861     } else {
3862 	for (r = head->ring.prev; r != head; r = r->ring.prev) {
3863 	    if (!r || r->mapped) break;
3864 	}
3865     }
3866 
3867     if (r && r != head) {
3868 	TwmWindow *p = Scr->RingLeader, *t;
3869 
3870 	Scr->RingLeader = r;
3871 	WarpToWindow (r);
3872 
3873 	if (p && p->mapped &&
3874 	    XFindContext (dpy, ev->window, TwmContext, (caddr_t *)&t) == XCSUCCESS &&
3875 	    p == t) {
3876 	    p->ring.cursor_valid = True;
3877 	    p->ring.curs_x = ev->x_root - t->frame_x;
3878 	    p->ring.curs_y = ev->y_root - t->frame_y;
3879 	    if (p->ring.curs_x < -p->frame_bw ||
3880 		p->ring.curs_x >= p->frame_width + p->frame_bw ||
3881 		p->ring.curs_y < -p->frame_bw ||
3882 		p->ring.curs_y >= p->frame_height + p->frame_bw) {
3883 		/* somehow out of window */
3884 		p->ring.curs_x = p->frame_width / 2;
3885 		p->ring.curs_y = p->frame_height / 2;
3886 	    }
3887 	}
3888     }
3889 }
3890 
3891 
3892 
WarpToWindow(t)3893 void WarpToWindow (t)
3894     TwmWindow *t;
3895 {
3896     int x, y;
3897 
3898     /* if we have the virtual desktop, attempt to make the window
3899      * somewhat visible
3900      */
3901     if (Scr->VirtualDesktop)
3902 	ScrollToQuadrant(t);
3903 
3904     if (t->auto_raise || !Scr->NoRaiseWarp) AutoRaiseWindow (t);
3905     if (t->ring.cursor_valid) {
3906 	x = t->ring.curs_x;
3907 	y = t->ring.curs_y;
3908     } else {
3909 	x = t->frame_width / 2;
3910 	y = t->frame_height / 2;
3911     }
3912     XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y);
3913 }
3914 
3915 
3916 
3917 /*
3918  * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
3919  * client messages will have the following form:
3920  *
3921  *     event type	ClientMessage
3922  *     message type	_XA_WM_PROTOCOLS
3923  *     window		tmp->w
3924  *     format		32
3925  *     data[0]		message atom
3926  *     data[1]		time stamp
3927  */
send_clientmessage(w,a,timestamp)3928 static void send_clientmessage (w, a, timestamp)
3929     Window w;
3930     Atom a;
3931     Time timestamp;
3932 {
3933     XClientMessageEvent ev;
3934 
3935     ev.type = ClientMessage;
3936     ev.window = w;
3937     ev.message_type = _XA_WM_PROTOCOLS;
3938     ev.format = 32;
3939     ev.data.l[0] = a;
3940     ev.data.l[1] = timestamp;
3941     XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
3942 }
3943 
SendDeleteWindowMessage(tmp,timestamp)3944 SendDeleteWindowMessage (tmp, timestamp)
3945     TwmWindow *tmp;
3946     Time timestamp;
3947 {
3948     send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
3949 }
3950 
SendSaveYourselfMessage(tmp,timestamp)3951 SendSaveYourselfMessage (tmp, timestamp)
3952     TwmWindow *tmp;
3953     Time timestamp;
3954 {
3955     send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
3956 }
3957 
3958 
SendTakeFocusMessage(tmp,timestamp)3959 SendTakeFocusMessage (tmp, timestamp)
3960     TwmWindow *tmp;
3961     Time timestamp;
3962 {
3963     send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
3964 }
3965