menus.c revision 3e747e6d
13e747e6dSmrg/* $XFree86: xc/programs/twm/menus.c,v 1.18tsi Exp $ */
23e747e6dSmrg/*****************************************************************************/
33e747e6dSmrg/*
43e747e6dSmrg
53e747e6dSmrgCopyright 1989, 1998  The Open Group
63e747e6dSmrg
73e747e6dSmrgPermission to use, copy, modify, distribute, and sell this software and its
83e747e6dSmrgdocumentation for any purpose is hereby granted without fee, provided that
93e747e6dSmrgthe above copyright notice appear in all copies and that both that
103e747e6dSmrgcopyright notice and this permission notice appear in supporting
113e747e6dSmrgdocumentation.
123e747e6dSmrg
133e747e6dSmrgThe above copyright notice and this permission notice shall be included in
143e747e6dSmrgall copies or substantial portions of the Software.
153e747e6dSmrg
163e747e6dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
173e747e6dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183e747e6dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
193e747e6dSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
203e747e6dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
213e747e6dSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
223e747e6dSmrg
233e747e6dSmrgExcept as contained in this notice, the name of The Open Group shall not be
243e747e6dSmrgused in advertising or otherwise to promote the sale, use or other dealings
253e747e6dSmrgin this Software without prior written authorization from The Open Group.
263e747e6dSmrg
273e747e6dSmrg*/
283e747e6dSmrg/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
293e747e6dSmrg/**                          Salt Lake City, Utah                           **/
303e747e6dSmrg/**                        Cambridge, Massachusetts                         **/
313e747e6dSmrg/**                                                                         **/
323e747e6dSmrg/**                           All Rights Reserved                           **/
333e747e6dSmrg/**                                                                         **/
343e747e6dSmrg/**    Permission to use, copy, modify, and distribute this software and    **/
353e747e6dSmrg/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
363e747e6dSmrg/**    granted, provided that the above copyright notice appear  in  all    **/
373e747e6dSmrg/**    copies and that both  that  copyright  notice  and  this  permis-    **/
383e747e6dSmrg/**    sion  notice appear in supporting  documentation,  and  that  the    **/
393e747e6dSmrg/**    name of Evans & Sutherland not be used in advertising    **/
403e747e6dSmrg/**    in publicity pertaining to distribution of the  software  without    **/
413e747e6dSmrg/**    specific, written prior permission.                                  **/
423e747e6dSmrg/**                                                                         **/
433e747e6dSmrg/**    EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD    **/
443e747e6dSmrg/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
453e747e6dSmrg/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND    **/
463e747e6dSmrg/**    BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
473e747e6dSmrg/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
483e747e6dSmrg/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
493e747e6dSmrg/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
503e747e6dSmrg/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
513e747e6dSmrg/*****************************************************************************/
523e747e6dSmrg
533e747e6dSmrg
543e747e6dSmrg/***********************************************************************
553e747e6dSmrg *
563e747e6dSmrg * $Xorg: menus.c,v 1.6 2001/02/09 02:05:36 xorgcvs Exp $
573e747e6dSmrg *
583e747e6dSmrg * twm menu code
593e747e6dSmrg *
603e747e6dSmrg * 17-Nov-87 Thomas E. LaStrange		File created
613e747e6dSmrg *
623e747e6dSmrg ***********************************************************************/
633e747e6dSmrg
643e747e6dSmrg#include <stdio.h>
653e747e6dSmrg#include <X11/Xos.h>
663e747e6dSmrg#include "twm.h"
673e747e6dSmrg#include "gc.h"
683e747e6dSmrg#include "menus.h"
693e747e6dSmrg#include "resize.h"
703e747e6dSmrg#include "events.h"
713e747e6dSmrg#include "util.h"
723e747e6dSmrg#include "parse.h"
733e747e6dSmrg#include "gram.h"
743e747e6dSmrg#include "screen.h"
753e747e6dSmrg#include "menus.h"
763e747e6dSmrg#include "iconmgr.h"
773e747e6dSmrg#include "add_window.h"
783e747e6dSmrg#include "icons.h"
793e747e6dSmrg#include "session.h"
803e747e6dSmrg#include <X11/Xmu/CharSet.h>
813e747e6dSmrg#include "version.h"
823e747e6dSmrg#include <X11/extensions/sync.h>
833e747e6dSmrg#include <X11/SM/SMlib.h>
843e747e6dSmrg
853e747e6dSmrgint RootFunction = 0;
863e747e6dSmrgMenuRoot *ActiveMenu = NULL;		/**< the active menu */
873e747e6dSmrgMenuItem *ActiveItem = NULL;		/**< the active menu item */
883e747e6dSmrgint MoveFunction;			/**< either F_MOVE or F_FORCEMOVE */
893e747e6dSmrgint WindowMoved = FALSE;
903e747e6dSmrgint menuFromFrameOrWindowOrTitlebar = FALSE;
913e747e6dSmrg
923e747e6dSmrgint ConstMove = FALSE;		/**< constrained move variables */
933e747e6dSmrgint ConstMoveDir;
943e747e6dSmrgint ConstMoveX;
953e747e6dSmrgint ConstMoveY;
963e747e6dSmrgint ConstMoveXL;
973e747e6dSmrgint ConstMoveXR;
983e747e6dSmrgint ConstMoveYT;
993e747e6dSmrgint ConstMoveYB;
1003e747e6dSmrg
1013e747e6dSmrg/* Globals used to keep track of whether the mouse has moved during
1023e747e6dSmrg   a resize function. */
1033e747e6dSmrgint ResizeOrigX;
1043e747e6dSmrgint ResizeOrigY;
1053e747e6dSmrg
1063e747e6dSmrgint MenuDepth = 0;		/**< number of menus up */
1073e747e6dSmrgstatic struct {
1083e747e6dSmrg    int x;
1093e747e6dSmrg    int y;
1103e747e6dSmrg} MenuOrigins[MAXMENUDEPTH];
1113e747e6dSmrgstatic Cursor LastCursor;
1123e747e6dSmrg
1133e747e6dSmrgstatic Bool belongs_to_twm_window ( TwmWindow *t, Window w );
1143e747e6dSmrgstatic void Identify ( TwmWindow *t );
1153e747e6dSmrgstatic void send_clientmessage ( Window w, Atom a, Time timestamp );
1163e747e6dSmrg
1173e747e6dSmrg#define SHADOWWIDTH 5			/* in pixels */
1183e747e6dSmrg
1193e747e6dSmrg
1203e747e6dSmrg
1213e747e6dSmrg
1223e747e6dSmrg/**
1233e747e6dSmrg * initialize menu roots
1243e747e6dSmrg */
1253e747e6dSmrgvoid
1263e747e6dSmrgInitMenus()
1273e747e6dSmrg{
1283e747e6dSmrg    int i, j, k;
1293e747e6dSmrg    FuncKey *key, *tmp;
1303e747e6dSmrg
1313e747e6dSmrg    for (i = 0; i < MAX_BUTTONS+1; i++)
1323e747e6dSmrg	for (j = 0; j < NUM_CONTEXTS; j++)
1333e747e6dSmrg	    for (k = 0; k < MOD_SIZE; k++)
1343e747e6dSmrg	    {
1353e747e6dSmrg		Scr->Mouse[i][j][k].func = 0;
1363e747e6dSmrg		Scr->Mouse[i][j][k].item = NULL;
1373e747e6dSmrg	    }
1383e747e6dSmrg
1393e747e6dSmrg    Scr->DefaultFunction.func = 0;
1403e747e6dSmrg    Scr->WindowFunction.func = 0;
1413e747e6dSmrg
1423e747e6dSmrg    if (FirstScreen)
1433e747e6dSmrg    {
1443e747e6dSmrg	for (key = Scr->FuncKeyRoot.next; key != NULL;)
1453e747e6dSmrg	{
1463e747e6dSmrg	    free(key->name);
1473e747e6dSmrg	    tmp = key;
1483e747e6dSmrg	    key = key->next;
1493e747e6dSmrg	    free((char *) tmp);
1503e747e6dSmrg	}
1513e747e6dSmrg	Scr->FuncKeyRoot.next = NULL;
1523e747e6dSmrg    }
1533e747e6dSmrg
1543e747e6dSmrg}
1553e747e6dSmrg
1563e747e6dSmrg
1573e747e6dSmrg
1583e747e6dSmrg/**
1593e747e6dSmrg * add a function key to the list
1603e747e6dSmrg *
1613e747e6dSmrg *  \param name     the name of the key
1623e747e6dSmrg *  \param cont     the context to look for the key press in
1633e747e6dSmrg *  \param mods     modifier keys that need to be pressed
1643e747e6dSmrg *  \param func     the function to perform
1653e747e6dSmrg *  \param win_name the window name (if any)
1663e747e6dSmrg *  \param action   the action string associated with the function (if any)
1673e747e6dSmrg */
1683e747e6dSmrgBool AddFuncKey (char *name, int cont, int mods, int func, char *win_name,
1693e747e6dSmrg                 char *action)
1703e747e6dSmrg{
1713e747e6dSmrg    FuncKey *tmp;
1723e747e6dSmrg    KeySym keysym;
1733e747e6dSmrg    KeyCode keycode;
1743e747e6dSmrg
1753e747e6dSmrg    /*
1763e747e6dSmrg     * Don't let a 0 keycode go through, since that means AnyKey to the
1773e747e6dSmrg     * XGrabKey call in GrabKeys().
1783e747e6dSmrg     */
1793e747e6dSmrg    if ((keysym = XStringToKeysym(name)) == NoSymbol ||
1803e747e6dSmrg	(keycode = XKeysymToKeycode(dpy, keysym)) == 0)
1813e747e6dSmrg    {
1823e747e6dSmrg	return False;
1833e747e6dSmrg    }
1843e747e6dSmrg
1853e747e6dSmrg    /* see if there already is a key defined for this context */
1863e747e6dSmrg    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
1873e747e6dSmrg    {
1883e747e6dSmrg	if (tmp->keysym == keysym &&
1893e747e6dSmrg	    tmp->cont == cont &&
1903e747e6dSmrg	    tmp->mods == mods)
1913e747e6dSmrg	    break;
1923e747e6dSmrg    }
1933e747e6dSmrg
1943e747e6dSmrg    if (tmp == NULL)
1953e747e6dSmrg    {
1963e747e6dSmrg	tmp = (FuncKey *) malloc(sizeof(FuncKey));
1973e747e6dSmrg	tmp->next = Scr->FuncKeyRoot.next;
1983e747e6dSmrg	Scr->FuncKeyRoot.next = tmp;
1993e747e6dSmrg    }
2003e747e6dSmrg
2013e747e6dSmrg    tmp->name = name;
2023e747e6dSmrg    tmp->keysym = keysym;
2033e747e6dSmrg    tmp->keycode = keycode;
2043e747e6dSmrg    tmp->cont = cont;
2053e747e6dSmrg    tmp->mods = mods;
2063e747e6dSmrg    tmp->func = func;
2073e747e6dSmrg    tmp->win_name = win_name;
2083e747e6dSmrg    tmp->action = action;
2093e747e6dSmrg
2103e747e6dSmrg    return True;
2113e747e6dSmrg}
2123e747e6dSmrg
2133e747e6dSmrg
2143e747e6dSmrg
2153e747e6dSmrgint CreateTitleButton (char *name, int func, char *action, MenuRoot *menuroot,
2163e747e6dSmrg                       Bool rightside, Bool append)
2173e747e6dSmrg{
2183e747e6dSmrg    TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton));
2193e747e6dSmrg
2203e747e6dSmrg    if (!tb) {
2213e747e6dSmrg	fprintf (stderr,
2223e747e6dSmrg		 "%s:  unable to allocate %ld bytes for title button\n",
2233e747e6dSmrg		 ProgramName, (unsigned long)sizeof(TitleButton));
2243e747e6dSmrg	return 0;
2253e747e6dSmrg    }
2263e747e6dSmrg
2273e747e6dSmrg    tb->next = NULL;
2283e747e6dSmrg    tb->name = name;			/* note that we are not copying */
2293e747e6dSmrg    tb->bitmap = None;			/* WARNING, values not set yet */
2303e747e6dSmrg    tb->width = 0;			/* see InitTitlebarButtons */
2313e747e6dSmrg    tb->height = 0;			/* ditto */
2323e747e6dSmrg    tb->func = func;
2333e747e6dSmrg    tb->action = action;
2343e747e6dSmrg    tb->menuroot = menuroot;
2353e747e6dSmrg    tb->rightside = rightside;
2363e747e6dSmrg    if (rightside) {
2373e747e6dSmrg	Scr->TBInfo.nright++;
2383e747e6dSmrg    } else {
2393e747e6dSmrg	Scr->TBInfo.nleft++;
2403e747e6dSmrg    }
2413e747e6dSmrg
2423e747e6dSmrg    /*
2433e747e6dSmrg     * Cases for list:
2443e747e6dSmrg     *
2453e747e6dSmrg     *     1.  empty list, prepend left       put at head of list
2463e747e6dSmrg     *     2.  append left, prepend right     put in between left and right
2473e747e6dSmrg     *     3.  append right                   put at tail of list
2483e747e6dSmrg     *
2493e747e6dSmrg     * Do not refer to widths and heights yet since buttons not created
2503e747e6dSmrg     * (since fonts not loaded and heights not known).
2513e747e6dSmrg     */
2523e747e6dSmrg    if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) {	/* 1 */
2533e747e6dSmrg	tb->next = Scr->TBInfo.head;
2543e747e6dSmrg	Scr->TBInfo.head = tb;
2553e747e6dSmrg    } else if (append && rightside) {	/* 3 */
2563e747e6dSmrg	register TitleButton *t;
2573e747e6dSmrg	for /* SUPPRESS 530 */
2583e747e6dSmrg	  (t = Scr->TBInfo.head; t->next; t = t->next);
2593e747e6dSmrg	t->next = tb;
2603e747e6dSmrg	tb->next = NULL;
2613e747e6dSmrg    } else {				/* 2 */
2623e747e6dSmrg	register TitleButton *t, *prev = NULL;
2633e747e6dSmrg	for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
2643e747e6dSmrg	    prev = t;
2653e747e6dSmrg	}
2663e747e6dSmrg	if (prev) {
2673e747e6dSmrg	    tb->next = prev->next;
2683e747e6dSmrg	    prev->next = tb;
2693e747e6dSmrg	} else {
2703e747e6dSmrg	    tb->next = Scr->TBInfo.head;
2713e747e6dSmrg	    Scr->TBInfo.head = tb;
2723e747e6dSmrg	}
2733e747e6dSmrg    }
2743e747e6dSmrg
2753e747e6dSmrg    return 1;
2763e747e6dSmrg}
2773e747e6dSmrg
2783e747e6dSmrg
2793e747e6dSmrg
2803e747e6dSmrg/**
2813e747e6dSmrg * Do all the necessary stuff to load in a titlebar button.  If we can't find
2823e747e6dSmrg * the button, then put in a question; if we can't find the question mark,
2833e747e6dSmrg * something is wrong and we are probably going to be in trouble later on.
2843e747e6dSmrg */
2853e747e6dSmrgvoid InitTitlebarButtons ()
2863e747e6dSmrg{
2873e747e6dSmrg    TitleButton *tb;
2883e747e6dSmrg    int h;
2893e747e6dSmrg
2903e747e6dSmrg    /*
2913e747e6dSmrg     * initialize dimensions
2923e747e6dSmrg     */
2933e747e6dSmrg    Scr->TBInfo.width = (Scr->TitleHeight -
2943e747e6dSmrg			 2 * (Scr->FramePadding + Scr->ButtonIndent));
2953e747e6dSmrg    Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
2963e747e6dSmrg		       ? ((Scr->TitlePadding + 1) / 2) : 1);
2973e747e6dSmrg    h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
2983e747e6dSmrg
2993e747e6dSmrg    /*
3003e747e6dSmrg     * add in some useful buttons and bindings so that novices can still
3013e747e6dSmrg     * use the system.
3023e747e6dSmrg     */
3033e747e6dSmrg    if (!Scr->NoDefaults) {
3043e747e6dSmrg	/* insert extra buttons */
3053e747e6dSmrg	if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
3063e747e6dSmrg				False, False)) {
3073e747e6dSmrg	    fprintf (stderr, "%s:  unable to add iconify button\n",
3083e747e6dSmrg		     ProgramName);
3093e747e6dSmrg	}
3103e747e6dSmrg	if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
3113e747e6dSmrg				True, True)) {
3123e747e6dSmrg	    fprintf (stderr, "%s:  unable to add resize button\n",
3133e747e6dSmrg		     ProgramName);
3143e747e6dSmrg	}
3153e747e6dSmrg	AddDefaultBindings ();
3163e747e6dSmrg    }
3173e747e6dSmrg    ComputeCommonTitleOffsets ();
3183e747e6dSmrg
3193e747e6dSmrg    /*
3203e747e6dSmrg     * load in images and do appropriate centering
3213e747e6dSmrg     */
3223e747e6dSmrg
3233e747e6dSmrg    for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
3243e747e6dSmrg	tb->bitmap = FindBitmap (tb->name, &tb->width, &tb->height);
3253e747e6dSmrg	if (!tb->bitmap) {
3263e747e6dSmrg	    tb->bitmap = FindBitmap (TBPM_QUESTION, &tb->width, &tb->height);
3273e747e6dSmrg	    if (!tb->bitmap) {		/* cannot happen (see util.c) */
3283e747e6dSmrg		fprintf (stderr,
3293e747e6dSmrg			 "%s:  unable to add titlebar button \"%s\"\n",
3303e747e6dSmrg			 ProgramName, tb->name);
3313e747e6dSmrg	    }
3323e747e6dSmrg	}
3333e747e6dSmrg
3343e747e6dSmrg	tb->dstx = (h - tb->width + 1) / 2;
3353e747e6dSmrg	if (tb->dstx < 0) {		/* clip to minimize copying */
3363e747e6dSmrg	    tb->srcx = -(tb->dstx);
3373e747e6dSmrg	    tb->width = h;
3383e747e6dSmrg	    tb->dstx = 0;
3393e747e6dSmrg	} else {
3403e747e6dSmrg	    tb->srcx = 0;
3413e747e6dSmrg	}
3423e747e6dSmrg	tb->dsty = (h - tb->height + 1) / 2;
3433e747e6dSmrg	if (tb->dsty < 0) {
3443e747e6dSmrg	    tb->srcy = -(tb->dsty);
3453e747e6dSmrg	    tb->height = h;
3463e747e6dSmrg	    tb->dsty = 0;
3473e747e6dSmrg	} else {
3483e747e6dSmrg	    tb->srcy = 0;
3493e747e6dSmrg	}
3503e747e6dSmrg    }
3513e747e6dSmrg}
3523e747e6dSmrg
3533e747e6dSmrg
3543e747e6dSmrg
3553e747e6dSmrgvoid
3563e747e6dSmrgPaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
3573e747e6dSmrg{
3583e747e6dSmrg    int y_offset;
3593e747e6dSmrg    int text_y;
3603e747e6dSmrg    GC gc;
3613e747e6dSmrg
3623e747e6dSmrg#ifdef DEBUG_MENUS
3633e747e6dSmrg    fprintf(stderr, "Paint entry\n");
3643e747e6dSmrg#endif
3653e747e6dSmrg    y_offset = mi->item_num * Scr->EntryHeight;
3663e747e6dSmrg    text_y = y_offset + Scr->MenuFont.y;
3673e747e6dSmrg
3683e747e6dSmrg    if (mi->func != F_TITLE)
3693e747e6dSmrg    {
3703e747e6dSmrg	int x, y;
3713e747e6dSmrg
3723e747e6dSmrg	if (mi->state)
3733e747e6dSmrg	{
3743e747e6dSmrg	    XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
3753e747e6dSmrg
3763e747e6dSmrg	    XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
3773e747e6dSmrg		mr->width, Scr->EntryHeight);
3783e747e6dSmrg
3793e747e6dSmrg	    MyFont_ChangeGC(mi->hi_fore, mi->hi_back, &Scr->MenuFont);
3803e747e6dSmrg
3813e747e6dSmrg	    MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x,
3823e747e6dSmrg		text_y, mi->item, mi->strlen);
3833e747e6dSmrg
3843e747e6dSmrg	    gc = Scr->NormalGC;
3853e747e6dSmrg	}
3863e747e6dSmrg	else
3873e747e6dSmrg	{
3883e747e6dSmrg	    if (mi->user_colors || !exposure)
3893e747e6dSmrg	    {
3903e747e6dSmrg		XSetForeground(dpy, Scr->NormalGC, mi->back);
3913e747e6dSmrg
3923e747e6dSmrg		XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
3933e747e6dSmrg		    mr->width, Scr->EntryHeight);
3943e747e6dSmrg
3953e747e6dSmrg		MyFont_ChangeGC(mi->fore, mi->back, &Scr->MenuFont);
3963e747e6dSmrg		gc = Scr->NormalGC;
3973e747e6dSmrg	    }
3983e747e6dSmrg	    else
3993e747e6dSmrg		gc = Scr->MenuGC;
4003e747e6dSmrg
4013e747e6dSmrg	    MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, gc,
4023e747e6dSmrg		    mi->x, text_y, mi->item, mi->strlen);
4033e747e6dSmrg
4043e747e6dSmrg	}
4053e747e6dSmrg
4063e747e6dSmrg	if (mi->func == F_MENU)
4073e747e6dSmrg	{
4083e747e6dSmrg	    /* create the pull right pixmap if needed */
4093e747e6dSmrg	    if (Scr->pullPm == None)
4103e747e6dSmrg	    {
4113e747e6dSmrg		Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height,
4123e747e6dSmrg					     &Scr->pullW, &Scr->pullH);
4133e747e6dSmrg	    }
4143e747e6dSmrg	    x = mr->width - Scr->pullW - 5;
4153e747e6dSmrg	    y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2);
4163e747e6dSmrg	    XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
4173e747e6dSmrg		Scr->pullW, Scr->pullH, x, y, 1);
4183e747e6dSmrg	}
4193e747e6dSmrg    }
4203e747e6dSmrg    else
4213e747e6dSmrg    {
4223e747e6dSmrg	int y;
4233e747e6dSmrg
4243e747e6dSmrg	XSetForeground(dpy, Scr->NormalGC, mi->back);
4253e747e6dSmrg
4263e747e6dSmrg	/* fill the rectangle with the title background color */
4273e747e6dSmrg	XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
4283e747e6dSmrg	    mr->width, Scr->EntryHeight);
4293e747e6dSmrg
4303e747e6dSmrg	{
4313e747e6dSmrg	    XSetForeground(dpy, Scr->NormalGC, mi->fore);
4323e747e6dSmrg	    /* now draw the dividing lines */
4333e747e6dSmrg	    if (y_offset)
4343e747e6dSmrg	      XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
4353e747e6dSmrg			 mr->width, y_offset);
4363e747e6dSmrg	    y = ((mi->item_num+1) * Scr->EntryHeight)-1;
4373e747e6dSmrg	    XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
4383e747e6dSmrg	}
4393e747e6dSmrg
4403e747e6dSmrg	MyFont_ChangeGC(mi->fore, mi->back, &Scr->MenuFont);
4413e747e6dSmrg	/* finally render the title */
4423e747e6dSmrg	MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x,
4433e747e6dSmrg	    text_y, mi->item, mi->strlen);
4443e747e6dSmrg    }
4453e747e6dSmrg}
4463e747e6dSmrg
4473e747e6dSmrg
4483e747e6dSmrgvoid
4493e747e6dSmrgPaintMenu(MenuRoot *mr, XEvent *e)
4503e747e6dSmrg{
4513e747e6dSmrg    MenuItem *mi;
4523e747e6dSmrg
4533e747e6dSmrg    for (mi = mr->first; mi != NULL; mi = mi->next)
4543e747e6dSmrg    {
4553e747e6dSmrg	int y_offset = mi->item_num * Scr->EntryHeight;
4563e747e6dSmrg
4573e747e6dSmrg	/* be smart about handling the expose, redraw only the entries
4583e747e6dSmrg	 * that we need to
4593e747e6dSmrg	 */
4603e747e6dSmrg	if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
4613e747e6dSmrg	    (e->xexpose.y + e->xexpose.height) > y_offset)
4623e747e6dSmrg	{
4633e747e6dSmrg	    PaintEntry(mr, mi, True);
4643e747e6dSmrg	}
4653e747e6dSmrg    }
4663e747e6dSmrg    XSync(dpy, 0);
4673e747e6dSmrg}
4683e747e6dSmrg
4693e747e6dSmrg
4703e747e6dSmrg
4713e747e6dSmrgstatic Bool fromMenu;
4723e747e6dSmrg
4733e747e6dSmrgvoid
4743e747e6dSmrgUpdateMenu()
4753e747e6dSmrg{
4763e747e6dSmrg    MenuItem *mi;
4773e747e6dSmrg    int i, x, y, x_root, y_root, entry;
4783e747e6dSmrg    int done;
4793e747e6dSmrg    MenuItem *badItem = NULL;
4803e747e6dSmrg
4813e747e6dSmrg    fromMenu = TRUE;
4823e747e6dSmrg
4833e747e6dSmrg    while (TRUE)
4843e747e6dSmrg    {
4853e747e6dSmrg	/* block until there is an event */
4863e747e6dSmrg        if (!menuFromFrameOrWindowOrTitlebar) {
4873e747e6dSmrg	  XMaskEvent(dpy,
4883e747e6dSmrg		     ButtonPressMask | ButtonReleaseMask |
4893e747e6dSmrg		     EnterWindowMask | ExposureMask |
4903e747e6dSmrg		     VisibilityChangeMask | LeaveWindowMask |
4913e747e6dSmrg		     ButtonMotionMask, &Event);
4923e747e6dSmrg	}
4933e747e6dSmrg	if (Event.type == MotionNotify) {
4943e747e6dSmrg	    /* discard any extra motion events before a release */
4953e747e6dSmrg	    while(XCheckMaskEvent(dpy,
4963e747e6dSmrg		ButtonMotionMask | ButtonReleaseMask, &Event))
4973e747e6dSmrg		if (Event.type == ButtonRelease)
4983e747e6dSmrg		    break;
4993e747e6dSmrg	}
5003e747e6dSmrg
5013e747e6dSmrg	if (!DispatchEvent ())
5023e747e6dSmrg	    continue;
5033e747e6dSmrg
5043e747e6dSmrg	if (Event.type == ButtonRelease || Cancel) {
5053e747e6dSmrg	  menuFromFrameOrWindowOrTitlebar = FALSE;
5063e747e6dSmrg	  fromMenu = FALSE;
5073e747e6dSmrg	  return;
5083e747e6dSmrg	}
5093e747e6dSmrg
5103e747e6dSmrg	if (Event.type != MotionNotify)
5113e747e6dSmrg	    continue;
5123e747e6dSmrg
5133e747e6dSmrg	done = FALSE;
5143e747e6dSmrg	XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
5153e747e6dSmrg	    &x_root, &y_root, &x, &y, &JunkMask);
5163e747e6dSmrg
5173e747e6dSmrg	/* if we haven't recieved the enter notify yet, wait */
5183e747e6dSmrg	if (ActiveMenu && !ActiveMenu->entered)
5193e747e6dSmrg	    continue;
5203e747e6dSmrg
5213e747e6dSmrg	XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *)&Scr);
5223e747e6dSmrg
5233e747e6dSmrg	if (x < 0 || y < 0 ||
5243e747e6dSmrg	    x >= ActiveMenu->width || y >= ActiveMenu->height)
5253e747e6dSmrg	{
5263e747e6dSmrg	    if (ActiveItem && ActiveItem->func != F_TITLE)
5273e747e6dSmrg	    {
5283e747e6dSmrg		ActiveItem->state = 0;
5293e747e6dSmrg		PaintEntry(ActiveMenu, ActiveItem, False);
5303e747e6dSmrg	    }
5313e747e6dSmrg	    ActiveItem = NULL;
5323e747e6dSmrg	    continue;
5333e747e6dSmrg	}
5343e747e6dSmrg
5353e747e6dSmrg	/* look for the entry that the mouse is in */
5363e747e6dSmrg	entry = y / Scr->EntryHeight;
5373e747e6dSmrg	for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
5383e747e6dSmrg	{
5393e747e6dSmrg	    if (i == entry)
5403e747e6dSmrg		break;
5413e747e6dSmrg	}
5423e747e6dSmrg
5433e747e6dSmrg	/* if there is an active item, we might have to turn it off */
5443e747e6dSmrg	if (ActiveItem)
5453e747e6dSmrg	{
5463e747e6dSmrg	    /* is the active item the one we are on ? */
5473e747e6dSmrg	    if (ActiveItem->item_num == entry && ActiveItem->state)
5483e747e6dSmrg		done = TRUE;
5493e747e6dSmrg
5503e747e6dSmrg	    /* if we weren't on the active entry, let's turn the old
5513e747e6dSmrg	     * active one off
5523e747e6dSmrg	     */
5533e747e6dSmrg	    if (!done && ActiveItem->func != F_TITLE)
5543e747e6dSmrg	    {
5553e747e6dSmrg		ActiveItem->state = 0;
5563e747e6dSmrg		PaintEntry(ActiveMenu, ActiveItem, False);
5573e747e6dSmrg	    }
5583e747e6dSmrg	}
5593e747e6dSmrg
5603e747e6dSmrg	/* if we weren't on the active item, change the active item and turn
5613e747e6dSmrg	 * it on
5623e747e6dSmrg	 */
5633e747e6dSmrg	if (!done)
5643e747e6dSmrg	{
5653e747e6dSmrg	    ActiveItem = mi;
5663e747e6dSmrg	    if (ActiveItem->func != F_TITLE && !ActiveItem->state)
5673e747e6dSmrg	    {
5683e747e6dSmrg		ActiveItem->state = 1;
5693e747e6dSmrg		PaintEntry(ActiveMenu, ActiveItem, False);
5703e747e6dSmrg	    }
5713e747e6dSmrg	}
5723e747e6dSmrg
5733e747e6dSmrg	/* now check to see if we were over the arrow of a pull right entry */
5743e747e6dSmrg	if (ActiveItem->func == F_MENU &&
5753e747e6dSmrg	    ((ActiveMenu->width - x) < (ActiveMenu->width >> 1)))
5763e747e6dSmrg	{
5773e747e6dSmrg	    MenuRoot *save = ActiveMenu;
5783e747e6dSmrg	    int savex = MenuOrigins[MenuDepth - 1].x;
5793e747e6dSmrg	    int savey = MenuOrigins[MenuDepth - 1].y;
5803e747e6dSmrg
5813e747e6dSmrg	    if (MenuDepth < MAXMENUDEPTH) {
5823e747e6dSmrg		PopUpMenu (ActiveItem->sub,
5833e747e6dSmrg			   (savex + (ActiveMenu->width >> 1)),
5843e747e6dSmrg			   (savey + ActiveItem->item_num * Scr->EntryHeight)
5853e747e6dSmrg			   /*(savey + ActiveItem->item_num * Scr->EntryHeight +
5863e747e6dSmrg			    (Scr->EntryHeight >> 1))*/, False);
5873e747e6dSmrg	    } else if (!badItem) {
5883e747e6dSmrg		Bell(XkbBI_MinorError,0,None);
5893e747e6dSmrg		badItem = ActiveItem;
5903e747e6dSmrg	    }
5913e747e6dSmrg
5923e747e6dSmrg	    /* if the menu did get popped up, unhighlight the active item */
5933e747e6dSmrg	    if (save != ActiveMenu && ActiveItem->state)
5943e747e6dSmrg	    {
5953e747e6dSmrg		ActiveItem->state = 0;
5963e747e6dSmrg		PaintEntry(save, ActiveItem, False);
5973e747e6dSmrg		ActiveItem = NULL;
5983e747e6dSmrg	    }
5993e747e6dSmrg	}
6003e747e6dSmrg	if (badItem != ActiveItem) badItem = NULL;
6013e747e6dSmrg	XFlush(dpy);
6023e747e6dSmrg    }
6033e747e6dSmrg
6043e747e6dSmrg}
6053e747e6dSmrg
6063e747e6dSmrg
6073e747e6dSmrg
6083e747e6dSmrg/**
6093e747e6dSmrg * create a new menu root
6103e747e6dSmrg *
6113e747e6dSmrg *  \param name  the name of the menu root
6123e747e6dSmrg */
6133e747e6dSmrgMenuRoot *
6143e747e6dSmrgNewMenuRoot(char *name)
6153e747e6dSmrg{
6163e747e6dSmrg    MenuRoot *tmp;
6173e747e6dSmrg
6183e747e6dSmrg#define UNUSED_PIXEL ((unsigned long) (~0))	/* more than 24 bits */
6193e747e6dSmrg
6203e747e6dSmrg    tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
6213e747e6dSmrg    tmp->hi_fore = UNUSED_PIXEL;
6223e747e6dSmrg    tmp->hi_back = UNUSED_PIXEL;
6233e747e6dSmrg    tmp->name = name;
6243e747e6dSmrg    tmp->prev = NULL;
6253e747e6dSmrg    tmp->first = NULL;
6263e747e6dSmrg    tmp->last = NULL;
6273e747e6dSmrg    tmp->items = 0;
6283e747e6dSmrg    tmp->width = 0;
6293e747e6dSmrg    tmp->mapped = NEVER_MAPPED;
6303e747e6dSmrg    tmp->pull = FALSE;
6313e747e6dSmrg    tmp->w = None;
6323e747e6dSmrg    tmp->shadow = None;
6333e747e6dSmrg    tmp->real_menu = FALSE;
6343e747e6dSmrg
6353e747e6dSmrg    if (Scr->MenuList == NULL)
6363e747e6dSmrg    {
6373e747e6dSmrg	Scr->MenuList = tmp;
6383e747e6dSmrg	Scr->MenuList->next = NULL;
6393e747e6dSmrg    }
6403e747e6dSmrg
6413e747e6dSmrg    if (Scr->LastMenu == NULL)
6423e747e6dSmrg    {
6433e747e6dSmrg	Scr->LastMenu = tmp;
6443e747e6dSmrg	Scr->LastMenu->next = NULL;
6453e747e6dSmrg    }
6463e747e6dSmrg    else
6473e747e6dSmrg    {
6483e747e6dSmrg	Scr->LastMenu->next = tmp;
6493e747e6dSmrg	Scr->LastMenu = tmp;
6503e747e6dSmrg	Scr->LastMenu->next = NULL;
6513e747e6dSmrg    }
6523e747e6dSmrg
6533e747e6dSmrg    if (strcmp(name, TWM_WINDOWS) == 0)
6543e747e6dSmrg	Scr->Windows = tmp;
6553e747e6dSmrg
6563e747e6dSmrg    return (tmp);
6573e747e6dSmrg}
6583e747e6dSmrg
6593e747e6dSmrg
6603e747e6dSmrg
6613e747e6dSmrg/**
6623e747e6dSmrg * add an item to a root menu
6633e747e6dSmrg *
6643e747e6dSmrg *  \param menu   pointer to the root menu to add the item
6653e747e6dSmrg *  \param item   the text to appear in the menu
6663e747e6dSmrg *  \param action the string to possibly execute
6673e747e6dSmrg *  \param sub    the menu root if it is a pull-right entry
6683e747e6dSmrg *  \param func   the numeric function
6693e747e6dSmrg *  \param fore   foreground color string
6703e747e6dSmrg *  \param back   background color string
6713e747e6dSmrg */
6723e747e6dSmrgMenuItem *
6733e747e6dSmrgAddToMenu(MenuRoot *menu, char *item, char *action, MenuRoot *sub, int func,
6743e747e6dSmrg          char *fore, char *back)
6753e747e6dSmrg{
6763e747e6dSmrg    MenuItem *tmp;
6773e747e6dSmrg    int width;
6783e747e6dSmrg
6793e747e6dSmrg#ifdef DEBUG_MENUS
6803e747e6dSmrg    fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
6813e747e6dSmrg	item, action, sub, func);
6823e747e6dSmrg#endif
6833e747e6dSmrg
6843e747e6dSmrg    tmp = (MenuItem *) malloc(sizeof(MenuItem));
6853e747e6dSmrg    tmp->root = menu;
6863e747e6dSmrg
6873e747e6dSmrg    if (menu->first == NULL)
6883e747e6dSmrg    {
6893e747e6dSmrg	menu->first = tmp;
6903e747e6dSmrg	tmp->prev = NULL;
6913e747e6dSmrg    }
6923e747e6dSmrg    else
6933e747e6dSmrg    {
6943e747e6dSmrg	menu->last->next = tmp;
6953e747e6dSmrg	tmp->prev = menu->last;
6963e747e6dSmrg    }
6973e747e6dSmrg    menu->last = tmp;
6983e747e6dSmrg
6993e747e6dSmrg    tmp->item = item;
7003e747e6dSmrg    tmp->strlen = strlen(item);
7013e747e6dSmrg    tmp->action = action;
7023e747e6dSmrg    tmp->next = NULL;
7033e747e6dSmrg    tmp->sub = NULL;
7043e747e6dSmrg    tmp->state = 0;
7053e747e6dSmrg    tmp->func = func;
7063e747e6dSmrg
7073e747e6dSmrg    if (!Scr->HaveFonts) CreateFonts();
7083e747e6dSmrg    width = MyFont_TextWidth(&Scr->MenuFont, item, tmp->strlen);
7093e747e6dSmrg    if (width <= 0)
7103e747e6dSmrg	width = 1;
7113e747e6dSmrg    if (width > menu->width)
7123e747e6dSmrg	menu->width = width;
7133e747e6dSmrg
7143e747e6dSmrg    tmp->user_colors = FALSE;
7153e747e6dSmrg    if (Scr->Monochrome == COLOR && fore != NULL)
7163e747e6dSmrg    {
7173e747e6dSmrg	int save;
7183e747e6dSmrg
7193e747e6dSmrg	save = Scr->FirstTime;
7203e747e6dSmrg	Scr->FirstTime = TRUE;
7213e747e6dSmrg	GetColor(COLOR, &tmp->fore, fore);
7223e747e6dSmrg	GetColor(COLOR, &tmp->back, back);
7233e747e6dSmrg	Scr->FirstTime = save;
7243e747e6dSmrg	tmp->user_colors = TRUE;
7253e747e6dSmrg    }
7263e747e6dSmrg    if (sub != NULL)
7273e747e6dSmrg    {
7283e747e6dSmrg	tmp->sub = sub;
7293e747e6dSmrg	menu->pull = TRUE;
7303e747e6dSmrg    }
7313e747e6dSmrg    tmp->item_num = menu->items++;
7323e747e6dSmrg
7333e747e6dSmrg    return (tmp);
7343e747e6dSmrg}
7353e747e6dSmrg
7363e747e6dSmrg
7373e747e6dSmrgvoid
7383e747e6dSmrgMakeMenus()
7393e747e6dSmrg{
7403e747e6dSmrg    MenuRoot *mr;
7413e747e6dSmrg
7423e747e6dSmrg    for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
7433e747e6dSmrg    {
7443e747e6dSmrg	if (mr->real_menu == FALSE)
7453e747e6dSmrg	    continue;
7463e747e6dSmrg
7473e747e6dSmrg	MakeMenu(mr);
7483e747e6dSmrg    }
7493e747e6dSmrg}
7503e747e6dSmrg
7513e747e6dSmrg
7523e747e6dSmrgvoid
7533e747e6dSmrgMakeMenu(MenuRoot *mr)
7543e747e6dSmrg{
7553e747e6dSmrg    MenuItem *start, *end, *cur, *tmp;
7563e747e6dSmrg    XColor f1, f2, f3;
7573e747e6dSmrg    XColor b1, b2, b3;
7583e747e6dSmrg    XColor save_fore, save_back;
7593e747e6dSmrg    int num, i;
7603e747e6dSmrg    int fred, fgreen, fblue;
7613e747e6dSmrg    int bred, bgreen, bblue;
7623e747e6dSmrg    int width;
7633e747e6dSmrg    unsigned long valuemask;
7643e747e6dSmrg    XSetWindowAttributes attributes;
7653e747e6dSmrg    Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
7663e747e6dSmrg
7673e747e6dSmrg    Scr->EntryHeight = Scr->MenuFont.height + 4;
7683e747e6dSmrg
7693e747e6dSmrg    /* lets first size the window accordingly */
7703e747e6dSmrg    if (mr->mapped == NEVER_MAPPED)
7713e747e6dSmrg    {
7723e747e6dSmrg	if (mr->pull == TRUE)
7733e747e6dSmrg	{
7743e747e6dSmrg	    mr->width += 16 + 10;
7753e747e6dSmrg	}
7763e747e6dSmrg
7773e747e6dSmrg	width = mr->width + 10;
7783e747e6dSmrg
7793e747e6dSmrg	for (cur = mr->first; cur != NULL; cur = cur->next)
7803e747e6dSmrg	{
7813e747e6dSmrg	    if (cur->func != F_TITLE)
7823e747e6dSmrg		cur->x = 5;
7833e747e6dSmrg	    else
7843e747e6dSmrg	    {
7853e747e6dSmrg		cur->x = width - MyFont_TextWidth(&Scr->MenuFont, cur->item,
7863e747e6dSmrg		    cur->strlen);
7873e747e6dSmrg		cur->x /= 2;
7883e747e6dSmrg	    }
7893e747e6dSmrg	}
7903e747e6dSmrg	mr->height = mr->items * Scr->EntryHeight;
7913e747e6dSmrg	mr->width += 10;
7923e747e6dSmrg
7933e747e6dSmrg	if (Scr->Shadow)
7943e747e6dSmrg	{
7953e747e6dSmrg	    /*
7963e747e6dSmrg	     * Make sure that you don't draw into the shadow window or else
7973e747e6dSmrg	     * the background bits there will get saved
7983e747e6dSmrg	     */
7993e747e6dSmrg	    valuemask = (CWBackPixel | CWBorderPixel);
8003e747e6dSmrg	    attributes.background_pixel = Scr->MenuShadowColor;
8013e747e6dSmrg	    attributes.border_pixel = Scr->MenuShadowColor;
8023e747e6dSmrg	    if (Scr->SaveUnder) {
8033e747e6dSmrg		valuemask |= CWSaveUnder;
8043e747e6dSmrg		attributes.save_under = True;
8053e747e6dSmrg	    }
8063e747e6dSmrg	    mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
8073e747e6dSmrg					(unsigned int) mr->width,
8083e747e6dSmrg					(unsigned int) mr->height,
8093e747e6dSmrg					(unsigned int)0,
8103e747e6dSmrg					CopyFromParent,
8113e747e6dSmrg					(unsigned int) CopyFromParent,
8123e747e6dSmrg					(Visual *) CopyFromParent,
8133e747e6dSmrg					valuemask, &attributes);
8143e747e6dSmrg	}
8153e747e6dSmrg
8163e747e6dSmrg	valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
8173e747e6dSmrg	attributes.background_pixel = Scr->MenuC.back;
8183e747e6dSmrg	attributes.border_pixel = Scr->MenuBorderColor;
8193e747e6dSmrg	attributes.event_mask = (ExposureMask | EnterWindowMask);
8203e747e6dSmrg	if (Scr->SaveUnder) {
8213e747e6dSmrg	    valuemask |= CWSaveUnder;
8223e747e6dSmrg	    attributes.save_under = True;
8233e747e6dSmrg	}
8243e747e6dSmrg	if (Scr->BackingStore) {
8253e747e6dSmrg	    valuemask |= CWBackingStore;
8263e747e6dSmrg	    attributes.backing_store = Always;
8273e747e6dSmrg	}
8283e747e6dSmrg	mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
8293e747e6dSmrg			       (unsigned int) mr->height,
8303e747e6dSmrg			       (unsigned int) Scr->MenuBorderWidth,
8313e747e6dSmrg			       CopyFromParent, (unsigned int) CopyFromParent,
8323e747e6dSmrg			       (Visual *) CopyFromParent,
8333e747e6dSmrg			       valuemask, &attributes);
8343e747e6dSmrg
8353e747e6dSmrg
8363e747e6dSmrg	XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
8373e747e6dSmrg	XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
8383e747e6dSmrg
8393e747e6dSmrg	mr->mapped = UNMAPPED;
8403e747e6dSmrg    }
8413e747e6dSmrg
8423e747e6dSmrg    /* get the default colors into the menus */
8433e747e6dSmrg    for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
8443e747e6dSmrg    {
8453e747e6dSmrg	if (!tmp->user_colors) {
8463e747e6dSmrg	    if (tmp->func != F_TITLE) {
8473e747e6dSmrg		tmp->fore = Scr->MenuC.fore;
8483e747e6dSmrg		tmp->back = Scr->MenuC.back;
8493e747e6dSmrg	    } else {
8503e747e6dSmrg		tmp->fore = Scr->MenuTitleC.fore;
8513e747e6dSmrg		tmp->back = Scr->MenuTitleC.back;
8523e747e6dSmrg	    }
8533e747e6dSmrg	}
8543e747e6dSmrg
8553e747e6dSmrg	if (mr->hi_fore != UNUSED_PIXEL)
8563e747e6dSmrg	{
8573e747e6dSmrg	    tmp->hi_fore = mr->hi_fore;
8583e747e6dSmrg	    tmp->hi_back = mr->hi_back;
8593e747e6dSmrg	}
8603e747e6dSmrg	else
8613e747e6dSmrg	{
8623e747e6dSmrg	    tmp->hi_fore = tmp->back;
8633e747e6dSmrg	    tmp->hi_back = tmp->fore;
8643e747e6dSmrg	}
8653e747e6dSmrg    }
8663e747e6dSmrg
8673e747e6dSmrg    if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
8683e747e6dSmrg	return;
8693e747e6dSmrg
8703e747e6dSmrg    start = mr->first;
8713e747e6dSmrg    while (TRUE)
8723e747e6dSmrg    {
8733e747e6dSmrg	for (; start != NULL; start = start->next)
8743e747e6dSmrg	{
8753e747e6dSmrg	    if (start->user_colors)
8763e747e6dSmrg		break;
8773e747e6dSmrg	}
8783e747e6dSmrg	if (start == NULL)
8793e747e6dSmrg	    break;
8803e747e6dSmrg
8813e747e6dSmrg	for (end = start->next; end != NULL; end = end->next)
8823e747e6dSmrg	{
8833e747e6dSmrg	    if (end->user_colors)
8843e747e6dSmrg		break;
8853e747e6dSmrg	}
8863e747e6dSmrg	if (end == NULL)
8873e747e6dSmrg	    break;
8883e747e6dSmrg
8893e747e6dSmrg	/* we have a start and end to interpolate between */
8903e747e6dSmrg	num = end->item_num - start->item_num;
8913e747e6dSmrg
8923e747e6dSmrg	f1.pixel = start->fore;
8933e747e6dSmrg	XQueryColor(dpy, cmap, &f1);
8943e747e6dSmrg	f2.pixel = end->fore;
8953e747e6dSmrg	XQueryColor(dpy, cmap, &f2);
8963e747e6dSmrg
8973e747e6dSmrg	b1.pixel = start->back;
8983e747e6dSmrg	XQueryColor(dpy, cmap, &b1);
8993e747e6dSmrg	b2.pixel = end->back;
9003e747e6dSmrg	XQueryColor(dpy, cmap, &b2);
9013e747e6dSmrg
9023e747e6dSmrg	fred = ((int)f2.red - (int)f1.red) / num;
9033e747e6dSmrg	fgreen = ((int)f2.green - (int)f1.green) / num;
9043e747e6dSmrg	fblue = ((int)f2.blue - (int)f1.blue) / num;
9053e747e6dSmrg
9063e747e6dSmrg	bred = ((int)b2.red - (int)b1.red) / num;
9073e747e6dSmrg	bgreen = ((int)b2.green - (int)b1.green) / num;
9083e747e6dSmrg	bblue = ((int)b2.blue - (int)b1.blue) / num;
9093e747e6dSmrg
9103e747e6dSmrg	f3 = f1;
9113e747e6dSmrg	f3.flags = DoRed | DoGreen | DoBlue;
9123e747e6dSmrg
9133e747e6dSmrg	b3 = b1;
9143e747e6dSmrg	b3.flags = DoRed | DoGreen | DoBlue;
9153e747e6dSmrg
9163e747e6dSmrg	num -= 1;
9173e747e6dSmrg	for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
9183e747e6dSmrg	{
9193e747e6dSmrg	    f3.red += fred;
9203e747e6dSmrg	    f3.green += fgreen;
9213e747e6dSmrg	    f3.blue += fblue;
9223e747e6dSmrg	    save_fore = f3;
9233e747e6dSmrg
9243e747e6dSmrg	    b3.red += bred;
9253e747e6dSmrg	    b3.green += bgreen;
9263e747e6dSmrg	    b3.blue += bblue;
9273e747e6dSmrg	    save_back = b3;
9283e747e6dSmrg
9293e747e6dSmrg	    XAllocColor(dpy, cmap, &f3);
9303e747e6dSmrg	    XAllocColor(dpy, cmap, &b3);
9313e747e6dSmrg	    cur->hi_back = cur->fore = f3.pixel;
9323e747e6dSmrg	    cur->hi_fore = cur->back = b3.pixel;
9333e747e6dSmrg	    cur->user_colors = True;
9343e747e6dSmrg
9353e747e6dSmrg	    f3 = save_fore;
9363e747e6dSmrg	    b3 = save_back;
9373e747e6dSmrg	}
9383e747e6dSmrg	start = end;
9393e747e6dSmrg    }
9403e747e6dSmrg}
9413e747e6dSmrg
9423e747e6dSmrg
9433e747e6dSmrg
9443e747e6dSmrg/**
9453e747e6dSmrg * pop up a pull down menu.
9463e747e6dSmrg *
9473e747e6dSmrg *  \param menu   the root pointer of the menu to pop up
9483e747e6dSmrg *  \param x,y    location of upper left of menu
9493e747e6dSmrg *  \param center whether or not to center horizontally over position
9503e747e6dSmrg */
9513e747e6dSmrgBool
9523e747e6dSmrgPopUpMenu (MenuRoot *menu, int x, int y, Bool center)
9533e747e6dSmrg{
9543e747e6dSmrg    int WindowNameCount;
9553e747e6dSmrg    TwmWindow **WindowNames;
9563e747e6dSmrg    TwmWindow *tmp_win2,*tmp_win3;
9573e747e6dSmrg    int i;
9583e747e6dSmrg    int (*compar)(const char *, const char *) =
9593e747e6dSmrg      (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
9603e747e6dSmrg
9613e747e6dSmrg    if (!menu) return False;
9623e747e6dSmrg
9633e747e6dSmrg    InstallRootColormap();
9643e747e6dSmrg
9653e747e6dSmrg    if (menu == Scr->Windows)
9663e747e6dSmrg    {
9673e747e6dSmrg	TwmWindow *tmp_win;
9683e747e6dSmrg
9693e747e6dSmrg	/* this is the twm windows menu,  let's go ahead and build it */
9703e747e6dSmrg
9713e747e6dSmrg	DestroyMenu (menu);
9723e747e6dSmrg
9733e747e6dSmrg	menu->first = NULL;
9743e747e6dSmrg	menu->last = NULL;
9753e747e6dSmrg	menu->items = 0;
9763e747e6dSmrg	menu->width = 0;
9773e747e6dSmrg	menu->mapped = NEVER_MAPPED;
9783e747e6dSmrg  	AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
9793e747e6dSmrg
9803e747e6dSmrg        for(tmp_win = Scr->TwmRoot.next , WindowNameCount=0;
9813e747e6dSmrg            tmp_win != NULL;
9823e747e6dSmrg            tmp_win = tmp_win->next)
9833e747e6dSmrg          WindowNameCount++;
9843e747e6dSmrg        if (WindowNameCount != 0)
9853e747e6dSmrg        {
9863e747e6dSmrg            WindowNames =
9873e747e6dSmrg              (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
9883e747e6dSmrg            WindowNames[0] = Scr->TwmRoot.next;
9893e747e6dSmrg            for(tmp_win = Scr->TwmRoot.next->next , WindowNameCount=1;
9903e747e6dSmrg                tmp_win != NULL;
9913e747e6dSmrg                tmp_win = tmp_win->next,WindowNameCount++)
9923e747e6dSmrg            {
9933e747e6dSmrg                tmp_win2 = tmp_win;
9943e747e6dSmrg                for (i=0;i<WindowNameCount;i++)
9953e747e6dSmrg                {
9963e747e6dSmrg                    if ((*compar)(tmp_win2->name,WindowNames[i]->name) < 0)
9973e747e6dSmrg                    {
9983e747e6dSmrg                        tmp_win3 = tmp_win2;
9993e747e6dSmrg                        tmp_win2 = WindowNames[i];
10003e747e6dSmrg                        WindowNames[i] = tmp_win3;
10013e747e6dSmrg                    }
10023e747e6dSmrg                }
10033e747e6dSmrg                WindowNames[WindowNameCount] = tmp_win2;
10043e747e6dSmrg            }
10053e747e6dSmrg            for (i=0; i<WindowNameCount; i++)
10063e747e6dSmrg            {
10073e747e6dSmrg                AddToMenu(menu, WindowNames[i]->name, (char *)WindowNames[i],
10083e747e6dSmrg                          NULL, F_POPUP,NULL,NULL);
10093e747e6dSmrg            }
10103e747e6dSmrg            free(WindowNames);
10113e747e6dSmrg        }
10123e747e6dSmrg
10133e747e6dSmrg	MakeMenu(menu);
10143e747e6dSmrg    }
10153e747e6dSmrg
10163e747e6dSmrg    if (menu->w == None || menu->items == 0) return False;
10173e747e6dSmrg
10183e747e6dSmrg    /* Prevent recursively bringing up menus. */
10193e747e6dSmrg    if (menu->mapped == MAPPED) return False;
10203e747e6dSmrg
10213e747e6dSmrg    /*
10223e747e6dSmrg     * Dynamically set the parent;  this allows pull-ups to also be main
10233e747e6dSmrg     * menus, or to be brought up from more than one place.
10243e747e6dSmrg     */
10253e747e6dSmrg    menu->prev = ActiveMenu;
10263e747e6dSmrg
10273e747e6dSmrg    XGrabPointer(dpy, Scr->Root, True,
10283e747e6dSmrg	ButtonPressMask | ButtonReleaseMask |
10293e747e6dSmrg	ButtonMotionMask | PointerMotionHintMask,
10303e747e6dSmrg	GrabModeAsync, GrabModeAsync,
10313e747e6dSmrg	Scr->Root, Scr->MenuCursor, CurrentTime);
10323e747e6dSmrg
10333e747e6dSmrg    ActiveMenu = menu;
10343e747e6dSmrg    menu->mapped = MAPPED;
10353e747e6dSmrg    menu->entered = FALSE;
10363e747e6dSmrg
10373e747e6dSmrg    if (center) {
10383e747e6dSmrg	x -= (menu->width / 2);
10393e747e6dSmrg	y -= (Scr->EntryHeight / 2);	/* sticky menus would be nice here */
10403e747e6dSmrg    }
10413e747e6dSmrg
10423e747e6dSmrg    /*
10433e747e6dSmrg     * clip to screen
10443e747e6dSmrg     */
10453e747e6dSmrg    if (x + menu->width > Scr->MyDisplayWidth) {
10463e747e6dSmrg	x = Scr->MyDisplayWidth - menu->width;
10473e747e6dSmrg    }
10483e747e6dSmrg    if (x < 0) x = 0;
10493e747e6dSmrg    if (y + menu->height > Scr->MyDisplayHeight) {
10503e747e6dSmrg	y = Scr->MyDisplayHeight - menu->height;
10513e747e6dSmrg    }
10523e747e6dSmrg    if (y < 0) y = 0;
10533e747e6dSmrg
10543e747e6dSmrg    MenuOrigins[MenuDepth].x = x;
10553e747e6dSmrg    MenuOrigins[MenuDepth].y = y;
10563e747e6dSmrg    MenuDepth++;
10573e747e6dSmrg
10583e747e6dSmrg    XMoveWindow(dpy, menu->w, x, y);
10593e747e6dSmrg    if (Scr->Shadow) {
10603e747e6dSmrg	XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
10613e747e6dSmrg    }
10623e747e6dSmrg    if (Scr->Shadow) {
10633e747e6dSmrg	XRaiseWindow (dpy, menu->shadow);
10643e747e6dSmrg    }
10653e747e6dSmrg    XMapRaised(dpy, menu->w);
10663e747e6dSmrg    if (Scr->Shadow) {
10673e747e6dSmrg	XMapWindow (dpy, menu->shadow);
10683e747e6dSmrg    }
10693e747e6dSmrg    XSync(dpy, 0);
10703e747e6dSmrg    return True;
10713e747e6dSmrg}
10723e747e6dSmrg
10733e747e6dSmrg
10743e747e6dSmrg
10753e747e6dSmrg/**
10763e747e6dSmrg * unhighlight the current menu selection and take down the menus
10773e747e6dSmrg */
10783e747e6dSmrgvoid
10793e747e6dSmrgPopDownMenu()
10803e747e6dSmrg{
10813e747e6dSmrg    MenuRoot *tmp;
10823e747e6dSmrg
10833e747e6dSmrg    if (ActiveMenu == NULL)
10843e747e6dSmrg	return;
10853e747e6dSmrg
10863e747e6dSmrg    if (ActiveItem)
10873e747e6dSmrg    {
10883e747e6dSmrg	ActiveItem->state = 0;
10893e747e6dSmrg	PaintEntry(ActiveMenu, ActiveItem, False);
10903e747e6dSmrg    }
10913e747e6dSmrg
10923e747e6dSmrg    for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
10933e747e6dSmrg    {
10943e747e6dSmrg	if (Scr->Shadow) {
10953e747e6dSmrg	    XUnmapWindow (dpy, tmp->shadow);
10963e747e6dSmrg	}
10973e747e6dSmrg	XUnmapWindow(dpy, tmp->w);
10983e747e6dSmrg	tmp->mapped = UNMAPPED;
10993e747e6dSmrg	UninstallRootColormap();
11003e747e6dSmrg    }
11013e747e6dSmrg
11023e747e6dSmrg    XFlush(dpy);
11033e747e6dSmrg    ActiveMenu = NULL;
11043e747e6dSmrg    ActiveItem = NULL;
11053e747e6dSmrg    MenuDepth = 0;
11063e747e6dSmrg    if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE)
11073e747e6dSmrg      menuFromFrameOrWindowOrTitlebar = TRUE;
11083e747e6dSmrg}
11093e747e6dSmrg
11103e747e6dSmrg
11113e747e6dSmrg
11123e747e6dSmrg/**
11133e747e6dSmrg * look for a menu root
11143e747e6dSmrg *
11153e747e6dSmrg *  \return a pointer to the menu root structure
11163e747e6dSmrg *
11173e747e6dSmrg *  \param name the name of the menu root
11183e747e6dSmrg */
11193e747e6dSmrgMenuRoot *
11203e747e6dSmrgFindMenuRoot(char *name)
11213e747e6dSmrg{
11223e747e6dSmrg    MenuRoot *tmp;
11233e747e6dSmrg
11243e747e6dSmrg    for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
11253e747e6dSmrg    {
11263e747e6dSmrg	if (strcmp(name, tmp->name) == 0)
11273e747e6dSmrg	    return (tmp);
11283e747e6dSmrg    }
11293e747e6dSmrg    return NULL;
11303e747e6dSmrg}
11313e747e6dSmrg
11323e747e6dSmrg
11333e747e6dSmrg
11343e747e6dSmrgstatic Bool
11353e747e6dSmrgbelongs_to_twm_window (TwmWindow *t, Window w)
11363e747e6dSmrg{
11373e747e6dSmrg    if (!t) return False;
11383e747e6dSmrg
11393e747e6dSmrg    if (w == t->frame || w == t->title_w || w == t->hilite_w ||
11403e747e6dSmrg	w == t->icon_w || w == t->icon_bm_w) return True;
11413e747e6dSmrg
11423e747e6dSmrg    if (t && t->titlebuttons) {
11433e747e6dSmrg	register TBWindow *tbw;
11443e747e6dSmrg	register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
11453e747e6dSmrg	for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
11463e747e6dSmrg	    if (tbw->window == w) return True;
11473e747e6dSmrg	}
11483e747e6dSmrg    }
11493e747e6dSmrg    return False;
11503e747e6dSmrg}
11513e747e6dSmrg
11523e747e6dSmrg
11533e747e6dSmrg
11543e747e6dSmrgvoid
11553e747e6dSmrgresizeFromCenter(Window w, TwmWindow *tmp_win)
11563e747e6dSmrg{
11573e747e6dSmrg  int lastx, lasty, bw2;
11583e747e6dSmrg  XEvent event;
11593e747e6dSmrg#if 0
11603e747e6dSmrg  int namelen;
11613e747e6dSmrg  int width, height;
11623e747e6dSmrg
11633e747e6dSmrg  namelen = strlen (tmp_win->name);
11643e747e6dSmrg#endif
11653e747e6dSmrg  bw2 = tmp_win->frame_bw * 2;
11663e747e6dSmrg  AddingW = tmp_win->attr.width + bw2;
11673e747e6dSmrg  AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
11683e747e6dSmrg#if 0
11693e747e6dSmrg  width = (SIZE_HINDENT + MyFont_TextWidth (&Scr->SizeFont,
11703e747e6dSmrg					     tmp_win->name, namelen));
11713e747e6dSmrg  height = Scr->SizeFont.height + SIZE_VINDENT * 2;
11723e747e6dSmrg#endif
11733e747e6dSmrg  XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
11743e747e6dSmrg	       (unsigned int *)&DragWidth, (unsigned int *)&DragHeight,
11753e747e6dSmrg	       &JunkBW, &JunkDepth);
11763e747e6dSmrg  XWarpPointer(dpy, None, w,
11773e747e6dSmrg	       0, 0, 0, 0, DragWidth/2, DragHeight/2);
11783e747e6dSmrg  XQueryPointer (dpy, Scr->Root, &JunkRoot,
11793e747e6dSmrg		 &JunkChild, &JunkX, &JunkY,
11803e747e6dSmrg		 &AddingX, &AddingY, &JunkMask);
11813e747e6dSmrg#if 0
11823e747e6dSmrg  Scr->SizeStringOffset = width +
11833e747e6dSmrg    MyFont_TextWidth(&Scr->SizeFont, ": ", 2);
11843e747e6dSmrg  XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
11853e747e6dSmrg		 Scr->SizeStringWidth, height);
11863e747e6dSmrg  MyFont_DrawImageString (dpy, Scr->SizeWindow, &Scr->SizeFont, Scr->NormalGC,
11873e747e6dSmrg		    width, SIZE_VINDENT + Scr->SizeFont.ascent,
11883e747e6dSmrg		    ": ", 2);
11893e747e6dSmrg#endif
11903e747e6dSmrg  lastx = -10000;
11913e747e6dSmrg  lasty = -10000;
11923e747e6dSmrg#if 0
11933e747e6dSmrg  MoveOutline(Scr->Root,
11943e747e6dSmrg	      origDragX - JunkBW, origDragY - JunkBW,
11953e747e6dSmrg	      DragWidth * JunkBW, DragHeight * JunkBW,
11963e747e6dSmrg	      tmp_win->frame_bw,
11973e747e6dSmrg	      tmp_win->title_height);
11983e747e6dSmrg#endif
11993e747e6dSmrg  MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
12003e747e6dSmrg  while (TRUE)
12013e747e6dSmrg    {
12023e747e6dSmrg      XMaskEvent(dpy,
12033e747e6dSmrg		 ButtonPressMask | PointerMotionMask, &event);
12043e747e6dSmrg
12053e747e6dSmrg      if (event.type == MotionNotify) {
12063e747e6dSmrg	/* discard any extra motion events before a release */
12073e747e6dSmrg	while(XCheckMaskEvent(dpy,
12083e747e6dSmrg			      ButtonMotionMask | ButtonPressMask, &event))
12093e747e6dSmrg	  if (event.type == ButtonPress)
12103e747e6dSmrg	    break;
12113e747e6dSmrg      }
12123e747e6dSmrg
12133e747e6dSmrg      if (event.type == ButtonPress)
12143e747e6dSmrg	{
12153e747e6dSmrg	  MenuEndResize(tmp_win);
12163e747e6dSmrg	  XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
12173e747e6dSmrg	  break;
12183e747e6dSmrg	}
12193e747e6dSmrg
12203e747e6dSmrg/*    if (!DispatchEvent ()) continue; */
12213e747e6dSmrg
12223e747e6dSmrg      if (event.type != MotionNotify) {
12233e747e6dSmrg	continue;
12243e747e6dSmrg      }
12253e747e6dSmrg
12263e747e6dSmrg      /*
12273e747e6dSmrg       * XXX - if we are going to do a loop, we ought to consider
12283e747e6dSmrg       * using multiple GXxor lines so that we don't need to
12293e747e6dSmrg       * grab the server.
12303e747e6dSmrg       */
12313e747e6dSmrg      XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
12323e747e6dSmrg		    &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
12333e747e6dSmrg
12343e747e6dSmrg      if (lastx != AddingX || lasty != AddingY)
12353e747e6dSmrg	{
12363e747e6dSmrg	  MenuDoResize(AddingX, AddingY, tmp_win);
12373e747e6dSmrg
12383e747e6dSmrg	  lastx = AddingX;
12393e747e6dSmrg	  lasty = AddingY;
12403e747e6dSmrg	}
12413e747e6dSmrg
12423e747e6dSmrg    }
12433e747e6dSmrg}
12443e747e6dSmrg
12453e747e6dSmrg
12463e747e6dSmrg
12473e747e6dSmrg/** \fn ExecuteFunction
12483e747e6dSmrg * execute a twm root function.
12493e747e6dSmrg *
12503e747e6dSmrg *  \param func     the function to execute
12513e747e6dSmrg *  \param action   the menu action to execute
12523e747e6dSmrg *  \param w        the window to execute this function on
12533e747e6dSmrg *  \param tmp_win  the twm window structure
12543e747e6dSmrg *  \param event    the event that caused the function
12553e747e6dSmrg *  \param context  the context in which the button was pressed
12563e747e6dSmrg *  \param pulldown flag indicating execution from pull down menu
12573e747e6dSmrg *
12583e747e6dSmrg *  \return TRUE if should continue with remaining actions,
12593e747e6dSmrg *           else FALSE to abort
12603e747e6dSmrg */
12613e747e6dSmrg
12623e747e6dSmrgint
12633e747e6dSmrgWarpThere(TwmWindow *t)
12643e747e6dSmrg{
12653e747e6dSmrg    if (Scr->WarpUnmapped || t->mapped) {
12663e747e6dSmrg        if (!t->mapped) DeIconify (t);
12673e747e6dSmrg        if (!Scr->NoRaiseWarp) XRaiseWindow (dpy, t->frame);
12683e747e6dSmrg        WarpToWindow (t);
12693e747e6dSmrg        return 1;
12703e747e6dSmrg    }
12713e747e6dSmrg    return 0;
12723e747e6dSmrg}
12733e747e6dSmrg
12743e747e6dSmrg
12753e747e6dSmrgint
12763e747e6dSmrgExecuteFunction(int func, char *action, Window w, TwmWindow *tmp_win,
12773e747e6dSmrg                XEvent *eventp, int context, int pulldown)
12783e747e6dSmrg{
12793e747e6dSmrg    static Time last_time = 0;
12803e747e6dSmrg    char tmp[200];
12813e747e6dSmrg    char *ptr;
12823e747e6dSmrg    char buff[MAX_FILE_SIZE];
12833e747e6dSmrg    int count, fd;
12843e747e6dSmrg    Window rootw;
12853e747e6dSmrg    int origX, origY;
12863e747e6dSmrg    int do_next_action = TRUE;
12873e747e6dSmrg    int moving_icon = FALSE;
12883e747e6dSmrg    Bool fromtitlebar = False;
12893e747e6dSmrg
12903e747e6dSmrg    RootFunction = 0;
12913e747e6dSmrg    if (Cancel)
12923e747e6dSmrg	return TRUE;			/* XXX should this be FALSE? */
12933e747e6dSmrg
12943e747e6dSmrg    switch (func)
12953e747e6dSmrg    {
12963e747e6dSmrg    case F_UPICONMGR:
12973e747e6dSmrg    case F_LEFTICONMGR:
12983e747e6dSmrg    case F_RIGHTICONMGR:
12993e747e6dSmrg    case F_DOWNICONMGR:
13003e747e6dSmrg    case F_FORWICONMGR:
13013e747e6dSmrg    case F_BACKICONMGR:
13023e747e6dSmrg    case F_NEXTICONMGR:
13033e747e6dSmrg    case F_PREVICONMGR:
13043e747e6dSmrg    case F_NOP:
13053e747e6dSmrg    case F_TITLE:
13063e747e6dSmrg    case F_DELTASTOP:
13073e747e6dSmrg    case F_RAISELOWER:
13083e747e6dSmrg    case F_WARPTOSCREEN:
13093e747e6dSmrg    case F_WARPTO:
13103e747e6dSmrg    case F_WARPRING:
13113e747e6dSmrg    case F_WARPTOICONMGR:
13123e747e6dSmrg    case F_WARPNEXT:
13133e747e6dSmrg    case F_WARPPREV:
13143e747e6dSmrg    case F_COLORMAP:
13153e747e6dSmrg	break;
13163e747e6dSmrg    default:
13173e747e6dSmrg        XGrabPointer(dpy, Scr->Root, True,
13183e747e6dSmrg            ButtonPressMask | ButtonReleaseMask,
13193e747e6dSmrg            GrabModeAsync, GrabModeAsync,
13203e747e6dSmrg            Scr->Root, Scr->WaitCursor, CurrentTime);
13213e747e6dSmrg	break;
13223e747e6dSmrg    }
13233e747e6dSmrg
13243e747e6dSmrg    switch (func)
13253e747e6dSmrg    {
13263e747e6dSmrg    case F_NOP:
13273e747e6dSmrg    case F_TITLE:
13283e747e6dSmrg	break;
13293e747e6dSmrg
13303e747e6dSmrg    case F_DELTASTOP:
13313e747e6dSmrg	if (WindowMoved) do_next_action = FALSE;
13323e747e6dSmrg	break;
13333e747e6dSmrg
13343e747e6dSmrg    case F_RESTART:
13353e747e6dSmrg    {
13363e747e6dSmrg	XSync (dpy, 0);
13373e747e6dSmrg	Reborder (eventp->xbutton.time);
13383e747e6dSmrg	XSync (dpy, 0);
13393e747e6dSmrg	if (smcConn)
13403e747e6dSmrg	    SmcCloseConnection (smcConn, 0, NULL);
13413e747e6dSmrg	execvp(*Argv, Argv);
13423e747e6dSmrg	fprintf (stderr, "%s:  unable to restart:  %s\n", ProgramName, *Argv);
13433e747e6dSmrg	break;
13443e747e6dSmrg    }
13453e747e6dSmrg
13463e747e6dSmrg    case F_UPICONMGR:
13473e747e6dSmrg    case F_DOWNICONMGR:
13483e747e6dSmrg    case F_LEFTICONMGR:
13493e747e6dSmrg    case F_RIGHTICONMGR:
13503e747e6dSmrg    case F_FORWICONMGR:
13513e747e6dSmrg    case F_BACKICONMGR:
13523e747e6dSmrg	MoveIconManager(func);
13533e747e6dSmrg        break;
13543e747e6dSmrg
13553e747e6dSmrg    case F_NEXTICONMGR:
13563e747e6dSmrg    case F_PREVICONMGR:
13573e747e6dSmrg	JumpIconManager(func);
13583e747e6dSmrg        break;
13593e747e6dSmrg
13603e747e6dSmrg    case F_SHOWLIST:
13613e747e6dSmrg	if (Scr->NoIconManagers)
13623e747e6dSmrg	    break;
13633e747e6dSmrg	DeIconify(Scr->iconmgr.twm_win);
13643e747e6dSmrg	XRaiseWindow(dpy, Scr->iconmgr.twm_win->frame);
13653e747e6dSmrg	break;
13663e747e6dSmrg
13673e747e6dSmrg    case F_HIDELIST:
13683e747e6dSmrg	if (Scr->NoIconManagers)
13693e747e6dSmrg	    break;
13703e747e6dSmrg	HideIconManager ();
13713e747e6dSmrg	break;
13723e747e6dSmrg
13733e747e6dSmrg    case F_SORTICONMGR:
13743e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
13753e747e6dSmrg	    return TRUE;
13763e747e6dSmrg
13773e747e6dSmrg	{
13783e747e6dSmrg	    int save_sort;
13793e747e6dSmrg
13803e747e6dSmrg	    save_sort = Scr->SortIconMgr;
13813e747e6dSmrg	    Scr->SortIconMgr = TRUE;
13823e747e6dSmrg
13833e747e6dSmrg	    if (context == C_ICONMGR)
13843e747e6dSmrg		SortIconManager((IconMgr *) NULL);
13853e747e6dSmrg	    else if (tmp_win->iconmgr)
13863e747e6dSmrg		SortIconManager(tmp_win->iconmgrp);
13873e747e6dSmrg	    else
13883e747e6dSmrg		Bell(XkbBI_Info,0,tmp_win->w);
13893e747e6dSmrg
13903e747e6dSmrg	    Scr->SortIconMgr = save_sort;
13913e747e6dSmrg	}
13923e747e6dSmrg	break;
13933e747e6dSmrg
13943e747e6dSmrg    case F_IDENTIFY:
13953e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
13963e747e6dSmrg	    return TRUE;
13973e747e6dSmrg
13983e747e6dSmrg	Identify(tmp_win);
13993e747e6dSmrg	break;
14003e747e6dSmrg
14013e747e6dSmrg    case F_VERSION:
14023e747e6dSmrg	Identify ((TwmWindow *) NULL);
14033e747e6dSmrg	break;
14043e747e6dSmrg
14053e747e6dSmrg    case F_AUTORAISE:
14063e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
14073e747e6dSmrg	    return TRUE;
14083e747e6dSmrg
14093e747e6dSmrg	tmp_win->auto_raise = !tmp_win->auto_raise;
14103e747e6dSmrg	if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
14113e747e6dSmrg	else --(Scr->NumAutoRaises);
14123e747e6dSmrg	break;
14133e747e6dSmrg
14143e747e6dSmrg    case F_BEEP:
14153e747e6dSmrg	Bell(XkbBI_Info,0,None);
14163e747e6dSmrg	break;
14173e747e6dSmrg
14183e747e6dSmrg    case F_POPUP:
14193e747e6dSmrg	tmp_win = (TwmWindow *)action;
14203e747e6dSmrg	if (Scr->WindowFunction.func != 0)
14213e747e6dSmrg	{
14223e747e6dSmrg	   ExecuteFunction(Scr->WindowFunction.func,
14233e747e6dSmrg			   Scr->WindowFunction.item->action,
14243e747e6dSmrg			   w, tmp_win, eventp, C_FRAME, FALSE);
14253e747e6dSmrg	}
14263e747e6dSmrg	else
14273e747e6dSmrg	{
14283e747e6dSmrg	    DeIconify(tmp_win);
14293e747e6dSmrg	    XRaiseWindow (dpy, tmp_win->frame);
14303e747e6dSmrg	}
14313e747e6dSmrg	break;
14323e747e6dSmrg
14333e747e6dSmrg    case F_RESIZE:
14343e747e6dSmrg	EventHandler[EnterNotify] = HandleUnknown;
14353e747e6dSmrg	EventHandler[LeaveNotify] = HandleUnknown;
14363e747e6dSmrg	if (DeferExecution(context, func, Scr->MoveCursor))
14373e747e6dSmrg	    return TRUE;
14383e747e6dSmrg
14393e747e6dSmrg	PopDownMenu();
14403e747e6dSmrg
14413e747e6dSmrg	if (pulldown)
14423e747e6dSmrg	    XWarpPointer(dpy, None, Scr->Root,
14433e747e6dSmrg		0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
14443e747e6dSmrg
14453e747e6dSmrg	if (w != tmp_win->icon_w) {	/* can't resize icons */
14463e747e6dSmrg
14473e747e6dSmrg	  if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE)
14483e747e6dSmrg	      && fromMenu)
14493e747e6dSmrg	    resizeFromCenter(w, tmp_win);
14503e747e6dSmrg	  else {
14513e747e6dSmrg	    /*
14523e747e6dSmrg	     * see if this is being done from the titlebar
14533e747e6dSmrg	     */
14543e747e6dSmrg	    fromtitlebar =
14553e747e6dSmrg	      belongs_to_twm_window (tmp_win, eventp->xbutton.window);
14563e747e6dSmrg
14573e747e6dSmrg	    /* Save pointer position so we can tell if it was moved or
14583e747e6dSmrg	       not during the resize. */
14593e747e6dSmrg	    ResizeOrigX = eventp->xbutton.x_root;
14603e747e6dSmrg	    ResizeOrigY = eventp->xbutton.y_root;
14613e747e6dSmrg
14623e747e6dSmrg	    StartResize (eventp, tmp_win, fromtitlebar);
14633e747e6dSmrg
14643e747e6dSmrg	    do {
14653e747e6dSmrg	      XMaskEvent(dpy,
14663e747e6dSmrg			   ButtonPressMask | ButtonReleaseMask |
14673e747e6dSmrg			   EnterWindowMask | LeaveWindowMask |
14683e747e6dSmrg			   ButtonMotionMask, &Event);
14693e747e6dSmrg
14703e747e6dSmrg		if (fromtitlebar && Event.type == ButtonPress) {
14713e747e6dSmrg		  fromtitlebar = False;
14723e747e6dSmrg		    continue;
14733e747e6dSmrg		  }
14743e747e6dSmrg
14753e747e6dSmrg	    	if (Event.type == MotionNotify) {
14763e747e6dSmrg		  /* discard any extra motion events before a release */
14773e747e6dSmrg		  while
14783e747e6dSmrg		    (XCheckMaskEvent
14793e747e6dSmrg		     (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
14803e747e6dSmrg		      if (Event.type == ButtonRelease)
14813e747e6dSmrg			break;
14823e747e6dSmrg		}
14833e747e6dSmrg
14843e747e6dSmrg	      if (!DispatchEvent ()) continue;
14853e747e6dSmrg
14863e747e6dSmrg	    } while (!(Event.type == ButtonRelease || Cancel));
14873e747e6dSmrg	    return TRUE;
14883e747e6dSmrg	  }
14893e747e6dSmrg	}
14903e747e6dSmrg	break;
14913e747e6dSmrg
14923e747e6dSmrg
14933e747e6dSmrg    case F_ZOOM:
14943e747e6dSmrg    case F_HORIZOOM:
14953e747e6dSmrg    case F_FULLZOOM:
14963e747e6dSmrg    case F_LEFTZOOM:
14973e747e6dSmrg    case F_RIGHTZOOM:
14983e747e6dSmrg    case F_TOPZOOM:
14993e747e6dSmrg    case F_BOTTOMZOOM:
15003e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
15013e747e6dSmrg	    return TRUE;
15023e747e6dSmrg	fullzoom(tmp_win, func);
15033e747e6dSmrg	break;
15043e747e6dSmrg
15053e747e6dSmrg    case F_MOVE:
15063e747e6dSmrg    case F_FORCEMOVE:
15073e747e6dSmrg	if (DeferExecution(context, func, Scr->MoveCursor))
15083e747e6dSmrg	    return TRUE;
15093e747e6dSmrg
15103e747e6dSmrg	PopDownMenu();
15113e747e6dSmrg	rootw = eventp->xbutton.root;
15123e747e6dSmrg	MoveFunction = func;
15133e747e6dSmrg
15143e747e6dSmrg	if (pulldown)
15153e747e6dSmrg	    XWarpPointer(dpy, None, Scr->Root,
15163e747e6dSmrg		0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
15173e747e6dSmrg
15183e747e6dSmrg	EventHandler[EnterNotify] = HandleUnknown;
15193e747e6dSmrg	EventHandler[LeaveNotify] = HandleUnknown;
15203e747e6dSmrg
15213e747e6dSmrg	if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
15223e747e6dSmrg	    XGrabServer(dpy);
15233e747e6dSmrg	}
15243e747e6dSmrg	XGrabPointer(dpy, eventp->xbutton.root, True,
15253e747e6dSmrg	    ButtonPressMask | ButtonReleaseMask |
15263e747e6dSmrg	    ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
15273e747e6dSmrg	    GrabModeAsync, GrabModeAsync,
15283e747e6dSmrg	    Scr->Root, Scr->MoveCursor, CurrentTime);
15293e747e6dSmrg
15303e747e6dSmrg	if (context == C_ICON && tmp_win->icon_w)
15313e747e6dSmrg	{
15323e747e6dSmrg	    w = tmp_win->icon_w;
15333e747e6dSmrg	    DragX = eventp->xbutton.x;
15343e747e6dSmrg	    DragY = eventp->xbutton.y;
15353e747e6dSmrg	    moving_icon = TRUE;
15363e747e6dSmrg	}
15373e747e6dSmrg
15383e747e6dSmrg	else if (w != tmp_win->icon_w)
15393e747e6dSmrg	{
15403e747e6dSmrg	    XTranslateCoordinates(dpy, w, tmp_win->frame,
15413e747e6dSmrg		eventp->xbutton.x,
15423e747e6dSmrg		eventp->xbutton.y,
15433e747e6dSmrg		&DragX, &DragY, &JunkChild);
15443e747e6dSmrg
15453e747e6dSmrg	    w = tmp_win->frame;
15463e747e6dSmrg	}
15473e747e6dSmrg
15483e747e6dSmrg	DragWindow = None;
15493e747e6dSmrg
15503e747e6dSmrg	XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
15513e747e6dSmrg	    (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW,
15523e747e6dSmrg	    &JunkDepth);
15533e747e6dSmrg
15543e747e6dSmrg	origX = eventp->xbutton.x_root;
15553e747e6dSmrg	origY = eventp->xbutton.y_root;
15563e747e6dSmrg	CurrentDragX = origDragX;
15573e747e6dSmrg	CurrentDragY = origDragY;
15583e747e6dSmrg
15593e747e6dSmrg	/*
15603e747e6dSmrg	 * only do the constrained move if timer is set; need to check it
15613e747e6dSmrg	 * in case of stupid or wicked fast servers
15623e747e6dSmrg	 */
15633e747e6dSmrg	if (ConstrainedMoveTime &&
15643e747e6dSmrg	    (eventp->xbutton.time - last_time) < ConstrainedMoveTime)
15653e747e6dSmrg	{
15663e747e6dSmrg	    int width, height;
15673e747e6dSmrg
15683e747e6dSmrg	    ConstMove = TRUE;
15693e747e6dSmrg	    ConstMoveDir = MOVE_NONE;
15703e747e6dSmrg	    ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
15713e747e6dSmrg	    ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
15723e747e6dSmrg	    width = DragWidth + 2 * JunkBW;
15733e747e6dSmrg	    height = DragHeight + 2 * JunkBW;
15743e747e6dSmrg	    ConstMoveXL = ConstMoveX + width/3;
15753e747e6dSmrg	    ConstMoveXR = ConstMoveX + 2*(width/3);
15763e747e6dSmrg	    ConstMoveYT = ConstMoveY + height/3;
15773e747e6dSmrg	    ConstMoveYB = ConstMoveY + 2*(height/3);
15783e747e6dSmrg
15793e747e6dSmrg	    XWarpPointer(dpy, None, w,
15803e747e6dSmrg		0, 0, 0, 0, DragWidth/2, DragHeight/2);
15813e747e6dSmrg
15823e747e6dSmrg	    XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
15833e747e6dSmrg		&JunkX, &JunkY, &DragX, &DragY, &JunkMask);
15843e747e6dSmrg	}
15853e747e6dSmrg	last_time = eventp->xbutton.time;
15863e747e6dSmrg
15873e747e6dSmrg	if (!Scr->OpaqueMove)
15883e747e6dSmrg	{
15893e747e6dSmrg	    InstallRootColormap();
15903e747e6dSmrg	    if (!Scr->MoveDelta)
15913e747e6dSmrg	    {
15923e747e6dSmrg		/*
15933e747e6dSmrg		 * Draw initial outline.  This was previously done the
15943e747e6dSmrg		 * first time though the outer loop by dropping out of
15953e747e6dSmrg		 * the XCheckMaskEvent inner loop down to one of the
15963e747e6dSmrg		 * MoveOutline's below.
15973e747e6dSmrg		 */
15983e747e6dSmrg		MoveOutline(rootw,
15993e747e6dSmrg		    origDragX - JunkBW, origDragY - JunkBW,
16003e747e6dSmrg		    DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
16013e747e6dSmrg		    tmp_win->frame_bw,
16023e747e6dSmrg		    moving_icon ? 0 : tmp_win->title_height);
16033e747e6dSmrg		/*
16043e747e6dSmrg		 * This next line causes HandleReleaseNotify to call
16053e747e6dSmrg		 * XRaiseWindow().  This is solely to preserve the
16063e747e6dSmrg		 * previous behaviour that raises a window being moved
16073e747e6dSmrg		 * on button release even if you never actually moved
16083e747e6dSmrg		 * any distance (unless you move less than MoveDelta or
16093e747e6dSmrg		 * NoRaiseMove is set or OpaqueMove is set).
16103e747e6dSmrg		 */
16113e747e6dSmrg		DragWindow = w;
16123e747e6dSmrg	    }
16133e747e6dSmrg	}
16143e747e6dSmrg
16153e747e6dSmrg	/*
16163e747e6dSmrg	 * see if this is being done from the titlebar
16173e747e6dSmrg	 */
16183e747e6dSmrg	fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window);
16193e747e6dSmrg
16203e747e6dSmrg	if (menuFromFrameOrWindowOrTitlebar) {
16213e747e6dSmrg	  /* warp the pointer to the middle of the window */
16223e747e6dSmrg	  XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
16233e747e6dSmrg		       origDragX + DragWidth / 2,
16243e747e6dSmrg		       origDragY + DragHeight / 2);
16253e747e6dSmrg	  XFlush(dpy);
16263e747e6dSmrg	}
16273e747e6dSmrg
16283e747e6dSmrg	while (TRUE)
16293e747e6dSmrg	{
16303e747e6dSmrg	    long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
16313e747e6dSmrg	                          ButtonPress : ButtonRelease;
16323e747e6dSmrg	    long movementMask = menuFromFrameOrWindowOrTitlebar ?
16333e747e6dSmrg	                          PointerMotionMask : ButtonMotionMask;
16343e747e6dSmrg
16353e747e6dSmrg	    /* block until there is an interesting event */
16363e747e6dSmrg	    XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
16373e747e6dSmrg				    EnterWindowMask | LeaveWindowMask |
16383e747e6dSmrg				    ExposureMask | movementMask |
16393e747e6dSmrg				    VisibilityChangeMask, &Event);
16403e747e6dSmrg
16413e747e6dSmrg	    /* throw away enter and leave events until release */
16423e747e6dSmrg	    if (Event.xany.type == EnterNotify ||
16433e747e6dSmrg		Event.xany.type == LeaveNotify) continue;
16443e747e6dSmrg
16453e747e6dSmrg	    if (Event.type == MotionNotify) {
16463e747e6dSmrg		/* discard any extra motion events before a logical release */
16473e747e6dSmrg		while(XCheckMaskEvent(dpy,
16483e747e6dSmrg		    movementMask | releaseEvent, &Event))
16493e747e6dSmrg		    if (Event.type == releaseEvent)
16503e747e6dSmrg			break;
16513e747e6dSmrg	    }
16523e747e6dSmrg
16533e747e6dSmrg	    /* test to see if we have a second button press to abort move */
16543e747e6dSmrg	    if (!menuFromFrameOrWindowOrTitlebar &&  !MovedFromKeyPress) {
16553e747e6dSmrg	        if (Event.type == ButtonPress && DragWindow != None) {
16563e747e6dSmrg		    if (Scr->OpaqueMove)
16573e747e6dSmrg		      XMoveWindow (dpy, DragWindow, origDragX, origDragY);
16583e747e6dSmrg		    else
16593e747e6dSmrg		        MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
16603e747e6dSmrg		    DragWindow = None;
16613e747e6dSmrg                }
16623e747e6dSmrg	    }
16633e747e6dSmrg	    if (fromtitlebar && Event.type == ButtonPress) {
16643e747e6dSmrg		fromtitlebar = False;
16653e747e6dSmrg		CurrentDragX = origX = Event.xbutton.x_root;
16663e747e6dSmrg		CurrentDragY = origY = Event.xbutton.y_root;
16673e747e6dSmrg		XTranslateCoordinates (dpy, rootw, tmp_win->frame,
16683e747e6dSmrg				       origX, origY,
16693e747e6dSmrg				       &DragX, &DragY, &JunkChild);
16703e747e6dSmrg		continue;
16713e747e6dSmrg	    }
16723e747e6dSmrg
16733e747e6dSmrg	    if (!DispatchEvent2 ()) continue;
16743e747e6dSmrg
16753e747e6dSmrg	    if (Cancel)
16763e747e6dSmrg	    {
16773e747e6dSmrg		WindowMoved = FALSE;
16783e747e6dSmrg		if (!Scr->OpaqueMove)
16793e747e6dSmrg		    UninstallRootColormap();
16803e747e6dSmrg		    return TRUE;	/* XXX should this be FALSE? */
16813e747e6dSmrg	    }
16823e747e6dSmrg	    if (Event.type == releaseEvent)
16833e747e6dSmrg	    {
16843e747e6dSmrg		MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
16853e747e6dSmrg		if (moving_icon &&
16863e747e6dSmrg		    ((CurrentDragX != origDragX ||
16873e747e6dSmrg		      CurrentDragY != origDragY)))
16883e747e6dSmrg		  tmp_win->icon_moved = TRUE;
16893e747e6dSmrg		if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar)
16903e747e6dSmrg		  XMoveWindow(dpy, DragWindow,
16913e747e6dSmrg			      Event.xbutton.x_root - DragWidth / 2,
16923e747e6dSmrg			      Event.xbutton.y_root - DragHeight / 2);
16933e747e6dSmrg		break;
16943e747e6dSmrg	    }
16953e747e6dSmrg
16963e747e6dSmrg	    /* something left to do only if the pointer moved */
16973e747e6dSmrg	    if (Event.type != MotionNotify)
16983e747e6dSmrg		continue;
16993e747e6dSmrg
17003e747e6dSmrg	    XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
17013e747e6dSmrg		&(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
17023e747e6dSmrg		&JunkX, &JunkY, &JunkMask);
17033e747e6dSmrg
17043e747e6dSmrg	    if (DragWindow == None &&
17053e747e6dSmrg		abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
17063e747e6dSmrg	        abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
17073e747e6dSmrg		continue;
17083e747e6dSmrg
17093e747e6dSmrg	    WindowMoved = TRUE;
17103e747e6dSmrg	    DragWindow = w;
17113e747e6dSmrg
17123e747e6dSmrg	    if (!Scr->NoRaiseMove && Scr->OpaqueMove)	/* can't restore... */
17133e747e6dSmrg	      XRaiseWindow(dpy, DragWindow);
17143e747e6dSmrg
17153e747e6dSmrg	    if (ConstMove)
17163e747e6dSmrg	    {
17173e747e6dSmrg		switch (ConstMoveDir)
17183e747e6dSmrg		{
17193e747e6dSmrg		    case MOVE_NONE:
17203e747e6dSmrg			if (eventp->xmotion.x_root < ConstMoveXL ||
17213e747e6dSmrg			    eventp->xmotion.x_root > ConstMoveXR)
17223e747e6dSmrg			    ConstMoveDir = MOVE_HORIZ;
17233e747e6dSmrg
17243e747e6dSmrg			if (eventp->xmotion.y_root < ConstMoveYT ||
17253e747e6dSmrg			    eventp->xmotion.y_root > ConstMoveYB)
17263e747e6dSmrg			    ConstMoveDir = MOVE_VERT;
17273e747e6dSmrg
17283e747e6dSmrg			XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
17293e747e6dSmrg			    &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
17303e747e6dSmrg			break;
17313e747e6dSmrg
17323e747e6dSmrg		    case MOVE_VERT:
17333e747e6dSmrg			ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
17343e747e6dSmrg			break;
17353e747e6dSmrg
17363e747e6dSmrg		    case MOVE_HORIZ:
17373e747e6dSmrg			ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
17383e747e6dSmrg			break;
17393e747e6dSmrg		}
17403e747e6dSmrg
17413e747e6dSmrg		if (ConstMoveDir != MOVE_NONE)
17423e747e6dSmrg		{
17433e747e6dSmrg		    int xl, yt, xr, yb, w, h;
17443e747e6dSmrg
17453e747e6dSmrg		    xl = ConstMoveX;
17463e747e6dSmrg		    yt = ConstMoveY;
17473e747e6dSmrg		    w = DragWidth + 2 * JunkBW;
17483e747e6dSmrg		    h = DragHeight + 2 * JunkBW;
17493e747e6dSmrg
17503e747e6dSmrg		    if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
17513e747e6dSmrg		    {
17523e747e6dSmrg			xr = xl + w;
17533e747e6dSmrg			yb = yt + h;
17543e747e6dSmrg
17553e747e6dSmrg			if (xl < 0)
17563e747e6dSmrg			    xl = 0;
17573e747e6dSmrg			if (xr > Scr->MyDisplayWidth)
17583e747e6dSmrg			    xl = Scr->MyDisplayWidth - w;
17593e747e6dSmrg
17603e747e6dSmrg			if (yt < 0)
17613e747e6dSmrg			    yt = 0;
17623e747e6dSmrg			if (yb > Scr->MyDisplayHeight)
17633e747e6dSmrg			    yt = Scr->MyDisplayHeight - h;
17643e747e6dSmrg		    }
17653e747e6dSmrg		    CurrentDragX = xl;
17663e747e6dSmrg		    CurrentDragY = yt;
17673e747e6dSmrg		    if (Scr->OpaqueMove)
17683e747e6dSmrg			XMoveWindow(dpy, DragWindow, xl, yt);
17693e747e6dSmrg		    else
17703e747e6dSmrg			MoveOutline(eventp->xmotion.root, xl, yt, w, h,
17713e747e6dSmrg			    tmp_win->frame_bw,
17723e747e6dSmrg			    moving_icon ? 0 : tmp_win->title_height);
17733e747e6dSmrg		}
17743e747e6dSmrg	    }
17753e747e6dSmrg	    else if (DragWindow != None)
17763e747e6dSmrg	    {
17773e747e6dSmrg		int xl, yt, xr, yb, w, h;
17783e747e6dSmrg		if (!menuFromFrameOrWindowOrTitlebar) {
17793e747e6dSmrg		  xl = eventp->xmotion.x_root - DragX - JunkBW;
17803e747e6dSmrg		  yt = eventp->xmotion.y_root - DragY - JunkBW;
17813e747e6dSmrg		}
17823e747e6dSmrg		else {
17833e747e6dSmrg		  xl = eventp->xmotion.x_root - (DragWidth / 2);
17843e747e6dSmrg		  yt = eventp->xmotion.y_root - (DragHeight / 2);
17853e747e6dSmrg		}
17863e747e6dSmrg		w = DragWidth + 2 * JunkBW;
17873e747e6dSmrg		h = DragHeight + 2 * JunkBW;
17883e747e6dSmrg
17893e747e6dSmrg		if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
17903e747e6dSmrg		{
17913e747e6dSmrg		    xr = xl + w;
17923e747e6dSmrg		    yb = yt + h;
17933e747e6dSmrg
17943e747e6dSmrg		    if (xl < 0)
17953e747e6dSmrg			xl = 0;
17963e747e6dSmrg		    if (xr > Scr->MyDisplayWidth)
17973e747e6dSmrg			xl = Scr->MyDisplayWidth - w;
17983e747e6dSmrg
17993e747e6dSmrg		    if (yt < 0)
18003e747e6dSmrg			yt = 0;
18013e747e6dSmrg		    if (yb > Scr->MyDisplayHeight)
18023e747e6dSmrg			yt = Scr->MyDisplayHeight - h;
18033e747e6dSmrg		}
18043e747e6dSmrg
18053e747e6dSmrg		CurrentDragX = xl;
18063e747e6dSmrg		CurrentDragY = yt;
18073e747e6dSmrg		if (Scr->OpaqueMove)
18083e747e6dSmrg		    XMoveWindow(dpy, DragWindow, xl, yt);
18093e747e6dSmrg		else
18103e747e6dSmrg		    MoveOutline(eventp->xmotion.root, xl, yt, w, h,
18113e747e6dSmrg			tmp_win->frame_bw,
18123e747e6dSmrg			moving_icon ? 0 : tmp_win->title_height);
18133e747e6dSmrg	    }
18143e747e6dSmrg
18153e747e6dSmrg	}
18163e747e6dSmrg        MovedFromKeyPress = False;
18173e747e6dSmrg
18183e747e6dSmrg
18193e747e6dSmrg	if (!Scr->OpaqueMove && DragWindow == None)
18203e747e6dSmrg	    UninstallRootColormap();
18213e747e6dSmrg
18223e747e6dSmrg        break;
18233e747e6dSmrg
18243e747e6dSmrg    case F_FUNCTION:
18253e747e6dSmrg	{
18263e747e6dSmrg	    MenuRoot *mroot;
18273e747e6dSmrg	    MenuItem *mitem;
18283e747e6dSmrg
18293e747e6dSmrg	    if ((mroot = FindMenuRoot(action)) == NULL)
18303e747e6dSmrg	    {
18313e747e6dSmrg		fprintf (stderr, "%s: couldn't find function \"%s\"\n",
18323e747e6dSmrg			 ProgramName, action);
18333e747e6dSmrg		return TRUE;
18343e747e6dSmrg	    }
18353e747e6dSmrg
18363e747e6dSmrg	    if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor))
18373e747e6dSmrg		return TRUE;
18383e747e6dSmrg	    else
18393e747e6dSmrg	    {
18403e747e6dSmrg		for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
18413e747e6dSmrg		{
18423e747e6dSmrg		    if (!ExecuteFunction (mitem->func, mitem->action, w,
18433e747e6dSmrg					  tmp_win, eventp, context, pulldown))
18443e747e6dSmrg		      break;
18453e747e6dSmrg		}
18463e747e6dSmrg	    }
18473e747e6dSmrg	}
18483e747e6dSmrg	break;
18493e747e6dSmrg
18503e747e6dSmrg    case F_DEICONIFY:
18513e747e6dSmrg    case F_ICONIFY:
18523e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
18533e747e6dSmrg	    return TRUE;
18543e747e6dSmrg
18553e747e6dSmrg	if (tmp_win->icon)
18563e747e6dSmrg	{
18573e747e6dSmrg	    DeIconify(tmp_win);
18583e747e6dSmrg	}
18593e747e6dSmrg        else if (func == F_ICONIFY)
18603e747e6dSmrg	{
18613e747e6dSmrg	    Iconify (tmp_win, eventp->xbutton.x_root - 5,
18623e747e6dSmrg		     eventp->xbutton.y_root - 5);
18633e747e6dSmrg	}
18643e747e6dSmrg	break;
18653e747e6dSmrg
18663e747e6dSmrg    case F_RAISELOWER:
18673e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
18683e747e6dSmrg	    return TRUE;
18693e747e6dSmrg
18703e747e6dSmrg	if (!WindowMoved) {
18713e747e6dSmrg	    XWindowChanges xwc;
18723e747e6dSmrg
18733e747e6dSmrg	    xwc.stack_mode = Opposite;
18743e747e6dSmrg	    if (w != tmp_win->icon_w)
18753e747e6dSmrg	      w = tmp_win->frame;
18763e747e6dSmrg	    XConfigureWindow (dpy, w, CWStackMode, &xwc);
18773e747e6dSmrg	}
18783e747e6dSmrg	break;
18793e747e6dSmrg
18803e747e6dSmrg    case F_RAISE:
18813e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
18823e747e6dSmrg	    return TRUE;
18833e747e6dSmrg
18843e747e6dSmrg	/* check to make sure raise is not from the WindowFunction */
18853e747e6dSmrg	if (w == tmp_win->icon_w && Context != C_ROOT)
18863e747e6dSmrg	    XRaiseWindow(dpy, tmp_win->icon_w);
18873e747e6dSmrg	else
18883e747e6dSmrg	    XRaiseWindow(dpy, tmp_win->frame);
18893e747e6dSmrg
18903e747e6dSmrg	break;
18913e747e6dSmrg
18923e747e6dSmrg    case F_LOWER:
18933e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
18943e747e6dSmrg	    return TRUE;
18953e747e6dSmrg
18963e747e6dSmrg	if (w == tmp_win->icon_w)
18973e747e6dSmrg	    XLowerWindow(dpy, tmp_win->icon_w);
18983e747e6dSmrg	else
18993e747e6dSmrg	    XLowerWindow(dpy, tmp_win->frame);
19003e747e6dSmrg
19013e747e6dSmrg	break;
19023e747e6dSmrg
19033e747e6dSmrg    case F_FOCUS:
19043e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
19053e747e6dSmrg	    return TRUE;
19063e747e6dSmrg
19073e747e6dSmrg	if (tmp_win->icon == FALSE)
19083e747e6dSmrg	{
19093e747e6dSmrg	    if (!Scr->FocusRoot && Scr->Focus == tmp_win)
19103e747e6dSmrg	    {
19113e747e6dSmrg		FocusOnRoot();
19123e747e6dSmrg	    }
19133e747e6dSmrg	    else
19143e747e6dSmrg	    {
19153e747e6dSmrg		if (Scr->Focus != NULL) {
19163e747e6dSmrg		    SetBorder (Scr->Focus, False);
19173e747e6dSmrg		    if (Scr->Focus->hilite_w)
19183e747e6dSmrg		      XUnmapWindow (dpy, Scr->Focus->hilite_w);
19193e747e6dSmrg		}
19203e747e6dSmrg
19213e747e6dSmrg		InstallWindowColormaps (0, tmp_win);
19223e747e6dSmrg		if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w);
19233e747e6dSmrg		SetBorder (tmp_win, True);
19243e747e6dSmrg		if (!tmp_win->wmhints || tmp_win->wmhints->input)
19253e747e6dSmrg		    SetFocus (tmp_win, eventp->xbutton.time);
19263e747e6dSmrg		Scr->FocusRoot = FALSE;
19273e747e6dSmrg		Scr->Focus = tmp_win;
19283e747e6dSmrg	    }
19293e747e6dSmrg	}
19303e747e6dSmrg	break;
19313e747e6dSmrg
19323e747e6dSmrg    case F_DESTROY:
19333e747e6dSmrg	if (DeferExecution(context, func, Scr->DestroyCursor))
19343e747e6dSmrg	    return TRUE;
19353e747e6dSmrg
19363e747e6dSmrg	if (tmp_win->iconmgr)
19373e747e6dSmrg	    Bell(XkbBI_MinorError,0,tmp_win->w);
19383e747e6dSmrg	else
19393e747e6dSmrg	    XKillClient(dpy, tmp_win->w);
19403e747e6dSmrg	break;
19413e747e6dSmrg
19423e747e6dSmrg    case F_DELETE:
19433e747e6dSmrg	if (DeferExecution(context, func, Scr->DestroyCursor))
19443e747e6dSmrg	    return TRUE;
19453e747e6dSmrg
19463e747e6dSmrg	if (tmp_win->iconmgr)		/* don't send ourself a message */
19473e747e6dSmrg	  HideIconManager ();
19483e747e6dSmrg	else if (tmp_win->protocols & DoesWmDeleteWindow)
19493e747e6dSmrg	  SendDeleteWindowMessage (tmp_win, LastTimestamp());
19503e747e6dSmrg	else
19513e747e6dSmrg	  Bell(XkbBI_MinorError,0,tmp_win->w);
19523e747e6dSmrg	break;
19533e747e6dSmrg
19543e747e6dSmrg    case F_SAVEYOURSELF:
19553e747e6dSmrg	if (DeferExecution (context, func, Scr->SelectCursor))
19563e747e6dSmrg	  return TRUE;
19573e747e6dSmrg
19583e747e6dSmrg	if (tmp_win->protocols & DoesWmSaveYourself)
19593e747e6dSmrg	  SendSaveYourselfMessage (tmp_win, LastTimestamp());
19603e747e6dSmrg	else
19613e747e6dSmrg	  Bell(XkbBI_MinorError,0,tmp_win->w);
19623e747e6dSmrg	break;
19633e747e6dSmrg
19643e747e6dSmrg    case F_CIRCLEUP:
19653e747e6dSmrg	XCirculateSubwindowsUp(dpy, Scr->Root);
19663e747e6dSmrg	break;
19673e747e6dSmrg
19683e747e6dSmrg    case F_CIRCLEDOWN:
19693e747e6dSmrg	XCirculateSubwindowsDown(dpy, Scr->Root);
19703e747e6dSmrg	break;
19713e747e6dSmrg
19723e747e6dSmrg    case F_EXEC:
19733e747e6dSmrg	PopDownMenu();
19743e747e6dSmrg	if (!Scr->NoGrabServer) {
19753e747e6dSmrg	    XUngrabServer (dpy);
19763e747e6dSmrg	    XSync (dpy, 0);
19773e747e6dSmrg	}
19783e747e6dSmrg	Execute(action);
19793e747e6dSmrg	break;
19803e747e6dSmrg
19813e747e6dSmrg    case F_UNFOCUS:
19823e747e6dSmrg	FocusOnRoot();
19833e747e6dSmrg	break;
19843e747e6dSmrg
19853e747e6dSmrg    case F_CUT:
19863e747e6dSmrg	strcpy(tmp, action);
19873e747e6dSmrg	strcat(tmp, "\n");
19883e747e6dSmrg	XStoreBytes(dpy, tmp, strlen(tmp));
19893e747e6dSmrg	break;
19903e747e6dSmrg
19913e747e6dSmrg    case F_CUTFILE:
19923e747e6dSmrg	ptr = XFetchBytes(dpy, &count);
19933e747e6dSmrg	if (ptr) {
19943e747e6dSmrg	    if (sscanf (ptr, "%s", tmp) == 1) {
19953e747e6dSmrg		XFree (ptr);
19963e747e6dSmrg		ptr = ExpandFilename(tmp);
19973e747e6dSmrg		if (ptr) {
19983e747e6dSmrg		    fd = open (ptr, O_RDONLY);
19993e747e6dSmrg		    if (fd >= 0) {
20003e747e6dSmrg			count = read (fd, buff, MAX_FILE_SIZE - 1);
20013e747e6dSmrg			if (count > 0) XStoreBytes (dpy, buff, count);
20023e747e6dSmrg			close(fd);
20033e747e6dSmrg		    } else {
20043e747e6dSmrg			fprintf (stderr,
20053e747e6dSmrg				 "%s:  unable to open cut file \"%s\"\n",
20063e747e6dSmrg				 ProgramName, tmp);
20073e747e6dSmrg		    }
20083e747e6dSmrg		    if (ptr != tmp) free (ptr);
20093e747e6dSmrg		}
20103e747e6dSmrg	    } else {
20113e747e6dSmrg		XFree(ptr);
20123e747e6dSmrg	    }
20133e747e6dSmrg	} else {
20143e747e6dSmrg	    fprintf(stderr, "%s:  cut buffer is empty\n", ProgramName);
20153e747e6dSmrg	}
20163e747e6dSmrg	break;
20173e747e6dSmrg
20183e747e6dSmrg    case F_WARPTOSCREEN:
20193e747e6dSmrg	{
20203e747e6dSmrg	    if (strcmp (action, WARPSCREEN_NEXT) == 0) {
20213e747e6dSmrg		WarpToScreen (Scr->screen + 1, 1);
20223e747e6dSmrg	    } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
20233e747e6dSmrg		WarpToScreen (Scr->screen - 1, -1);
20243e747e6dSmrg	    } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
20253e747e6dSmrg		WarpToScreen (PreviousScreen, 0);
20263e747e6dSmrg	    } else {
20273e747e6dSmrg		WarpToScreen (atoi (action), 0);
20283e747e6dSmrg	    }
20293e747e6dSmrg	}
20303e747e6dSmrg	break;
20313e747e6dSmrg
20323e747e6dSmrg    case F_COLORMAP:
20333e747e6dSmrg	{
20343e747e6dSmrg	    if (strcmp (action, COLORMAP_NEXT) == 0) {
20353e747e6dSmrg		BumpWindowColormap (tmp_win, 1);
20363e747e6dSmrg	    } else if (strcmp (action, COLORMAP_PREV) == 0) {
20373e747e6dSmrg		BumpWindowColormap (tmp_win, -1);
20383e747e6dSmrg	    } else {
20393e747e6dSmrg		BumpWindowColormap (tmp_win, 0);
20403e747e6dSmrg	    }
20413e747e6dSmrg	}
20423e747e6dSmrg	break;
20433e747e6dSmrg
20443e747e6dSmrg    case F_WARPPREV:
20453e747e6dSmrg    case F_WARPNEXT:
20463e747e6dSmrg	{
20473e747e6dSmrg		register TwmWindow *t;
20483e747e6dSmrg		static TwmWindow *savedwarp = NULL;
20493e747e6dSmrg		TwmWindow *of, *l, *n;
20503e747e6dSmrg		int c=0;
20513e747e6dSmrg
20523e747e6dSmrg#define wseq(w) (func == F_WARPNEXT ? (w)->next : (w)->prev)
20533e747e6dSmrg#define nwin(w) ((w) && (n=wseq(w)) != NULL && n != &Scr->TwmRoot ? n : l)
20543e747e6dSmrg#define bwin(w) (!(w)||(w)->iconmgr||(w)==of||!(Scr->WarpUnmapped||(w)->mapped))
20553e747e6dSmrg
20563e747e6dSmrg		of=(Scr->Focus ? Scr->Focus : &Scr->TwmRoot);
20573e747e6dSmrg
20583e747e6dSmrg		for(t=Scr->TwmRoot.next; t; t=t->next) if(!bwin(t)) break;
20593e747e6dSmrg		if(!t) break;	/* no windows we can use */
20603e747e6dSmrg
20613e747e6dSmrg		if(func == F_WARPPREV) for(l=of; l->next; l=l->next) ;
20623e747e6dSmrg		else l = Scr->TwmRoot.next;
20633e747e6dSmrg
20643e747e6dSmrg		for(t=of; bwin(t) && c < 2; t=nwin(t)) if(t == of) c++;
20653e747e6dSmrg
20663e747e6dSmrg		if(bwin(t) || c >= 2) Bell(XkbBI_MinorError,0,None);
20673e747e6dSmrg		else {
20683e747e6dSmrg			if(of && of == savedwarp) {
20693e747e6dSmrg				Iconify(of, 0, 0);
20703e747e6dSmrg				savedwarp = NULL;
20713e747e6dSmrg			}
20723e747e6dSmrg			if(!t->mapped) savedwarp = t; else savedwarp = NULL;
20733e747e6dSmrg			WarpThere(t);
20743e747e6dSmrg		}
20753e747e6dSmrg		break;
20763e747e6dSmrg	}
20773e747e6dSmrg
20783e747e6dSmrg    case F_WARPTO:
20793e747e6dSmrg	{
20803e747e6dSmrg	    register TwmWindow *t;
20813e747e6dSmrg	    int len;
20823e747e6dSmrg
20833e747e6dSmrg	    len = strlen(action);
20843e747e6dSmrg
20853e747e6dSmrg	    for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
20863e747e6dSmrg		if (!strncmp(action, t->name, len))
20873e747e6dSmrg                    if (WarpThere(t)) break;
20883e747e6dSmrg	    }
20893e747e6dSmrg	    if (!t) {
20903e747e6dSmrg		for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
20913e747e6dSmrg		    if (!strncmp(action, t->class.res_name, len))
20923e747e6dSmrg                        if (WarpThere(t)) break;
20933e747e6dSmrg		}
20943e747e6dSmrg		if (!t) {
20953e747e6dSmrg		    for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
20963e747e6dSmrg			if (!strncmp(action, t->class.res_class, len))
20973e747e6dSmrg                            if (WarpThere(t)) break;
20983e747e6dSmrg		    }
20993e747e6dSmrg		}
21003e747e6dSmrg	    }
21013e747e6dSmrg
21023e747e6dSmrg	    if (!t)
21033e747e6dSmrg		Bell(XkbBI_MinorError,0,None);
21043e747e6dSmrg	}
21053e747e6dSmrg	break;
21063e747e6dSmrg
21073e747e6dSmrg    case F_WARPTOICONMGR:
21083e747e6dSmrg	{
21093e747e6dSmrg	    TwmWindow *t;
21103e747e6dSmrg	    int len;
21113e747e6dSmrg	    Window raisewin = None, iconwin = None;
21123e747e6dSmrg
21133e747e6dSmrg	    len = strlen(action);
21143e747e6dSmrg	    if (len == 0) {
21153e747e6dSmrg		if (tmp_win && tmp_win->list) {
21163e747e6dSmrg		    raisewin = tmp_win->list->iconmgr->twm_win->frame;
21173e747e6dSmrg		    iconwin = tmp_win->list->icon;
21183e747e6dSmrg		} else if (Scr->iconmgr.active) {
21193e747e6dSmrg		    raisewin = Scr->iconmgr.twm_win->frame;
21203e747e6dSmrg		    iconwin = Scr->iconmgr.active->w;
21213e747e6dSmrg		}
21223e747e6dSmrg	    } else {
21233e747e6dSmrg		for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
21243e747e6dSmrg		    if (strncmp (action, t->icon_name, len) == 0) {
21253e747e6dSmrg			if (t->list && t->list->iconmgr->twm_win->mapped) {
21263e747e6dSmrg			    raisewin = t->list->iconmgr->twm_win->frame;
21273e747e6dSmrg			    iconwin = t->list->icon;
21283e747e6dSmrg			    break;
21293e747e6dSmrg			}
21303e747e6dSmrg		    }
21313e747e6dSmrg		}
21323e747e6dSmrg	    }
21333e747e6dSmrg
21343e747e6dSmrg	    if (raisewin) {
21353e747e6dSmrg		XRaiseWindow (dpy, raisewin);
21363e747e6dSmrg		XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
21373e747e6dSmrg	    } else {
21383e747e6dSmrg		Bell(XkbBI_MinorError,0,None);
21393e747e6dSmrg	    }
21403e747e6dSmrg	}
21413e747e6dSmrg	break;
21423e747e6dSmrg
21433e747e6dSmrg    case F_WARPRING:
21443e747e6dSmrg	switch (action[0]) {
21453e747e6dSmrg	  case 'n':
21463e747e6dSmrg	    WarpAlongRing (&eventp->xbutton, True);
21473e747e6dSmrg	    break;
21483e747e6dSmrg	  case 'p':
21493e747e6dSmrg	    WarpAlongRing (&eventp->xbutton, False);
21503e747e6dSmrg	    break;
21513e747e6dSmrg	  default:
21523e747e6dSmrg	    Bell(XkbBI_MinorError,0,None);
21533e747e6dSmrg	    break;
21543e747e6dSmrg	}
21553e747e6dSmrg	break;
21563e747e6dSmrg
21573e747e6dSmrg    case F_FILE:
21583e747e6dSmrg	ptr = ExpandFilename(action);
21593e747e6dSmrg	fd = open(ptr, O_RDONLY);
21603e747e6dSmrg	if (fd >= 0)
21613e747e6dSmrg	{
21623e747e6dSmrg	    count = read(fd, buff, MAX_FILE_SIZE - 1);
21633e747e6dSmrg	    if (count > 0)
21643e747e6dSmrg		XStoreBytes(dpy, buff, count);
21653e747e6dSmrg
21663e747e6dSmrg	    close(fd);
21673e747e6dSmrg	}
21683e747e6dSmrg	else
21693e747e6dSmrg	{
21703e747e6dSmrg	    fprintf (stderr, "%s:  unable to open file \"%s\"\n",
21713e747e6dSmrg		     ProgramName, ptr);
21723e747e6dSmrg	}
21733e747e6dSmrg	if (ptr != action) free(ptr);
21743e747e6dSmrg	break;
21753e747e6dSmrg
21763e747e6dSmrg    case F_REFRESH:
21773e747e6dSmrg	{
21783e747e6dSmrg	    XSetWindowAttributes attributes;
21793e747e6dSmrg	    unsigned long valuemask;
21803e747e6dSmrg
21813e747e6dSmrg	    valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
21823e747e6dSmrg	    attributes.background_pixel = Scr->Black;
21833e747e6dSmrg	    attributes.backing_store = NotUseful;
21843e747e6dSmrg	    attributes.save_under = False;
21853e747e6dSmrg	    w = XCreateWindow (dpy, Scr->Root, 0, 0,
21863e747e6dSmrg			       (unsigned int) Scr->MyDisplayWidth,
21873e747e6dSmrg			       (unsigned int) Scr->MyDisplayHeight,
21883e747e6dSmrg			       (unsigned int) 0,
21893e747e6dSmrg			       CopyFromParent, (unsigned int) CopyFromParent,
21903e747e6dSmrg			       (Visual *) CopyFromParent, valuemask,
21913e747e6dSmrg			       &attributes);
21923e747e6dSmrg	    XMapWindow (dpy, w);
21933e747e6dSmrg	    XDestroyWindow (dpy, w);
21943e747e6dSmrg	    XFlush (dpy);
21953e747e6dSmrg	}
21963e747e6dSmrg	break;
21973e747e6dSmrg
21983e747e6dSmrg    case F_WINREFRESH:
21993e747e6dSmrg	if (DeferExecution(context, func, Scr->SelectCursor))
22003e747e6dSmrg	    return TRUE;
22013e747e6dSmrg
22023e747e6dSmrg	if (context == C_ICON && tmp_win->icon_w)
22033e747e6dSmrg	    w = XCreateSimpleWindow(dpy, tmp_win->icon_w,
22043e747e6dSmrg		0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
22053e747e6dSmrg	else
22063e747e6dSmrg	    w = XCreateSimpleWindow(dpy, tmp_win->frame,
22073e747e6dSmrg		0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
22083e747e6dSmrg
22093e747e6dSmrg	XMapWindow(dpy, w);
22103e747e6dSmrg	XDestroyWindow(dpy, w);
22113e747e6dSmrg	XFlush(dpy);
22123e747e6dSmrg	break;
22133e747e6dSmrg
22143e747e6dSmrg    case F_QUIT:
22153e747e6dSmrg	Done(NULL, NULL);
22163e747e6dSmrg	break;
22173e747e6dSmrg
22183e747e6dSmrg    case F_PRIORITY:
22193e747e6dSmrg	if (HasSync)
22203e747e6dSmrg	{
22213e747e6dSmrg	    if (DeferExecution (context, func, Scr->SelectCursor))
22223e747e6dSmrg		return TRUE;
22233e747e6dSmrg	    (void)XSyncSetPriority(dpy, tmp_win->w, atoi(action));
22243e747e6dSmrg        }
22253e747e6dSmrg	break;
22263e747e6dSmrg   case F_STARTWM:
22273e747e6dSmrg	execlp("/bin/sh", "sh", "-c", action, (void *)NULL);
22283e747e6dSmrg	fprintf (stderr, "%s:  unable to start:  %s\n", ProgramName, *Argv);
22293e747e6dSmrg	break;
22303e747e6dSmrg
22313e747e6dSmrg    }
22323e747e6dSmrg
22333e747e6dSmrg    if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
22343e747e6dSmrg    return do_next_action;
22353e747e6dSmrg}
22363e747e6dSmrg
22373e747e6dSmrg
22383e747e6dSmrg
22393e747e6dSmrg/**
22403e747e6dSmrg * defer the execution of a function to the next button press if the context
22413e747e6dSmrg *  is C_ROOT
22423e747e6dSmrg *
22433e747e6dSmrg *  \param context the context in which the mouse button was pressed
22443e747e6dSmrg *	\param func    the function to defer
22453e747e6dSmrg *  \param cursor  cursor the cursor to display while waiting
22463e747e6dSmrg */
22473e747e6dSmrgint
22483e747e6dSmrgDeferExecution(int context, int func, Cursor cursor)
22493e747e6dSmrg{
22503e747e6dSmrg  if (context == C_ROOT)
22513e747e6dSmrg    {
22523e747e6dSmrg	LastCursor = cursor;
22533e747e6dSmrg	XGrabPointer(dpy, Scr->Root, True,
22543e747e6dSmrg	    ButtonPressMask | ButtonReleaseMask,
22553e747e6dSmrg	    GrabModeAsync, GrabModeAsync,
22563e747e6dSmrg	    Scr->Root, cursor, CurrentTime);
22573e747e6dSmrg
22583e747e6dSmrg	RootFunction = func;
22593e747e6dSmrg
22603e747e6dSmrg	return (TRUE);
22613e747e6dSmrg    }
22623e747e6dSmrg
22633e747e6dSmrg    return (FALSE);
22643e747e6dSmrg}
22653e747e6dSmrg
22663e747e6dSmrg
22673e747e6dSmrg
22683e747e6dSmrg/**
22693e747e6dSmrg *regrab the pointer with the LastCursor;
22703e747e6dSmrg */
22713e747e6dSmrgvoid
22723e747e6dSmrgReGrab()
22733e747e6dSmrg{
22743e747e6dSmrg    XGrabPointer(dpy, Scr->Root, True,
22753e747e6dSmrg	ButtonPressMask | ButtonReleaseMask,
22763e747e6dSmrg	GrabModeAsync, GrabModeAsync,
22773e747e6dSmrg	Scr->Root, LastCursor, CurrentTime);
22783e747e6dSmrg}
22793e747e6dSmrg
22803e747e6dSmrg
22813e747e6dSmrg
22823e747e6dSmrg/**
22833e747e6dSmrg * checks each function in the list to see if it is one that needs
22843e747e6dSmrg * to be deferred.
22853e747e6dSmrg *
22863e747e6dSmrg *  \param root the menu root to check
22873e747e6dSmrg */
22883e747e6dSmrgBool
22893e747e6dSmrgNeedToDefer(MenuRoot *root)
22903e747e6dSmrg{
22913e747e6dSmrg    MenuItem *mitem;
22923e747e6dSmrg
22933e747e6dSmrg    for (mitem = root->first; mitem != NULL; mitem = mitem->next)
22943e747e6dSmrg    {
22953e747e6dSmrg	switch (mitem->func)
22963e747e6dSmrg	{
22973e747e6dSmrg	case F_IDENTIFY:
22983e747e6dSmrg	case F_RESIZE:
22993e747e6dSmrg	case F_MOVE:
23003e747e6dSmrg	case F_FORCEMOVE:
23013e747e6dSmrg	case F_DEICONIFY:
23023e747e6dSmrg	case F_ICONIFY:
23033e747e6dSmrg	case F_RAISELOWER:
23043e747e6dSmrg	case F_RAISE:
23053e747e6dSmrg	case F_LOWER:
23063e747e6dSmrg	case F_FOCUS:
23073e747e6dSmrg	case F_DESTROY:
23083e747e6dSmrg	case F_WINREFRESH:
23093e747e6dSmrg	case F_ZOOM:
23103e747e6dSmrg	case F_FULLZOOM:
23113e747e6dSmrg	case F_HORIZOOM:
23123e747e6dSmrg        case F_RIGHTZOOM:
23133e747e6dSmrg        case F_LEFTZOOM:
23143e747e6dSmrg        case F_TOPZOOM:
23153e747e6dSmrg        case F_BOTTOMZOOM:
23163e747e6dSmrg	case F_AUTORAISE:
23173e747e6dSmrg	    return TRUE;
23183e747e6dSmrg	}
23193e747e6dSmrg    }
23203e747e6dSmrg    return FALSE;
23213e747e6dSmrg}
23223e747e6dSmrg
23233e747e6dSmrg
23243e747e6dSmrg
23253e747e6dSmrg#if defined(sun) && defined(SVR4)
23263e747e6dSmrg#include <sys/wait.h>
23273e747e6dSmrg
23283e747e6dSmrg/**
23293e747e6dSmrg * execute the string by /bin/sh
23303e747e6dSmrg *  \param s  the string containing the command
23313e747e6dSmrg */
23323e747e6dSmrgstatic int
23333e747e6dSmrgSystem (char *s)
23343e747e6dSmrg{
23353e747e6dSmrg    int pid, status;
23363e747e6dSmrg    if ((pid = fork ()) == 0) {
23373e747e6dSmrg	(void) setpgrp();
23383e747e6dSmrg	execl ("/bin/sh", "sh", "-c", s, 0);
23393e747e6dSmrg    } else
23403e747e6dSmrg	waitpid (pid, &status, 0);
23413e747e6dSmrg    return status;
23423e747e6dSmrg}
23433e747e6dSmrg#define system(s) System(s)
23443e747e6dSmrg
23453e747e6dSmrg#endif
23463e747e6dSmrg
23473e747e6dSmrgvoid
23483e747e6dSmrgExecute(char *s)
23493e747e6dSmrg{
23503e747e6dSmrg	/* FIXME: is all this stuff needed?  There could be security problems here. */
23513e747e6dSmrg    static char buf[256];
23523e747e6dSmrg    char *ds = DisplayString (dpy);
23533e747e6dSmrg    char *colon, *dot1;
23543e747e6dSmrg    char oldDisplay[256];
23553e747e6dSmrg    char *doisplay;
23563e747e6dSmrg    int restorevar = 0;
23573e747e6dSmrg
23583e747e6dSmrg    oldDisplay[0] = '\0';
23593e747e6dSmrg    doisplay=getenv("DISPLAY");
23603e747e6dSmrg    if (doisplay)
23613e747e6dSmrg	strcpy (oldDisplay, doisplay);
23623e747e6dSmrg
23633e747e6dSmrg    /*
23643e747e6dSmrg     * Build a display string using the current screen number, so that
23653e747e6dSmrg     * X programs which get fired up from a menu come up on the screen
23663e747e6dSmrg     * that they were invoked from, unless specifically overridden on
23673e747e6dSmrg     * their command line.
23683e747e6dSmrg     */
23693e747e6dSmrg    colon = strrchr (ds, ':');
23703e747e6dSmrg    if (colon) {			/* if host[:]:dpy */
23713e747e6dSmrg	strcpy (buf, "DISPLAY=");
23723e747e6dSmrg	strcat (buf, ds);
23733e747e6dSmrg	colon = buf + 8 + (colon - ds);	/* use version in buf */
23743e747e6dSmrg	dot1 = strchr (colon, '.');	/* first period after colon */
23753e747e6dSmrg	if (!dot1) dot1 = colon + strlen (colon);  /* if not there, append */
23763e747e6dSmrg	(void) sprintf (dot1, ".%d", Scr->screen);
23773e747e6dSmrg	putenv (buf);
23783e747e6dSmrg	restorevar = 1;
23793e747e6dSmrg    }
23803e747e6dSmrg
23813e747e6dSmrg    (void) system (s);
23823e747e6dSmrg
23833e747e6dSmrg    if (restorevar) {		/* why bother? */
23843e747e6dSmrg	(void) sprintf (buf, "DISPLAY=%s", oldDisplay);
23853e747e6dSmrg	putenv (buf);
23863e747e6dSmrg    }
23873e747e6dSmrg}
23883e747e6dSmrg
23893e747e6dSmrg
23903e747e6dSmrg
23913e747e6dSmrg/**
23923e747e6dSmrg * put input focus on the root window.
23933e747e6dSmrg */
23943e747e6dSmrgvoid
23953e747e6dSmrgFocusOnRoot()
23963e747e6dSmrg{
23973e747e6dSmrg    SetFocus ((TwmWindow *) NULL, LastTimestamp());
23983e747e6dSmrg    if (Scr->Focus != NULL)
23993e747e6dSmrg    {
24003e747e6dSmrg	SetBorder (Scr->Focus, False);
24013e747e6dSmrg	if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w);
24023e747e6dSmrg    }
24033e747e6dSmrg    InstallWindowColormaps(0, &Scr->TwmRoot);
24043e747e6dSmrg    Scr->Focus = NULL;
24053e747e6dSmrg    Scr->FocusRoot = TRUE;
24063e747e6dSmrg}
24073e747e6dSmrg
24083e747e6dSmrgvoid
24093e747e6dSmrgDeIconify(TwmWindow *tmp_win)
24103e747e6dSmrg{
24113e747e6dSmrg    TwmWindow *t;
24123e747e6dSmrg
24133e747e6dSmrg    /* de-iconify the main window */
24143e747e6dSmrg    if (tmp_win->icon)
24153e747e6dSmrg    {
24163e747e6dSmrg	if (tmp_win->icon_on)
24173e747e6dSmrg	    Zoom(tmp_win->icon_w, tmp_win->frame);
24183e747e6dSmrg	else if (tmp_win->group != (Window) 0)
24193e747e6dSmrg	{
24203e747e6dSmrg	    for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
24213e747e6dSmrg	    {
24223e747e6dSmrg		if (tmp_win->group == t->w && t->icon_on)
24233e747e6dSmrg		{
24243e747e6dSmrg		    Zoom(t->icon_w, tmp_win->frame);
24253e747e6dSmrg		    break;
24263e747e6dSmrg		}
24273e747e6dSmrg	    }
24283e747e6dSmrg	}
24293e747e6dSmrg    }
24303e747e6dSmrg
24313e747e6dSmrg    XMapWindow(dpy, tmp_win->w);
24323e747e6dSmrg    tmp_win->mapped = TRUE;
24333e747e6dSmrg    if (Scr->NoRaiseDeicon)
24343e747e6dSmrg	XMapWindow(dpy, tmp_win->frame);
24353e747e6dSmrg    else
24363e747e6dSmrg	XMapRaised(dpy, tmp_win->frame);
24373e747e6dSmrg    SetMapStateProp(tmp_win, NormalState);
24383e747e6dSmrg
24393e747e6dSmrg    if (tmp_win->icon_w) {
24403e747e6dSmrg	XUnmapWindow(dpy, tmp_win->icon_w);
24413e747e6dSmrg	IconDown (tmp_win);
24423e747e6dSmrg    }
24433e747e6dSmrg    if (tmp_win->list)
24443e747e6dSmrg	XUnmapWindow(dpy, tmp_win->list->icon);
24453e747e6dSmrg    if ((Scr->WarpCursor ||
24463e747e6dSmrg	 LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)) &&
24473e747e6dSmrg	tmp_win->icon)
24483e747e6dSmrg      WarpToWindow (tmp_win);
24493e747e6dSmrg    tmp_win->icon = FALSE;
24503e747e6dSmrg    tmp_win->icon_on = FALSE;
24513e747e6dSmrg
24523e747e6dSmrg
24533e747e6dSmrg    /* now de-iconify transients */
24543e747e6dSmrg	for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
24553e747e6dSmrg	{
24563e747e6dSmrg	  if (t->transient && t->transientfor == tmp_win->w)
24573e747e6dSmrg	    {
24583e747e6dSmrg	      if (t->icon_on)
24593e747e6dSmrg		Zoom(t->icon_w, t->frame);
24603e747e6dSmrg	      else
24613e747e6dSmrg		Zoom(tmp_win->icon_w, t->frame);
24623e747e6dSmrg
24633e747e6dSmrg	      XMapWindow(dpy, t->w);
24643e747e6dSmrg	      t->mapped = TRUE;
24653e747e6dSmrg	      if (Scr->NoRaiseDeicon)
24663e747e6dSmrg		XMapWindow(dpy, t->frame);
24673e747e6dSmrg	      else
24683e747e6dSmrg		XMapRaised(dpy, t->frame);
24693e747e6dSmrg	      SetMapStateProp(t, NormalState);
24703e747e6dSmrg
24713e747e6dSmrg	      if (t->icon_w) {
24723e747e6dSmrg		XUnmapWindow(dpy, t->icon_w);
24733e747e6dSmrg		IconDown (t);
24743e747e6dSmrg	      }
24753e747e6dSmrg	      if (t->list) XUnmapWindow(dpy, t->list->icon);
24763e747e6dSmrg	      t->icon = FALSE;
24773e747e6dSmrg	      t->icon_on = FALSE;
24783e747e6dSmrg	    }
24793e747e6dSmrg	}
24803e747e6dSmrg
24813e747e6dSmrg    XSync (dpy, 0);
24823e747e6dSmrg}
24833e747e6dSmrg
24843e747e6dSmrg
24853e747e6dSmrg
24863e747e6dSmrgvoid
24873e747e6dSmrgIconify(TwmWindow *tmp_win, int def_x, int def_y)
24883e747e6dSmrg{
24893e747e6dSmrg    TwmWindow *t;
24903e747e6dSmrg    int iconify;
24913e747e6dSmrg    XWindowAttributes winattrs;
24923e747e6dSmrg    unsigned long eventMask;
24933e747e6dSmrg
24943e747e6dSmrg    iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
24953e747e6dSmrg    if (iconify)
24963e747e6dSmrg    {
24973e747e6dSmrg	if (tmp_win->icon_w == (Window) 0)
24983e747e6dSmrg	    CreateIconWindow(tmp_win, def_x, def_y);
24993e747e6dSmrg	else
25003e747e6dSmrg	    IconUp(tmp_win);
25013e747e6dSmrg	XMapRaised(dpy, tmp_win->icon_w);
25023e747e6dSmrg    }
25033e747e6dSmrg    if (tmp_win->list)
25043e747e6dSmrg	XMapWindow(dpy, tmp_win->list->icon);
25053e747e6dSmrg
25063e747e6dSmrg    XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
25073e747e6dSmrg    eventMask = winattrs.your_event_mask;
25083e747e6dSmrg
25093e747e6dSmrg    /* iconify transients first */
25103e747e6dSmrg    for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
25113e747e6dSmrg      {
25123e747e6dSmrg	if (t->transient && t->transientfor == tmp_win->w)
25133e747e6dSmrg	  {
25143e747e6dSmrg	    if (iconify)
25153e747e6dSmrg	      {
25163e747e6dSmrg		if (t->icon_on)
25173e747e6dSmrg			Zoom(t->icon_w, tmp_win->icon_w);
25183e747e6dSmrg		else
25193e747e6dSmrg		  Zoom(t->frame, tmp_win->icon_w);
25203e747e6dSmrg	      }
25213e747e6dSmrg
25223e747e6dSmrg	    /*
25233e747e6dSmrg	     * Prevent the receipt of an UnmapNotify, since that would
25243e747e6dSmrg	     * cause a transition to the Withdrawn state.
25253e747e6dSmrg	     */
25263e747e6dSmrg	    t->mapped = FALSE;
25273e747e6dSmrg	    XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
25283e747e6dSmrg	    XUnmapWindow(dpy, t->w);
25293e747e6dSmrg	    XSelectInput(dpy, t->w, eventMask);
25303e747e6dSmrg	    XUnmapWindow(dpy, t->frame);
25313e747e6dSmrg	    if (t->icon_w)
25323e747e6dSmrg	      XUnmapWindow(dpy, t->icon_w);
25333e747e6dSmrg	    SetMapStateProp(t, IconicState);
25343e747e6dSmrg	    SetBorder (t, False);
25353e747e6dSmrg	    if (t == Scr->Focus)
25363e747e6dSmrg	      {
25373e747e6dSmrg		SetFocus ((TwmWindow *) NULL, LastTimestamp());
25383e747e6dSmrg		Scr->Focus = NULL;
25393e747e6dSmrg		Scr->FocusRoot = TRUE;
25403e747e6dSmrg	      }
25413e747e6dSmrg	    if (t->list) XMapWindow(dpy, t->list->icon);
25423e747e6dSmrg	    t->icon = TRUE;
25433e747e6dSmrg	    t->icon_on = FALSE;
25443e747e6dSmrg	  }
25453e747e6dSmrg      }
25463e747e6dSmrg
25473e747e6dSmrg    if (iconify)
25483e747e6dSmrg	Zoom(tmp_win->frame, tmp_win->icon_w);
25493e747e6dSmrg
25503e747e6dSmrg    /*
25513e747e6dSmrg     * Prevent the receipt of an UnmapNotify, since that would
25523e747e6dSmrg     * cause a transition to the Withdrawn state.
25533e747e6dSmrg     */
25543e747e6dSmrg    tmp_win->mapped = FALSE;
25553e747e6dSmrg    XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
25563e747e6dSmrg    XUnmapWindow(dpy, tmp_win->w);
25573e747e6dSmrg    XSelectInput(dpy, tmp_win->w, eventMask);
25583e747e6dSmrg    XUnmapWindow(dpy, tmp_win->frame);
25593e747e6dSmrg    SetMapStateProp(tmp_win, IconicState);
25603e747e6dSmrg
25613e747e6dSmrg    SetBorder (tmp_win, False);
25623e747e6dSmrg    if (tmp_win == Scr->Focus)
25633e747e6dSmrg    {
25643e747e6dSmrg	SetFocus ((TwmWindow *) NULL, LastTimestamp());
25653e747e6dSmrg	Scr->Focus = NULL;
25663e747e6dSmrg	Scr->FocusRoot = TRUE;
25673e747e6dSmrg    }
25683e747e6dSmrg    tmp_win->icon = TRUE;
25693e747e6dSmrg    if (iconify)
25703e747e6dSmrg	tmp_win->icon_on = TRUE;
25713e747e6dSmrg    else
25723e747e6dSmrg	tmp_win->icon_on = FALSE;
25733e747e6dSmrg    XSync (dpy, 0);
25743e747e6dSmrg}
25753e747e6dSmrg
25763e747e6dSmrg
25773e747e6dSmrg
25783e747e6dSmrgstatic void
25793e747e6dSmrgIdentify (TwmWindow *t)
25803e747e6dSmrg{
25813e747e6dSmrg    int i, n, twidth, width, height;
25823e747e6dSmrg    int x, y;
25833e747e6dSmrg    unsigned int wwidth, wheight, bw, depth;
25843e747e6dSmrg    Window junk;
25853e747e6dSmrg    int px, py, dummy;
25863e747e6dSmrg    unsigned udummy;
25873e747e6dSmrg
25883e747e6dSmrg    n = 0;
25893e747e6dSmrg    (void) sprintf(Info[n++], "Twm version:  %s", Version);
25903e747e6dSmrg    Info[n++][0] = '\0';
25913e747e6dSmrg
25923e747e6dSmrg    if (t) {
25933e747e6dSmrg	XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
25943e747e6dSmrg		      &wwidth, &wheight, &bw, &depth);
25953e747e6dSmrg	(void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
25963e747e6dSmrg				      &x, &y, &junk);
25973e747e6dSmrg	(void) sprintf(Info[n++], "Name             = \"%s\"", t->full_name);
25983e747e6dSmrg	(void) sprintf(Info[n++], "Class.res_name   = \"%s\"", t->class.res_name);
25993e747e6dSmrg	(void) sprintf(Info[n++], "Class.res_class  = \"%s\"", t->class.res_class);
26003e747e6dSmrg	Info[n++][0] = '\0';
26013e747e6dSmrg	(void) sprintf(Info[n++], "Geometry/root    = %dx%d+%d+%d", wwidth, wheight,
26023e747e6dSmrg		x, y);
26033e747e6dSmrg	(void) sprintf(Info[n++], "Border width     = %d", bw);
26043e747e6dSmrg	(void) sprintf(Info[n++], "Depth            = %d", depth);
26053e747e6dSmrg	if (HasSync)
26063e747e6dSmrg	{
26073e747e6dSmrg	    int priority;
26083e747e6dSmrg	    (void)XSyncGetPriority(dpy, t->w, &priority);
26093e747e6dSmrg	    (void) sprintf(Info[n++], "Priority         = %d", priority);
26103e747e6dSmrg	}
26113e747e6dSmrg    }
26123e747e6dSmrg
26133e747e6dSmrg    Info[n++][0] = '\0';
26143e747e6dSmrg    (void) sprintf(Info[n++], "Click to dismiss....");
26153e747e6dSmrg
26163e747e6dSmrg    /* figure out the width and height of the info window */
26173e747e6dSmrg    height = n * (Scr->DefaultFont.height+2);
26183e747e6dSmrg    width = 1;
26193e747e6dSmrg    for (i = 0; i < n; i++)
26203e747e6dSmrg    {
26213e747e6dSmrg	twidth = MyFont_TextWidth(&Scr->DefaultFont, Info[i],
26223e747e6dSmrg	    strlen(Info[i]));
26233e747e6dSmrg	if (twidth > width)
26243e747e6dSmrg	    width = twidth;
26253e747e6dSmrg    }
26263e747e6dSmrg    if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
26273e747e6dSmrg
26283e747e6dSmrg    width += 10;		/* some padding */
26293e747e6dSmrg    if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py,
26303e747e6dSmrg		       &dummy, &dummy, &udummy)) {
26313e747e6dSmrg	px -= (width / 2);
26323e747e6dSmrg	py -= (height / 3);
26333e747e6dSmrg	if (px + width + BW2 >= Scr->MyDisplayWidth)
26343e747e6dSmrg	  px = Scr->MyDisplayWidth - width - BW2;
26353e747e6dSmrg	if (py + height + BW2 >= Scr->MyDisplayHeight)
26363e747e6dSmrg	  py = Scr->MyDisplayHeight - height - BW2;
26373e747e6dSmrg	if (px < 0) px = 0;
26383e747e6dSmrg	if (py < 0) py = 0;
26393e747e6dSmrg    } else {
26403e747e6dSmrg	px = py = 0;
26413e747e6dSmrg    }
26423e747e6dSmrg    XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
26433e747e6dSmrg    XMapRaised(dpy, Scr->InfoWindow);
26443e747e6dSmrg    InfoLines = n;
26453e747e6dSmrg}
26463e747e6dSmrg
26473e747e6dSmrg
26483e747e6dSmrgvoid
26493e747e6dSmrgSetMapStateProp(TwmWindow *tmp_win, int state)
26503e747e6dSmrg{
26513e747e6dSmrg    unsigned long data[2];		/* "suggested" by ICCCM version 1 */
26523e747e6dSmrg
26533e747e6dSmrg    data[0] = (unsigned long) state;
26543e747e6dSmrg    data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
26553e747e6dSmrg			   tmp_win->icon_w);
26563e747e6dSmrg
26573e747e6dSmrg    XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
26583e747e6dSmrg		 PropModeReplace, (unsigned char *) data, 2);
26593e747e6dSmrg}
26603e747e6dSmrg
26613e747e6dSmrg
26623e747e6dSmrg
26633e747e6dSmrgBool
26643e747e6dSmrgGetWMState (Window w, int *statep, Window *iwp)
26653e747e6dSmrg{
26663e747e6dSmrg    Atom actual_type;
26673e747e6dSmrg    int actual_format;
26683e747e6dSmrg    unsigned long nitems, bytesafter;
26693e747e6dSmrg    unsigned long *datap = NULL;
26703e747e6dSmrg    Bool retval = False;
26713e747e6dSmrg
26723e747e6dSmrg    if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
26733e747e6dSmrg			    &actual_type, &actual_format, &nitems, &bytesafter,
26743e747e6dSmrg			    (unsigned char **) &datap) != Success || !datap)
26753e747e6dSmrg      return False;
26763e747e6dSmrg
26773e747e6dSmrg    if (nitems <= 2) {			/* "suggested" by ICCCM version 1 */
26783e747e6dSmrg	*statep = (int) datap[0];
26793e747e6dSmrg	*iwp = (Window) datap[1];
26803e747e6dSmrg	retval = True;
26813e747e6dSmrg    }
26823e747e6dSmrg
26833e747e6dSmrg    XFree ((char *) datap);
26843e747e6dSmrg    return retval;
26853e747e6dSmrg}
26863e747e6dSmrg
26873e747e6dSmrg
26883e747e6dSmrgvoid
26893e747e6dSmrgWarpToScreen (int n, int inc)
26903e747e6dSmrg{
26913e747e6dSmrg    Window dumwin;
26923e747e6dSmrg    int x, y, dumint;
26933e747e6dSmrg    unsigned int dummask;
26943e747e6dSmrg    ScreenInfo *newscr = NULL;
26953e747e6dSmrg
26963e747e6dSmrg    while (!newscr) {
26973e747e6dSmrg					/* wrap around */
26983e747e6dSmrg	if (n < 0)
26993e747e6dSmrg	  n = NumScreens - 1;
27003e747e6dSmrg	else if (n >= NumScreens)
27013e747e6dSmrg	  n = 0;
27023e747e6dSmrg
27033e747e6dSmrg	newscr = ScreenList[n];
27043e747e6dSmrg	if (!newscr) {			/* make sure screen is managed */
27053e747e6dSmrg	    if (inc) {			/* walk around the list */
27063e747e6dSmrg		n += inc;
27073e747e6dSmrg		continue;
27083e747e6dSmrg	    }
27093e747e6dSmrg	    fprintf (stderr, "%s:  unable to warp to unmanaged screen %d\n",
27103e747e6dSmrg		     ProgramName, n);
27113e747e6dSmrg	    Bell(XkbBI_MinorError,0,None);
27123e747e6dSmrg	    return;
27133e747e6dSmrg	}
27143e747e6dSmrg    }
27153e747e6dSmrg
27163e747e6dSmrg    if (Scr->screen == n) return;	/* already on that screen */
27173e747e6dSmrg
27183e747e6dSmrg    PreviousScreen = Scr->screen;
27193e747e6dSmrg    XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
27203e747e6dSmrg		   &dumint, &dumint, &dummask);
27213e747e6dSmrg
27223e747e6dSmrg    XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
27233e747e6dSmrg    return;
27243e747e6dSmrg}
27253e747e6dSmrg
27263e747e6dSmrg
27273e747e6dSmrg
27283e747e6dSmrg
27293e747e6dSmrg/**
27303e747e6dSmrg * rotate our internal copy of WM_COLORMAP_WINDOWS
27313e747e6dSmrg */
27323e747e6dSmrgvoid
27333e747e6dSmrgBumpWindowColormap (TwmWindow *tmp, int inc)
27343e747e6dSmrg{
27353e747e6dSmrg    int i, j, previously_installed;
27363e747e6dSmrg    ColormapWindow **cwins;
27373e747e6dSmrg
27383e747e6dSmrg    if (!tmp) return;
27393e747e6dSmrg
27403e747e6dSmrg    if (inc && tmp->cmaps.number_cwins > 0) {
27413e747e6dSmrg	cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
27423e747e6dSmrg					   tmp->cmaps.number_cwins);
27433e747e6dSmrg	if (cwins) {
27443e747e6dSmrg	    if ((previously_installed =
27453e747e6dSmrg		/* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps &&
27463e747e6dSmrg	        tmp->cmaps.number_cwins))) {
27473e747e6dSmrg		for (i = tmp->cmaps.number_cwins; i-- > 0; )
27483e747e6dSmrg		    tmp->cmaps.cwins[i]->colormap->state = 0;
27493e747e6dSmrg	    }
27503e747e6dSmrg
27513e747e6dSmrg	    for (i = 0; i < tmp->cmaps.number_cwins; i++) {
27523e747e6dSmrg		j = i - inc;
27533e747e6dSmrg		if (j >= tmp->cmaps.number_cwins)
27543e747e6dSmrg		    j -= tmp->cmaps.number_cwins;
27553e747e6dSmrg		else if (j < 0)
27563e747e6dSmrg		    j += tmp->cmaps.number_cwins;
27573e747e6dSmrg		cwins[j] = tmp->cmaps.cwins[i];
27583e747e6dSmrg	    }
27593e747e6dSmrg
27603e747e6dSmrg	    free((char *) tmp->cmaps.cwins);
27613e747e6dSmrg
27623e747e6dSmrg	    tmp->cmaps.cwins = cwins;
27633e747e6dSmrg
27643e747e6dSmrg	    if (tmp->cmaps.number_cwins > 1)
27653e747e6dSmrg		bzero (tmp->cmaps.scoreboard,
27663e747e6dSmrg		       ColormapsScoreboardLength(&tmp->cmaps));
27673e747e6dSmrg
27683e747e6dSmrg	    if (previously_installed)
27693e747e6dSmrg		InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
27703e747e6dSmrg	}
27713e747e6dSmrg    } else
27723e747e6dSmrg	FetchWmColormapWindows (tmp);
27733e747e6dSmrg}
27743e747e6dSmrg
27753e747e6dSmrg
27763e747e6dSmrgvoid
27773e747e6dSmrgHideIconManager ()
27783e747e6dSmrg{
27793e747e6dSmrg    SetMapStateProp (Scr->iconmgr.twm_win, WithdrawnState);
27803e747e6dSmrg    XUnmapWindow(dpy, Scr->iconmgr.twm_win->frame);
27813e747e6dSmrg    if (Scr->iconmgr.twm_win->icon_w)
27823e747e6dSmrg      XUnmapWindow (dpy, Scr->iconmgr.twm_win->icon_w);
27833e747e6dSmrg    Scr->iconmgr.twm_win->mapped = FALSE;
27843e747e6dSmrg    Scr->iconmgr.twm_win->icon = TRUE;
27853e747e6dSmrg}
27863e747e6dSmrg
27873e747e6dSmrg
27883e747e6dSmrg
27893e747e6dSmrgvoid
27903e747e6dSmrgSetBorder (TwmWindow *tmp, Bool onoroff)
27913e747e6dSmrg{
27923e747e6dSmrg    if (tmp->highlight) {
27933e747e6dSmrg	if (onoroff) {
27943e747e6dSmrg	    XSetWindowBorder (dpy, tmp->frame, tmp->border);
27953e747e6dSmrg	    if (tmp->title_w)
27963e747e6dSmrg	      XSetWindowBorder (dpy, tmp->title_w, tmp->border);
27973e747e6dSmrg	} else {
27983e747e6dSmrg	    XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray);
27993e747e6dSmrg	    if (tmp->title_w)
28003e747e6dSmrg	      XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray);
28013e747e6dSmrg	}
28023e747e6dSmrg    }
28033e747e6dSmrg}
28043e747e6dSmrg
28053e747e6dSmrg
28063e747e6dSmrgvoid
28073e747e6dSmrgDestroyMenu (MenuRoot *menu)
28083e747e6dSmrg{
28093e747e6dSmrg    MenuItem *item;
28103e747e6dSmrg
28113e747e6dSmrg    if (menu->w) {
28123e747e6dSmrg	XDeleteContext (dpy, menu->w, MenuContext);
28133e747e6dSmrg	XDeleteContext (dpy, menu->w, ScreenContext);
28143e747e6dSmrg	if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
28153e747e6dSmrg	XDestroyWindow(dpy, menu->w);
28163e747e6dSmrg    }
28173e747e6dSmrg
28183e747e6dSmrg    for (item = menu->first; item; ) {
28193e747e6dSmrg	MenuItem *tmp = item;
28203e747e6dSmrg	item = item->next;
28213e747e6dSmrg	free ((char *) tmp);
28223e747e6dSmrg    }
28233e747e6dSmrg}
28243e747e6dSmrg
28253e747e6dSmrg
28263e747e6dSmrg
28273e747e6dSmrg/*
28283e747e6dSmrg * warping routines
28293e747e6dSmrg */
28303e747e6dSmrg
28313e747e6dSmrgvoid
28323e747e6dSmrgWarpAlongRing (XButtonEvent *ev, Bool forward)
28333e747e6dSmrg{
28343e747e6dSmrg    TwmWindow *r, *head;
28353e747e6dSmrg
28363e747e6dSmrg    if (Scr->RingLeader)
28373e747e6dSmrg      head = Scr->RingLeader;
28383e747e6dSmrg    else if (!(head = Scr->Ring))
28393e747e6dSmrg      return;
28403e747e6dSmrg
28413e747e6dSmrg    if (forward) {
28423e747e6dSmrg	for (r = head->ring.next; r != head; r = r->ring.next) {
28433e747e6dSmrg	    if (!r || r->mapped) break;
28443e747e6dSmrg	}
28453e747e6dSmrg    } else {
28463e747e6dSmrg	for (r = head->ring.prev; r != head; r = r->ring.prev) {
28473e747e6dSmrg	    if (!r || r->mapped) break;
28483e747e6dSmrg	}
28493e747e6dSmrg    }
28503e747e6dSmrg
28513e747e6dSmrg    if (r && r != head) {
28523e747e6dSmrg	TwmWindow *p = Scr->RingLeader, *t;
28533e747e6dSmrg
28543e747e6dSmrg	Scr->RingLeader = r;
28553e747e6dSmrg	WarpToWindow (r);
28563e747e6dSmrg
28573e747e6dSmrg	if (p && p->mapped &&
28583e747e6dSmrg	    XFindContext (dpy, ev->window, TwmContext, (caddr_t *)&t) == XCSUCCESS &&
28593e747e6dSmrg	    p == t) {
28603e747e6dSmrg	    p->ring.cursor_valid = True;
28613e747e6dSmrg	    p->ring.curs_x = ev->x_root - t->frame_x;
28623e747e6dSmrg	    p->ring.curs_y = ev->y_root - t->frame_y;
28633e747e6dSmrg	    if (p->ring.curs_x < -p->frame_bw ||
28643e747e6dSmrg		p->ring.curs_x >= p->frame_width + p->frame_bw ||
28653e747e6dSmrg		p->ring.curs_y < -p->frame_bw ||
28663e747e6dSmrg		p->ring.curs_y >= p->frame_height + p->frame_bw) {
28673e747e6dSmrg		/* somehow out of window */
28683e747e6dSmrg		p->ring.curs_x = p->frame_width / 2;
28693e747e6dSmrg		p->ring.curs_y = p->frame_height / 2;
28703e747e6dSmrg	    }
28713e747e6dSmrg	}
28723e747e6dSmrg    }
28733e747e6dSmrg}
28743e747e6dSmrg
28753e747e6dSmrg
28763e747e6dSmrg
28773e747e6dSmrgvoid
28783e747e6dSmrgWarpToWindow (TwmWindow *t)
28793e747e6dSmrg{
28803e747e6dSmrg    int x, y;
28813e747e6dSmrg
28823e747e6dSmrg    if (t->auto_raise || !Scr->NoRaiseWarp) AutoRaiseWindow (t);
28833e747e6dSmrg    if (t->ring.cursor_valid) {
28843e747e6dSmrg	x = t->ring.curs_x;
28853e747e6dSmrg	y = t->ring.curs_y;
28863e747e6dSmrg    } else {
28873e747e6dSmrg	x = t->frame_width / 2;
28883e747e6dSmrg	y = t->frame_height / 2;
28893e747e6dSmrg    }
28903e747e6dSmrg    XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y);
28913e747e6dSmrg}
28923e747e6dSmrg
28933e747e6dSmrg
28943e747e6dSmrg
28953e747e6dSmrg
28963e747e6dSmrg/*
28973e747e6dSmrg * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
28983e747e6dSmrg * client messages will have the following form:
28993e747e6dSmrg *
29003e747e6dSmrg *     event type	ClientMessage
29013e747e6dSmrg *     message type	_XA_WM_PROTOCOLS
29023e747e6dSmrg *     window		tmp->w
29033e747e6dSmrg *     format		32
29043e747e6dSmrg *     data[0]		message atom
29053e747e6dSmrg *     data[1]		time stamp
29063e747e6dSmrg */
29073e747e6dSmrgstatic void
29083e747e6dSmrgsend_clientmessage (Window w, Atom a, Time timestamp)
29093e747e6dSmrg{
29103e747e6dSmrg    XClientMessageEvent ev;
29113e747e6dSmrg
29123e747e6dSmrg    ev.type = ClientMessage;
29133e747e6dSmrg    ev.window = w;
29143e747e6dSmrg    ev.message_type = _XA_WM_PROTOCOLS;
29153e747e6dSmrg    ev.format = 32;
29163e747e6dSmrg    ev.data.l[0] = a;
29173e747e6dSmrg    ev.data.l[1] = timestamp;
29183e747e6dSmrg    XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
29193e747e6dSmrg}
29203e747e6dSmrg
29213e747e6dSmrgvoid
29223e747e6dSmrgSendDeleteWindowMessage (TwmWindow *tmp, Time timestamp)
29233e747e6dSmrg{
29243e747e6dSmrg    send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
29253e747e6dSmrg}
29263e747e6dSmrg
29273e747e6dSmrgvoid
29283e747e6dSmrgSendSaveYourselfMessage (TwmWindow *tmp, Time timestamp)
29293e747e6dSmrg{
29303e747e6dSmrg    send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
29313e747e6dSmrg}
29323e747e6dSmrg
29333e747e6dSmrgvoid
29343e747e6dSmrgSendTakeFocusMessage (TwmWindow *tmp, Time timestamp)
29353e747e6dSmrg{
29363e747e6dSmrg    send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
29373e747e6dSmrg}
2938