menus.c revision 4ff1c2d1
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 *  [ ctwm ]
29 *
30 *  Copyright 1992 Claude Lecommandeur.
31 *
32 * Permission to use, copy, modify  and distribute this software  [ctwm] and
33 * its documentation for any purpose is hereby granted without fee, provided
34 * that the above  copyright notice appear  in all copies and that both that
35 * copyright notice and this permission notice appear in supporting documen-
36 * tation, and that the name of  Claude Lecommandeur not be used in adverti-
37 * sing or  publicity  pertaining to  distribution of  the software  without
38 * specific, written prior permission. Claude Lecommandeur make no represen-
39 * tations  about the suitability  of this software  for any purpose.  It is
40 * provided "as is" without express or implied warranty.
41 *
42 * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
43 * INCLUDING ALL  IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS.  IN NO
44 * EVENT SHALL  Claude Lecommandeur  BE LIABLE FOR ANY SPECIAL,  INDIRECT OR
45 * CONSEQUENTIAL  DAMAGES OR ANY  DAMAGES WHATSOEVER  RESULTING FROM LOSS OF
46 * USE, DATA  OR PROFITS,  WHETHER IN AN ACTION  OF CONTRACT,  NEGLIGENCE OR
47 * OTHER  TORTIOUS ACTION,  ARISING OUT OF OR IN  CONNECTION WITH THE USE OR
48 * PERFORMANCE OF THIS SOFTWARE.
49 *
50 * Author:  Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ]
51 */
52
53
54/***********************************************************************
55 *
56 * $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $
57 *
58 * twm menu code
59 *
60 * 17-Nov-87 Thomas E. LaStrange		File created
61 *
62 * Do the necessary modification to be integrated in ctwm.
63 * Can no longer be used for the standard twm.
64 *
65 * 22-April-92 Claude Lecommandeur.
66 *
67 *
68 ***********************************************************************/
69
70#if defined(USE_SIGNALS) && defined(__sgi)
71#  define _BSD_SIGNALS
72#endif
73
74#include <stdio.h>
75#include <signal.h>
76
77#ifdef VMS
78#include <stdlib.h>
79#include <string.h>
80#include <unixio.h>
81#include <file.h>
82#include <decw$include/Xos.h>
83#include <decw$include/Xatom.h>
84#else
85#include <X11/Xos.h>
86#include <X11/Xatom.h>
87#endif
88#include "twm.h"
89#include "ctwm.h"
90#include "gc.h"
91#include "menus.h"
92#include "resize.h"
93#include "events.h"
94#include "list.h"
95#include "util.h"
96#include "parse.h"
97#include "screen.h"
98#include "icons.h"
99#include "add_window.h"
100#include "windowbox.h"
101#include "workmgr.h"
102#include "cursor.h"
103#include "gnomewindefs.h"
104#ifdef SOUNDS
105#  include "sound.h"
106#endif
107#ifdef VMS
108#  include <X11Xmu/CharSet.h>
109#  include <decw$bitmaps/menu12.xbm>
110#  include <X11SM/SMlib.h>
111#  include "vms_cmd_services.h"
112#  include <lib$routines.h>
113#else
114#  include <X11/Xmu/CharSet.h>
115#  include <X11/SM/SMlib.h>
116#endif
117#include "version.h"
118
119#if defined(MACH) || defined(__MACH__) || defined(sony_news) || defined(NeXT)
120#define lrand48 random
121#endif
122#if defined(VMS) || defined(__DARWIN__)
123#define lrand48 rand
124#endif
125
126#ifndef VMS
127#define MAX(x,y) ((x)>(y)?(x):(y))
128#define MIN(x,y) ((x)<(y)?(x):(y))
129#endif
130#define ABS(x) ((x)<0?-(x):(x))
131
132int RootFunction = 0;
133MenuRoot *ActiveMenu = NULL;		/* the active menu */
134MenuItem *ActiveItem = NULL;		/* the active menu item */
135int MoveFunction;			/* either F_MOVE or F_FORCEMOVE */
136int WindowMoved = FALSE;
137int menuFromFrameOrWindowOrTitlebar = FALSE;
138char *CurrentSelectedWorkspace;
139int AlternateKeymap;
140Bool AlternateContext;
141
142extern char *captivename;
143
144int ConstMove = FALSE;		/* constrained move variables */
145int ConstMoveDir;
146int ConstMoveX;
147int ConstMoveY;
148int ConstMoveXL;
149int ConstMoveXR;
150int ConstMoveYT;
151int ConstMoveYB;
152
153/* Globals used to keep track of whether the mouse has moved during
154   a resize function. */
155int ResizeOrigX;
156int ResizeOrigY;
157
158int MenuDepth = 0;		/* number of menus up */
159static struct {
160    int x;
161    int y;
162} MenuOrigins[MAXMENUDEPTH];
163static Cursor LastCursor;
164static Bool addingdefaults = False;
165
166void jump (TwmWindow *tmp_win, int  direction, char *action);
167void waitamoment (float timeout);
168
169extern char *Action;
170extern int Context;
171extern TwmWindow *ButtonWindow, *Tmp_win;
172extern XEvent ButtonEvent;
173extern char *InitFile;
174extern int ConstrainedMoveTime;
175static void Identify (TwmWindow *t);
176
177#define SHADOWWIDTH 5			/* in pixels */
178
179#ifdef GNOME
180  extern Atom _XA_WIN_STATE;
181#endif /* GNOME */
182
183
184
185/***********************************************************************
186 *
187 *  Procedure:
188 *	InitMenus - initialize menu roots
189 *
190 ***********************************************************************
191 */
192
193void InitMenus(void)
194{
195    Scr->DefaultFunction.func = 0;
196    Scr->WindowFunction.func  = 0;
197    Scr->ChangeWorkspaceFunction.func  = 0;
198    Scr->DeIconifyFunction.func  = 0;
199    Scr->IconifyFunction.func  = 0;
200
201    Scr->FuncKeyRoot.next = NULL;
202    Scr->FuncButtonRoot.next = NULL;
203}
204
205
206
207/***********************************************************************
208 *
209 *  Procedure:
210 *	AddFuncKey - add a function key to the list
211 *
212 *  Inputs:
213 *	name	- the name of the key
214 *	cont	- the context to look for the key press in
215 *	mods	- modifier keys that need to be pressed
216 *	func	- the function to perform
217 *	win_name- the window name (if any)
218 *	action	- the action string associated with the function (if any)
219 *
220 ***********************************************************************
221 */
222
223Bool AddFuncKey (char *name, int cont, int mods, int func,
224		 MenuRoot *menu, char *win_name, char *action)
225{
226    FuncKey *tmp;
227    KeySym keysym;
228    KeyCode keycode;
229
230    /*
231     * Don't let a 0 keycode go through, since that means AnyKey to the
232     * XGrabKey call in GrabKeys().
233     */
234    if ((keysym = XStringToKeysym(name)) == NoSymbol ||
235	(keycode = XKeysymToKeycode(dpy, keysym)) == 0)
236    {
237	return False;
238    }
239
240    /* see if there already is a key defined for this context */
241    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
242    {
243	if (tmp->keysym == keysym &&
244	    tmp->cont == cont &&
245	    tmp->mods == mods)
246	    break;
247    }
248    if (tmp && addingdefaults) return (True);
249
250    if (tmp == NULL)
251    {
252	tmp = (FuncKey *) malloc(sizeof(FuncKey));
253	tmp->next = Scr->FuncKeyRoot.next;
254	Scr->FuncKeyRoot.next = tmp;
255    }
256
257    tmp->name = name;
258    tmp->keysym = keysym;
259    tmp->keycode = keycode;
260    tmp->cont = cont;
261    tmp->mods = mods;
262    tmp->func = func;
263    tmp->menu = menu;
264    tmp->win_name = win_name;
265    tmp->action = action;
266
267    return True;
268}
269
270/***********************************************************************
271 *
272 *  Procedure:
273 *	AddFuncButton - add a function button to the list
274 *
275 *  Inputs:
276 *	num	- the num of the button
277 *	cont	- the context to look for the key press in
278 *	mods	- modifier keys that need to be pressed
279 *	func	- the function to perform
280 *	menu    - the menu (if any)
281 *	item	- the menu item (if any)
282 *
283 ***********************************************************************
284 */
285
286Bool AddFuncButton (int num, int cont, int mods, int func,
287		    MenuRoot *menu, MenuItem *item)
288{
289    FuncButton *tmp;
290
291    /* see if there already is a key defined for this context */
292    for (tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) {
293	if ((tmp->num == num) && (tmp->cont == cont) && (tmp->mods == mods))
294	    break;
295    }
296    if (tmp && addingdefaults) return (True);
297
298    if (tmp == NULL) {
299	tmp = (FuncButton*) malloc (sizeof (FuncButton));
300	tmp->next = Scr->FuncButtonRoot.next;
301	Scr->FuncButtonRoot.next = tmp;
302    }
303
304    tmp->num  = num;
305    tmp->cont = cont;
306    tmp->mods = mods;
307    tmp->func = func;
308    tmp->menu = menu;
309    tmp->item = item;
310
311    return True;
312}
313
314
315
316static TitleButton *cur_tb = NULL;
317
318void ModifyCurrentTB(int button, int mods, int func, char *action,
319		     MenuRoot *menuroot)
320{
321    TitleButtonFunc *tbf;
322
323    if (!cur_tb) {
324        fprintf (stderr, "%s: can't find titlebutton\n", ProgramName);
325	return;
326    }
327    for (tbf = cur_tb->funs; tbf; tbf = tbf->next) {
328	if (tbf->num == button && tbf->mods == mods)
329	    break;
330    }
331    if (!tbf) {
332	tbf = (TitleButtonFunc *)malloc(sizeof(TitleButtonFunc));
333	if (!tbf) {
334	    fprintf (stderr, "%s: out of memory\n", ProgramName);
335	    return;
336	}
337	tbf->next = cur_tb->funs;
338	cur_tb->funs = tbf;
339    }
340    tbf->num = button;
341    tbf->mods = mods;
342    tbf->func = func;
343    tbf->action = action;
344    tbf->menuroot = menuroot;
345}
346
347int CreateTitleButton (char *name, int func, char *action, MenuRoot *menuroot,
348		       Bool rightside, Bool append)
349{
350    int button;
351    cur_tb = (TitleButton *) malloc (sizeof(TitleButton));
352
353    if (!cur_tb) {
354	fprintf (stderr,
355		 "%s:  unable to allocate %lu bytes for title button\n",
356		 ProgramName, (unsigned long) sizeof(TitleButton));
357	return 0;
358    }
359
360    cur_tb->next = NULL;
361    cur_tb->name = name;                      /* note that we are not copying */
362    cur_tb->image = None;                     /* WARNING, values not set yet */
363    cur_tb->width = 0;                        /* see InitTitlebarButtons */
364    cur_tb->height = 0;                       /* ditto */
365    cur_tb->rightside = rightside;
366    cur_tb->funs = NULL;
367    if (rightside) {
368	Scr->TBInfo.nright++;
369    } else {
370	Scr->TBInfo.nleft++;
371    }
372
373    for(button = 0; button < MAX_BUTTONS; button++){
374	ModifyCurrentTB(button + 1, 0, func, action, menuroot);
375    }
376
377    /*
378     * Cases for list:
379     *
380     *     1.  empty list, prepend left       put at head of list
381     *     2.  append left, prepend right     put in between left and right
382     *     3.  append right                   put at tail of list
383     *
384     * Do not refer to widths and heights yet since buttons not created
385     * (since fonts not loaded and heights not known).
386     */
387    if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) {	/* 1 */
388	cur_tb->next = Scr->TBInfo.head;
389	Scr->TBInfo.head = cur_tb;
390    } else if (append && rightside) {	/* 3 */
391	register TitleButton *t;
392	for /* SUPPRESS 530 */
393	  (t = Scr->TBInfo.head; t->next; t = t->next);
394	t->next = cur_tb;
395	cur_tb->next = NULL;
396    } else {				/* 2 */
397	register TitleButton *t, *prev = NULL;
398	for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
399	    prev = t;
400	}
401	if (prev) {
402	    cur_tb->next = prev->next;
403	    prev->next = cur_tb;
404	} else {
405	    cur_tb->next = Scr->TBInfo.head;
406	    Scr->TBInfo.head = cur_tb;
407	}
408    }
409
410    return 1;
411}
412
413
414
415/*
416 * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
417 * button.  If we can't find the button, then put in a question; if we can't
418 * find the question mark, something is wrong and we are probably going to be
419 * in trouble later on.
420 */
421void InitTitlebarButtons (void)
422{
423    TitleButton *tb;
424    int h;
425
426    /*
427     * initialize dimensions
428     */
429    Scr->TBInfo.width = (Scr->TitleHeight -
430			 2 * (Scr->FramePadding + Scr->ButtonIndent));
431    if (Scr->use3Dtitles)
432	Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
433		       ? ((Scr->TitlePadding + 1) / 2) : 0);
434    else
435	Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
436		       ? ((Scr->TitlePadding + 1) / 2) : 1);
437    h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
438
439    /*
440     * add in some useful buttons and bindings so that novices can still
441     * use the system.
442     */
443    if (!Scr->NoDefaults) {
444	/* insert extra buttons */
445	if (Scr->use3Dtitles) {
446	    if (!CreateTitleButton (TBPM_3DDOT, F_ICONIFY, "", (MenuRoot *) NULL,
447				False, False)) {
448	        fprintf (stderr, "%s:  unable to add iconify button\n", ProgramName);
449	    }
450	    if (!CreateTitleButton (TBPM_3DRESIZE, F_RESIZE, "", (MenuRoot *) NULL,
451				True, True)) {
452	        fprintf (stderr, "%s:  unable to add resize button\n", ProgramName);
453	    }
454	}
455	else {
456	    if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
457				False, False)) {
458	        fprintf (stderr, "%s:  unable to add iconify button\n", ProgramName);
459	    }
460	    if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
461				True, True)) {
462	        fprintf (stderr, "%s:  unable to add resize button\n", ProgramName);
463	    }
464	}
465	addingdefaults = True;
466	AddDefaultBindings ();
467	addingdefaults = False;
468    }
469    ComputeCommonTitleOffsets ();
470
471    /*
472     * load in images and do appropriate centering
473     */
474
475    for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
476	tb->image = GetImage (tb->name, Scr->TitleC);
477	if (!tb->image) {
478	    tb->image = GetImage (TBPM_QUESTION, Scr->TitleC);
479	    if (!tb->image) {		/* cannot happen (see util.c) */
480		fprintf (stderr, "%s:  unable to add titlebar button \"%s\"\n",
481			 ProgramName, tb->name);
482		continue;
483	    }
484	}
485	tb->width  = tb->image->width;
486	tb->height = tb->image->height;
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}
505
506
507void PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
508{
509    if (Scr->use3Dmenus)
510	Paint3DEntry (mr, mi, exposure);
511    else
512	PaintNormalEntry (mr, mi, exposure);
513    if (mi->state) mr->lastactive = mi;
514}
515
516void Paint3DEntry(MenuRoot *mr, MenuItem *mi, int exposure)
517{
518    int y_offset;
519    int text_y;
520    GC gc;
521
522    y_offset = mi->item_num * Scr->EntryHeight + Scr->MenuShadowDepth;
523    text_y = y_offset + Scr->MenuFont.y + 2;
524
525    if (mi->func != F_TITLE) {
526	int x, y;
527
528	gc = Scr->NormalGC;
529	if (mi->state) {
530	    Draw3DBorder (mr->w, Scr->MenuShadowDepth, y_offset,
531			mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1,
532			mi->highlight, off, True, False);
533	    FB(mi->highlight.fore, mi->highlight.back);
534	    XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, gc,
535		mi->x + Scr->MenuShadowDepth, text_y, mi->item, mi->strlen);
536	}
537	else {
538	    if (mi->user_colors || !exposure) {
539		XSetForeground (dpy, gc, mi->normal.back);
540		XFillRectangle (dpy, mr->w, gc,
541			Scr->MenuShadowDepth, y_offset,
542			mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight);
543		FB (mi->normal.fore, mi->normal.back);
544	    }
545	    else {
546		gc = Scr->MenuGC;
547	    }
548	    XmbDrawImageString (dpy, mr->w, Scr->MenuFont.font_set, gc,
549				mi->x + Scr->MenuShadowDepth, text_y,
550				mi->item, mi->strlen);
551	    if (mi->separated) {
552		FB (Scr->MenuC.shadd, Scr->MenuC.shadc);
553		XDrawLine (dpy, mr->w, Scr->NormalGC,
554				Scr->MenuShadowDepth,
555				y_offset + Scr->EntryHeight - 2,
556				mr->width - Scr->MenuShadowDepth,
557				y_offset + Scr->EntryHeight - 2);
558		FB (Scr->MenuC.shadc, Scr->MenuC.shadd);
559		XDrawLine (dpy, mr->w, Scr->NormalGC,
560				Scr->MenuShadowDepth,
561				y_offset + Scr->EntryHeight - 1,
562				mr->width - Scr->MenuShadowDepth,
563				y_offset + Scr->EntryHeight - 1);
564	    }
565	}
566
567	if (mi->func == F_MENU) {
568	    /* create the pull right pixmap if needed */
569	    if (Scr->pullPm == None)
570	    {
571		Scr->pullPm = Create3DMenuIcon (Scr->MenuFont.height, &Scr->pullW,
572				&Scr->pullH, Scr->MenuC);
573	    }
574	    x = mr->width - Scr->pullW - Scr->MenuShadowDepth - 2;
575	    y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2) + 2;
576	    XCopyArea (dpy, Scr->pullPm, mr->w, gc, 0, 0, Scr->pullW, Scr->pullH, x, y);
577	}
578    }
579    else
580    {
581	Draw3DBorder (mr->w, Scr->MenuShadowDepth, y_offset,
582			mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1,
583			mi->normal, off, True, False);
584	FB (mi->normal.fore, mi->normal.back);
585	XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC,
586			   mi->x + 2, text_y, mi->item, mi->strlen);
587    }
588}
589
590
591
592void PaintNormalEntry(MenuRoot *mr, MenuItem *mi, int exposure)
593{
594    int y_offset;
595    int text_y;
596    GC gc;
597
598    y_offset = mi->item_num * Scr->EntryHeight;
599    text_y = y_offset + Scr->MenuFont.y;
600
601    if (mi->func != F_TITLE)
602    {
603	int x, y;
604
605	if (mi->state)
606	{
607	    XSetForeground(dpy, Scr->NormalGC, mi->highlight.back);
608
609	    XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
610		mr->width, Scr->EntryHeight);
611	    FB(mi->highlight.fore, mi->highlight.back);
612	    XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC,
613			  mi->x, text_y, mi->item, mi->strlen);
614
615	    gc = Scr->NormalGC;
616	}
617	else
618	{
619	    if (mi->user_colors || !exposure)
620	    {
621		XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
622
623		XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
624		    mr->width, Scr->EntryHeight);
625
626		FB(mi->normal.fore, mi->normal.back);
627		gc = Scr->NormalGC;
628	    }
629	    else {
630		gc = Scr->MenuGC;
631	    }
632	    XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, gc, mi->x,
633			  text_y, mi->item, mi->strlen);
634	    if (mi->separated)
635		XDrawLine (dpy, mr->w, gc, 0, y_offset + Scr->EntryHeight - 1,
636				mr->width, y_offset + Scr->EntryHeight - 1);
637	}
638
639	if (mi->func == F_MENU)
640	{
641	    /* create the pull right pixmap if needed */
642	    if (Scr->pullPm == None)
643	    {
644		Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height,
645					     &Scr->pullW, &Scr->pullH);
646	    }
647	    x = mr->width - Scr->pullW - 5;
648	    y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2);
649	    XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
650		Scr->pullW, Scr->pullH, x, y, 1);
651	}
652    }
653    else
654    {
655	int y;
656
657	XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
658
659	/* fill the rectangle with the title background color */
660	XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
661	    mr->width, Scr->EntryHeight);
662
663	{
664	    XSetForeground(dpy, Scr->NormalGC, mi->normal.fore);
665	    /* now draw the dividing lines */
666	    if (y_offset)
667	      XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
668			 mr->width, y_offset);
669	    y = ((mi->item_num+1) * Scr->EntryHeight)-1;
670	    XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
671	}
672
673	FB(mi->normal.fore, mi->normal.back);
674	/* finally render the title */
675	XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC, mi->x,
676		      text_y, mi->item, mi->strlen);
677    }
678}
679
680void PaintMenu(MenuRoot *mr, XEvent *e)
681{
682    MenuItem *mi;
683
684    if (Scr->use3Dmenus) {
685	Draw3DBorder (mr->w, 0, 0, mr->width, mr->height,
686		Scr->MenuShadowDepth, Scr->MenuC, off, False, False);
687    }
688    for (mi = mr->first; mi != NULL; mi = mi->next)
689    {
690	int y_offset = mi->item_num * Scr->EntryHeight;
691
692	/* be smart about handling the expose, redraw only the entries
693	 * that we need to
694	 */
695	if (e->xexpose.y <= (y_offset + Scr->EntryHeight) &&
696	    (e->xexpose.y + e->xexpose.height) >= y_offset)
697	{
698	    PaintEntry(mr, mi, True);
699	}
700    }
701    XSync(dpy, 0);
702}
703
704
705
706void MakeWorkspacesMenu (void)
707{
708    static char **actions = NULL;
709    WorkSpace *wlist;
710    char **act;
711
712    if (! Scr->Workspaces) return;
713    AddToMenu (Scr->Workspaces, "TWM Workspaces", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
714    if (! actions) {
715	int count = 0;
716
717        for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) {
718            count++;
719        }
720	count++;
721	actions = (char**) malloc (count * sizeof (char*));
722	act = actions;
723        for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) {
724	    *act = (char*) malloc (strlen ("WGOTO : ") + strlen (wlist->name) + 1);
725	    sprintf (*act, "WGOTO : %s", wlist->name);
726	    act++;
727	}
728	*act = NULL;
729    }
730    act = actions;
731    for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) {
732        AddToMenu (Scr->Workspaces, wlist->name, *act, Scr->Windows, F_MENU, NULL, NULL);
733	act++;
734    }
735    Scr->Workspaces->pinned = False;
736    MakeMenu (Scr->Workspaces);
737}
738
739static Bool fromMenu;
740
741int UpdateMenu(void)
742{
743    MenuItem *mi;
744    int i, x, y, x_root, y_root, entry;
745    int done;
746    MenuItem *badItem = NULL;
747
748    fromMenu = TRUE;
749
750    while (TRUE)
751    {
752	/* block until there is an event */
753        if (!menuFromFrameOrWindowOrTitlebar) {
754	  XMaskEvent(dpy,
755		     ButtonPressMask | ButtonReleaseMask |
756		     KeyPressMask | KeyReleaseMask |
757		     EnterWindowMask | ExposureMask |
758		     VisibilityChangeMask | LeaveWindowMask |
759		     ButtonMotionMask, &Event);
760	}
761	if (Event.type == MotionNotify) {
762	    /* discard any extra motion events before a release */
763	    while(XCheckMaskEvent(dpy,
764		ButtonMotionMask | ButtonReleaseMask, &Event))
765		if (Event.type == ButtonRelease)
766		    break;
767	}
768
769	if (!DispatchEvent ())
770	    continue;
771
772	if ((! ActiveMenu) || Cancel) {
773	  menuFromFrameOrWindowOrTitlebar = FALSE;
774	  fromMenu = FALSE;
775	  return (0);
776	}
777
778	if (Event.type != MotionNotify)
779	    continue;
780
781	done = FALSE;
782	XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
783	    &x_root, &y_root, &x, &y, &JunkMask);
784
785	/* if we haven't recieved the enter notify yet, wait */
786	if (ActiveMenu && !ActiveMenu->entered)
787	    continue;
788
789	if (XFindContext(dpy, ActiveMenu->w, ScreenContext, (XPointer *)&Scr)
790	    != XCSUCCESS)
791	    continue;
792
793	if (x < 0 || y < 0 ||
794	    x >= ActiveMenu->width || y >= ActiveMenu->height)
795	{
796	    if (ActiveItem && ActiveItem->func != F_TITLE)
797	    {
798		ActiveItem->state = 0;
799		PaintEntry(ActiveMenu, ActiveItem, False);
800	    }
801	    ActiveItem = NULL;
802	    continue;
803	}
804
805	/* look for the entry that the mouse is in */
806	entry = y / Scr->EntryHeight;
807	for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
808	{
809	    if (i == entry)
810		break;
811	}
812
813	/* if there is an active item, we might have to turn it off */
814	if (ActiveItem)
815	{
816	    /* is the active item the one we are on ? */
817	    if (ActiveItem->item_num == entry && ActiveItem->state)
818		done = TRUE;
819
820	    /* if we weren't on the active entry, let's turn the old
821	     * active one off
822	     */
823	    if (!done && ActiveItem->func != F_TITLE)
824	    {
825		ActiveItem->state = 0;
826		PaintEntry(ActiveMenu, ActiveItem, False);
827	    }
828	}
829
830	/* if we weren't on the active item, change the active item and turn
831	 * it on
832	 */
833	if (!done)
834	{
835	    ActiveItem = mi;
836	    if (ActiveItem && ActiveItem->func != F_TITLE && !ActiveItem->state)
837	    {
838		ActiveItem->state = 1;
839		PaintEntry(ActiveMenu, ActiveItem, False);
840	    }
841	}
842
843	/* now check to see if we were over the arrow of a pull right entry */
844	if (ActiveItem && ActiveItem->func == F_MENU &&
845	   ((ActiveMenu->width - x) < (ActiveMenu->width / 3)))
846	{
847	    MenuRoot *save = ActiveMenu;
848	    int savex = MenuOrigins[MenuDepth - 1].x;
849	    int savey = MenuOrigins[MenuDepth - 1].y;
850
851	    if (MenuDepth < MAXMENUDEPTH) {
852		if (ActiveMenu == Scr->Workspaces)
853		    CurrentSelectedWorkspace = ActiveItem->item;
854		PopUpMenu (ActiveItem->sub,
855			   (savex + (((2 * ActiveMenu->width) / 3) - 1)),
856			   (savey + ActiveItem->item_num * Scr->EntryHeight)
857			   /*(savey + ActiveItem->item_num * Scr->EntryHeight +
858			    (Scr->EntryHeight >> 1))*/, False);
859		CurrentSelectedWorkspace = NULL;
860	    } else if (!badItem) {
861		XBell (dpy, 0);
862		badItem = ActiveItem;
863	    }
864
865	    /* if the menu did get popped up, unhighlight the active item */
866	    if (save != ActiveMenu && ActiveItem->state)
867	    {
868		ActiveItem->state = 0;
869		PaintEntry(save, ActiveItem, False);
870		ActiveItem = NULL;
871	    }
872	}
873	if (badItem != ActiveItem) badItem = NULL;
874	XFlush(dpy);
875    }
876}
877
878
879
880/***********************************************************************
881 *
882 *  Procedure:
883 *	NewMenuRoot - create a new menu root
884 *
885 *  Returned Value:
886 *	(MenuRoot *)
887 *
888 *  Inputs:
889 *	name	- the name of the menu root
890 *
891 ***********************************************************************
892 */
893
894MenuRoot *NewMenuRoot(char *name)
895{
896    MenuRoot *tmp;
897
898#define UNUSED_PIXEL ((unsigned long) (~0))	/* more than 24 bits */
899
900    tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
901    tmp->highlight.fore = UNUSED_PIXEL;
902    tmp->highlight.back = UNUSED_PIXEL;
903    tmp->name = name;
904    tmp->prev = NULL;
905    tmp->first = NULL;
906    tmp->last = NULL;
907    tmp->defaultitem = NULL;
908    tmp->items = 0;
909    tmp->width = 0;
910    tmp->mapped = NEVER_MAPPED;
911    tmp->pull = FALSE;
912    tmp->w = None;
913    tmp->shadow = None;
914    tmp->real_menu = FALSE;
915
916    if (Scr->MenuList == NULL)
917    {
918	Scr->MenuList = tmp;
919	Scr->MenuList->next = NULL;
920    }
921
922    if (Scr->LastMenu == NULL)
923    {
924	Scr->LastMenu = tmp;
925	Scr->LastMenu->next = NULL;
926    }
927    else
928    {
929	Scr->LastMenu->next = tmp;
930	Scr->LastMenu = tmp;
931	Scr->LastMenu->next = NULL;
932    }
933
934    if (strcmp(name, TWM_WINDOWS) == 0)
935	Scr->Windows = tmp;
936
937    if (strcmp(name, TWM_ICONS) == 0)
938	Scr->Icons = tmp;
939
940    if (strcmp(name, TWM_WORKSPACES) == 0) {
941	Scr->Workspaces = tmp;
942	if (!Scr->Windows) NewMenuRoot (TWM_WINDOWS);
943    }
944    if (strcmp(name, TWM_ALLWINDOWS) == 0)
945	Scr->AllWindows = tmp;
946
947    /* Added by dl 2004 */
948    if (strcmp(name, TWM_ALLICONS) == 0)
949    Scr->AllIcons = tmp;
950
951    /* Added by Dan Lilliehorn (dl@dl.nu) 2000-02-29       */
952    if (strcmp(name, TWM_KEYS) == 0)
953	Scr->Keys = tmp;
954
955    if (strcmp(name, TWM_VISIBLE) == 0)
956      Scr->Visible = tmp;
957
958    /* End addition */
959
960    return (tmp);
961}
962
963
964
965/***********************************************************************
966 *
967 *  Procedure:
968 *	AddToMenu - add an item to a root menu
969 *
970 *  Returned Value:
971 *	(MenuItem *)
972 *
973 *  Inputs:
974 *	menu	- pointer to the root menu to add the item
975 *	item	- the text to appear in the menu
976 *	action	- the string to possibly execute
977 *	sub	- the menu root if it is a pull-right entry
978 *	func	- the numeric function
979 *	fore	- foreground color string
980 *	back	- background color string
981 *
982 ***********************************************************************
983 */
984
985MenuItem *AddToMenu(MenuRoot *menu, char *item, char *action,
986		    MenuRoot *sub, int func, char *fore, char *back)
987{
988    MenuItem *tmp;
989    int width;
990    char *itemname;
991    XRectangle ink_rect;
992    XRectangle logical_rect;
993
994#ifdef DEBUG_MENUS
995    fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
996	item, action, sub, func);
997#endif
998
999    tmp = (MenuItem *) malloc(sizeof(MenuItem));
1000    tmp->root = menu;
1001
1002    if (menu->first == NULL)
1003    {
1004	menu->first = tmp;
1005	tmp->prev = NULL;
1006    }
1007    else
1008    {
1009	menu->last->next = tmp;
1010	tmp->prev = menu->last;
1011    }
1012    menu->last = tmp;
1013
1014    if ((menu == Scr->Workspaces) ||
1015	(menu == Scr->Windows) ||
1016	(menu == Scr->Icons) ||
1017	(menu == Scr->AllWindows) ||
1018
1019	/* Added by dl 2004 */
1020	(menu == Scr->AllIcons) ||
1021
1022	/* Added by Dan Lillehorn (dl@dl.nu) 2000-02-29 */
1023	(menu == Scr->Keys) ||
1024	(menu == Scr->Visible)) {
1025
1026	itemname = item;
1027    } else
1028    if (*item == '*') {
1029	itemname = item + 1;
1030	menu->defaultitem = tmp;
1031    }
1032    else {
1033	itemname = item;
1034    }
1035
1036    tmp->item = itemname;
1037    tmp->strlen = strlen(itemname);
1038    tmp->action = action;
1039    tmp->next = NULL;
1040    tmp->sub = NULL;
1041    tmp->state = 0;
1042    tmp->func = func;
1043    tmp->separated = 0;
1044
1045    if (!Scr->HaveFonts) CreateFonts();
1046
1047    XmbTextExtents(Scr->MenuFont.font_set,
1048		   itemname, tmp->strlen,
1049		   &ink_rect, &logical_rect);
1050    width = logical_rect.width;
1051
1052    if (width <= 0)
1053	width = 1;
1054    if (width > menu->width)
1055	menu->width = width;
1056
1057    tmp->user_colors = FALSE;
1058    if (Scr->Monochrome == COLOR && fore != NULL)
1059    {
1060	int save;
1061
1062	save = Scr->FirstTime;
1063	Scr->FirstTime = TRUE;
1064	GetColor(COLOR, &tmp->normal.fore, fore);
1065	GetColor(COLOR, &tmp->normal.back, back);
1066	if (Scr->use3Dmenus && !Scr->BeNiceToColormap) GetShadeColors (&tmp->normal);
1067	Scr->FirstTime = save;
1068	tmp->user_colors = TRUE;
1069    }
1070    if (sub != NULL)
1071    {
1072	tmp->sub = sub;
1073	menu->pull = TRUE;
1074    }
1075    tmp->item_num = menu->items++;
1076
1077    return (tmp);
1078}
1079
1080
1081void MakeMenus(void)
1082{
1083    MenuRoot *mr;
1084
1085    for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
1086    {
1087	if (mr->real_menu == FALSE)
1088	    continue;
1089
1090	mr->pinned = False;
1091	MakeMenu(mr);
1092    }
1093}
1094
1095
1096
1097int MakeMenu(MenuRoot *mr)
1098{
1099    MenuItem *start, *end, *cur, *tmp;
1100    XColor f1, f2, f3;
1101    XColor b1, b2, b3;
1102    XColor save_fore, save_back;
1103    int num, i;
1104    int fred, fgreen, fblue;
1105    int bred, bgreen, bblue;
1106    int width, borderwidth;
1107    unsigned long valuemask;
1108    XSetWindowAttributes attributes;
1109    Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c;
1110    XRectangle ink_rect;
1111    XRectangle logical_rect;
1112
1113    Scr->EntryHeight = Scr->MenuFont.height + 4;
1114
1115    /* lets first size the window accordingly */
1116    if (mr->mapped == NEVER_MAPPED)
1117    {
1118	if (mr->pull == TRUE) {
1119	    mr->width += 16 + 10;
1120	}
1121	width = mr->width + 10;
1122	for (cur = mr->first; cur != NULL; cur = cur->next) {
1123	    if (cur->func != F_TITLE)
1124		cur->x = 5;
1125	    else {
1126		XmbTextExtents(Scr->MenuFont.font_set, cur->item, cur->strlen,
1127			       &ink_rect, &logical_rect);
1128		cur->x = width - logical_rect.width;
1129		cur->x /= 2;
1130	    }
1131	}
1132	mr->height = mr->items * Scr->EntryHeight;
1133	mr->width += 10;
1134	if (Scr->use3Dmenus) {
1135	    mr->width  += 2 * Scr->MenuShadowDepth;
1136	    mr->height += 2 * Scr->MenuShadowDepth;
1137	}
1138	if (Scr->Shadow && ! mr->pinned)
1139	{
1140	    /*
1141	     * Make sure that you don't draw into the shadow window or else
1142	     * the background bits there will get saved
1143	     */
1144	    valuemask = (CWBackPixel | CWBorderPixel);
1145	    attributes.background_pixel = Scr->MenuShadowColor;
1146	    attributes.border_pixel = Scr->MenuShadowColor;
1147	    if (Scr->SaveUnder) {
1148		valuemask |= CWSaveUnder;
1149		attributes.save_under = True;
1150	    }
1151	    mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
1152					(unsigned int) mr->width,
1153					(unsigned int) mr->height,
1154					(unsigned int)0,
1155					CopyFromParent,
1156					(unsigned int) CopyFromParent,
1157					(Visual *) CopyFromParent,
1158					valuemask, &attributes);
1159	}
1160
1161	valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
1162	attributes.background_pixel = Scr->MenuC.back;
1163	attributes.border_pixel = Scr->MenuC.fore;
1164	if (mr->pinned) {
1165	    attributes.event_mask = (ExposureMask | EnterWindowMask
1166				| LeaveWindowMask | ButtonPressMask
1167				| ButtonReleaseMask | PointerMotionMask
1168				| ButtonMotionMask
1169				);
1170	    attributes.cursor = Scr->MenuCursor;
1171	    valuemask |= CWCursor;
1172	}
1173	else
1174	    attributes.event_mask = (ExposureMask | EnterWindowMask);
1175
1176	if (Scr->SaveUnder && ! mr->pinned) {
1177	    valuemask |= CWSaveUnder;
1178	    attributes.save_under = True;
1179	}
1180	if (Scr->BackingStore) {
1181	    valuemask |= CWBackingStore;
1182	    attributes.backing_store = Always;
1183	}
1184	borderwidth = Scr->use3Dmenus ? 0 : 1;
1185	mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
1186			       (unsigned int) mr->height, (unsigned int) borderwidth,
1187			       CopyFromParent, (unsigned int) CopyFromParent,
1188			       (Visual *) CopyFromParent,
1189			       valuemask, &attributes);
1190
1191
1192	XSaveContext(dpy, mr->w, MenuContext, (XPointer)mr);
1193	XSaveContext(dpy, mr->w, ScreenContext, (XPointer)Scr);
1194
1195	mr->mapped = UNMAPPED;
1196    }
1197
1198    if (Scr->use3Dmenus && (Scr->Monochrome == COLOR) &&  (mr->highlight.back == UNUSED_PIXEL)) {
1199	XColor xcol;
1200	char colname [32];
1201	short save;
1202
1203	xcol.pixel = Scr->MenuC.back;
1204	XQueryColor (dpy, cmap, &xcol);
1205	sprintf (colname, "#%04x%04x%04x",
1206		5 * ((int)xcol.red   / 6),
1207		5 * ((int)xcol.green / 6),
1208		5 * ((int)xcol.blue  / 6));
1209	save = Scr->FirstTime;
1210	Scr->FirstTime = True;
1211	GetColor (Scr->Monochrome, &mr->highlight.back, colname);
1212	Scr->FirstTime = save;
1213    }
1214
1215    if (Scr->use3Dmenus && (Scr->Monochrome == COLOR) && (mr->highlight.fore == UNUSED_PIXEL)) {
1216	XColor xcol;
1217	char colname [32];
1218	short save;
1219
1220	xcol.pixel = Scr->MenuC.fore;
1221	XQueryColor (dpy, cmap, &xcol);
1222	sprintf (colname, "#%04x%04x%04x",
1223		5 * ((int)xcol.red   / 6),
1224		5 * ((int)xcol.green / 6),
1225		5 * ((int)xcol.blue  / 6));
1226	save = Scr->FirstTime;
1227	Scr->FirstTime = True;
1228	GetColor (Scr->Monochrome, &mr->highlight.fore, colname);
1229	Scr->FirstTime = save;
1230    }
1231    if (Scr->use3Dmenus && !Scr->BeNiceToColormap) GetShadeColors (&mr->highlight);
1232
1233    /* get the default colors into the menus */
1234    for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
1235    {
1236	if (!tmp->user_colors) {
1237	    if (tmp->func != F_TITLE) {
1238		tmp->normal.fore = Scr->MenuC.fore;
1239		tmp->normal.back = Scr->MenuC.back;
1240	    } else {
1241		tmp->normal.fore = Scr->MenuTitleC.fore;
1242		tmp->normal.back = Scr->MenuTitleC.back;
1243	    }
1244	}
1245
1246	if (mr->highlight.fore != UNUSED_PIXEL)
1247	{
1248	    tmp->highlight.fore = mr->highlight.fore;
1249	    tmp->highlight.back = mr->highlight.back;
1250	}
1251	else
1252	{
1253	    tmp->highlight.fore = tmp->normal.back;
1254	    tmp->highlight.back = tmp->normal.fore;
1255	}
1256	if (Scr->use3Dmenus && !Scr->BeNiceToColormap) {
1257	    if (tmp->func != F_TITLE)
1258		GetShadeColors (&tmp->highlight);
1259	    else
1260		GetShadeColors (&tmp->normal);
1261	}
1262    }
1263    mr->pmenu = NULL;
1264
1265    if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
1266	return 0;
1267
1268    start = mr->first;
1269    while (TRUE)
1270    {
1271	for (; start != NULL; start = start->next)
1272	{
1273	    if (start->user_colors)
1274		break;
1275	}
1276	if (start == NULL)
1277	    break;
1278
1279	for (end = start->next; end != NULL; end = end->next)
1280	{
1281	    if (end->user_colors)
1282		break;
1283	}
1284	if (end == NULL)
1285	    break;
1286
1287	/* we have a start and end to interpolate between */
1288	num = end->item_num - start->item_num;
1289
1290	f1.pixel = start->normal.fore;
1291	XQueryColor(dpy, cmap, &f1);
1292	f2.pixel = end->normal.fore;
1293	XQueryColor(dpy, cmap, &f2);
1294
1295	b1.pixel = start->normal.back;
1296	XQueryColor(dpy, cmap, &b1);
1297	b2.pixel = end->normal.back;
1298	XQueryColor(dpy, cmap, &b2);
1299
1300	fred = ((int)f2.red - (int)f1.red) / num;
1301	fgreen = ((int)f2.green - (int)f1.green) / num;
1302	fblue = ((int)f2.blue - (int)f1.blue) / num;
1303
1304	bred = ((int)b2.red - (int)b1.red) / num;
1305	bgreen = ((int)b2.green - (int)b1.green) / num;
1306	bblue = ((int)b2.blue - (int)b1.blue) / num;
1307
1308	f3 = f1;
1309	f3.flags = DoRed | DoGreen | DoBlue;
1310
1311	b3 = b1;
1312	b3.flags = DoRed | DoGreen | DoBlue;
1313
1314	start->highlight.back = start->normal.fore;
1315	start->highlight.fore = start->normal.back;
1316	num -= 1;
1317	for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
1318	{
1319	    f3.red += fred;
1320	    f3.green += fgreen;
1321	    f3.blue += fblue;
1322	    save_fore = f3;
1323
1324	    b3.red += bred;
1325	    b3.green += bgreen;
1326	    b3.blue += bblue;
1327	    save_back = b3;
1328
1329	    XAllocColor(dpy, cmap, &f3);
1330	    XAllocColor(dpy, cmap, &b3);
1331	    cur->highlight.back = cur->normal.fore = f3.pixel;
1332	    cur->highlight.fore = cur->normal.back = b3.pixel;
1333	    cur->user_colors = True;
1334
1335	    f3 = save_fore;
1336	    b3 = save_back;
1337	}
1338	start = end;
1339	start->highlight.back = start->normal.fore;
1340	start->highlight.fore = start->normal.back;
1341    }
1342    return 1;
1343}
1344
1345
1346
1347/***********************************************************************
1348 *
1349 *  Procedure:
1350 *	PopUpMenu - pop up a pull down menu
1351 *
1352 *  Inputs:
1353 *	menu	- the root pointer of the menu to pop up
1354 *	x, y	- location of upper left of menu
1355 *      center	- whether or not to center horizontally over position
1356 *
1357 ***********************************************************************
1358 */
1359
1360Bool PopUpMenu (MenuRoot *menu, int x, int y, Bool center)
1361{
1362    int WindowNameCount;
1363    TwmWindow **WindowNames;
1364    TwmWindow *tmp_win2,*tmp_win3;
1365    int i;
1366    int xl, yt;
1367    Bool clipped;
1368#ifdef CLAUDE
1369    char tmpname3 [256], tmpname4 [256];
1370    int hasmoz = 0;
1371#endif
1372    if (!menu) return False;
1373
1374    InstallRootColormap();
1375
1376    if ((menu == Scr->Windows) ||
1377	(menu == Scr->Icons) ||
1378	(menu == Scr->AllWindows) ||
1379	/* Added by Dan 'dl' Lilliehorn 040607 */
1380	(menu == Scr->AllIcons) ||
1381	/* Added by Dan Lilliehorn (dl@dl.nu) 2000-02-29 */
1382	(menu == Scr->Visible))
1383    {
1384	TwmWindow *tmp_win;
1385	WorkSpace *ws;
1386	Boolean all, icons, visible_, allicons; /* visible, allicons:
1387						  Added by dl */
1388	int func;
1389
1390	/* this is the twm windows menu,  let's go ahead and build it */
1391
1392	all = (menu == Scr->AllWindows);
1393	icons = (menu == Scr->Icons);
1394	visible_ = (menu == Scr->Visible);    /* Added by dl */
1395	allicons = (menu == Scr->AllIcons);
1396	DestroyMenu (menu);
1397
1398	menu->first = NULL;
1399	menu->last = NULL;
1400	menu->items = 0;
1401	menu->width = 0;
1402	menu->mapped = NEVER_MAPPED;
1403	menu->highlight.fore = UNUSED_PIXEL;
1404	menu->highlight.back = UNUSED_PIXEL;
1405	if (menu == Scr->Windows)
1406  	    AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
1407	else
1408	if (menu == Scr->Icons)
1409  	    AddToMenu(menu, "TWM Icons", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
1410	else
1411	if (menu == Scr->Visible) /* Added by dl 2000 */
1412	    AddToMenu(menu, "TWM Visible", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
1413	else
1414	if (menu == Scr->AllIcons) /* Added by dl 2004 */
1415	    AddToMenu(menu, "TWM All Icons", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
1416	else
1417  	    AddToMenu(menu, "TWM All Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
1418
1419	ws = NULL;
1420
1421	if (! (all || allicons)
1422	    && CurrentSelectedWorkspace && Scr->workSpaceManagerActive) {
1423	    for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1424		if (strcmp (ws->name, CurrentSelectedWorkspace) == 0) break;
1425	    }
1426	}
1427	if (!Scr->currentvs) return False;
1428	if (!ws) ws = Scr->currentvs->wsw->currentwspc;
1429
1430        for (tmp_win = Scr->FirstWindow, WindowNameCount = 0;
1431             tmp_win != NULL;
1432             tmp_win = tmp_win->next) {
1433	  if (tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) continue;
1434	  if (Scr->ShortAllWindowsMenus && (tmp_win->wspmgr || tmp_win->iconmgr)) continue;
1435
1436	  if (!(all || allicons) && !OCCUPY (tmp_win, ws)) continue;
1437	  if (allicons && !tmp_win->isicon) continue;
1438	  if (icons && !tmp_win->isicon) continue;
1439	  if (visible_ && tmp_win->isicon) continue;  /* added by dl */
1440	  WindowNameCount++;
1441	}
1442        WindowNames = (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
1443	WindowNameCount = 0;
1444        for (tmp_win = Scr->FirstWindow;
1445             tmp_win != NULL;
1446             tmp_win = tmp_win->next)
1447        {
1448	    if (LookInList (Scr->IconMenuDontShow, tmp_win->full_name, &tmp_win->class)) continue;
1449
1450	    if (tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) continue;
1451	    if (Scr->ShortAllWindowsMenus &&
1452		tmp_win == Scr->currentvs->wsw->twm_win) continue;
1453	    if (Scr->ShortAllWindowsMenus && tmp_win->iconmgr) continue;
1454
1455	    if (!(all || allicons)&& ! OCCUPY (tmp_win, ws)) continue;
1456	    if (allicons && !tmp_win->isicon) continue;
1457	    if (icons && !tmp_win->isicon) continue;
1458	    if (visible_ && tmp_win->isicon) continue;  /* added by dl */
1459            tmp_win2 = tmp_win;
1460
1461            for (i = 0; i < WindowNameCount; i++) {
1462		int compresult;
1463		char *tmpname1, *tmpname2;
1464		tmpname1 = tmp_win2->name;
1465		tmpname2 = WindowNames[i]->name;
1466#ifdef CLAUDE
1467		if (strlen (tmpname1) == 1) tmpname1 = " No title";
1468		if (strlen (tmpname2) == 1) tmpname2 = " No title";
1469
1470                if (!strncasecmp (tmp_win2->class.res_class, "navigator", 9) ||
1471		    !strncasecmp (tmp_win2->class.res_class, "mozilla",   7)) {
1472		  tmpname3 [0] = ' '; tmpname3 [1] = '\0';
1473		  strcat (tmpname3, tmpname1);
1474		} else {
1475		  strcpy (tmpname3, tmpname1);
1476		}
1477                if (!strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) ||
1478		    !strncasecmp (WindowNames[i]->class.res_class, "mozilla",   7)) {
1479		  tmpname4 [0] = ' '; tmpname4 [1] = '\0';
1480		  strcat (tmpname4, tmpname2);
1481		} else {
1482		  strcpy (tmpname4, tmpname2);
1483		}
1484		tmpname1 = tmpname3;
1485		tmpname2 = tmpname4;
1486#endif
1487		if (Scr->CaseSensitive)
1488		    compresult = strcmp(tmpname1,tmpname2);
1489		else
1490		    compresult = XmuCompareISOLatin1(tmpname1,tmpname2);
1491                if (compresult < 0) {
1492                    tmp_win3 = tmp_win2;
1493                    tmp_win2 = WindowNames[i];
1494                    WindowNames[i] = tmp_win3;
1495                }
1496            }
1497            WindowNames[WindowNameCount] = tmp_win2;
1498	    WindowNameCount++;
1499        }
1500	func = (all || allicons || CurrentSelectedWorkspace) ? F_WINWARP :
1501	      F_POPUP;
1502        for (i = 0; i < WindowNameCount; i++)
1503        {
1504	    char *tmpname;
1505	    tmpname = WindowNames[i]->name;
1506#ifdef CLAUDE
1507	    if (!strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) ||
1508		!strncasecmp (WindowNames[i]->class.res_class, "mozilla",   7) ||
1509		!strncasecmp (WindowNames[i]->class.res_class, "netscape",  8) ||
1510		!strncasecmp (WindowNames[i]->class.res_class, "konqueror", 9)) {
1511	      hasmoz = 1;
1512	    }
1513	    if (hasmoz && strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) &&
1514		          strncasecmp (WindowNames[i]->class.res_class, "mozilla",   7) &&
1515		          strncasecmp (WindowNames[i]->class.res_class, "netscape",  8) &&
1516		          strncasecmp (WindowNames[i]->class.res_class, "konqueror", 9)) {
1517	      menu->last->separated = 1;
1518	      hasmoz = 0;
1519	    }
1520#endif
1521            AddToMenu(menu, tmpname, (char *)WindowNames[i],
1522                      NULL, func,NULL,NULL);
1523        }
1524        free(WindowNames);
1525
1526	menu->pinned = False;
1527	MakeMenu(menu);
1528    }
1529
1530    /* Keys added by dl */
1531
1532    if (menu == Scr->Keys) {
1533	FuncKey *tmpKey;
1534	char *tmpStr, *tmpStr2;
1535	char modStr[5];
1536	char *oldact = 0;
1537	int oldmod = 0;
1538	int tmpLen;
1539
1540	DestroyMenu (menu);
1541
1542	menu->first = NULL;
1543	menu->last = NULL;
1544	menu->items = 0;
1545	menu->width = 0;
1546	menu->mapped = NEVER_MAPPED;
1547	menu->highlight.fore = UNUSED_PIXEL;
1548	menu->highlight.back = UNUSED_PIXEL;
1549
1550	AddToMenu(menu, "Twm Keys", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR);
1551
1552	for (tmpKey = Scr->FuncKeyRoot.next; tmpKey != NULL;  tmpKey = tmpKey->next) {
1553	    if (tmpKey->func != F_EXEC) continue;
1554	    if ((tmpKey->action == oldact) && (tmpKey->mods == oldmod)) continue;
1555	    strcpy (modStr, "");
1556	    switch (tmpKey->mods) {
1557	        case  1: strcpy (modStr, "S");     break;
1558	        case  4: strcpy (modStr, "C");     break;
1559		case  5: strcpy (modStr, "S + C"); break;
1560		case  8: strcpy (modStr, "M");     break;
1561		case  9: strcpy (modStr, "S + M"); break;
1562		case 12: strcpy (modStr, "C + M"); break;
1563		default: break;
1564	    }
1565	    tmpLen = (strlen (tmpKey->name) + strlen (modStr) + 5);
1566	    tmpStr = malloc (sizeof(char) * tmpLen);
1567	    sprintf (tmpStr,"[%s + %s]", tmpKey->name, modStr);
1568	    tmpStr2 = malloc (sizeof(char) * (strlen (tmpKey->action) + tmpLen + 2));
1569	    sprintf (tmpStr2, "%s %s", tmpStr, tmpKey->action);
1570
1571	    AddToMenu (menu, tmpStr2, tmpKey->action, NULL, tmpKey->func, NULLSTR, NULLSTR);
1572	    oldact = tmpKey->action;
1573	    oldmod = tmpKey->mods;
1574	}
1575	menu->pinned = False;
1576	MakeMenu(menu);
1577    }
1578    if (menu->w == None || menu->items == 0) return False;
1579
1580    /* Prevent recursively bringing up menus. */
1581    if ((!menu->pinned) && (menu->mapped == MAPPED)) return False;
1582
1583    /*
1584     * Dynamically set the parent;  this allows pull-ups to also be main
1585     * menus, or to be brought up from more than one place.
1586     */
1587    menu->prev = ActiveMenu;
1588
1589    if (menu->pinned) {
1590	ActiveMenu    = menu;
1591	menu->mapped  = MAPPED;
1592	menu->entered = TRUE;
1593	MenuOrigins [MenuDepth].x = menu->x;
1594	MenuOrigins [MenuDepth].y = menu->y;
1595	MenuDepth++;
1596
1597	XRaiseWindow (dpy, menu->w);
1598	return (True);
1599    }
1600
1601    XGrabPointer(dpy, Scr->Root, True,
1602	ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
1603	ButtonMotionMask | PointerMotionHintMask,
1604	GrabModeAsync, GrabModeAsync,
1605	Scr->Root,
1606	Scr->MenuCursor, CurrentTime);
1607
1608    XGrabKeyboard (dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
1609
1610    ActiveMenu = menu;
1611    menu->mapped = MAPPED;
1612    menu->entered = FALSE;
1613
1614    if (center) {
1615	x -= (menu->width / 2);
1616	y -= (Scr->EntryHeight / 2);	/* sticky menus would be nice here */
1617    }
1618
1619    /*
1620    * clip to screen
1621    */
1622    clipped = FALSE;
1623    if (x + menu->width > Scr->rootw) {
1624	x = Scr->rootw - menu->width;
1625	clipped = TRUE;
1626    }
1627    if (x < 0) {
1628	x = 0;
1629	clipped = TRUE;
1630    }
1631    if (y + menu->height > Scr->rooth) {
1632	y = Scr->rooth - menu->height;
1633	clipped = TRUE;
1634    }
1635    if (y < 0) {
1636	y = 0;
1637	clipped = TRUE;
1638    }
1639    MenuOrigins[MenuDepth].x = x;
1640    MenuOrigins[MenuDepth].y = y;
1641    MenuDepth++;
1642
1643    if (Scr->Root != Scr->CaptiveRoot) {
1644      XReparentWindow (dpy, menu->shadow, Scr->Root, x, y);
1645      XReparentWindow (dpy, menu->w, Scr->Root, x, y);
1646    } else
1647      XMoveWindow (dpy, menu->w, x, y);
1648    if (Scr->Shadow) {
1649	XMoveWindow  (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
1650	XRaiseWindow (dpy, menu->shadow);
1651    }
1652    XMapRaised(dpy, menu->w);
1653if (!Scr->NoWarpToMenuTitle && clipped && center) {
1654	xl = x + (menu->width      / 2);
1655	yt = y + (Scr->EntryHeight / 2);
1656	XWarpPointer (dpy, Scr->Root, Scr->Root, x, y, menu->width, menu->height, xl, yt);
1657    }
1658    if (Scr->Shadow) XMapWindow (dpy, menu->shadow);
1659    XSync(dpy, 0);
1660    return True;
1661}
1662
1663
1664
1665/***********************************************************************
1666 *
1667 *  Procedure:
1668 *	PopDownMenu - unhighlight the current menu selection and
1669 *		take down the menus
1670 *
1671 ***********************************************************************
1672 */
1673
1674int PopDownMenu(void)
1675{
1676    MenuRoot *tmp;
1677
1678    if (ActiveMenu == NULL)
1679	return (1);
1680
1681    if (ActiveItem)
1682    {
1683	ActiveItem->state = 0;
1684	PaintEntry(ActiveMenu, ActiveItem, False);
1685    }
1686
1687    for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
1688    {
1689	if (! tmp->pinned) HideMenu (tmp);
1690	UninstallRootColormap();
1691    }
1692
1693    XFlush(dpy);
1694    ActiveMenu = NULL;
1695    ActiveItem = NULL;
1696    MenuDepth = 0;
1697    XUngrabKeyboard (dpy, CurrentTime);
1698    if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE || Context == C_ICON)
1699      menuFromFrameOrWindowOrTitlebar = TRUE;
1700
1701    return 1;
1702}
1703
1704
1705
1706Bool HideMenu (MenuRoot *menu)
1707{
1708    if (!menu) return False;
1709
1710    if (Scr->Shadow) {
1711	XUnmapWindow (dpy, menu->shadow);
1712    }
1713    XUnmapWindow (dpy, menu->w);
1714    menu->mapped = UNMAPPED;
1715
1716    return True;
1717}
1718
1719/***********************************************************************
1720 *
1721 *  Procedure:
1722 *	FindMenuRoot - look for a menu root
1723 *
1724 *  Returned Value:
1725 *	(MenuRoot *)  - a pointer to the menu root structure
1726 *
1727 *  Inputs:
1728 *	name	- the name of the menu root
1729 *
1730 ***********************************************************************
1731 */
1732
1733MenuRoot *FindMenuRoot(char *name)
1734{
1735    MenuRoot *tmp;
1736
1737    for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
1738    {
1739	if (strcmp(name, tmp->name) == 0)
1740	    return (tmp);
1741    }
1742    return NULL;
1743}
1744
1745
1746
1747static Bool belongs_to_twm_window (register TwmWindow *t, register Window w)
1748{
1749    if (!t) return False;
1750
1751    if (w == t->frame || w == t->title_w || w == t->hilite_wl || w == t->hilite_wr ||
1752	(t->icon && (w == t->icon->w || w == t->icon->bm_w))) return True;
1753
1754    if (t && t->titlebuttons) {
1755	register TBWindow *tbw;
1756	register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1757	for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
1758	    if (tbw->window == w) return True;
1759	}
1760    }
1761    return False;
1762}
1763
1764
1765
1766
1767/***********************************************************************
1768 *
1769 *  Procedure:
1770 *	resizeFromCenter -
1771 *
1772 ***********************************************************************
1773 */
1774
1775void resizeFromCenter(Window w, TwmWindow *tmp_win)
1776{
1777  int lastx, lasty, bw2;
1778  int namelen;
1779  XRectangle inc_rect;
1780  XRectangle logical_rect;
1781
1782  namelen = strlen (tmp_win->name);
1783  bw2 = tmp_win->frame_bw * 2;
1784  AddingW = tmp_win->attr.width + bw2 + 2 * tmp_win->frame_bw3D;
1785  AddingH = tmp_win->attr.height + tmp_win->title_height + bw2 + 2 * tmp_win->frame_bw3D;
1786
1787  XmbTextExtents(Scr->SizeFont.font_set, tmp_win->name, namelen,
1788		 &inc_rect, &logical_rect);
1789
1790  XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
1791	       &DragWidth, &DragHeight,
1792	       &JunkBW, &JunkDepth);
1793
1794  XWarpPointer(dpy, None, w,
1795	       0, 0, 0, 0, DragWidth/2, DragHeight/2);
1796  XQueryPointer (dpy, Scr->Root, &JunkRoot,
1797		 &JunkChild, &JunkX, &JunkY,
1798		 &AddingX, &AddingY, &JunkMask);
1799
1800  lastx = -10000;
1801  lasty = -10000;
1802
1803  MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
1804  while (TRUE)
1805    {
1806      XMaskEvent(dpy,
1807		 ButtonPressMask | PointerMotionMask | ExposureMask, &Event);
1808
1809      if (Event.type == MotionNotify) {
1810	/* discard any extra motion events before a release */
1811	while(XCheckMaskEvent(dpy,
1812			      ButtonMotionMask | ButtonPressMask, &Event))
1813	  if (Event.type == ButtonPress)
1814	    break;
1815      }
1816
1817      if (Event.type == ButtonPress)
1818	{
1819	  MenuEndResize(tmp_win);
1820	  XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
1821	  break;
1822	}
1823
1824      if (Event.type != MotionNotify) {
1825	(void)DispatchEvent2 ();
1826	continue;
1827      }
1828
1829      /*
1830       * XXX - if we are going to do a loop, we ought to consider
1831       * using multiple GXxor lines so that we don't need to
1832       * grab the server.
1833       */
1834      XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
1835		    &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
1836
1837      if (lastx != AddingX || lasty != AddingY)
1838	{
1839	  MenuDoResize(AddingX, AddingY, tmp_win);
1840
1841	  lastx = AddingX;
1842	  lasty = AddingY;
1843	}
1844
1845    }
1846}
1847
1848
1849
1850/***********************************************************************
1851 *
1852 *  Procedure:
1853 *	ExecuteFunction - execute a twm root function
1854 *
1855 *  Inputs:
1856 *	func	- the function to execute
1857 *	action	- the menu action to execute
1858 *	w	- the window to execute this function on
1859 *	tmp_win	- the twm window structure
1860 *	event	- the event that caused the function
1861 *	context - the context in which the button was pressed
1862 *	pulldown- flag indicating execution from pull down menu
1863 *
1864 *  Returns:
1865 *	TRUE if should continue with remaining actions else FALSE to abort
1866 *
1867 ***********************************************************************
1868 */
1869
1870int ExecuteFunction(int func, void *action, Window w, TwmWindow *tmp_win,
1871		    XEvent *eventp, int context, int pulldown)
1872{
1873    static Time last_time = 0;
1874    char tmp[200];
1875    char *ptr;
1876    char buff[MAX_FILE_SIZE];
1877    int count, fd;
1878    Window rootw;
1879    int origX, origY;
1880    int do_next_action = TRUE;
1881    int moving_icon = FALSE;
1882    Bool fromtitlebar = False;
1883    Bool from3dborder = False;
1884    TwmWindow *t;
1885
1886    RootFunction = 0;
1887    if (Cancel)
1888	return TRUE;			/* XXX should this be FALSE? */
1889
1890    switch (func)
1891    {
1892    case F_UPICONMGR:
1893    case F_LEFTICONMGR:
1894    case F_RIGHTICONMGR:
1895    case F_DOWNICONMGR:
1896    case F_FORWICONMGR:
1897    case F_BACKICONMGR:
1898    case F_NEXTICONMGR:
1899    case F_PREVICONMGR:
1900    case F_NOP:
1901    case F_TITLE:
1902    case F_DELTASTOP:
1903    case F_RAISELOWER:
1904    case F_WARPTOSCREEN:
1905    case F_WARPTO:
1906    case F_WARPRING:
1907    case F_WARPTOICONMGR:
1908    case F_COLORMAP:
1909    case F_ALTKEYMAP:
1910    case F_ALTCONTEXT:
1911	break;
1912
1913    default:
1914        XGrabPointer(dpy, Scr->Root, True,
1915            ButtonPressMask | ButtonReleaseMask,
1916            GrabModeAsync, GrabModeAsync,
1917            Scr->Root, Scr->WaitCursor, CurrentTime);
1918	break;
1919    }
1920
1921    switch (func)
1922    {
1923#ifdef SOUNDS
1924    case F_TOGGLESOUND:
1925	toggle_sound();
1926	break;
1927    case F_REREADSOUNDS:
1928	reread_sounds();
1929	break;
1930#endif
1931    case F_NOP:
1932    case F_TITLE:
1933	break;
1934
1935    case F_DELTASTOP:
1936	if (WindowMoved) do_next_action = FALSE;
1937	break;
1938
1939    case F_RESTART: {
1940	DoRestart(eventp->xbutton.time);
1941	break;
1942    }
1943    case F_UPICONMGR:
1944    case F_DOWNICONMGR:
1945    case F_LEFTICONMGR:
1946    case F_RIGHTICONMGR:
1947    case F_FORWICONMGR:
1948    case F_BACKICONMGR:
1949	MoveIconManager(func);
1950        break;
1951
1952    case F_FORWMAPICONMGR:
1953    case F_BACKMAPICONMGR:
1954	MoveMappedIconManager(func);
1955	break;
1956
1957    case F_NEXTICONMGR:
1958    case F_PREVICONMGR:
1959	JumpIconManager(func);
1960        break;
1961
1962    case F_SHOWLIST:
1963	if (Scr->NoIconManagers) break;
1964	ShowIconManager ();
1965	break;
1966
1967    case F_STARTANIMATION :
1968	StartAnimation ();
1969	break;
1970
1971    case F_STOPANIMATION :
1972	StopAnimation ();
1973	break;
1974
1975    case F_SPEEDUPANIMATION :
1976	ModifyAnimationSpeed (1);
1977	break;
1978
1979    case F_SLOWDOWNANIMATION :
1980	ModifyAnimationSpeed (-1);
1981	break;
1982
1983    case F_HIDELIST:
1984	if (Scr->NoIconManagers) break;
1985	HideIconManager ();
1986	break;
1987
1988    case F_SHOWWORKMGR:
1989	if (! Scr->workSpaceManagerActive) break;
1990	DeIconify (Scr->currentvs->wsw->twm_win);
1991	RaiseWindow(Scr->currentvs->wsw->twm_win);
1992	break;
1993
1994    case F_HIDEWORKMGR:
1995	if (! Scr->workSpaceManagerActive) break;
1996	Iconify (Scr->currentvs->wsw->twm_win, eventp->xbutton.x_root - 5,
1997		     eventp->xbutton.y_root - 5);
1998	break;
1999
2000    case F_TOGGLEWORKMGR:
2001	if (! Scr->workSpaceManagerActive) break;
2002	if (Scr->currentvs->wsw->twm_win->mapped)
2003	    Iconify (Scr->currentvs->wsw->twm_win, eventp->xbutton.x_root - 5,
2004		     eventp->xbutton.y_root - 5);
2005	else {
2006	    DeIconify (Scr->currentvs->wsw->twm_win);
2007	    RaiseWindow(Scr->currentvs->wsw->twm_win);
2008	}
2009	break;
2010
2011    case F_TOGGLESTATE :
2012	WMapToggleState (Scr->currentvs);
2013	break;
2014
2015    case F_SETBUTTONSTATE :
2016	WMapSetButtonsState (Scr->currentvs);
2017	break;
2018
2019    case F_SETMAPSTATE :
2020	WMapSetMapState (Scr->currentvs);
2021	break;
2022
2023    case F_PIN :
2024	if (! ActiveMenu) break;
2025	if (ActiveMenu->pinned) {
2026	    XUnmapWindow (dpy, ActiveMenu->w);
2027	    ActiveMenu->mapped = UNMAPPED;
2028	}
2029	else {
2030	    XWindowAttributes attr;
2031	    MenuRoot *menu;
2032
2033	    if (ActiveMenu->pmenu == NULL) {
2034		menu  = (MenuRoot*) malloc (sizeof (struct MenuRoot));
2035		*menu = *ActiveMenu;
2036		menu->pinned = True;
2037		menu->mapped = NEVER_MAPPED;
2038		menu->width -= 10;
2039		if (menu->pull) menu->width -= 16 + 10;
2040		MakeMenu (menu);
2041		ActiveMenu->pmenu = menu;
2042	    }
2043	    else menu = ActiveMenu->pmenu;
2044	    if (menu->mapped == MAPPED) break;
2045	    XGetWindowAttributes (dpy, ActiveMenu->w, &attr);
2046	    menu->x = attr.x;
2047	    menu->y = attr.y;
2048	    XMoveWindow (dpy, menu->w, menu->x, menu->y);
2049	    XMapRaised  (dpy, menu->w);
2050	    menu->mapped = MAPPED;
2051	}
2052	PopDownMenu();
2053	break;
2054
2055    case F_MOVEMENU:
2056	break;
2057
2058    case F_FITTOCONTENT :
2059	if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2060	if (!tmp_win->iswinbox) {
2061	    XBell (dpy, 0);
2062	    break;
2063	}
2064	fittocontent (tmp_win);
2065	break;
2066
2067    case F_VANISH:
2068	if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2069
2070	WMgrRemoveFromCurrentWorkSpace (Scr->currentvs, tmp_win);
2071	break;
2072
2073    case F_WARPHERE:
2074	WMgrAddToCurrentWorkSpaceAndWarp (Scr->currentvs, action);
2075	break;
2076
2077    case F_ADDTOWORKSPACE:
2078	if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2079	AddToWorkSpace (action, tmp_win);
2080	break;
2081
2082    case F_REMOVEFROMWORKSPACE:
2083	if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2084	RemoveFromWorkSpace (action, tmp_win);
2085	break;
2086
2087    case F_TOGGLEOCCUPATION:
2088	if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2089	ToggleOccupation (action, tmp_win);
2090	break;
2091
2092    case F_MOVETONEXTWORKSPACE:
2093		if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2094		MoveToNextWorkSpace(Scr->currentvs,tmp_win);
2095		break;
2096
2097    case F_MOVETOPREVWORKSPACE:
2098		if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2099		MoveToPrevWorkSpace(Scr->currentvs,tmp_win);
2100		break;
2101
2102    case F_MOVETONEXTWORKSPACEANDFOLLOW:
2103		if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2104		MoveToNextWorkSpaceAndFollow(Scr->currentvs,tmp_win);
2105		break;
2106
2107    case F_MOVETOPREVWORKSPACEANDFOLLOW:
2108		if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2109		MoveToPrevWorkSpaceAndFollow(Scr->currentvs,tmp_win);
2110		break;
2111
2112    case F_SORTICONMGR:
2113	if (DeferExecution(context, func, Scr->SelectCursor))
2114	    return TRUE;
2115
2116	{
2117	    int save_sort;
2118
2119	    save_sort = Scr->SortIconMgr;
2120	    Scr->SortIconMgr = TRUE;
2121
2122	    if (context == C_ICONMGR)
2123		SortIconManager((IconMgr *) NULL);
2124	    else if (tmp_win->iconmgr)
2125		SortIconManager(tmp_win->iconmgrp);
2126	    else
2127		XBell(dpy, 0);
2128
2129	    Scr->SortIconMgr = save_sort;
2130	}
2131	break;
2132
2133    case F_ALTKEYMAP: {
2134	int alt, stat_;
2135
2136	if (! action) return TRUE;
2137	stat_ = sscanf (action, "%d", &alt);
2138	if (stat_ != 1) return TRUE;
2139	if ((alt < 1) || (alt > 5)) return TRUE;
2140	AlternateKeymap = Alt1Mask << (alt - 1);
2141	XGrabPointer (dpy, Scr->Root, True, ButtonPressMask | ButtonReleaseMask,
2142			GrabModeAsync, GrabModeAsync,
2143			Scr->Root, Scr->AlterCursor, CurrentTime);
2144	XGrabKeyboard (dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
2145	return TRUE;
2146    }
2147
2148    case F_ALTCONTEXT: {
2149	AlternateContext = True;
2150	XGrabPointer (dpy, Scr->Root, False, ButtonPressMask | ButtonReleaseMask,
2151			GrabModeAsync, GrabModeAsync,
2152			Scr->Root, Scr->AlterCursor, CurrentTime);
2153	XGrabKeyboard (dpy, Scr->Root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
2154	return TRUE;
2155    }
2156    case F_IDENTIFY:
2157	if (DeferExecution(context, func, Scr->SelectCursor))
2158	    return TRUE;
2159
2160	Identify(tmp_win);
2161	break;
2162
2163    case F_INITSIZE: {
2164	int grav, x, y;
2165	unsigned int width, height, swidth, sheight;
2166
2167	if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2168	grav = ((tmp_win->hints.flags & PWinGravity)
2169		      ? tmp_win->hints.win_gravity : NorthWestGravity);
2170
2171	if (!(tmp_win->hints.flags & USSize) && !(tmp_win->hints.flags & PSize)) break;
2172
2173	width  = tmp_win->hints.width  + 2 * tmp_win->frame_bw3D;
2174	height  = tmp_win->hints.height + 2 * tmp_win->frame_bw3D + tmp_win->title_height;
2175	ConstrainSize (tmp_win, &width, &height);
2176
2177	x  = tmp_win->frame_x;
2178	y  = tmp_win->frame_y;
2179	swidth = tmp_win->frame_width;
2180	sheight = tmp_win->frame_height;
2181	switch (grav) {
2182	    case ForgetGravity :
2183	    case StaticGravity :
2184	    case NorthWestGravity :
2185	    case NorthGravity :
2186	    case WestGravity :
2187	    case CenterGravity :
2188		break;
2189
2190	    case NorthEastGravity :
2191	    case EastGravity :
2192		x += swidth - width;
2193		break;
2194
2195	    case SouthWestGravity :
2196	    case SouthGravity :
2197		y += sheight - height;
2198		break;
2199
2200	    case SouthEastGravity :
2201		x += swidth - width;
2202		y += sheight - height;
2203		break;
2204	}
2205	SetupWindow (tmp_win, x, y, width, height, -1);
2206	break;
2207    }
2208
2209    case F_MOVERESIZE: {
2210	int x, y, mask;
2211	unsigned int width, height;
2212	int px = 20, py = 30;
2213
2214	if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
2215	mask = XParseGeometry (action, &x, &y, &width, &height);
2216	if (!(mask &  WidthValue)) width = tmp_win->frame_width;
2217	else width += 2 * tmp_win->frame_bw3D;
2218	if (!(mask & HeightValue)) height = tmp_win->frame_height;
2219	else height += 2 * tmp_win->frame_bw3D + tmp_win->title_height;
2220	ConstrainSize (tmp_win, &width, &height);
2221	if (mask & XValue) {
2222	    if (mask & XNegative) x += Scr->rootw  - width;
2223	} else x = tmp_win->frame_x;
2224	if (mask & YValue) {
2225	    if (mask & YNegative) y += Scr->rooth - height;
2226	} else y = tmp_win->frame_y;
2227
2228	{
2229	    int		 junkX, junkY;
2230	    unsigned int junkK;
2231	    Window	 junkW;
2232	    XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
2233	}
2234	px -= tmp_win->frame_x; if (px > width) px = width / 2;
2235	py -= tmp_win->frame_y; if (py > height) px = height / 2;
2236	SetupWindow (tmp_win, x, y, width, height, -1);
2237	XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, x + px, y + py);
2238	break;
2239    }
2240
2241    case F_VERSION:
2242	Identify ((TwmWindow *) NULL);
2243	break;
2244
2245    case F_AUTORAISE:
2246	if (DeferExecution(context, func, Scr->SelectCursor))
2247	    return TRUE;
2248
2249	tmp_win->auto_raise = !tmp_win->auto_raise;
2250	if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
2251	else --(Scr->NumAutoRaises);
2252	break;
2253
2254    case F_AUTOLOWER:
2255	if (DeferExecution(context, func, Scr->SelectCursor))
2256	    return TRUE;
2257
2258	tmp_win->auto_lower = !tmp_win->auto_lower;
2259	if (tmp_win->auto_lower) ++(Scr->NumAutoLowers);
2260	else --(Scr->NumAutoLowers);
2261	break;
2262
2263    case F_BEEP:
2264	XBell(dpy, 0);
2265	break;
2266
2267    case F_POPUP:
2268	tmp_win = (TwmWindow *)action;
2269	if (! tmp_win) break;
2270	if (Scr->WindowFunction.func != 0)
2271	{
2272	   ExecuteFunction(Scr->WindowFunction.func,
2273			   Scr->WindowFunction.item->action,
2274			   w, tmp_win, eventp, C_FRAME, FALSE);
2275	}
2276	else
2277	{
2278	    DeIconify(tmp_win);
2279	    RaiseWindow (tmp_win);
2280	}
2281	break;
2282
2283    case F_WINWARP:
2284	tmp_win = (TwmWindow *)action;
2285
2286	if (! tmp_win) break;
2287	if (Scr->WarpUnmapped || tmp_win->mapped) {
2288	    if (!tmp_win->mapped) DeIconify (tmp_win);
2289	    WarpToWindow (tmp_win, Scr->RaiseOnWarp);
2290	}
2291	break;
2292
2293    case F_RESIZE:
2294	EventHandler[EnterNotify] = HandleUnknown;
2295	EventHandler[LeaveNotify] = HandleUnknown;
2296	if (DeferExecution(context, func, Scr->MoveCursor))
2297	    return TRUE;
2298
2299	PopDownMenu();
2300	if (tmp_win->squeezed) {
2301	    XBell (dpy, 0);
2302	    break;
2303	}
2304	if (tmp_win->OpaqueResize) {
2305	    /*
2306	     * OpaqueResize defaults to a thousand.  Assume that any number
2307	     * >= 1000 is "infinity" and don't bother calculating.
2308	     */
2309	    if (Scr->OpaqueResizeThreshold >= 1000)
2310		Scr->OpaqueResize = TRUE;
2311	    else {
2312		/*
2313		 * scrsz will hold the number of pixels in your resolution,
2314		 * which can get big.  [signed] int may not cut it.
2315		 */
2316		unsigned long winsz, scrsz;
2317		winsz = tmp_win->frame_width * tmp_win->frame_height;
2318		scrsz = Scr->rootw  * Scr->rooth;
2319		if (winsz > (scrsz * (Scr->OpaqueResizeThreshold / 100.0)))
2320		    Scr->OpaqueResize = FALSE;
2321		else
2322		    Scr->OpaqueResize = TRUE;
2323	    }
2324	}
2325	else
2326	    Scr->OpaqueResize = FALSE;
2327
2328	if (pulldown)
2329	    XWarpPointer(dpy, None, Scr->Root,
2330		0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
2331
2332	if (!tmp_win->icon || (w != tmp_win->icon->w)) {	/* can't resize icons */
2333
2334/*	  fromMenu = False;  ????? */
2335	  if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE)
2336	      && fromMenu)
2337	    resizeFromCenter(w, tmp_win);
2338	  else {
2339	    /*
2340	     * see if this is being done from the titlebar
2341	     */
2342	    from3dborder = (eventp->xbutton.window == tmp_win->frame);
2343	    fromtitlebar = !from3dborder &&
2344	      belongs_to_twm_window (tmp_win, eventp->xbutton.window);
2345
2346	    /* Save pointer position so we can tell if it was moved or
2347	       not during the resize. */
2348	    ResizeOrigX = eventp->xbutton.x_root;
2349	    ResizeOrigY = eventp->xbutton.y_root;
2350
2351	    StartResize (eventp, tmp_win, fromtitlebar, from3dborder);
2352
2353	    do {
2354		XMaskEvent(dpy,
2355			   ButtonPressMask | ButtonReleaseMask |
2356			   EnterWindowMask | LeaveWindowMask |
2357			   ButtonMotionMask | VisibilityChangeMask | ExposureMask, &Event);
2358
2359		if (fromtitlebar && Event.type == ButtonPress) {
2360		    fromtitlebar = False;
2361		    continue;
2362		}
2363
2364	    	if (Event.type == MotionNotify) {
2365		  /* discard any extra motion events before a release */
2366		  while
2367		    (XCheckMaskEvent
2368		     (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
2369		      if (Event.type == ButtonRelease)
2370			break;
2371		}
2372
2373	      if (!DispatchEvent2 ()) continue;
2374
2375	    } while (!(Event.type == ButtonRelease || Cancel));
2376	    return TRUE;
2377	  }
2378	}
2379	break;
2380
2381
2382    case F_ZOOM:
2383    case F_HORIZOOM:
2384    case F_FULLZOOM:
2385    case F_LEFTZOOM:
2386    case F_RIGHTZOOM:
2387    case F_TOPZOOM:
2388    case F_BOTTOMZOOM:
2389	if (DeferExecution(context, func, Scr->SelectCursor))
2390	    return TRUE;
2391	if (tmp_win->squeezed) {
2392	    XBell(dpy, 0);
2393	    break;
2394	}
2395	fullzoom(tmp_win, func);
2396	break;
2397
2398    case F_PACK:
2399	if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE;
2400	if (tmp_win->squeezed) { XBell(dpy, 0); break; }
2401	packwindow (tmp_win, action);
2402	break;
2403
2404    case F_FILL:
2405	if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE;
2406	if (tmp_win->squeezed) { XBell(dpy, 0); break; }
2407	fillwindow (tmp_win, action);
2408	break;
2409
2410    case F_JUMPLEFT:
2411	if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
2412	if (tmp_win->squeezed) { XBell(dpy, 0); break; }
2413	jump (tmp_win, J_LEFT, action);
2414	break;
2415    case F_JUMPRIGHT:
2416	if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
2417	if (tmp_win->squeezed) { XBell(dpy, 0); break; }
2418	jump (tmp_win, J_RIGHT, action);
2419	break;
2420    case F_JUMPDOWN:
2421	if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
2422	if (tmp_win->squeezed) { XBell(dpy, 0); break; }
2423	jump (tmp_win, J_BOTTOM, action);
2424	break;
2425    case F_JUMPUP:
2426	if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
2427	if (tmp_win->squeezed) { XBell(dpy, 0); break; }
2428	jump (tmp_win, J_TOP, action);
2429	break;
2430
2431    case F_SAVEGEOMETRY:
2432	if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE;
2433	savegeometry (tmp_win);
2434	break;
2435
2436    case F_RESTOREGEOMETRY:
2437	if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE;
2438	restoregeometry (tmp_win);
2439	break;
2440
2441    case F_HYPERMOVE: {
2442	Bool	cont = True;
2443	Window	root = RootWindow (dpy, Scr->screen);
2444	Cursor	cursor;
2445	CaptiveCTWM cctwm0, cctwm;
2446
2447	if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE;
2448
2449	if (tmp_win->iswinbox || tmp_win->wspmgr) {
2450	    XBell (dpy, 0);
2451	    break;
2452	}
2453	cctwm0 = GetCaptiveCTWMUnderPointer ();
2454	cursor = MakeStringCursor (cctwm0.name);
2455	free (cctwm0.name);
2456	if (DeferExecution (context, func, Scr->MoveCursor)) return TRUE;
2457
2458	XGrabPointer (dpy, root, True,
2459		ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
2460		GrabModeAsync, GrabModeAsync, root, cursor, CurrentTime);
2461	while (cont) {
2462	    XMaskEvent (dpy, ButtonPressMask | ButtonMotionMask |
2463				ButtonReleaseMask, &Event);
2464	    switch (Event.xany.type) {
2465		case ButtonPress :
2466		    cont = False;
2467		    break;
2468
2469		case ButtonRelease :
2470		    cont = False;
2471		    cctwm = GetCaptiveCTWMUnderPointer ();
2472		    free (cctwm.name);
2473		    if (cctwm.root == Scr->Root) break;
2474		    SetNoRedirect (tmp_win->w);
2475		    XUngrabButton (dpy, AnyButton, AnyModifier, tmp_win->w);
2476		    XReparentWindow (dpy, tmp_win->w, cctwm.root, 0, 0);
2477		    XMapWindow (dpy, tmp_win->w);
2478		    break;
2479
2480		case MotionNotify :
2481		    cctwm = GetCaptiveCTWMUnderPointer ();
2482		    if (cctwm.root != cctwm0.root) {
2483			XFreeCursor (dpy, cursor);
2484			cursor = MakeStringCursor (cctwm.name);
2485			cctwm0 = cctwm;
2486			XChangeActivePointerGrab (dpy,
2487				ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
2488				cursor, CurrentTime);
2489		    }
2490		    free (cctwm.name);
2491		    break;
2492	    }
2493	}
2494	ButtonPressed = -1;
2495	XUngrabPointer (dpy, CurrentTime);
2496	XFreeCursor (dpy, cursor);
2497	break;
2498    }
2499
2500    case F_MOVE:
2501    case F_FORCEMOVE:
2502    case F_MOVEPACK:
2503    case F_MOVEPUSH: {
2504        Window grabwin, dragroot;
2505
2506	if (DeferExecution(context, func, Scr->MoveCursor))
2507	    return TRUE;
2508
2509	PopDownMenu();
2510	if (tmp_win->OpaqueMove) {
2511	    int sw, ss;
2512	    float sf;
2513
2514	    sw = tmp_win->frame_width * tmp_win->frame_height;
2515	    ss = Scr->rootw  * Scr->rooth;
2516	    sf = Scr->OpaqueMoveThreshold / 100.0;
2517	    if (sw > (ss * sf))
2518		Scr->OpaqueMove = FALSE;
2519	    else
2520		Scr->OpaqueMove = TRUE;
2521	}
2522	else
2523	    Scr->OpaqueMove = FALSE;
2524
2525	dragroot = Scr->XineramaRoot;
2526
2527	if (tmp_win->winbox) {
2528	    XTranslateCoordinates (dpy, dragroot, tmp_win->winbox->window,
2529		eventp->xbutton.x_root, eventp->xbutton.y_root,
2530		&(eventp->xbutton.x_root), &(eventp->xbutton.y_root), &JunkChild);
2531	}
2532	rootw = eventp->xbutton.root;
2533	MoveFunction = func;
2534
2535	if (pulldown)
2536	    XWarpPointer(dpy, None, Scr->Root,
2537		0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
2538
2539	EventHandler[EnterNotify] = HandleUnknown;
2540	EventHandler[LeaveNotify] = HandleUnknown;
2541
2542	if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
2543	    XGrabServer(dpy);
2544	}
2545
2546	Scr->SizeStringOffset = SIZE_HINDENT;
2547	XResizeWindow (dpy, Scr->SizeWindow,
2548		   Scr->SizeStringWidth + SIZE_HINDENT * 2,
2549		   Scr->SizeFont.height + SIZE_VINDENT * 2);
2550	XMapRaised (dpy, Scr->SizeWindow);
2551
2552	grabwin = Scr->XineramaRoot;
2553	if (tmp_win->winbox) grabwin = tmp_win->winbox->window;
2554	XGrabPointer(dpy, grabwin, True,
2555	    ButtonPressMask | ButtonReleaseMask |
2556	    ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
2557	    GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor, CurrentTime);
2558
2559	if (context == C_ICON && tmp_win->icon && tmp_win->icon->w)
2560	{
2561	    w = tmp_win->icon->w;
2562	    DragX = eventp->xbutton.x;
2563	    DragY = eventp->xbutton.y;
2564	    moving_icon = TRUE;
2565	    if (tmp_win->OpaqueMove) Scr->OpaqueMove = TRUE;
2566	}
2567
2568	else if (! tmp_win->icon || w != tmp_win->icon->w)
2569	{
2570	    XTranslateCoordinates(dpy, w, tmp_win->frame,
2571		eventp->xbutton.x,
2572		eventp->xbutton.y,
2573		&DragX, &DragY, &JunkChild);
2574
2575	    w = tmp_win->frame;
2576	}
2577
2578	DragWindow = None;
2579
2580	/* Get x/y relative to parent window, i.e. the virtual screen, Root.
2581	 * XMoveWindow() moves are relative to this.
2582	 * MoveOutline()s however are drawn from the XineramaRoot since they
2583	 * may cross virtual screens.
2584	 */
2585	XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
2586	    &DragWidth, &DragHeight, &DragBW,
2587	    &JunkDepth);
2588
2589	JunkBW = DragBW;
2590	origX = eventp->xbutton.x_root;
2591	origY = eventp->xbutton.y_root;
2592	CurrentDragX = origDragX;
2593	CurrentDragY = origDragY;
2594
2595	/*
2596	 * only do the constrained move if timer is set; need to check it
2597	 * in case of stupid or wicked fast servers
2598	 */
2599	if (ConstrainedMoveTime &&
2600	    (eventp->xbutton.time - last_time) < ConstrainedMoveTime)
2601	{
2602	    int width, height;
2603
2604	    ConstMove = TRUE;
2605	    ConstMoveDir = MOVE_NONE;
2606	    ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
2607	    ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
2608	    width = DragWidth + 2 * JunkBW;
2609	    height = DragHeight + 2 * JunkBW;
2610	    ConstMoveXL = ConstMoveX + width/3;
2611	    ConstMoveXR = ConstMoveX + 2*(width/3);
2612	    ConstMoveYT = ConstMoveY + height/3;
2613	    ConstMoveYB = ConstMoveY + 2*(height/3);
2614
2615	    XWarpPointer(dpy, None, w,
2616		0, 0, 0, 0, DragWidth/2, DragHeight/2);
2617
2618	    XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
2619		&JunkX, &JunkY, &DragX, &DragY, &JunkMask);
2620	}
2621	last_time = eventp->xbutton.time;
2622
2623	if (!Scr->OpaqueMove)
2624	{
2625	    InstallRootColormap();
2626	    if (!Scr->MoveDelta)
2627	    {
2628		/*
2629		 * Draw initial outline.  This was previously done the
2630		 * first time though the outer loop by dropping out of
2631		 * the XCheckMaskEvent inner loop down to one of the
2632		 * MoveOutline's below.
2633		 */
2634		MoveOutline(dragroot,
2635		    origDragX - JunkBW + Scr->currentvs->x,
2636		    origDragY - JunkBW + Scr->currentvs->y,
2637		    DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
2638		    tmp_win->frame_bw,
2639		    moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
2640		/*
2641		 * This next line causes HandleReleaseNotify to call
2642		 * XRaiseWindow().  This is solely to preserve the
2643		 * previous behaviour that raises a window being moved
2644		 * on button release even if you never actually moved
2645		 * any distance (unless you move less than MoveDelta or
2646		 * NoRaiseMove is set or OpaqueMove is set).
2647		 */
2648		DragWindow = w;
2649	    }
2650	}
2651
2652	/*
2653	 * see if this is being done from the titlebar
2654	 */
2655	fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window);
2656
2657	if (menuFromFrameOrWindowOrTitlebar) {
2658	  /* warp the pointer to the middle of the window */
2659	  XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
2660		       origDragX + DragWidth / 2,
2661		       origDragY + DragHeight / 2);
2662	  XFlush(dpy);
2663	}
2664
2665	DisplayPosition (tmp_win, CurrentDragX, CurrentDragY);
2666	while (TRUE)
2667	{
2668	    long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
2669	                          ButtonPress : ButtonRelease;
2670	    long movementMask = menuFromFrameOrWindowOrTitlebar ?
2671	                          PointerMotionMask : ButtonMotionMask;
2672
2673	    /* block until there is an interesting event */
2674	    XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
2675				    EnterWindowMask | LeaveWindowMask |
2676				    ExposureMask | movementMask |
2677				    VisibilityChangeMask, &Event);
2678
2679	    /* throw away enter and leave events until release */
2680	    if (Event.xany.type == EnterNotify ||
2681		Event.xany.type == LeaveNotify) continue;
2682
2683	    if (Event.type == MotionNotify) {
2684		/* discard any extra motion events before a logical release */
2685		while(XCheckMaskEvent(dpy,
2686		    movementMask | releaseEvent, &Event))
2687		  if (Event.type == releaseEvent) {
2688		    break;
2689		  }
2690	    }
2691
2692	    /* test to see if we have a second button press to abort move */
2693	    if (!menuFromFrameOrWindowOrTitlebar)
2694	      if (Event.type == ButtonPress && DragWindow != None) {
2695		Cursor cur;
2696		if (Scr->OpaqueMove) {
2697		  XMoveWindow (dpy, DragWindow, origDragX, origDragY);
2698		} else {
2699		  MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
2700		}
2701		DragWindow = None;
2702
2703		XUnmapWindow (dpy, Scr->SizeWindow);
2704		cur = LeftButt;
2705		if (Event.xbutton.button == Button2)
2706		    cur = MiddleButt;
2707		else if (Event.xbutton.button >= Button3)
2708		    cur = RightButt;
2709
2710		XGrabPointer (dpy, Scr->Root, True,
2711		    ButtonReleaseMask | ButtonPressMask,
2712		    GrabModeAsync, GrabModeAsync,
2713		    Scr->Root, cur, CurrentTime);
2714		return TRUE;
2715	      }
2716
2717	    if (fromtitlebar && Event.type == ButtonPress) {
2718		fromtitlebar = False;
2719		CurrentDragX = origX = Event.xbutton.x_root;
2720		CurrentDragY = origY = Event.xbutton.y_root;
2721		XTranslateCoordinates (dpy, rootw, tmp_win->frame,
2722				       origX, origY,
2723				       &DragX, &DragY, &JunkChild);
2724		continue;
2725	    }
2726
2727	    if (!DispatchEvent2 ()) continue;
2728
2729	    if (Cancel)
2730	    {
2731		WindowMoved = FALSE;
2732		if (!Scr->OpaqueMove)
2733		    UninstallRootColormap();
2734		return TRUE;	/* XXX should this be FALSE? */
2735	    }
2736	    if (Event.type == releaseEvent)
2737	    {
2738		MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
2739		if (moving_icon &&
2740		    ((CurrentDragX != origDragX ||
2741		      CurrentDragY != origDragY)))
2742		    tmp_win->icon_moved = TRUE;
2743		if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar) {
2744		    int xl = Event.xbutton.x_root - (DragWidth  / 2),
2745		        yt = Event.xbutton.y_root - (DragHeight / 2);
2746		    if (!moving_icon &&
2747		       (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH))
2748			TryToPack (tmp_win, &xl, &yt);
2749		    XMoveWindow(dpy, DragWindow, xl, yt);
2750		}
2751		if (menuFromFrameOrWindowOrTitlebar) DragWindow = None;
2752		break;
2753	    }
2754
2755	    /* something left to do only if the pointer moved */
2756	    if (Event.type != MotionNotify)
2757		continue;
2758
2759	    XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
2760		&(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
2761		&JunkX, &JunkY, &JunkMask);
2762
2763	    FixRootEvent (eventp);
2764	    if (tmp_win->winbox) {
2765		XTranslateCoordinates (dpy, dragroot, tmp_win->winbox->window,
2766		    eventp->xmotion.x_root, eventp->xmotion.y_root,
2767		    &(eventp->xmotion.x_root), &(eventp->xmotion.y_root), &JunkChild);
2768	    }
2769	    if (DragWindow == None &&
2770		abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
2771	        abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
2772		continue;
2773
2774	    DragWindow = w;
2775
2776	    if (!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved)
2777	      RaiseFrame(DragWindow);
2778
2779	    WindowMoved = TRUE;
2780
2781	    if (ConstMove)
2782	    {
2783		switch (ConstMoveDir)
2784		{
2785		    case MOVE_NONE:
2786			if (eventp->xmotion.x_root < ConstMoveXL ||
2787			    eventp->xmotion.x_root > ConstMoveXR)
2788			    ConstMoveDir = MOVE_HORIZ;
2789
2790			if (eventp->xmotion.y_root < ConstMoveYT ||
2791			    eventp->xmotion.y_root > ConstMoveYB)
2792			    ConstMoveDir = MOVE_VERT;
2793
2794			XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
2795			    &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
2796			break;
2797
2798		    case MOVE_VERT:
2799			ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
2800			break;
2801
2802		    case MOVE_HORIZ:
2803			ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
2804			break;
2805		}
2806
2807		if (ConstMoveDir != MOVE_NONE)
2808		{
2809		    int xl, yt, width, height;
2810
2811		    xl = ConstMoveX;
2812		    yt = ConstMoveY;
2813		    width = DragWidth + 2 * JunkBW;
2814		    height = DragHeight + 2 * JunkBW;
2815
2816		    if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2817		        TryToGrid (tmp_win, &xl, &yt);
2818		    if (!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove)
2819			TryToPush (tmp_win, xl, yt, 0);
2820
2821		    if (!moving_icon &&
2822			(MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH))
2823			TryToPack (tmp_win, &xl, &yt);
2824
2825		    if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2826		    {
2827                        ConstrainByBorders (tmp_win, &xl, width, &yt, height);
2828		    }
2829		    CurrentDragX = xl;
2830		    CurrentDragY = yt;
2831		    if (Scr->OpaqueMove) {
2832		      if (MoveFunction == F_MOVEPUSH && !moving_icon) {
2833			SetupWindow (tmp_win, xl, yt,
2834				     tmp_win->frame_width, tmp_win->frame_height, -1);
2835		      } else {
2836			XMoveWindow(dpy, DragWindow, xl, yt);
2837		      }
2838			WMapSetupWindow (tmp_win, xl, yt, -1, -1);
2839		    }
2840		    else {
2841			MoveOutline(dragroot, xl + Scr->currentvs->x,
2842			    yt + Scr->currentvs->y, width, height,
2843			    tmp_win->frame_bw,
2844			    moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
2845		    }
2846		}
2847	    }
2848	    else if (DragWindow != None)
2849	    {
2850		int xroot, yroot;
2851		int xl, yt, width, height;
2852
2853
2854		/*
2855		 * this is split out for virtual screens.  In that case, it's
2856		 * possible to drag windows from one workspace to another, and
2857		 * as such, these need to be adjusted to the root, rather
2858		 * than this virtual screen...
2859		 */
2860		xroot = eventp->xmotion.x_root;
2861		yroot = eventp->xmotion.y_root;
2862
2863		if (!menuFromFrameOrWindowOrTitlebar) {
2864		  xl = xroot - DragX - JunkBW;
2865		  yt = yroot - DragY - JunkBW;
2866		}
2867		else {
2868		  xl = xroot - (DragWidth / 2);
2869		  yt = yroot - (DragHeight / 2);
2870		}
2871		width = DragWidth + 2 * JunkBW;
2872		height = DragHeight + 2 * JunkBW;
2873
2874		if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2875		    TryToGrid (tmp_win, &xl, &yt);
2876		if (!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove)
2877		    TryToPush (tmp_win, xl, yt, 0);
2878
2879		if (!moving_icon &&
2880		    (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH))
2881		    TryToPack (tmp_win, &xl, &yt);
2882
2883		if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
2884		{
2885                    ConstrainByBorders (tmp_win, &xl, width, &yt, height);
2886		}
2887
2888		CurrentDragX = xl;
2889		CurrentDragY = yt;
2890		if (Scr->OpaqueMove) {
2891		  if (MoveFunction == F_MOVEPUSH && !moving_icon) {
2892		        SetupWindow (tmp_win, xl, yt,
2893				tmp_win->frame_width, tmp_win->frame_height, -1);
2894		  } else {
2895			XMoveWindow(dpy, DragWindow, xl, yt);
2896		  }
2897		  if (! moving_icon) WMapSetupWindow (tmp_win, xl, yt, -1, -1);
2898		}
2899		else {
2900		    MoveOutline(dragroot, xl + Scr->currentvs->x,
2901			yt + Scr->currentvs->y, width, height,
2902			tmp_win->frame_bw,
2903			moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
2904		}
2905	    }
2906	    DisplayPosition (tmp_win, CurrentDragX, CurrentDragY);
2907	}
2908	XUnmapWindow (dpy, Scr->SizeWindow);
2909
2910	if (!Scr->OpaqueMove && DragWindow == None)
2911	    UninstallRootColormap();
2912        break;
2913    }
2914    case F_MOVETITLEBAR:
2915    {
2916        Window grabwin;
2917	int deltax = 0, newx = 0;
2918	int origNum;
2919	SqueezeInfo *si;
2920
2921	if (DeferExecution(context, func, Scr->MoveCursor))
2922	    return TRUE;
2923
2924	PopDownMenu();
2925	if (tmp_win->squeezed ||
2926		!tmp_win->squeeze_info ||
2927		!tmp_win->title_w ||
2928		context == C_ICON ) {
2929	    XBell (dpy, 0);
2930	    break;
2931	}
2932
2933	/* If the SqueezeInfo isn't copied yet, do it now */
2934	if (!tmp_win->squeeze_info_copied) {
2935	    SqueezeInfo *s = malloc(sizeof(SqueezeInfo));
2936	    if (!s)
2937		break;
2938	    *s = *tmp_win->squeeze_info;
2939	    tmp_win->squeeze_info = s;
2940	    tmp_win->squeeze_info_copied = 1;
2941	}
2942	si = tmp_win->squeeze_info;
2943
2944	if (si->denom != 0) {
2945	    int target_denom = tmp_win->frame_width;
2946	    /*
2947	     * If not pixel based, scale the denominator to equal the
2948	     * window width, so the numerator equals pixels.
2949	     * That way we can just modify it by pixel units, just
2950	     * like the other case.
2951	     */
2952
2953	    if (si->denom != target_denom) {
2954		float scale = (float)target_denom / si->denom;
2955		si->num *= scale;
2956		si->denom = target_denom; /* s->denom *= scale; */
2957	    }
2958	}
2959
2960	/* now move the mouse */
2961	if (tmp_win->winbox) {
2962	    XTranslateCoordinates (dpy, Scr->Root, tmp_win->winbox->window,
2963		eventp->xbutton.x_root, eventp->xbutton.y_root,
2964		&eventp->xbutton.x_root, &eventp->xbutton.y_root, &JunkChild);
2965	}
2966	/*
2967	 * the event is always a button event, since key events
2968	 * are "weeded out" - although incompletely only
2969	 * F_MOVE and F_RESIZE - in HandleKeyPress().
2970	 */
2971	rootw = eventp->xbutton.root;
2972
2973	EventHandler[EnterNotify] = HandleUnknown;
2974	EventHandler[LeaveNotify] = HandleUnknown;
2975
2976	if (!Scr->NoGrabServer) {
2977	    XGrabServer(dpy);
2978	}
2979
2980	grabwin = Scr->Root;
2981	if (tmp_win->winbox) grabwin = tmp_win->winbox->window;
2982	XGrabPointer(dpy, grabwin, True,
2983	    ButtonPressMask | ButtonReleaseMask |
2984	    ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
2985	    GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor, CurrentTime);
2986
2987#if 0	/* what's this for ? */
2988	if (! tmp_win->icon || w != tmp_win->icon->w)
2989	{
2990	    XTranslateCoordinates(dpy, w, tmp_win->frame,
2991		eventp->xbutton.x,
2992		eventp->xbutton.y,
2993		&DragX, &DragY, &JunkChild);
2994
2995	    w = tmp_win->frame;
2996	}
2997#endif
2998
2999	DragWindow = None;
3000
3001	XGetGeometry(dpy, tmp_win->title_w, &JunkRoot, &origDragX, &origDragY,
3002	    &DragWidth, &DragHeight, &DragBW,
3003	    &JunkDepth);
3004
3005	origX = eventp->xbutton.x_root;
3006	origNum = si->num;
3007
3008	if (menuFromFrameOrWindowOrTitlebar) {
3009	  /* warp the pointer to the middle of the window */
3010	  XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
3011		       origDragX + DragWidth / 2,
3012		       origDragY + DragHeight / 2);
3013	  XFlush(dpy);
3014	}
3015
3016	while (TRUE)
3017	{
3018	    long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
3019	                          ButtonPress : ButtonRelease;
3020	    long movementMask = menuFromFrameOrWindowOrTitlebar ?
3021	                          PointerMotionMask : ButtonMotionMask;
3022
3023	    /* block until there is an interesting event */
3024	    XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
3025				    EnterWindowMask | LeaveWindowMask |
3026				    ExposureMask | movementMask |
3027				    VisibilityChangeMask, &Event);
3028
3029	    /* throw away enter and leave events until release */
3030	    if (Event.xany.type == EnterNotify ||
3031		Event.xany.type == LeaveNotify) continue;
3032
3033	    if (Event.type == MotionNotify) {
3034		/* discard any extra motion events before a logical release */
3035		while (XCheckMaskEvent(dpy,
3036					movementMask | releaseEvent, &Event)) {
3037		    if (Event.type == releaseEvent) {
3038			break;
3039		    }
3040		}
3041	    }
3042
3043	    if (!DispatchEvent2())
3044		continue;
3045
3046	    if (Event.type == releaseEvent)
3047		break;
3048
3049	    /* something left to do only if the pointer moved */
3050	    if (Event.type != MotionNotify)
3051		continue;
3052
3053	    /* get current pointer pos, useful when there is lag */
3054	    XQueryPointer(dpy, rootw, &eventp->xmotion.root, &JunkChild,
3055		&eventp->xmotion.x_root, &eventp->xmotion.y_root,
3056		&JunkX, &JunkY, &JunkMask);
3057
3058	    FixRootEvent(eventp);
3059	    if (tmp_win->winbox) {
3060		XTranslateCoordinates(dpy, Scr->Root, tmp_win->winbox->window,
3061		    eventp->xmotion.x_root, eventp->xmotion.y_root,
3062		    &eventp->xmotion.x_root, &eventp->xmotion.y_root, &JunkChild);
3063	    }
3064
3065	    if (!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved)
3066	      RaiseFrame(w);
3067
3068	    deltax = eventp->xmotion.x_root - origX;
3069	    newx = origNum + deltax;
3070
3071	    /*
3072	     * Clamp to left and right.
3073	     * If we're in pixel size, keep within [ 0, frame_width >.
3074	     * If we're proportional, don't cross the 0.
3075	     * Also don't let the nominator get bigger than the denominator.
3076	     * Keep within [ -denom, -1] or [ 0, denom >.
3077	     */
3078	    {
3079		int wtmp = tmp_win->frame_width; /* or si->denom; if it were != 0 */
3080		if (origNum < 0) {
3081		    if (newx >= 0)
3082			newx = -1;
3083		    else if (newx < -wtmp)
3084			newx = -wtmp;
3085		} else if (origNum >= 0) {
3086		    if (newx < 0)
3087			newx = 0;
3088		    else if (newx >= wtmp)
3089			newx = wtmp - 1;
3090		}
3091	    }
3092
3093	    si->num = newx;
3094	    /* This, finally, actually moves the title bar */
3095	    /* XXX pressing a second button should cancel and undo this */
3096	    SetFrameShape(tmp_win);
3097	}
3098	break;
3099    }
3100    case F_FUNCTION:
3101	{
3102	    MenuRoot *mroot;
3103	    MenuItem *mitem;
3104
3105	    if ((mroot = FindMenuRoot(action)) == NULL)
3106	    {
3107		if (!action) action = "undef";
3108		fprintf (stderr, "%s: couldn't find function \"%s\"\n",
3109			 ProgramName, (char *)action);
3110		return TRUE;
3111	    }
3112
3113	    if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor))
3114		return TRUE;
3115	    else
3116	    {
3117		for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
3118		{
3119		    if (!ExecuteFunction (mitem->func, mitem->action, w,
3120					  tmp_win, eventp, context, pulldown))
3121		      /* pebl FIXME: the focus should be updated here,
3122			 or the function would operate on the same window */
3123		      break;
3124		}
3125	    }
3126	}
3127	break;
3128
3129    case F_DEICONIFY:
3130    case F_ICONIFY:
3131	if (DeferExecution(context, func, Scr->SelectCursor))
3132	    return TRUE;
3133
3134	if (tmp_win->isicon)
3135	{
3136	    DeIconify(tmp_win);
3137	}
3138        else if (func == F_ICONIFY)
3139	{
3140	    Iconify (tmp_win, eventp->xbutton.x_root - 5,
3141		     eventp->xbutton.y_root - 5);
3142	}
3143	break;
3144
3145    case F_SQUEEZE:
3146	if (DeferExecution(context, func, Scr->SelectCursor))
3147	    return TRUE;
3148
3149	Squeeze (tmp_win);
3150	break;
3151
3152    case F_SHOWBGRD:
3153	ShowBackground (Scr->currentvs);
3154	break;
3155
3156    case F_RAISELOWER:
3157	if (DeferExecution(context, func, Scr->SelectCursor))
3158	    return TRUE;
3159
3160	if (!WindowMoved) {
3161	    if (tmp_win->icon && w == tmp_win->icon->w) {
3162		RaiseLowerFrame(w, ONTOP_DEFAULT);
3163	    } else {
3164		RaiseLower(tmp_win);
3165		WMapRaiseLower (tmp_win);
3166	    }
3167	}
3168	break;
3169
3170    case F_RAISE:
3171	if (DeferExecution(context, func, Scr->SelectCursor))
3172	    return TRUE;
3173
3174	/* check to make sure raise is not from the WindowFunction */
3175	if (tmp_win->icon && (w == tmp_win->icon->w) && Context != C_ROOT)
3176	    XRaiseWindow(dpy, tmp_win->icon->w);
3177	else {
3178	    RaiseWindow (tmp_win);
3179	    WMapRaise   (tmp_win);
3180	}
3181	break;
3182
3183    case F_LOWER:
3184	if (DeferExecution(context, func, Scr->SelectCursor))
3185	    return TRUE;
3186
3187	if (tmp_win->icon && (w == tmp_win->icon->w))
3188	    XLowerWindow(dpy, tmp_win->icon->w);
3189	else {
3190	    LowerWindow(tmp_win);
3191	    WMapLower (tmp_win);
3192	}
3193	break;
3194
3195    case F_RAISEICONS:
3196	for (t = Scr->FirstWindow; t != NULL; t = t->next) {
3197	    if (t->icon && t->icon->w) {
3198		XRaiseWindow (dpy, t->icon->w);
3199	    }
3200	}
3201	break;
3202
3203    case F_FOCUS:
3204	if (DeferExecution(context, func, Scr->SelectCursor))
3205	    return TRUE;
3206
3207	if (tmp_win->isicon == FALSE)
3208	{
3209	    if (!Scr->FocusRoot && Scr->Focus == tmp_win)
3210	    {
3211		FocusOnRoot();
3212	    }
3213	    else
3214	    {
3215		InstallWindowColormaps (0, tmp_win);
3216		SetFocus (tmp_win, eventp->xbutton.time);
3217		Scr->FocusRoot = FALSE;
3218	    }
3219	}
3220	break;
3221
3222    case F_DESTROY:
3223	if (DeferExecution(context, func, Scr->DestroyCursor))
3224	    return TRUE;
3225
3226	if (tmp_win->iconmgr || tmp_win->iswinbox || tmp_win->wspmgr
3227	    || (Scr->workSpaceMgr.occupyWindow
3228		&& tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
3229	    XBell(dpy, 0);
3230	    break;
3231	}
3232	XKillClient(dpy, tmp_win->w);
3233	if (ButtonPressed != -1) {
3234	    XEvent kev;
3235
3236	    XMaskEvent (dpy, ButtonReleaseMask, &kev);
3237	    if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root;
3238	    XPutBackEvent (dpy, &kev);
3239	}
3240	break;
3241
3242    case F_DELETE:
3243	if (DeferExecution(context, func, Scr->DestroyCursor))
3244	    return TRUE;
3245
3246	if (tmp_win->iconmgr) {		/* don't send ourself a message */
3247	    HideIconManager ();
3248	    break;
3249	}
3250	if (tmp_win->iswinbox || tmp_win->wspmgr
3251	    || (Scr->workSpaceMgr.occupyWindow
3252		&& tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
3253	    XBell (dpy, 0);
3254	    break;
3255	}
3256	if (tmp_win->protocols & DoesWmDeleteWindow) {
3257	    SendDeleteWindowMessage (tmp_win, LastTimestamp());
3258	    if (ButtonPressed != -1) {
3259		XEvent kev;
3260
3261		XMaskEvent (dpy, ButtonReleaseMask, &kev);
3262		if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root;
3263		XPutBackEvent (dpy, &kev);
3264	    }
3265	    break;
3266	}
3267	XBell (dpy, 0);
3268	break;
3269
3270    case F_DELETEORDESTROY:
3271	if (DeferExecution(context, func, Scr->DestroyCursor)) return TRUE;
3272
3273	if (tmp_win->iconmgr) {
3274	    HideIconManager ();
3275	    break;
3276	}
3277	if (tmp_win->iswinbox || tmp_win->wspmgr
3278	    || (Scr->workSpaceMgr.occupyWindow
3279		&& tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
3280	    XBell (dpy, 0);
3281	    break;
3282	}
3283	if (tmp_win->protocols & DoesWmDeleteWindow) {
3284	    SendDeleteWindowMessage (tmp_win, LastTimestamp());
3285	} else {
3286	    XKillClient(dpy, tmp_win->w);
3287	}
3288	if (ButtonPressed != -1) {
3289	    XEvent kev;
3290
3291	    XMaskEvent (dpy, ButtonReleaseMask, &kev);
3292	    if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root;
3293	    XPutBackEvent (dpy, &kev);
3294	}
3295	break;
3296
3297    case F_SAVEYOURSELF:
3298	if (DeferExecution (context, func, Scr->SelectCursor))
3299	  return TRUE;
3300
3301	if (tmp_win->protocols & DoesWmSaveYourself)
3302	  SendSaveYourselfMessage (tmp_win, LastTimestamp());
3303	else
3304	  XBell (dpy, 0);
3305	break;
3306
3307    case F_CIRCLEUP:
3308	XCirculateSubwindowsUp(dpy, Scr->Root);
3309	break;
3310
3311    case F_CIRCLEDOWN:
3312	XCirculateSubwindowsDown(dpy, Scr->Root);
3313	break;
3314
3315    case F_EXEC:
3316	PopDownMenu();
3317	if (!Scr->NoGrabServer) {
3318	    XUngrabServer (dpy);
3319	    XSync (dpy, 0);
3320	}
3321	XUngrabPointer (dpy, CurrentTime);
3322	XSync (dpy, 0);
3323	Execute(action);
3324	break;
3325
3326    case F_UNFOCUS:
3327	FocusOnRoot();
3328	break;
3329
3330    case F_CUT:
3331	strcpy(tmp, action);
3332	strcat(tmp, "\n");
3333	XStoreBytes(dpy, tmp, strlen(tmp));
3334	break;
3335
3336    case F_CUTFILE:
3337	ptr = XFetchBytes(dpy, &count);
3338	if (ptr) {
3339	    if (sscanf (ptr, "%s", tmp) == 1) {
3340		XFree (ptr);
3341		ptr = ExpandFilename(tmp);
3342		if (ptr) {
3343#ifdef VMS
3344		    fd = open (ptr, O_RDONLY, 0);
3345#else
3346		    fd = open (ptr, 0);
3347#endif
3348		    if (fd >= 0) {
3349			count = read (fd, buff, MAX_FILE_SIZE - 1);
3350			if (count > 0) XStoreBytes (dpy, buff, count);
3351			close(fd);
3352		    } else {
3353			fprintf (stderr,
3354				 "%s:  unable to open cut file \"%s\"\n",
3355				 ProgramName, tmp);
3356		    }
3357		    if (ptr != tmp) free (ptr);
3358		}
3359	    } else {
3360		XFree(ptr);
3361	    }
3362	} else {
3363	    fprintf(stderr, "%s:  cut buffer is empty\n", ProgramName);
3364	}
3365	break;
3366
3367    case F_WARPTOSCREEN:
3368	{
3369	    if (strcmp (action, WARPSCREEN_NEXT) == 0) {
3370		WarpToScreen (Scr->screen + 1, 1);
3371	    } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
3372		WarpToScreen (Scr->screen - 1, -1);
3373	    } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
3374		WarpToScreen (PreviousScreen, 0);
3375	    } else {
3376		WarpToScreen (atoi (action), 0);
3377	    }
3378	}
3379	break;
3380
3381    case F_COLORMAP:
3382	{
3383	    if (strcmp (action, COLORMAP_NEXT) == 0) {
3384		BumpWindowColormap (tmp_win, 1);
3385	    } else if (strcmp (action, COLORMAP_PREV) == 0) {
3386		BumpWindowColormap (tmp_win, -1);
3387	    } else {
3388		BumpWindowColormap (tmp_win, 0);
3389	    }
3390	}
3391	break;
3392
3393    case F_WARPTO:
3394	{
3395	    register TwmWindow *tw;
3396	    int len;
3397
3398	    len = strlen(action);
3399
3400#ifdef WARPTO_FROM_ICONMGR
3401		if (len == 0 && tmp_win && tmp_win->iconmgr)
3402		{
3403			printf ("curren iconmgr entry: %s", tmp_win->iconmgr->Current);
3404		}
3405#endif /* #ifdef WARPTO_FROM_ICONMGR */
3406	    for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
3407		if (!strncmp(action, tw->full_name, len)) break;
3408		if (match (action, tw->full_name)) break;
3409	    }
3410	    if (!tw) {
3411		for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
3412		    if (!strncmp(action, tw->class.res_name, len)) break;
3413		    if (match (action, tw->class.res_name)) break;
3414		}
3415		if (!tw) {
3416		    for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
3417			if (!strncmp(action, tw->class.res_class, len)) break;
3418			if (match (action, tw->class.res_class)) break;
3419		    }
3420		}
3421	    }
3422
3423	    if (tw) {
3424		if (Scr->WarpUnmapped || tw->mapped) {
3425		    if (!tw->mapped) DeIconify (tw);
3426		    WarpToWindow (tw, Scr->RaiseOnWarp);
3427		}
3428	    } else {
3429		XBell (dpy, 0);
3430	    }
3431	}
3432	break;
3433
3434    case F_WARPTOICONMGR:
3435	{
3436	    TwmWindow *tw;
3437	    int len;
3438	    Window raisewin = None, iconwin = None;
3439
3440	    len = strlen(action);
3441	    if (len == 0) {
3442		if (tmp_win && tmp_win->iconmanagerlist) {
3443		    raisewin = tmp_win->iconmanagerlist->iconmgr->twm_win->frame;
3444		    iconwin = tmp_win->iconmanagerlist->icon;
3445		} else if (Scr->iconmgr->active) {
3446		    raisewin = Scr->iconmgr->twm_win->frame;
3447		    iconwin = Scr->iconmgr->active->w;
3448		}
3449	    } else {
3450		for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
3451		    if (strncmp (action, tw->icon_name, len) == 0) {
3452			if (tw->iconmanagerlist &&
3453			    tw->iconmanagerlist->iconmgr->twm_win->mapped) {
3454			    raisewin = tw->iconmanagerlist->iconmgr->twm_win->frame;
3455			    break;
3456			}
3457		    }
3458		}
3459	    }
3460
3461	    if (raisewin) {
3462		RaiseFrame(raisewin);
3463		XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
3464	    } else {
3465		XBell (dpy, 0);
3466	    }
3467	}
3468	break;
3469
3470    case F_RING:  /* Taken from vtwm version 5.3 */
3471	if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE;
3472	if ( tmp_win->ring.next || tmp_win->ring.prev ) {
3473	    /* It's in the ring, let's take it out. */
3474	   TwmWindow *prev = tmp_win->ring.prev, *next = tmp_win->ring.next;
3475
3476	    /*
3477	    * 1. Unlink window
3478	    * 2. If window was only thing in ring, null out ring
3479	    * 3. If window was ring leader, set to next (or null)
3480	    */
3481	    if (prev) prev->ring.next = next;
3482	    if (next) next->ring.prev = prev;
3483	    if (Scr->Ring == tmp_win)
3484		Scr->Ring = (next != tmp_win ? next : (TwmWindow *) NULL);
3485
3486	    if (!Scr->Ring || Scr->RingLeader == tmp_win)
3487		Scr->RingLeader = Scr->Ring;
3488	    tmp_win->ring.next = tmp_win->ring.prev = NULL;
3489	} else {
3490	    /* Not in the ring, so put it in. */
3491	    if (Scr->Ring) {
3492		tmp_win->ring.next = Scr->Ring->ring.next;
3493		if (Scr->Ring->ring.next->ring.prev)
3494		    Scr->Ring->ring.next->ring.prev = tmp_win;
3495		Scr->Ring->ring.next = tmp_win;
3496		tmp_win->ring.prev = Scr->Ring;
3497	    } else {
3498		tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
3499	    }
3500	}
3501	/*tmp_win->ring.cursor_valid = False;*/
3502	break;
3503
3504    case F_WARPRING:
3505	switch (((char *)action)[0]) {
3506	  case 'n':
3507	    WarpAlongRing (&eventp->xbutton, True);
3508	    break;
3509	  case 'p':
3510	    WarpAlongRing (&eventp->xbutton, False);
3511	    break;
3512	  default:
3513	    XBell (dpy, 0);
3514	    break;
3515	}
3516	break;
3517
3518    case F_FILE:
3519	action = ExpandFilename(action);
3520#ifdef VMS
3521	fd = open (action, O_RDONLY, 0);
3522#else
3523	fd = open(action, 0);
3524#endif
3525	if (fd >= 0)
3526	{
3527	    count = read(fd, buff, MAX_FILE_SIZE - 1);
3528	    if (count > 0)
3529		XStoreBytes(dpy, buff, count);
3530
3531	    close(fd);
3532	}
3533	else
3534	{
3535	    fprintf (stderr, "%s:  unable to open file \"%s\"\n",
3536		     ProgramName, (char *)action);
3537	}
3538	free(action);
3539	break;
3540
3541    case F_REFRESH:
3542	{
3543	    XSetWindowAttributes attributes;
3544	    unsigned long valuemask;
3545
3546	    valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
3547	    attributes.background_pixel = Scr->Black;
3548	    attributes.backing_store = NotUseful;
3549	    attributes.save_under = False;
3550	    w = XCreateWindow (dpy, Scr->Root, 0, 0,
3551			       (unsigned int) Scr->rootw,
3552			       (unsigned int) Scr->rooth,
3553			       (unsigned int) 0,
3554			       CopyFromParent, (unsigned int) CopyFromParent,
3555			       (Visual *) CopyFromParent, valuemask,
3556			       &attributes);
3557	    XMapWindow (dpy, w);
3558	    XDestroyWindow (dpy, w);
3559	    XFlush (dpy);
3560	}
3561	break;
3562
3563    case F_OCCUPY:
3564	if (DeferExecution(context, func, Scr->SelectCursor))
3565	    return TRUE;
3566	Occupy (tmp_win);
3567	break;
3568
3569    case F_OCCUPYALL:
3570	if (DeferExecution(context, func, Scr->SelectCursor))
3571	    return TRUE;
3572	OccupyAll (tmp_win);
3573	break;
3574
3575    case F_GOTOWORKSPACE:
3576	GotoWorkSpaceByName (Scr->currentvs, action);
3577	break;
3578
3579    case F_PREVWORKSPACE:
3580	GotoPrevWorkSpace (Scr->currentvs);
3581	break;
3582
3583    case F_NEXTWORKSPACE:
3584	GotoNextWorkSpace (Scr->currentvs);
3585	break;
3586
3587    case F_RIGHTWORKSPACE:
3588	GotoRightWorkSpace (Scr->currentvs);
3589	break;
3590
3591    case F_LEFTWORKSPACE:
3592	GotoLeftWorkSpace (Scr->currentvs);
3593	break;
3594
3595    case F_UPWORKSPACE:
3596	GotoUpWorkSpace (Scr->currentvs);
3597	break;
3598
3599    case F_DOWNWORKSPACE:
3600	GotoDownWorkSpace (Scr->currentvs);
3601	break;
3602
3603    case F_MENU:
3604	if (action && ! strncmp (action, "WGOTO : ", 8)) {
3605	    GotoWorkSpaceByName (/* XXXXX */ Scr->currentvs,
3606		((char *)action) + 8);
3607	}
3608	else {
3609	    MenuItem *item;
3610
3611	    item = ActiveItem;
3612	    while (item && item->sub) {
3613		if (!item->sub->defaultitem) break;
3614		if (item->sub->defaultitem->func != F_MENU) break;
3615		item = item->sub->defaultitem;
3616	    }
3617	    if (item && item->sub && item->sub->defaultitem) {
3618		ExecuteFunction (item->sub->defaultitem->func,
3619				 item->sub->defaultitem->action,
3620				 w, tmp_win, eventp, context, pulldown);
3621	    }
3622	}
3623	break;
3624
3625    case F_WINREFRESH:
3626	if (DeferExecution(context, func, Scr->SelectCursor))
3627	    return TRUE;
3628
3629	if (context == C_ICON && tmp_win->icon && tmp_win->icon->w)
3630	    w = XCreateSimpleWindow(dpy, tmp_win->icon->w,
3631		0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
3632	else
3633	    w = XCreateSimpleWindow(dpy, tmp_win->frame,
3634		0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
3635
3636	XMapWindow(dpy, w);
3637	XDestroyWindow(dpy, w);
3638	XFlush(dpy);
3639	break;
3640
3641    case F_ADOPTWINDOW:
3642	adoptWindow ();
3643	break;
3644
3645    case F_TRACE:
3646	DebugTrace (action);
3647	break;
3648
3649    case F_CHANGESIZE:
3650	ChangeSize (action, tmp_win);
3651	break;
3652
3653    case F_QUIT:
3654	Done(0);
3655	break;
3656    }
3657
3658    if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
3659    return do_next_action;
3660}
3661
3662
3663
3664/***********************************************************************
3665 *
3666 *  Procedure:
3667 *	DeferExecution - defer the execution of a function to the
3668 *	    next button press if the context is C_ROOT
3669 *
3670 *  Inputs:
3671 *	context	- the context in which the mouse button was pressed
3672 *	func	- the function to defer
3673 *	cursor	- the cursor to display while waiting
3674 *
3675 ***********************************************************************
3676 */
3677
3678int DeferExecution(int context, int func, Cursor cursor)
3679{
3680    if ((context == C_ROOT) || (context == C_ALTERNATE))
3681    {
3682	LastCursor = cursor;
3683	if (func == F_ADOPTWINDOW) {
3684	    XGrabPointer(dpy, Scr->Root, True,
3685		ButtonPressMask | ButtonReleaseMask,
3686		GrabModeAsync, GrabModeAsync,
3687		None, cursor, CurrentTime);
3688	} else {
3689	    XGrabPointer(dpy, Scr->Root, True,
3690		ButtonPressMask | ButtonReleaseMask,
3691		GrabModeAsync, GrabModeAsync,
3692		Scr->Root, cursor, CurrentTime);
3693	}
3694	RootFunction = func;
3695
3696	return (TRUE);
3697    }
3698
3699    return (FALSE);
3700}
3701
3702
3703
3704/***********************************************************************
3705 *
3706 *  Procedure:
3707 *	ReGrab - regrab the pointer with the LastCursor;
3708 *
3709 ***********************************************************************
3710 */
3711
3712void ReGrab(void)
3713{
3714    XGrabPointer(dpy, Scr->Root, True,
3715	ButtonPressMask | ButtonReleaseMask,
3716	GrabModeAsync, GrabModeAsync,
3717	Scr->Root, LastCursor, CurrentTime);
3718}
3719
3720
3721
3722/***********************************************************************
3723 *
3724 *  Procedure:
3725 *	NeedToDefer - checks each function in the list to see if it
3726 *		is one that needs to be defered.
3727 *
3728 *  Inputs:
3729 *	root	- the menu root to check
3730 *
3731 ***********************************************************************
3732 */
3733
3734int NeedToDefer(MenuRoot *root)
3735{
3736    MenuItem *mitem;
3737
3738    for (mitem = root->first; mitem != NULL; mitem = mitem->next)
3739    {
3740	switch (mitem->func)
3741	{
3742	case F_IDENTIFY:
3743	case F_RESIZE:
3744	case F_MOVE:
3745	case F_FORCEMOVE:
3746	case F_DEICONIFY:
3747	case F_ICONIFY:
3748	case F_RAISELOWER:
3749	case F_RAISE:
3750	case F_LOWER:
3751	case F_FOCUS:
3752	case F_DESTROY:
3753	case F_WINREFRESH:
3754	case F_ZOOM:
3755	case F_FULLZOOM:
3756	case F_HORIZOOM:
3757        case F_RIGHTZOOM:
3758        case F_LEFTZOOM:
3759        case F_TOPZOOM:
3760        case F_BOTTOMZOOM:
3761        case F_SQUEEZE:
3762	case F_AUTORAISE:
3763	case F_AUTOLOWER:
3764	    return TRUE;
3765	}
3766    }
3767    return FALSE;
3768}
3769
3770
3771
3772/***********************************************************************
3773 *
3774 *  Procedure:
3775 *	Execute - execute the string by /bin/sh
3776 *
3777 *  Inputs:
3778 *	s	- the string containing the command
3779 *
3780 ***********************************************************************
3781 */
3782
3783void Execute(char *s)
3784{
3785#ifdef VMS
3786    createProcess(s);
3787#else
3788    static char buf[256];
3789    char *ds = DisplayString (dpy);
3790    char *colon, *dot1;
3791    char oldDisplay[256];
3792    char *doisplay;
3793    int restorevar = 0;
3794    Bool replace;
3795    char *subs, *name, *news;
3796    int len;
3797
3798    oldDisplay[0] = '\0';
3799    doisplay=getenv("DISPLAY");
3800    if (doisplay)
3801	strcpy (oldDisplay, doisplay);
3802
3803    /*
3804     * Build a display string using the current screen number, so that
3805     * X programs which get fired up from a menu come up on the screen
3806     * that they were invoked from, unless specifically overridden on
3807     * their command line.
3808     */
3809    colon = strrchr (ds, ':');
3810    if (colon) {			/* if host[:]:dpy */
3811	strcpy (buf, "DISPLAY=");
3812	strcat (buf, ds);
3813	colon = buf + 8 + (colon - ds);	/* use version in buf */
3814	dot1 = strchr (colon, '.');	/* first period after colon */
3815	if (!dot1) dot1 = colon + strlen (colon);  /* if not there, append */
3816	(void) sprintf (dot1, ".%d", Scr->screen);
3817	putenv (buf);
3818	restorevar = 1;
3819    }
3820    replace = False;
3821    subs = strstr (s, "$currentworkspace");
3822    name = GetCurrentWorkSpaceName (Scr->currentvs);
3823    if (subs && name) {
3824	len = strlen (s) - strlen ("$currentworkspace") + strlen (name);
3825	news = (char*) malloc (len + 1);
3826	*subs = '\0';
3827	strcpy (news, s);
3828	*subs = '$';
3829	strcat (news, name);
3830	subs += strlen ("$currentworkspace");
3831	strcat (news, subs);
3832	s = news;
3833	replace = True;
3834    }
3835    subs = strstr (s, "$redirect");
3836    if (subs) {
3837	if (captive) {
3838	    name = (char*) malloc (21 + strlen (captivename) + 1);
3839	    sprintf (name, "-xrm 'ctwm.redirect:%s'", captivename);
3840	} else {
3841	    name = (char*) malloc (1);
3842	    *name = '\0';
3843	}
3844	len = strlen (s) - strlen ("$redirect") + strlen (name);
3845	news = (char*) malloc (len + 1);
3846	*subs = '\0';
3847	strcpy (news, s);
3848	*subs = '$';
3849	strcat (news, name);
3850	subs += strlen ("$redirect");
3851	strcat (news, subs);
3852	s = news;
3853	free (name);
3854	replace = True;
3855    }
3856#ifdef USE_SIGNALS
3857  {
3858    SigProc	sig;
3859
3860    sig = signal (SIGALRM, SIG_IGN);
3861    (void) system (s);
3862    signal (SIGALRM, sig);
3863  }
3864#else  /* USE_SIGNALS */
3865    (void) system (s);
3866#endif  /* USE_SIGNALS */
3867
3868    if (restorevar) {		/* why bother? */
3869	(void) sprintf (buf, "DISPLAY=%s", oldDisplay);
3870	putenv (buf);
3871    }
3872    if (replace) free (s);
3873#endif
3874}
3875
3876
3877
3878Window lowerontop = -1;
3879
3880void PlaceTransients (TwmWindow *tmp_win, int where)
3881{
3882    int	sp, sc;
3883    TwmWindow *t;
3884    XWindowChanges xwc;
3885    xwc.stack_mode = where;
3886
3887    sp = tmp_win->frame_width * tmp_win->frame_height;
3888    for (t = Scr->FirstWindow; t != NULL; t = t->next) {
3889	if (t != tmp_win &&
3890	    ((t->transient && t->transientfor == tmp_win->w) ||
3891	     t->group == tmp_win->w)) {
3892	    if (t->frame) {
3893		sc = t->frame_width * t->frame_height;
3894		if (sc < ((sp * Scr->TransientOnTop) / 100)) {
3895		    xwc.sibling = tmp_win->frame;
3896		    XConfigureWindow(dpy, t->frame, CWSibling | CWStackMode, &xwc);
3897		    if (lowerontop == t->frame) {
3898			lowerontop = (Window)-1;
3899		    }
3900		}
3901	    }
3902	}
3903    }
3904}
3905
3906#include <assert.h>
3907
3908void PlaceOntop (int ontop, int where)
3909{
3910    TwmWindow *t;
3911    XWindowChanges xwc;
3912    xwc.stack_mode = where;
3913
3914    lowerontop = (Window)-1;
3915
3916    for (t = Scr->FirstWindow; t != NULL; t = t->next) {
3917	if (t->ontoppriority > ontop) {
3918	    XConfigureWindow(dpy, t->frame, CWStackMode, &xwc);
3919	    PlaceTransients(t, Above);
3920	    if (lowerontop == (Window)-1) {
3921		lowerontop = t->frame;
3922	    }
3923	}
3924    }
3925}
3926
3927void MapRaised (TwmWindow *tmp_win)
3928{
3929    XMapWindow(dpy, tmp_win->frame);
3930    RaiseWindow(tmp_win);
3931}
3932
3933void RaiseWindow (TwmWindow *tmp_win)
3934{
3935    XWindowChanges xwc;
3936    int xwcm;
3937
3938    if (tmp_win->ontoppriority == ONTOP_MAX) {
3939	XRaiseWindow(dpy, tmp_win->frame);
3940	if (lowerontop == (Window)-1) {
3941	    lowerontop = tmp_win->frame;
3942	} else if (lowerontop == tmp_win->frame) {
3943	    lowerontop = (Window)-1;
3944	}
3945    } else {
3946	if (lowerontop == (Window)-1) {
3947	    PlaceOntop(tmp_win->ontoppriority, Above);
3948	}
3949	xwcm = CWStackMode;
3950	if (lowerontop != (Window)-1) {
3951	    xwc.stack_mode = Below;
3952	    xwc.sibling = lowerontop;
3953	    xwcm |= CWSibling;
3954	} else {
3955	    xwc.stack_mode = Above;
3956	}
3957	XConfigureWindow(dpy, tmp_win->frame, xwcm, &xwc);
3958    }
3959    PlaceTransients(tmp_win, Above);
3960}
3961
3962void RaiseLower (TwmWindow *tmp_win)
3963{
3964    XWindowChanges xwc;
3965
3966    PlaceOntop(tmp_win->ontoppriority, Below);
3967    PlaceTransients(tmp_win, Below);
3968    lowerontop = (Window)-1;
3969    xwc.stack_mode = Opposite;
3970    XConfigureWindow(dpy, tmp_win->frame, CWStackMode, &xwc);
3971    PlaceOntop(tmp_win->ontoppriority, Above);
3972    PlaceTransients(tmp_win, Above);
3973}
3974
3975void RaiseLowerFrame (Window frame, int ontop)
3976{
3977    XWindowChanges xwc;
3978
3979    PlaceOntop(ontop, Below);
3980    lowerontop = (Window)-1;
3981    xwc.stack_mode = Opposite;
3982    XConfigureWindow(dpy, frame, CWStackMode, &xwc);
3983    PlaceOntop(ontop, Above);
3984}
3985
3986void LowerWindow (TwmWindow *tmp_win)
3987{
3988    XLowerWindow(dpy, tmp_win->frame);
3989    if (tmp_win->frame == lowerontop) {
3990	lowerontop = (Window)-1;
3991    }
3992    PlaceTransients(tmp_win, Above);
3993}
3994
3995void RaiseFrame (Window frame)
3996{
3997    TwmWindow *tmp_win;
3998
3999    tmp_win = GetTwmWindow(frame);
4000
4001    if (tmp_win != NULL) {
4002	RaiseWindow(tmp_win);
4003    } else {
4004	XRaiseWindow(dpy, frame);
4005    }
4006}
4007
4008/***********************************************************************
4009 *
4010 *  Procedure:
4011 *	FocusOnRoot - put input focus on the root window
4012 *
4013 ***********************************************************************
4014 */
4015
4016void FocusOnRoot(void)
4017{
4018    SetFocus ((TwmWindow *) NULL, LastTimestamp());
4019    InstallColormaps(0, &Scr->RootColormaps);
4020    if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE;
4021}
4022
4023static void ReMapOne(TwmWindow *t, TwmWindow *leader)
4024{
4025    if (t->icon_on)
4026	Zoom(t->icon->w, t->frame);
4027    else if (leader->icon)
4028	Zoom(leader->icon->w, t->frame);
4029
4030    if (!t->squeezed)
4031	XMapWindow(dpy, t->w);
4032    t->mapped = TRUE;
4033    if (Scr->Root != Scr->CaptiveRoot)	/* XXX dubious test */
4034	XReparentWindow (dpy, t->frame, Scr->Root, t->frame_x, t->frame_y);
4035    if (Scr->NoRaiseDeicon)
4036	XMapWindow(dpy, t->frame);
4037    else
4038	MapRaised(t);
4039    SetMapStateProp(t, NormalState);
4040
4041    if (t->icon && t->icon->w) {
4042	XUnmapWindow(dpy, t->icon->w);
4043	IconDown(t);
4044	if (Scr->ShrinkIconTitles)
4045	    t->icon->title_shrunk = True;
4046    }
4047    if (t->iconmanagerlist) {
4048	WList *wl;
4049
4050	for (wl = t->iconmanagerlist; wl != NULL; wl = wl->nextv)
4051	    XUnmapWindow(dpy, wl->icon);
4052    }
4053    t->isicon = FALSE;
4054    t->icon_on = FALSE;
4055    WMapDeIconify(t);
4056}
4057
4058static void ReMapTransients(TwmWindow *tmp_win)
4059{
4060    TwmWindow *t;
4061
4062    /* find t such that it is a transient or group member window */
4063    for (t = Scr->FirstWindow; t != NULL; t = t->next) {
4064	if (t != tmp_win &&
4065		((t->transient && t->transientfor == tmp_win->w) ||
4066		 (t->group == tmp_win->w && t->isicon))) {
4067	    ReMapOne(t, tmp_win);
4068	}
4069    }
4070}
4071
4072void DeIconify(TwmWindow *tmp_win)
4073{
4074    TwmWindow *t = tmp_win;
4075    int isicon = FALSE;
4076
4077    /* de-iconify the main window */
4078    if (Scr->WindowMask)
4079	XRaiseWindow (dpy, Scr->WindowMask);
4080    if (tmp_win && tmp_win->isicon)
4081    {
4082	isicon = TRUE;
4083	if (tmp_win->icon_on && tmp_win->icon && tmp_win->icon->w)
4084	    Zoom(tmp_win->icon->w, tmp_win->frame);
4085	else if (tmp_win->group != (Window) 0)
4086	{
4087	    t = GetTwmWindow(tmp_win->group);
4088	    if (t && t->icon_on && t->icon && t->icon->w)
4089	    {
4090		Zoom(t->icon->w, tmp_win->frame);
4091	    }
4092	}
4093    }
4094
4095    ReMapOne(tmp_win, t);
4096
4097    if (isicon &&
4098	(Scr->WarpCursor ||
4099	 LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)))
4100      WarpToWindow (tmp_win, 0);
4101
4102    /* now de-iconify and window group transients */
4103    ReMapTransients(tmp_win);
4104
4105    if (! Scr->WindowMask && Scr->DeIconifyFunction.func != 0) {
4106	char *action;
4107	XEvent event;
4108
4109	action = Scr->DeIconifyFunction.item ?
4110		Scr->DeIconifyFunction.item->action : NULL;
4111	ExecuteFunction (Scr->DeIconifyFunction.func, action,
4112			   (Window) 0, tmp_win, &event, C_ROOT, FALSE);
4113    }
4114    XSync (dpy, 0);
4115}
4116
4117
4118static void UnmapTransients(TwmWindow *tmp_win, int iconify, unsigned long eventMask)
4119{
4120    TwmWindow *t;
4121
4122    for (t = Scr->FirstWindow; t != NULL; t = t->next) {
4123	if (t != tmp_win &&
4124		((t->transient && t->transientfor == tmp_win->w) ||
4125		 t->group == tmp_win->w)) {
4126	    if (iconify && tmp_win->icon) {
4127		if (t->icon_on)
4128		    Zoom(t->icon->w, tmp_win->icon->w);
4129		else
4130		    Zoom(t->frame, tmp_win->icon->w);
4131	    }
4132
4133	    /*
4134	     * Prevent the receipt of an UnmapNotify, since that would
4135	     * cause a transition to the Withdrawn state.
4136	     */
4137	    t->mapped = FALSE;
4138	    XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
4139	    XUnmapWindow(dpy, t->w);
4140	    XUnmapWindow(dpy, t->frame);
4141	    XSelectInput(dpy, t->w, eventMask);
4142	    if (t->icon && t->icon->w) XUnmapWindow(dpy, t->icon->w);
4143	    SetMapStateProp(t, IconicState);
4144	    if (t == Scr->Focus) {
4145		SetFocus ((TwmWindow *) NULL, LastTimestamp());
4146		if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE;
4147	    }
4148	    if (t->iconmanagerlist)
4149		XMapWindow(dpy, t->iconmanagerlist->icon);
4150	    t->isicon = TRUE;
4151	    t->icon_on = FALSE;
4152	    WMapIconify (t);
4153	}
4154    }
4155}
4156
4157void Iconify(TwmWindow *tmp_win, int def_x, int def_y)
4158{
4159    TwmWindow *t;
4160    int iconify;
4161    XWindowAttributes winattrs;
4162    unsigned long eventMask;
4163    WList *wl;
4164    Window leader = (Window)-1;
4165    Window blanket = (Window)-1;
4166
4167    iconify = (!tmp_win->iconify_by_unmapping);
4168    t = (TwmWindow*) 0;
4169    if (tmp_win->transient) {
4170	leader = tmp_win->transientfor;
4171	t = GetTwmWindow(leader);
4172    }
4173    else
4174    if ((leader = tmp_win->group) != 0 && leader != tmp_win->w) {
4175	t = GetTwmWindow(leader);
4176    }
4177    if (t && t->icon_on) iconify = False;
4178    if (iconify)
4179    {
4180	if (!tmp_win->icon || !tmp_win->icon->w)
4181	    CreateIconWindow(tmp_win, def_x, def_y);
4182	else
4183	    IconUp(tmp_win);
4184	if (visible (tmp_win)) {
4185	    if (Scr->WindowMask) {
4186		XRaiseWindow (dpy, Scr->WindowMask);
4187		XMapWindow(dpy, tmp_win->icon->w);
4188	    }
4189	    else
4190		XMapRaised(dpy, tmp_win->icon->w);
4191	}
4192    }
4193    if (tmp_win->iconmanagerlist) {
4194      for (wl = tmp_win->iconmanagerlist; wl != NULL; wl = wl->nextv) {
4195	XMapWindow(dpy, wl->icon);
4196      }
4197    }
4198
4199    XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
4200    eventMask = winattrs.your_event_mask;
4201
4202    /* iconify transients and window group first */
4203    UnmapTransients(tmp_win, iconify, eventMask);
4204
4205    if (iconify) Zoom(tmp_win->frame, tmp_win->icon->w);
4206
4207    /*
4208     * Prevent the receipt of an UnmapNotify, since that would
4209     * cause a transition to the Withdrawn state.
4210     */
4211    tmp_win->mapped = FALSE;
4212
4213    if ((Scr->IconifyStyle != ICONIFY_NORMAL) && !Scr->WindowMask) {
4214	XSetWindowAttributes attr;
4215	XGetWindowAttributes(dpy, tmp_win->frame, &winattrs);
4216	attr.backing_store = NotUseful;
4217	attr.save_under    = False;
4218	blanket = XCreateWindow (dpy, Scr->Root, winattrs.x, winattrs.y,
4219				 winattrs.width, winattrs.height, (unsigned int) 0,
4220				 CopyFromParent, (unsigned int) CopyFromParent,
4221				 (Visual *) CopyFromParent, CWBackingStore | CWSaveUnder, &attr);
4222	XMapWindow (dpy, blanket);
4223    }
4224    XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
4225    XUnmapWindow(dpy, tmp_win->w);
4226    XUnmapWindow(dpy, tmp_win->frame);
4227    XSelectInput(dpy, tmp_win->w, eventMask);
4228    SetMapStateProp(tmp_win, IconicState);
4229
4230    if ((Scr->IconifyStyle != ICONIFY_NORMAL) && !Scr->WindowMask) {
4231      switch (Scr->IconifyStyle) {
4232        case ICONIFY_MOSAIC:  MosaicFade    (tmp_win, blanket); break;
4233        case ICONIFY_ZOOMIN:  ZoomInWindow  (tmp_win, blanket); break;
4234        case ICONIFY_ZOOMOUT: ZoomOutWindow (tmp_win, blanket); break;
4235	case ICONIFY_SWEEP:   SweepWindow   (tmp_win, blanket); break;
4236      }
4237      XDestroyWindow (dpy, blanket);
4238    }
4239    if (tmp_win == Scr->Focus) {
4240	SetFocus ((TwmWindow *) NULL, LastTimestamp());
4241	if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE;
4242    }
4243    tmp_win->isicon = TRUE;
4244    tmp_win->icon_on = iconify ? TRUE : FALSE;
4245    WMapIconify (tmp_win);
4246    if (! Scr->WindowMask && Scr->IconifyFunction.func != 0) {
4247	char *action;
4248	XEvent event;
4249
4250	action = Scr->IconifyFunction.item ? Scr->IconifyFunction.item->action : NULL;
4251	ExecuteFunction (Scr->IconifyFunction.func, action,
4252			   (Window) 0, tmp_win, &event, C_ROOT, FALSE);
4253    }
4254    XSync (dpy, 0);
4255}
4256
4257void AutoSqueeze (TwmWindow *tmp_win)
4258{
4259    if (tmp_win->iconmgr) return;
4260    if (Scr->RaiseWhenAutoUnSqueeze && tmp_win->squeezed) XRaiseWindow (dpy, tmp_win->frame);
4261    Squeeze (tmp_win);
4262}
4263
4264void Squeeze (TwmWindow *tmp_win)
4265{
4266    long fx, fy, savex, savey;
4267    int  neww, newh, south;
4268    int	 grav = ((tmp_win->hints.flags & PWinGravity)
4269		      ? tmp_win->hints.win_gravity : NorthWestGravity);
4270    XWindowAttributes winattrs;
4271    unsigned long eventMask;
4272#ifdef GNOME
4273    unsigned char	*prop;
4274    unsigned long	nitems, bytesafter;
4275    Atom		actual_type;
4276    int			actual_format;
4277    long		gwkspc;
4278#endif /* GNOME */
4279    if (tmp_win->squeezed) {
4280	tmp_win->squeezed = False;
4281#ifdef GNOME
4282 	XGetWindowAttributes (dpy, tmp_win->w, &winattrs);
4283	eventMask = winattrs.your_event_mask;
4284	XSelectInput (dpy, tmp_win->w, eventMask & ~PropertyChangeMask);
4285 	if (XGetWindowProperty (dpy, tmp_win->w, _XA_WIN_STATE, 0L, 32, False,
4286			       XA_CARDINAL, &actual_type, &actual_format,
4287			       &nitems, &bytesafter, &prop)
4288	    != Success || nitems == 0) {
4289	    gwkspc = 0;
4290	} else {
4291	    gwkspc = (int)*prop;
4292	    XFree ((char *)prop);
4293	}
4294 	gwkspc &= ~WIN_STATE_SHADED;
4295 	XChangeProperty (dpy, tmp_win->w, _XA_WIN_STATE, XA_CARDINAL, 32,
4296			 PropModeReplace, (unsigned char *)&gwkspc, 1);
4297	XSelectInput(dpy, tmp_win->w, eventMask);
4298#endif /* GNOME */
4299	if (!tmp_win->isicon) XMapWindow (dpy, tmp_win->w);
4300	SetupWindow (tmp_win, tmp_win->actual_frame_x, tmp_win->actual_frame_y,
4301		     tmp_win->actual_frame_width, tmp_win->actual_frame_height, -1);
4302	ReMapTransients(tmp_win);
4303	return;
4304    }
4305
4306    newh = tmp_win->title_height + 2 * tmp_win->frame_bw3D;
4307    if (newh < 3) { XBell (dpy, 0); return; }
4308    switch (grav) {
4309	case SouthWestGravity :
4310	case SouthGravity :
4311	case SouthEastGravity :
4312	    south = True; break;
4313	default :
4314	    south = False; break;
4315    }
4316    if (tmp_win->title_height && !tmp_win->AlwaysSqueezeToGravity) south = False;
4317
4318    tmp_win->squeezed = True;
4319    tmp_win->actual_frame_width  = tmp_win->frame_width;
4320    tmp_win->actual_frame_height = tmp_win->frame_height;
4321    savex = fx = tmp_win->frame_x;
4322    savey = fy = tmp_win->frame_y;
4323    neww  = tmp_win->actual_frame_width;
4324    if (south) fy += tmp_win->frame_height - newh;
4325    if (tmp_win->squeeze_info) {
4326	fx  += tmp_win->title_x - tmp_win->frame_bw3D;
4327	neww = tmp_win->title_width + 2 * (tmp_win->frame_bw + tmp_win->frame_bw3D);
4328    }
4329    XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
4330    eventMask = winattrs.your_event_mask;
4331#ifdef GNOME
4332    XSelectInput (dpy, tmp_win->w, eventMask & ~(StructureNotifyMask | PropertyChangeMask));
4333    if (XGetWindowProperty (dpy, tmp_win->w, _XA_WIN_STATE, 0L, 32, False,
4334			    XA_CARDINAL, &actual_type, &actual_format, &nitems,
4335			    &bytesafter, &prop)
4336	!= Success || nitems == 0) {
4337	gwkspc = 0;
4338    } else {
4339	gwkspc = (int)*prop;
4340	XFree ((char *)prop);
4341    }
4342    gwkspc |= WIN_STATE_SHADED;
4343    XChangeProperty (dpy, tmp_win->w, _XA_WIN_STATE, XA_CARDINAL, 32,
4344		     PropModeReplace, (unsigned char *)&gwkspc, 1);
4345#else
4346    XSelectInput (dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
4347#endif /* GNOME */
4348    XUnmapWindow(dpy, tmp_win->w);
4349    XSelectInput(dpy, tmp_win->w, eventMask);
4350
4351    if (fx + neww >= Scr->rootw - Scr->BorderRight)
4352        fx = Scr->rootw - Scr->BorderRight - neww;
4353    if (fy + newh >= Scr->rooth - Scr->BorderBottom)
4354        fy = Scr->rooth - Scr->BorderBottom - newh;
4355    SetupWindow (tmp_win, fx, fy, neww, newh, -1);
4356    tmp_win->actual_frame_x = savex;
4357    tmp_win->actual_frame_y = savey;
4358
4359    /* Now make the group members disappear */
4360    UnmapTransients(tmp_win, 0, eventMask);
4361}
4362
4363static void Identify (TwmWindow *t)
4364{
4365    int i, n, twidth, width, height;
4366    int x, y;
4367    unsigned int wwidth, wheight, bw, depth;
4368    Window junk;
4369    int px, py, dummy;
4370    unsigned udummy;
4371    unsigned char	*prop;
4372    unsigned long	nitems, bytesafter;
4373    Atom		actual_type;
4374    int			actual_format;
4375    XRectangle inc_rect;
4376    XRectangle logical_rect;
4377    Bool first = True;
4378
4379    n = 0;
4380    (void) sprintf(Info[n++], "Twm version:  %s", Version);
4381    (void) sprintf(Info[n], "Compile time options :");
4382#ifdef XPM
4383    (void) strcat (Info[n], " XPM");
4384    first = False;
4385#endif
4386#ifdef IMCONV
4387    if (!first) (void) strcat(Info[n], ", ");
4388    (void) strcat (Info[n], "IMCONV");
4389    first = False;
4390#endif
4391#ifdef USEM4
4392    if (!first) (void) strcat(Info[n], ", ");
4393    (void) strcat (Info[n], "USEM4");
4394    first = False;
4395#endif
4396#ifdef GNOME
4397    if (!first) (void) strcat(Info[n], ", ");
4398    (void) strcat (Info[n], "GNOME");
4399    first = False;
4400#endif
4401#ifdef SOUNDS
4402    if (!first) (void) strcat(Info[n], ", ");
4403    (void) strcat (Info[n], "SOUNDS");
4404    first = False;
4405#endif
4406#ifdef DEBUG
4407    if (!first) (void) strcat(Info[n], ", ");
4408    (void) strcat (Info[n], "debug");
4409    first = False;
4410#endif
4411    if (!first) (void) strcat(Info[n], ", ");
4412    (void) strcat (Info[n], "I18N");
4413    first = False;
4414    n++;
4415    Info[n++][0] = '\0';
4416
4417    if (t) {
4418	XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
4419		      &wwidth, &wheight, &bw, &depth);
4420	(void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
4421				      &x, &y, &junk);
4422	(void) sprintf(Info[n++], "Name               = \"%s\"", t->full_name);
4423	(void) sprintf(Info[n++], "Class.res_name     = \"%s\"", t->class.res_name);
4424	(void) sprintf(Info[n++], "Class.res_class    = \"%s\"", t->class.res_class);
4425	Info[n++][0] = '\0';
4426	(void) sprintf(Info[n++], "Geometry/root (UL)  = %dx%d+%d+%d (Inner: %dx%d+%d+%d)",
4427		       wwidth + 2 * (bw + t->frame_bw3D),
4428		       wheight + 2 * (bw + t->frame_bw3D) + t->title_height,
4429		       x - (bw + t->frame_bw3D),
4430		       y - (bw + t->frame_bw3D + t->title_height),
4431		       wwidth, wheight, x, y);
4432	(void) sprintf(Info[n++], "Geometry/root (LR)  = %dx%d-%d-%d (Inner: %dx%d-%d-%d)",
4433		       wwidth + 2 * (bw + t->frame_bw3D),
4434		       wheight + 2 * (bw + t->frame_bw3D) + t->title_height,
4435		       Scr->rootw - (x + wwidth + bw + t->frame_bw3D),
4436		       Scr->rooth - (y + wheight + bw + t->frame_bw3D),
4437		       wwidth, wheight,
4438		       Scr->rootw - (x + wwidth), Scr->rooth - (y + wheight));
4439	(void) sprintf(Info[n++], "Border width       = %d", bw);
4440	(void) sprintf(Info[n++], "3D border width    = %d", t->frame_bw3D);
4441	(void) sprintf(Info[n++], "Depth              = %d", depth);
4442
4443	if (XGetWindowProperty (dpy, t->w, _XA_WM_CLIENT_MACHINE, 0L, 64, False,
4444				XA_STRING, &actual_type, &actual_format, &nitems,
4445				&bytesafter, &prop) == Success) {
4446	    if (nitems && prop) {
4447		(void) sprintf(Info[n++], "Client machine     = %s", (char*)prop);
4448		XFree ((char *) prop);
4449	    }
4450	}
4451	Info[n++][0] = '\0';
4452    }
4453
4454    (void) sprintf(Info[n++], "Click to dismiss....");
4455
4456    /* figure out the width and height of the info window */
4457    height = n * (Scr->DefaultFont.height+2);
4458    width = 1;
4459    for (i = 0; i < n; i++)
4460    {
4461	XmbTextExtents(Scr->DefaultFont.font_set, Info[i],
4462		       strlen(Info[i]), &inc_rect, &logical_rect);
4463
4464	twidth = logical_rect.width;
4465	if (twidth > width)
4466	    width = twidth;
4467    }
4468    if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
4469
4470    width += 10;		/* some padding */
4471    height += 10;		/* some padding */
4472    if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild,
4473		       &dummy, &dummy, &px, &py, &udummy)) {
4474	px -= (width / 2);
4475	py -= (height / 3);
4476	if (px + width + BW2 >= Scr->rootw)
4477	  px = Scr->rootw - width - BW2;
4478	if (py + height + BW2 >= Scr->rooth)
4479	  py = Scr->rooth - height - BW2;
4480	if (px < 0) px = 0;
4481	if (py < 0) py = 0;
4482    } else {
4483	px = py = 0;
4484    }
4485    XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
4486    XMapRaised(dpy, Scr->InfoWindow);
4487    InfoLines  = n;
4488    InfoWidth  = width;
4489    InfoHeight = height;
4490}
4491
4492
4493
4494 void SetMapStateProp(TwmWindow *tmp_win, int state)
4495{
4496    unsigned long data[2];		/* "suggested" by ICCCM version 1 */
4497
4498    data[0] = (unsigned long) state;
4499    data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
4500			   (tmp_win->icon ? tmp_win->icon->w : None));
4501
4502    XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
4503		 PropModeReplace, (unsigned char *) data, 2);
4504}
4505
4506
4507
4508Bool GetWMState (Window w, int *statep, Window *iwp)
4509{
4510    Atom actual_type;
4511    int actual_format;
4512    unsigned long nitems, bytesafter;
4513    unsigned long *datap = NULL;
4514    Bool retval = False;
4515
4516    if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
4517			    &actual_type, &actual_format, &nitems, &bytesafter,
4518			    (unsigned char **) &datap) != Success || !datap)
4519      return False;
4520
4521    if (nitems <= 2) {			/* "suggested" by ICCCM version 1 */
4522	*statep = (int) datap[0];
4523	*iwp = (Window) datap[1];
4524	retval = True;
4525    }
4526
4527    XFree ((char *) datap);
4528    return retval;
4529}
4530
4531
4532
4533int WarpToScreen (int n, int inc)
4534{
4535    Window dumwin;
4536    int x, y, dumint;
4537    unsigned int dummask;
4538    ScreenInfo *newscr = NULL;
4539
4540    while (!newscr) {
4541					/* wrap around */
4542	if (n < 0)
4543	  n = NumScreens - 1;
4544	else if (n >= NumScreens)
4545	  n = 0;
4546
4547	newscr = ScreenList[n];
4548	if (!newscr) {			/* make sure screen is managed */
4549	    if (inc) {			/* walk around the list */
4550		n += inc;
4551		continue;
4552	    }
4553	    fprintf (stderr, "%s:  unable to warp to unmanaged screen %d\n",
4554		     ProgramName, n);
4555	    XBell (dpy, 0);
4556	    return (1);
4557	}
4558    }
4559
4560    if (Scr->screen == n) return (0);	/* already on that screen */
4561
4562    PreviousScreen = Scr->screen;
4563    XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
4564		   &dumint, &dumint, &dummask);
4565
4566    XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
4567    Scr = newscr;
4568    return (0);
4569}
4570
4571
4572
4573
4574/*
4575 * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
4576 */
4577
4578int BumpWindowColormap (TwmWindow *tmp, int inc)
4579{
4580    int i, j, previously_installed;
4581    ColormapWindow **cwins;
4582
4583    if (!tmp) return (1);
4584
4585    if (inc && tmp->cmaps.number_cwins > 0) {
4586	cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
4587					   tmp->cmaps.number_cwins);
4588	if (cwins) {
4589	    if ((previously_installed =
4590		 /* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps &&
4591				    tmp->cmaps.number_cwins))) {
4592		for (i = tmp->cmaps.number_cwins; i-- > 0; )
4593		    tmp->cmaps.cwins[i]->colormap->state = 0;
4594	    }
4595
4596	    for (i = 0; i < tmp->cmaps.number_cwins; i++) {
4597		j = i - inc;
4598		if (j >= tmp->cmaps.number_cwins)
4599		    j -= tmp->cmaps.number_cwins;
4600		else if (j < 0)
4601		    j += tmp->cmaps.number_cwins;
4602		cwins[j] = tmp->cmaps.cwins[i];
4603	    }
4604
4605	    free((char *) tmp->cmaps.cwins);
4606
4607	    tmp->cmaps.cwins = cwins;
4608
4609	    if (tmp->cmaps.number_cwins > 1)
4610		memset (tmp->cmaps.scoreboard, 0,
4611		       ColormapsScoreboardLength(&tmp->cmaps));
4612
4613	    if (previously_installed) {
4614		InstallColormaps(PropertyNotify, NULL);
4615	    }
4616	}
4617    } else
4618	FetchWmColormapWindows (tmp);
4619    return (1);
4620}
4621
4622
4623
4624void ShowIconManager (void)
4625{
4626    IconMgr   *i;
4627    WorkSpace *wl;
4628
4629    if (! Scr->workSpaceManagerActive) return;
4630
4631    if (Scr->NoIconManagers) return;
4632    for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) {
4633	for (i = wl->iconmgr; i != NULL; i = i->next) {
4634	    if (i->count == 0) continue;
4635	    if (visible (i->twm_win)) {
4636		SetMapStateProp (i->twm_win, NormalState);
4637		XMapWindow (dpy, i->twm_win->w);
4638		MapRaised (i->twm_win);
4639		if (i->twm_win->icon && i->twm_win->icon->w)
4640		    XUnmapWindow (dpy, i->twm_win->icon->w);
4641	    }
4642	    i->twm_win->mapped = TRUE;
4643	    i->twm_win->isicon = FALSE;
4644	}
4645    }
4646}
4647
4648
4649void HideIconManager (void)
4650{
4651    IconMgr   *i;
4652    WorkSpace *wl;
4653
4654    if (Scr->NoIconManagers) return;
4655    for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) {
4656	for (i = wl->iconmgr; i != NULL; i = i->next) {
4657	    SetMapStateProp (i->twm_win, WithdrawnState);
4658	    XUnmapWindow(dpy, i->twm_win->frame);
4659	    if (i->twm_win->icon && i->twm_win->icon->w) XUnmapWindow (dpy, i->twm_win->icon->w);
4660	    i->twm_win->mapped = FALSE;
4661	    i->twm_win->isicon = TRUE;
4662	}
4663    }
4664}
4665
4666
4667
4668
4669void DestroyMenu (MenuRoot *menu)
4670{
4671    MenuItem *item;
4672
4673    if (menu->w) {
4674	XDeleteContext (dpy, menu->w, MenuContext);
4675	XDeleteContext (dpy, menu->w, ScreenContext);
4676	if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
4677	XDestroyWindow(dpy, menu->w);
4678    }
4679
4680    for (item = menu->first; item; ) {
4681	MenuItem *tmp = item;
4682	item = item->next;
4683	free ((char *) tmp);
4684    }
4685}
4686
4687
4688
4689/*
4690 * warping routines
4691 */
4692
4693void WarpAlongRing (XButtonEvent *ev, Bool forward)
4694{
4695    TwmWindow *r, *head;
4696
4697    if (Scr->RingLeader)
4698      head = Scr->RingLeader;
4699    else if (!(head = Scr->Ring))
4700      return;
4701
4702    if (forward) {
4703	for (r = head->ring.next; r != head; r = r->ring.next) {
4704	    if (!r) break;
4705	    if (r->mapped && (Scr->WarpRingAnyWhere || visible (r))) break;
4706	}
4707    } else {
4708	for (r = head->ring.prev; r != head; r = r->ring.prev) {
4709	    if (!r) break;
4710	    if (r->mapped && (Scr->WarpRingAnyWhere || visible (r))) break;
4711	}
4712    }
4713
4714    /* Note: (Scr->Focus != r) is necessary when we move to a workspace that
4715       has a single window and we want warping to warp to it. */
4716    if (r && (r != head || Scr->Focus != r)) {
4717	TwmWindow *p = Scr->RingLeader, *t;
4718
4719	Scr->RingLeader = r;
4720	WarpToWindow (r, 1);
4721
4722	if (p && p->mapped &&
4723	    (t = GetTwmWindow(ev->window)) &&
4724	    p == t) {
4725	    p->ring.cursor_valid = True;
4726	    p->ring.curs_x = ev->x_root - t->frame_x;
4727	    p->ring.curs_y = ev->y_root - t->frame_y;
4728#ifdef DEBUG
4729	    fprintf(stderr, "WarpAlongRing: cursor_valid := True; x := %d (%d-%d), y := %d (%d-%d)\n", Tmp_win->ring.curs_x, ev->x_root, t->frame_x, Tmp_win->ring.curs_y, ev->y_root, t->frame_y);
4730#endif
4731	    /*
4732	     * The check if the cursor position is inside the window is now
4733	     * done in WarpToWindow().
4734	     */
4735	}
4736    }
4737}
4738
4739
4740
4741void WarpToWindow (TwmWindow *t, int must_raise)
4742{
4743    int x, y;
4744
4745    if (t->ring.cursor_valid) {
4746	x = t->ring.curs_x;
4747	y = t->ring.curs_y;
4748#ifdef DEBUG
4749	fprintf(stderr, "WarpToWindow: cursor_valid; x == %d, y == %d\n", x, y);
4750#endif
4751
4752	/*
4753	 * XXX is this correct with 3D borders? Easier check possible?
4754	 * frame_bw is for the left border.
4755	 */
4756	if (x < t->frame_bw)
4757	    x = t->frame_bw;
4758	if (x >= t->frame_width + t->frame_bw)
4759	    x  = t->frame_width + t->frame_bw - 1;
4760	if (y < t->title_height + t->frame_bw)
4761	    y = t->title_height + t->frame_bw;
4762	if (y >= t->frame_height + t->frame_bw)
4763	    y  = t->frame_height + t->frame_bw - 1;
4764#ifdef DEBUG
4765	fprintf(stderr, "WarpToWindow: adjusted    ; x := %d, y := %d\n", x, y);
4766#endif
4767    } else {
4768	x = t->frame_width / 2;
4769	y = t->frame_height / 2;
4770#ifdef DEBUG
4771	fprintf(stderr, "WarpToWindow: middle; x := %d, y := %d\n", x, y);
4772#endif
4773    }
4774#if 0
4775    int dest_x, dest_y;
4776    Window child;
4777
4778    /*
4779     * Check if the proposed position actually is visible. If not, raise the window.
4780     * "If the coordinates are contained in a mapped
4781     * child of dest_w, that child is returned to child_return."
4782     * We'll need to check for the right child window; the frame probably.
4783     * (What about XXX window boxes?)
4784     *
4785     * Alternatively, use XQueryPointer() which returns the root window
4786     * the pointer is in, but XXX that won't work for VirtualScreens.
4787     */
4788    if (XTranslateCoordinates(dpy, t->frame, Scr->Root, x, y, &dest_x, &dest_y, &child)) {
4789	if (child != t->frame)
4790	    must_raise = 1;
4791    }
4792#endif
4793    if (t->auto_raise || must_raise) AutoRaiseWindow (t);
4794    if (! visible (t)) {
4795	WorkSpace *wlist;
4796
4797	for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) {
4798	    if (OCCUPY (t, wlist)) break;
4799	}
4800	if (wlist != NULL) GotoWorkSpace (Scr->currentvs, wlist);
4801    }
4802    XWarpPointer (dpy, None, Scr->Root, 0, 0, 0, 0, x + t->frame_x, y + t->frame_y);
4803#ifdef DEBUG
4804    {
4805	Window root_return;
4806	Window child_return;
4807	int root_x_return;
4808	int root_y_return;
4809	int win_x_return;
4810	int win_y_return;
4811	unsigned int mask_return;
4812
4813	if (XQueryPointer(dpy, t->frame, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return)) {
4814	    fprintf(stderr, "XQueryPointer: root_return=%x, child_return=%x, root_x_return=%d, root_y_return=%d, win_x_return=%d, win_y_return=%d\n", root_return, child_return, root_x_return, root_y_return, win_x_return, win_y_return);
4815	}
4816    }
4817#endif
4818}
4819
4820
4821
4822
4823/*
4824 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
4825 * client messages will have the following form:
4826 *
4827 *     event type	ClientMessage
4828 *     message type	_XA_WM_PROTOCOLS
4829 *     window		tmp->w
4830 *     format		32
4831 *     data[0]		message atom
4832 *     data[1]		time stamp
4833 */
4834static void send_clientmessage (Window w, Atom a, Time timestamp)
4835{
4836    XClientMessageEvent ev;
4837
4838    ev.type = ClientMessage;
4839    ev.window = w;
4840    ev.message_type = _XA_WM_PROTOCOLS;
4841    ev.format = 32;
4842    ev.data.l[0] = a;
4843    ev.data.l[1] = timestamp;
4844    XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
4845}
4846
4847void SendDeleteWindowMessage (TwmWindow *tmp, Time timestamp)
4848{
4849    send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
4850}
4851
4852void SendSaveYourselfMessage (TwmWindow *tmp, Time timestamp)
4853{
4854    send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
4855}
4856
4857
4858void SendTakeFocusMessage (TwmWindow *tmp, Time timestamp)
4859{
4860    send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
4861}
4862
4863int MoveMenu (XEvent *eventp)
4864{
4865    int    XW, YW, newX, newY, cont;
4866    Bool   newev;
4867    unsigned long event_mask;
4868    XEvent ev;
4869
4870    if (! ActiveMenu) return (1);
4871    if (! ActiveMenu->pinned) return (1);
4872
4873    XW = eventp->xbutton.x_root - ActiveMenu->x;
4874    YW = eventp->xbutton.y_root - ActiveMenu->y;
4875    XGrabPointer (dpy, ActiveMenu->w, True,
4876		ButtonPressMask  | ButtonReleaseMask | ButtonMotionMask,
4877		GrabModeAsync, GrabModeAsync,
4878		None, Scr->MoveCursor, CurrentTime);
4879
4880    newX = ActiveMenu->x;
4881    newY = ActiveMenu->y;
4882    cont = TRUE;
4883    event_mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask | ExposureMask;
4884    XMaskEvent (dpy, event_mask, &ev);
4885    while (cont) {
4886	ev.xbutton.x_root -= Scr->rootx;
4887	ev.xbutton.y_root -= Scr->rooty;
4888	switch (ev.xany.type) {
4889	    case ButtonRelease :
4890		cont = FALSE;
4891	    case MotionNotify :
4892		if (!cont) {
4893		    newev = False;
4894		    while (XCheckMaskEvent (dpy, ButtonMotionMask | ButtonReleaseMask, &ev)) {
4895			newev = True;
4896			if (ev.type == ButtonRelease) break;
4897		    }
4898		    if (ev.type == ButtonRelease) continue;
4899		    if (newev) {
4900			ev.xbutton.x_root -= Scr->rootx;
4901			ev.xbutton.y_root -= Scr->rooty;
4902		    }
4903		}
4904        	newX = ev.xbutton.x_root - XW;
4905        	newY = ev.xbutton.y_root - YW;
4906		if (Scr->DontMoveOff)
4907                {
4908                    ConstrainByBorders1 (&newX, ActiveMenu->width,
4909                                        &newY, ActiveMenu->height);
4910		}
4911		XMoveWindow (dpy, ActiveMenu->w, newX, newY);
4912		XMaskEvent (dpy, event_mask, &ev);
4913		break;
4914	    case ButtonPress :
4915		cont = FALSE;
4916		newX = ActiveMenu->x;
4917		newY = ActiveMenu->y;
4918		break;
4919	    case Expose:
4920	    case NoExpose:
4921                Event = ev;
4922                DispatchEvent ();
4923		XMaskEvent (dpy, event_mask, &ev);
4924		break;
4925	}
4926    }
4927    XUngrabPointer (dpy, CurrentTime);
4928    if (ev.xany.type == ButtonRelease) ButtonPressed = -1;
4929    /*XPutBackEvent (dpy, &ev);*/
4930    XMoveWindow (dpy, ActiveMenu->w, newX, newY);
4931    ActiveMenu->x = newX;
4932    ActiveMenu->y = newY;
4933    MenuOrigins [MenuDepth - 1].x = newX;
4934    MenuOrigins [MenuDepth - 1].y = newY;
4935
4936    return (1);
4937}
4938
4939/***********************************************************************
4940 *
4941 *  Procedure:
4942 *      DisplayPosition - display the position in the dimensions window
4943 *
4944 *  Inputs:
4945 *      tmp_win - the current twm window
4946 *      x, y    - position of the window
4947 *
4948 ***********************************************************************
4949 */
4950
4951void DisplayPosition (TwmWindow *tmp_win, int x, int y)
4952{
4953    char str [100];
4954    char signx = '+';
4955    char signy = '+';
4956
4957    if (x < 0) {
4958	x = -x;
4959	signx = '-';
4960    }
4961    if (y < 0) {
4962	y = -y;
4963	signy = '-';
4964    }
4965    (void) sprintf (str, " %c%-4d %c%-4d ", signx, x, signy, y);
4966    XRaiseWindow (dpy, Scr->SizeWindow);
4967
4968    Draw3DBorder (Scr->SizeWindow, 0, 0,
4969		Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT,
4970		Scr->SizeFont.height + SIZE_VINDENT * 2,
4971		2, Scr->DefaultC, off, False, False);
4972
4973    FB(Scr->DefaultC.fore, Scr->DefaultC.back);
4974    XmbDrawImageString (dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
4975			Scr->NormalGC, Scr->SizeStringOffset,
4976			Scr->SizeFont.ascent + SIZE_VINDENT , str, 13);
4977}
4978
4979void MosaicFade (TwmWindow *tmp_win, Window blanket)
4980{
4981    int		srect;
4982    int		i, j, nrects;
4983    Pixmap	mask;
4984    GC		gc;
4985    XGCValues	gcv;
4986    XRectangle *rectangles;
4987    int  width = tmp_win->frame_width;
4988    int height = tmp_win->frame_height;
4989
4990    srect = (width < height) ? (width / 20) : (height / 20);
4991    mask  = XCreatePixmap (dpy, blanket, width, height, 1);
4992
4993    gcv.foreground = 1;
4994    gc = XCreateGC (dpy, mask, GCForeground, &gcv);
4995    XFillRectangle (dpy, mask, gc, 0, 0, width, height);
4996    gcv.function = GXclear;
4997    XChangeGC (dpy, gc, GCFunction, &gcv);
4998
4999    nrects = ((width * height) / (srect * srect)) / 10;
5000    rectangles = (XRectangle*) malloc (nrects * sizeof (XRectangle));
5001    for (j = 0; j < nrects; j++) {
5002	rectangles [j].width  = srect;
5003	rectangles [j].height = srect;
5004    }
5005    for (i = 0; i < 10; i++) {
5006	for (j = 0; j < nrects; j++) {
5007	    /* coverity[dc.weak_crypto] */
5008	    rectangles [j].x = ((lrand48 () %  width) / srect) * srect;
5009	    /* coverity[dc.weak_crypto] */
5010	    rectangles [j].y = ((lrand48 () % height) / srect) * srect;
5011	}
5012	XFillRectangles (dpy, mask, gc, rectangles, nrects);
5013	XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet);
5014	XFlush (dpy);
5015	waitamoment (0.020);
5016    }
5017    XFreePixmap (dpy, mask);
5018    XFreeGC (dpy, gc);
5019    free (rectangles);
5020}
5021
5022void ZoomInWindow (TwmWindow *tmp_win, Window blanket)
5023{
5024  Pixmap	mask;
5025  GC		gc, gcn;
5026  XGCValues	gcv;
5027
5028  int i, nsteps = 20;
5029  int w = tmp_win->frame_width;
5030  int h = tmp_win->frame_height;
5031  int step = (MAX (w, h)) / (2.0 * nsteps);
5032
5033  mask = XCreatePixmap (dpy, blanket, w, h, 1);
5034  gcv.foreground = 1;
5035  gc  = XCreateGC (dpy, mask, GCForeground, &gcv);
5036  gcv.function = GXclear;
5037  gcn = XCreateGC (dpy, mask, GCForeground | GCFunction, &gcv);
5038
5039  for (i = 0; i < nsteps; i++) {
5040    XFillRectangle (dpy, mask, gcn, 0, 0, w, h);
5041    XFillArc (dpy, mask, gc, (w / 2) - ((nsteps - i) * step),
5042	                     (h / 2) - ((nsteps - i) * step),
5043	                     2 * (nsteps - i) * step,
5044	                     2 * (nsteps - i) * step,
5045	                     0, 360*64);
5046    XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet);
5047    XFlush (dpy);
5048    waitamoment (0.020);
5049  }
5050}
5051
5052void ZoomOutWindow (TwmWindow *tmp_win, Window blanket)
5053{
5054  Pixmap	mask;
5055  GC		gc;
5056  XGCValues	gcv;
5057
5058  int i, nsteps = 20;
5059  int w = tmp_win->frame_width;
5060  int h = tmp_win->frame_height;
5061  int step = (MAX (w, h)) / (2.0 * nsteps);
5062
5063  mask  = XCreatePixmap (dpy, blanket, w, h, 1);
5064  gcv.foreground = 1;
5065  gc = XCreateGC (dpy, mask, GCForeground, &gcv);
5066  XFillRectangle (dpy, mask, gc, 0, 0, w, h);
5067  gcv.function = GXclear;
5068  XChangeGC (dpy, gc, GCFunction, &gcv);
5069
5070  for (i = 0; i < nsteps; i++) {
5071    XFillArc (dpy, mask, gc, (w / 2) - (i * step),
5072	                     (h / 2) - (i * step),
5073	                     2 * i * step,
5074	                     2 * i * step,
5075	                     0, 360*64);
5076    XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet);
5077    XFlush (dpy);
5078    waitamoment (0.020);
5079  }
5080}
5081
5082void FadeWindow (TwmWindow *tmp_win, Window blanket)
5083{
5084  Pixmap	mask, stipple;
5085  GC		gc;
5086  XGCValues	gcv;
5087  static unsigned char stipple_bits[] = { 0x0F, 0x0F,
5088					  0xF0, 0xF0,
5089					  0x0F, 0x0F,
5090					  0xF0, 0xF0,
5091					  0x0F, 0x0F,
5092					  0xF0, 0xF0,
5093					  0x0F, 0x0F,
5094					  0xF0, 0xF0,
5095  };
5096  int w = tmp_win->frame_width;
5097  int h = tmp_win->frame_height;
5098
5099  stipple = XCreateBitmapFromData (dpy, blanket, (char *)stipple_bits, 8, 8);
5100  mask    = XCreatePixmap (dpy, blanket, w, h, 1);
5101  gcv.background = 0;
5102  gcv.foreground = 1;
5103  gcv.stipple    = stipple;
5104  gcv.fill_style = FillOpaqueStippled;
5105  gc = XCreateGC (dpy, mask, GCBackground | GCForeground | GCFillStyle | GCStipple, &gcv);
5106  XFillRectangle (dpy, mask, gc, 0, 0, w, h);
5107
5108  XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet);
5109  XFlush (dpy);
5110  waitamoment (10.0);
5111  XFreePixmap (dpy, stipple);
5112}
5113
5114void SweepWindow (TwmWindow *tmp_win, Window	blanket)
5115{
5116  float step = 0.0;
5117  int i, nsteps = 20;
5118  int dir = 0, dist = tmp_win->frame_x, dist1;
5119
5120  dist1 = tmp_win->frame_y;
5121  if (dist1 < dist) { dir = 1; dist = dist1; }
5122  dist1 = tmp_win->vs->w - (tmp_win->frame_x + tmp_win->frame_width);
5123  if (dist1 < dist) { dir = 2; dist = dist1; }
5124  dist1 = tmp_win->vs->h - (tmp_win->frame_y + tmp_win->frame_height);
5125  if (dist1 < dist) { dir = 3; dist = dist1; }
5126
5127  switch (dir) {
5128    case 0: step = tmp_win->frame_x + tmp_win->frame_width;  break;
5129    case 1: step = tmp_win->frame_y + tmp_win->frame_height; break;
5130    case 2: step = tmp_win->vs->w - tmp_win->frame_x;        break;
5131    case 3: step = tmp_win->vs->h - tmp_win->frame_y;        break;
5132  }
5133  step /= (float) nsteps;
5134  step /= (float) nsteps;
5135  for (i = 0; i < 20; i++) {
5136    int x = tmp_win->frame_x;
5137    int y = tmp_win->frame_y;
5138    switch (dir) {
5139      case 0: x -= i * i * step; break;
5140      case 1: y -= i * i * step; break;
5141      case 2: x += i * i * step; break;
5142      case 3: y += i * i * step; break;
5143    }
5144    XMoveWindow (dpy, blanket, x, y);
5145    XFlush (dpy);
5146    waitamoment (0.020);
5147  }
5148}
5149
5150void waitamoment (float timeout)
5151{
5152#ifdef VMS
5153  lib$wait (&timeout);
5154#else
5155  struct timeval timeoutstruct;
5156  int usec = timeout * 1000000;
5157  timeoutstruct.tv_usec = usec % (unsigned long) 1000000;
5158  timeoutstruct.tv_sec  = usec / (unsigned long) 1000000;
5159  select (0, (void *) 0, (void *) 0, (void *) 0, &timeoutstruct);
5160#endif
5161}
5162
5163void packwindow (TwmWindow *tmp_win, char *direction)
5164{
5165    int			cons, newx, newy;
5166    int			x, y, px, py, junkX, junkY;
5167    unsigned int	junkK;
5168    Window		junkW;
5169
5170    if (!strcmp (direction,   "left")) {
5171	cons  = FindConstraint (tmp_win, J_LEFT);
5172	if (cons == -1) return;
5173    	newx  = cons;
5174	newy  = tmp_win->frame_y;
5175    } else
5176    if (!strcmp (direction,  "right")) {
5177	cons  = FindConstraint (tmp_win, J_RIGHT);
5178	if (cons == -1) return;
5179    	newx  = cons;
5180	newx -= tmp_win->frame_width  + 2 * tmp_win->frame_bw;
5181	newy  = tmp_win->frame_y;
5182    } else
5183    if (!strcmp (direction,    "top")) {
5184	cons  = FindConstraint (tmp_win, J_TOP);
5185	if (cons == -1) return;
5186	newx  = tmp_win->frame_x;
5187    	newy  = cons;
5188    } else
5189    if (!strcmp (direction, "bottom")) {
5190	cons  = FindConstraint (tmp_win, J_BOTTOM);
5191	if (cons == -1) return;
5192	newx  = tmp_win->frame_x;
5193    	newy  = cons;
5194	newy -= tmp_win->frame_height  + 2 * tmp_win->frame_bw;
5195    } else return;
5196
5197    XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &x, &y, &junkK);
5198    px = x - tmp_win->frame_x + newx;
5199    py = y - tmp_win->frame_y + newy;
5200    XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, px, py);
5201    XRaiseWindow(dpy, tmp_win->frame);
5202    XMoveWindow (dpy, tmp_win->frame, newx, newy);
5203    SetupWindow (tmp_win, newx, newy, tmp_win->frame_width, tmp_win->frame_height, -1);
5204}
5205
5206void fillwindow (TwmWindow *tmp_win, char *direction)
5207{
5208    int	cons, newx, newy, save;
5209    unsigned int neww, newh;
5210    int	i;
5211    int	winx = tmp_win->frame_x;
5212    int	winy = tmp_win->frame_y;
5213    int	winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
5214    int	winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
5215
5216    if (!strcmp (direction, "left")) {
5217	cons = FindConstraint (tmp_win, J_LEFT);
5218	if (cons == -1) return;
5219    	newx = cons;
5220	newy = tmp_win->frame_y;
5221	neww = winw + winx - newx;
5222	newh = winh;
5223	neww -= 2 * tmp_win->frame_bw;
5224	newh -= 2 * tmp_win->frame_bw;
5225	ConstrainSize (tmp_win, &neww, &newh);
5226    } else
5227    if (!strcmp (direction, "right")) {
5228	for (i = 0; i < 2; i++) {
5229	    cons = FindConstraint (tmp_win, J_RIGHT);
5230	    if (cons == -1) return;
5231    	    newx = tmp_win->frame_x;
5232	    newy = tmp_win->frame_y;
5233    	    neww = cons - winx;
5234	    newh = winh;
5235	    save = neww;
5236	    neww -= 2 * tmp_win->frame_bw;
5237	    newh -= 2 * tmp_win->frame_bw;
5238	    ConstrainSize (tmp_win, &neww, &newh);
5239	    if ((neww != winw) || (newh != winh) ||
5240                (cons == Scr->rootw - Scr->BorderRight))
5241                break;
5242	    neww = save;
5243	    SetupWindow (tmp_win, newx, newy, neww, newh, -1);
5244	}
5245    } else
5246    if (!strcmp (direction, "top")) {
5247	cons = FindConstraint (tmp_win, J_TOP);
5248	if (cons == -1) return;
5249    	newx = tmp_win->frame_x;
5250	newy = cons;
5251	neww = winw;
5252	newh = winh + winy - newy;
5253	neww -= 2 * tmp_win->frame_bw;
5254	newh -= 2 * tmp_win->frame_bw;
5255	ConstrainSize (tmp_win, &neww, &newh);
5256    } else
5257    if (!strcmp (direction, "bottom")) {
5258	for (i = 0; i < 2; i++) {
5259	    cons = FindConstraint (tmp_win, J_BOTTOM);
5260	    if (cons == -1) return;
5261    	    newx = tmp_win->frame_x;
5262	    newy = tmp_win->frame_y;
5263    	    neww = winw;
5264	    newh = cons - winy;
5265	    save = newh;
5266	    neww -= 2 * tmp_win->frame_bw;
5267	    newh -= 2 * tmp_win->frame_bw;
5268	    ConstrainSize (tmp_win, &neww, &newh);
5269	    if ((neww != winw) || (newh != winh) ||
5270                (cons == Scr->rooth - Scr->BorderBottom))
5271                break;
5272	    newh = save;
5273	    SetupWindow (tmp_win, newx, newy, neww, newh, -1);
5274	}
5275	}
5276	else if (!strcmp (direction, "vertical"))
5277	{
5278		if (tmp_win->zoomed == ZOOM_NONE)
5279		{
5280			tmp_win->save_frame_height = tmp_win->frame_height;
5281			tmp_win->save_frame_width = tmp_win->frame_width;
5282			tmp_win->save_frame_y = tmp_win->frame_y;
5283			tmp_win->save_frame_x = tmp_win->frame_x;
5284
5285			tmp_win->frame_y++;
5286			newy = FindConstraint (tmp_win, J_TOP);
5287			tmp_win->frame_y--;
5288			newh = FindConstraint (tmp_win, J_BOTTOM) - newy;
5289			newh -= 2 * tmp_win->frame_bw;
5290
5291			newx = tmp_win->frame_x;
5292			neww = tmp_win->frame_width;
5293
5294			ConstrainSize (tmp_win, &neww, &newh);
5295
5296			/* if the bottom of the window has moved up
5297			 * it will be pushed down */
5298			if (newy + newh <
5299			    tmp_win->save_frame_y + tmp_win->save_frame_height)
5300			  newy = tmp_win->save_frame_y +
5301			    tmp_win->save_frame_height - newh;
5302			tmp_win->zoomed = F_ZOOM;
5303			SetupWindow (tmp_win, newx, newy, neww, newh, -1);
5304		}
5305		else
5306		{
5307			fullzoom (tmp_win, tmp_win->zoomed);
5308		}
5309		return;
5310	}
5311    else return;
5312    SetupWindow (tmp_win, newx, newy, neww, newh, -1);
5313}
5314
5315void jump (TwmWindow *tmp_win, int  direction, char *action)
5316{
5317    int			fx, fy, px, py, step, status, cons;
5318    int			fwidth, fheight;
5319    int			junkX, junkY;
5320    unsigned int	junkK;
5321    Window		junkW;
5322
5323    if (! action) return;
5324    status = sscanf (action, "%d", &step);
5325    if (status != 1) return;
5326    if (step < 1) return;
5327
5328    fx = tmp_win->frame_x;
5329    fy = tmp_win->frame_y;
5330    XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
5331    px -= fx; py -= fy;
5332
5333    fwidth  = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
5334    fheight = tmp_win->frame_height + 2 * tmp_win->frame_bw;
5335    switch (direction) {
5336	case J_LEFT   :
5337	    cons  = FindConstraint (tmp_win, J_LEFT);
5338	    if (cons == -1) return;
5339	    fx -= step * Scr->XMoveGrid;
5340	    if (fx < cons) fx = cons;
5341	    break;
5342	case J_RIGHT  :
5343	    cons  = FindConstraint (tmp_win, J_RIGHT);
5344	    if (cons == -1) return;
5345	    fx += step * Scr->XMoveGrid;
5346	    if (fx + fwidth > cons) fx = cons - fwidth;
5347	    break;
5348	case J_TOP    :
5349	    cons  = FindConstraint (tmp_win, J_TOP);
5350	    if (cons == -1) return;
5351	    fy -= step * Scr->YMoveGrid;
5352	    if (fy < cons) fy = cons;
5353	    break;
5354	case J_BOTTOM :
5355	    cons  = FindConstraint (tmp_win, J_BOTTOM);
5356	    if (cons == -1) return;
5357	    fy += step * Scr->YMoveGrid;
5358	    if (fy + fheight > cons) fy = cons - fheight;
5359	    break;
5360    }
5361    /* Pebl Fixme: don't warp if jump happens through iconmgr */
5362    XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, fx + px, fy + py);
5363    if (!Scr->NoRaiseMove)
5364        XRaiseWindow (dpy, tmp_win->frame);
5365    SetupWindow (tmp_win, fx, fy, tmp_win->frame_width, tmp_win->frame_height, -1);
5366}
5367
5368int FindConstraint (TwmWindow *tmp_win, int direction)
5369{
5370    TwmWindow	*t;
5371    int		w, h;
5372    int		winx = tmp_win->frame_x;
5373    int		winy = tmp_win->frame_y;
5374    int		winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
5375    int		winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
5376    int 	ret;
5377
5378    switch (direction) {
5379	case J_LEFT   : if (winx < Scr->BorderLeft) return -1;
5380			ret = Scr->BorderLeft; break;
5381	case J_RIGHT  : if (winx + winw > Scr->rootw - Scr->BorderRight) return -1;
5382			ret = Scr->rootw - Scr->BorderRight; break;
5383	case J_TOP    : if (winy < Scr->BorderTop) return -1;
5384			ret = Scr->BorderTop; break;
5385	case J_BOTTOM : if (winy + winh > Scr->rooth - Scr->BorderBottom) return -1;
5386			ret = Scr->rooth - Scr->BorderBottom; break;
5387	default       : return -1;
5388    }
5389    for (t = Scr->FirstWindow; t != NULL; t = t->next) {
5390	if (t == tmp_win) continue;
5391	if (!visible (t)) continue;
5392	if (!t->mapped) continue;
5393	w = t->frame_width  + 2 * t->frame_bw;
5394	h = t->frame_height + 2 * t->frame_bw;
5395
5396	switch (direction) {
5397	    case J_LEFT :
5398		if (winx        <= t->frame_x + w) continue;
5399		if (winy        >= t->frame_y + h) continue;
5400		if (winy + winh <= t->frame_y    ) continue;
5401		ret = MAX (ret, t->frame_x + w);
5402		break;
5403	    case J_RIGHT :
5404		if (winx + winw >= t->frame_x    ) continue;
5405		if (winy        >= t->frame_y + h) continue;
5406		if (winy + winh <= t->frame_y    ) continue;
5407		ret = MIN (ret, t->frame_x);
5408		break;
5409	    case J_TOP :
5410		if (winy        <= t->frame_y + h) continue;
5411		if (winx        >= t->frame_x + w) continue;
5412		if (winx + winw <= t->frame_x    ) continue;
5413		ret = MAX (ret, t->frame_y + h);
5414		break;
5415	    case J_BOTTOM :
5416		if (winy + winh >= t->frame_y    ) continue;
5417		if (winx        >= t->frame_x + w) continue;
5418		if (winx + winw <= t->frame_x    ) continue;
5419		ret = MIN (ret, t->frame_y);
5420		break;
5421	}
5422    }
5423    return ret;
5424}
5425
5426void TryToPack (TwmWindow *tmp_win, int *x, int *y)
5427{
5428    TwmWindow	*t;
5429    int		newx, newy;
5430    int		w, h;
5431    int		winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
5432    int		winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
5433
5434    newx = *x;
5435    newy = *y;
5436    for (t = Scr->FirstWindow; t != NULL; t = t->next) {
5437	if (t == tmp_win) continue;
5438	if (t->winbox != tmp_win->winbox) continue;
5439	if (t->vs != tmp_win->vs) continue;
5440	if (!t->mapped) continue;
5441
5442	w = t->frame_width  + 2 * t->frame_bw;
5443	h = t->frame_height + 2 * t->frame_bw;
5444	if (newx >= t->frame_x + w) continue;
5445	if (newy >= t->frame_y + h) continue;
5446	if (newx + winw <= t->frame_x) continue;
5447	if (newy + winh <= t->frame_y) continue;
5448
5449	if (newx + Scr->MovePackResistance > t->frame_x + w) { /* left */
5450	    newx = MAX (newx, t->frame_x + w);
5451	    continue;
5452	}
5453	if (newx + winw < t->frame_x + Scr->MovePackResistance) { /* right */
5454	    newx = MIN (newx, t->frame_x - winw);
5455	    continue;
5456	}
5457	if (newy + Scr->MovePackResistance > t->frame_y + h) { /* top */
5458	    newy = MAX (newy, t->frame_y + h);
5459	    continue;
5460	}
5461	if (newy + winh < t->frame_y + Scr->MovePackResistance) { /* bottom */
5462	    newy = MIN (newy, t->frame_y - winh);
5463	    continue;
5464	}
5465    }
5466    *x = newx;
5467    *y = newy;
5468}
5469
5470void TryToPush (TwmWindow *tmp_win, int x, int y, int dir)
5471{
5472    TwmWindow	*t;
5473    int		newx, newy, ndir;
5474    Boolean	move;
5475    int		w, h;
5476    int		winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
5477    int		winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
5478
5479    for (t = Scr->FirstWindow; t != NULL; t = t->next) {
5480	if (t == tmp_win) continue;
5481	if (t->winbox != tmp_win->winbox) continue;
5482	if (t->vs != tmp_win->vs) continue;
5483	if (!t->mapped) continue;
5484
5485	w = t->frame_width  + 2 * t->frame_bw;
5486	h = t->frame_height + 2 * t->frame_bw;
5487	if (x >= t->frame_x + w) continue;
5488	if (y >= t->frame_y + h) continue;
5489	if (x + winw <= t->frame_x) continue;
5490	if (y + winh <= t->frame_y) continue;
5491
5492	move = False;
5493	if ((dir == 0 || dir == J_LEFT) &&
5494	    (x + Scr->MovePackResistance > t->frame_x + w)) {
5495	    newx = x - w;
5496	    newy = t->frame_y;
5497	    ndir = J_LEFT;
5498	    move = True;
5499	}
5500	else
5501	if ((dir == 0 || dir == J_RIGHT) &&
5502	   (x + winw < t->frame_x + Scr->MovePackResistance)) {
5503	    newx = x + winw;
5504	    newy = t->frame_y;
5505	    ndir = J_RIGHT;
5506	    move = True;
5507	}
5508	else
5509	if ((dir == 0 || dir == J_TOP) &&
5510	    (y + Scr->MovePackResistance > t->frame_y + h)) {
5511	    newx = t->frame_x;
5512	    newy = y - h;
5513	    ndir = J_TOP;
5514	    move = True;
5515	}
5516	else
5517	if ((dir == 0 || dir == J_BOTTOM) &&
5518	    (y + winh < t->frame_y + Scr->MovePackResistance)) {
5519	    newx = t->frame_x;
5520	    newy = y + winh;
5521	    ndir = J_BOTTOM;
5522	    move = True;
5523	}
5524	if (move) {
5525	    TryToPush (t, newx, newy, ndir);
5526	    TryToPack (t, &newx, &newy);
5527            ConstrainByBorders (tmp_win,
5528				&newx, t->frame_width  + 2 * t->frame_bw,
5529                                &newy, t->frame_height + 2 * t->frame_bw);
5530	    SetupWindow (t, newx, newy, t->frame_width, t->frame_height, -1);
5531	}
5532    }
5533}
5534
5535void TryToGrid (TwmWindow *tmp_win, int *x, int *y)
5536{
5537    int	w    = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
5538    int	h    = tmp_win->frame_height + 2 * tmp_win->frame_bw;
5539    int	grav = ((tmp_win->hints.flags & PWinGravity)
5540		      ? tmp_win->hints.win_gravity : NorthWestGravity);
5541
5542    switch (grav) {
5543	case ForgetGravity :
5544	case StaticGravity :
5545	case NorthWestGravity :
5546	case NorthGravity :
5547	case WestGravity :
5548	case CenterGravity :
5549	    *x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
5550                + Scr->BorderLeft;
5551	    *y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid
5552                + Scr->BorderTop;
5553	    break;
5554	case NorthEastGravity :
5555	case EastGravity :
5556	    *x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
5557                  Scr->XMoveGrid) - w + Scr->BorderLeft;
5558	    *y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) *
5559                Scr->YMoveGrid + Scr->BorderTop;
5560	    break;
5561	case SouthWestGravity :
5562	case SouthGravity :
5563	    *x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
5564                + Scr->BorderLeft;
5565	    *y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid)
5566                - h + Scr->BorderTop;
5567	    break;
5568	case SouthEastGravity :
5569	    *x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
5570                  Scr->XMoveGrid) - w + Scr->BorderLeft;
5571	    *y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) *
5572                  Scr->YMoveGrid) - h + Scr->BorderTop;
5573	    break;
5574    }
5575}
5576
5577int WarpCursorToDefaultEntry (MenuRoot *menu)
5578{
5579    MenuItem	*item;
5580    Window	 root;
5581    int		 i, x, y, xl, yt;
5582    unsigned int w, h, bw, d;
5583
5584    for (i = 0, item = menu->first; item != menu->last; item = item->next) {
5585	if (item == menu->defaultitem) break;
5586	i++;
5587     }
5588     if (!XGetGeometry (dpy, menu->w, &root, &x, &y, &w, &h, &bw, &d)) return 0;
5589     xl = x + (menu->width / 2);
5590     yt = y + (i + 0.5) * Scr->EntryHeight;
5591
5592     XWarpPointer (dpy, Scr->Root, Scr->Root,
5593		   Event.xbutton.x_root, Event.xbutton.y_root,
5594		   menu->width, menu->height, xl, yt);
5595     return 1;
5596}
5597
5598