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