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