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 * twm menu code
553e747e6dSmrg *
56f66df612Smrg * 17-Nov-87 Thomas E. LaStrange                File created
573e747e6dSmrg *
583e747e6dSmrg ***********************************************************************/
593e747e6dSmrg
60ffd25bcaSmrg#ifdef HAVE_CONFIG_H
61f66df612Smrg#include "config.h"
62ffd25bcaSmrg#endif
63ffd25bcaSmrg
643e747e6dSmrg#include <stdio.h>
653e747e6dSmrg#include <X11/Xos.h>
663e747e6dSmrg#include "twm.h"
673e747e6dSmrg#include "gc.h"
683e747e6dSmrg#include "menus.h"
693e747e6dSmrg#include "resize.h"
703e747e6dSmrg#include "events.h"
713e747e6dSmrg#include "util.h"
723e747e6dSmrg#include "parse.h"
733e747e6dSmrg#include "screen.h"
743e747e6dSmrg#include "menus.h"
753e747e6dSmrg#include "iconmgr.h"
763e747e6dSmrg#include "add_window.h"
773e747e6dSmrg#include "icons.h"
783e747e6dSmrg#include "session.h"
793e747e6dSmrg#include <X11/Xmu/CharSet.h>
803e747e6dSmrg#include <X11/extensions/sync.h>
813e747e6dSmrg#include <X11/SM/SMlib.h>
823e747e6dSmrg
833e747e6dSmrgint RootFunction = 0;
84f66df612SmrgMenuRoot *ActiveMenu = NULL;            /**< the active menu */
85f66df612SmrgMenuItem *ActiveItem = NULL;            /**< the active menu item */
86f66df612Smrgint MoveFunction;                       /**< either F_MOVE or F_FORCEMOVE */
873e747e6dSmrgint WindowMoved = FALSE;
883e747e6dSmrgint menuFromFrameOrWindowOrTitlebar = FALSE;
893e747e6dSmrg
90f66df612Smrgint ConstMove = FALSE;          /**< constrained move variables */
913e747e6dSmrgint ConstMoveDir;
923e747e6dSmrgint ConstMoveX;
933e747e6dSmrgint ConstMoveY;
943e747e6dSmrgint ConstMoveXL;
953e747e6dSmrgint ConstMoveXR;
963e747e6dSmrgint ConstMoveYT;
973e747e6dSmrgint ConstMoveYB;
98ffd25bcaSmrg
993e747e6dSmrg/* Globals used to keep track of whether the mouse has moved during
1003e747e6dSmrg   a resize function. */
1013e747e6dSmrgint ResizeOrigX;
1023e747e6dSmrgint ResizeOrigY;
1033e747e6dSmrg
104f66df612Smrgint MenuDepth = 0;              /**< number of menus up */
1053e747e6dSmrgstatic struct {
1063e747e6dSmrg    int x;
1073e747e6dSmrg    int y;
1083e747e6dSmrg} MenuOrigins[MAXMENUDEPTH];
1093e747e6dSmrgstatic Cursor LastCursor;
1103e747e6dSmrg
111f66df612Smrgstatic Bool belongs_to_twm_window(TwmWindow *t, Window w);
112f66df612Smrgstatic void Identify(TwmWindow *t);
113f66df612Smrgstatic void send_clientmessage(Window w, Atom a, Time timestamp);
114f66df612Smrgstatic void BumpWindowColormap(TwmWindow *tmp, int inc);
115f66df612Smrgstatic int DeferExecution(int context, int func, Cursor cursor);
116f66df612Smrgstatic Bool NeedToDefer(MenuRoot *root);
117f66df612Smrgstatic void DestroyMenu(MenuRoot *menu);
118f66df612Smrgstatic void MakeMenu(MenuRoot *mr);
119f66df612Smrgstatic void Execute(const char *s);
120f66df612Smrgstatic void HideIconManager(void);
121f66df612Smrgstatic void WarpAlongRing(XButtonEvent *ev, Bool forward);
122f66df612Smrgstatic int WarpThere(TwmWindow *t);
123f66df612Smrgstatic void WarpToWindow(TwmWindow *t);
124f66df612Smrg
125f66df612Smrg#define SHADOWWIDTH 5           /* in pixels */
1263e747e6dSmrg
1273e747e6dSmrg/**
1283e747e6dSmrg * initialize menu roots
1293e747e6dSmrg */
1303e747e6dSmrgvoid
131c2535118SmrgInitMenus(void)
1323e747e6dSmrg{
1333e747e6dSmrg    int i, j, k;
1343e747e6dSmrg
135f66df612Smrg    for (i = 0; i < MAX_BUTTONS + 1; i++)
136f66df612Smrg        for (j = 0; j < NUM_CONTEXTS; j++)
137f66df612Smrg            for (k = 0; k < MOD_SIZE; k++) {
138f66df612Smrg                Scr->Mouse[i][j][k].func = 0;
139f66df612Smrg                Scr->Mouse[i][j][k].item = NULL;
140f66df612Smrg            }
1413e747e6dSmrg
1423e747e6dSmrg    Scr->DefaultFunction.func = 0;
1433e747e6dSmrg    Scr->WindowFunction.func = 0;
1446d8e82c3Smrg}
1453e747e6dSmrg
1466d8e82c3Smrgvoid
1476d8e82c3SmrgInitMenusFirst(void)
1486d8e82c3Smrg{
1496d8e82c3Smrg    FuncKey *key;
150f66df612Smrg
1516d8e82c3Smrg    for (key = Scr->FuncKeyRoot.next; key != NULL;) {
1526d8e82c3Smrg        FuncKey *tmp = key;
1533e747e6dSmrg
1546d8e82c3Smrg        free(key->name);
1556d8e82c3Smrg        key = key->next;
1566d8e82c3Smrg        free(tmp);
1576d8e82c3Smrg    }
1586d8e82c3Smrg    Scr->FuncKeyRoot.next = NULL;
1593e747e6dSmrg}
1603e747e6dSmrg
1613e747e6dSmrg/**
1623e747e6dSmrg * add a function key to the list
1633e747e6dSmrg *
1643e747e6dSmrg *  \param name     the name of the key
1653e747e6dSmrg *  \param cont     the context to look for the key press in
166f66df612Smrg *  \param mods2    modifier keys that need to be pressed
1673e747e6dSmrg *  \param func     the function to perform
1683e747e6dSmrg *  \param win_name the window name (if any)
1693e747e6dSmrg *  \param action   the action string associated with the function (if any)
1703e747e6dSmrg */
171f66df612SmrgBool
172f66df612SmrgAddFuncKey(char *name, int cont, int mods2, int func, char *win_name,
173f66df612Smrg           char *action)
1743e747e6dSmrg{
1753e747e6dSmrg    FuncKey *tmp;
1763e747e6dSmrg    KeySym keysym;
1773e747e6dSmrg    KeyCode keycode;
1783e747e6dSmrg
1793e747e6dSmrg    /*
1803e747e6dSmrg     * Don't let a 0 keycode go through, since that means AnyKey to the
1813e747e6dSmrg     * XGrabKey call in GrabKeys().
1823e747e6dSmrg     */
1833e747e6dSmrg    if ((keysym = XStringToKeysym(name)) == NoSymbol ||
184f66df612Smrg        (keycode = XKeysymToKeycode(dpy, keysym)) == 0) {
185f66df612Smrg        return False;
1863e747e6dSmrg    }
1873e747e6dSmrg
1883e747e6dSmrg    /* see if there already is a key defined for this context */
189f66df612Smrg    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) {
190f66df612Smrg        if (tmp->keysym == keysym && tmp->cont == cont && tmp->mods == mods2)
191f66df612Smrg            break;
1923e747e6dSmrg    }
1933e747e6dSmrg
194f66df612Smrg    if (tmp == NULL) {
1956d8e82c3Smrg        tmp = (FuncKey *) malloc(sizeof(FuncKey));
196f66df612Smrg        tmp->next = Scr->FuncKeyRoot.next;
197f66df612Smrg        Scr->FuncKeyRoot.next = tmp;
1983e747e6dSmrg    }
1993e747e6dSmrg
2003e747e6dSmrg    tmp->name = name;
2013e747e6dSmrg    tmp->keysym = keysym;
2023e747e6dSmrg    tmp->keycode = keycode;
2033e747e6dSmrg    tmp->cont = cont;
204f66df612Smrg    tmp->mods = mods2;
2053e747e6dSmrg    tmp->func = func;
2063e747e6dSmrg    tmp->win_name = win_name;
2073e747e6dSmrg    tmp->action = action;
2083e747e6dSmrg
2093e747e6dSmrg    return True;
2103e747e6dSmrg}
2113e747e6dSmrg
212f66df612Smrgint
213f66df612SmrgCreateTitleButton(const char *name, int func, const char *action,
214f66df612Smrg                  MenuRoot *menuroot, Bool rightside, Bool append)
2153e747e6dSmrg{
2166d8e82c3Smrg    TitleButton *tb = (TitleButton *) malloc(sizeof(TitleButton));
2173e747e6dSmrg
2183e747e6dSmrg    if (!tb) {
219f66df612Smrg        twmWarning("unable to allocate %lu bytes for title button",
220f66df612Smrg                   (unsigned long) sizeof(TitleButton));
221f66df612Smrg        return 0;
2223e747e6dSmrg    }
2233e747e6dSmrg
2243e747e6dSmrg    tb->next = NULL;
225f66df612Smrg    tb->name = name;            /* note that we are not copying */
226f66df612Smrg    tb->bitmap = None;          /* WARNING, values not set yet */
227f66df612Smrg    tb->width = 0;              /* see InitTitlebarButtons */
228f66df612Smrg    tb->height = 0;             /* ditto */
2293e747e6dSmrg    tb->func = func;
2303e747e6dSmrg    tb->action = action;
2313e747e6dSmrg    tb->menuroot = menuroot;
2323e747e6dSmrg    tb->rightside = rightside;
2333e747e6dSmrg    if (rightside) {
234f66df612Smrg        Scr->TBInfo.nright++;
235f66df612Smrg    }
236f66df612Smrg    else {
237f66df612Smrg        Scr->TBInfo.nleft++;
2383e747e6dSmrg    }
2393e747e6dSmrg
2403e747e6dSmrg    /*
2413e747e6dSmrg     * Cases for list:
242ffd25bcaSmrg     *
2433e747e6dSmrg     *     1.  empty list, prepend left       put at head of list
2443e747e6dSmrg     *     2.  append left, prepend right     put in between left and right
2453e747e6dSmrg     *     3.  append right                   put at tail of list
2463e747e6dSmrg     *
2473e747e6dSmrg     * Do not refer to widths and heights yet since buttons not created
2483e747e6dSmrg     * (since fonts not loaded and heights not known).
2493e747e6dSmrg     */
250f66df612Smrg    if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) {   /* 1 */
251f66df612Smrg        tb->next = Scr->TBInfo.head;
252f66df612Smrg        Scr->TBInfo.head = tb;
253f66df612Smrg    }
254f66df612Smrg    else if (append && rightside) {     /* 3 */
2556d8e82c3Smrg        TitleButton *t;
256f66df612Smrg
257f66df612Smrg        /* SUPPRESS 530 */
258f66df612Smrg        for (t = Scr->TBInfo.head; t->next; t = t->next);
259f66df612Smrg        t->next = tb;
260f66df612Smrg        tb->next = NULL;
261f66df612Smrg    }
262f66df612Smrg    else {                      /* 2 */
2636d8e82c3Smrg        TitleButton *t, *prev = NULL;
264f66df612Smrg
265f66df612Smrg        for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
266f66df612Smrg            prev = t;
267f66df612Smrg        }
268f66df612Smrg        if (prev) {
269f66df612Smrg            tb->next = prev->next;
270f66df612Smrg            prev->next = tb;
271f66df612Smrg        }
272f66df612Smrg        else {
273f66df612Smrg            tb->next = Scr->TBInfo.head;
274f66df612Smrg            Scr->TBInfo.head = tb;
275f66df612Smrg        }
2763e747e6dSmrg    }
2773e747e6dSmrg
2783e747e6dSmrg    return 1;
2793e747e6dSmrg}
2803e747e6dSmrg
2813e747e6dSmrg/**
282ffd25bcaSmrg * Do all the necessary stuff to load in a titlebar button.  If we can't find
283ffd25bcaSmrg * the button, then put in a question; if we can't find the question mark,
2843e747e6dSmrg * something is wrong and we are probably going to be in trouble later on.
2853e747e6dSmrg */
286f66df612Smrgvoid
287f66df612SmrgInitTitlebarButtons(void)
2883e747e6dSmrg{
2893e747e6dSmrg    TitleButton *tb;
2903e747e6dSmrg    int h;
2913e747e6dSmrg
2923e747e6dSmrg    /*
2933e747e6dSmrg     * initialize dimensions
2943e747e6dSmrg     */
2953e747e6dSmrg    Scr->TBInfo.width = (Scr->TitleHeight -
296f66df612Smrg                         2 * (Scr->FramePadding + Scr->ButtonIndent));
2973e747e6dSmrg    Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
298f66df612Smrg                       ? ((Scr->TitlePadding + 1) / 2) : 1);
2993e747e6dSmrg    h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
3003e747e6dSmrg
3013e747e6dSmrg    /*
3023e747e6dSmrg     * add in some useful buttons and bindings so that novices can still
3033e747e6dSmrg     * use the system.
3043e747e6dSmrg     */
3053e747e6dSmrg    if (!Scr->NoDefaults) {
306f66df612Smrg        /* insert extra buttons */
307f66df612Smrg        if (!CreateTitleButton(TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
308f66df612Smrg                               False, False)) {
309f66df612Smrg            twmWarning("unable to add iconify button");
310f66df612Smrg        }
311f66df612Smrg        if (!CreateTitleButton(TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
312f66df612Smrg                               True, True)) {
313f66df612Smrg            twmWarning("unable to add resize button");
314f66df612Smrg        }
315f66df612Smrg        AddDefaultBindings();
316f66df612Smrg    }
317f66df612Smrg    ComputeCommonTitleOffsets();
3183e747e6dSmrg
3193e747e6dSmrg    /*
3203e747e6dSmrg     * load in images and do appropriate centering
3213e747e6dSmrg     */
3223e747e6dSmrg
3233e747e6dSmrg    for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
324f66df612Smrg        tb->bitmap = FindBitmap(tb->name, &tb->width, &tb->height);
325f66df612Smrg        if (!tb->bitmap) {
326f66df612Smrg            tb->bitmap = FindBitmap(TBPM_QUESTION, &tb->width, &tb->height);
327f66df612Smrg            if (!tb->bitmap) {  /* cannot happen (see util.c) */
328f66df612Smrg                twmWarning("unable to add titlebar button \"%s\"", tb->name);
329f66df612Smrg            }
330f66df612Smrg        }
331f66df612Smrg
332f66df612Smrg        tb->dstx = (int) (((unsigned) h - tb->width + 1) / 2);
333f66df612Smrg        if (tb->dstx < 0) {     /* clip to minimize copying */
334f66df612Smrg            tb->srcx = -(tb->dstx);
335f66df612Smrg            tb->width = (unsigned) h;
336f66df612Smrg            tb->dstx = 0;
337f66df612Smrg        }
338f66df612Smrg        else {
339f66df612Smrg            tb->srcx = 0;
340f66df612Smrg        }
341f66df612Smrg        tb->dsty = (int) (((unsigned) h - tb->height + 1) / 2);
342f66df612Smrg        if (tb->dsty < 0) {
343f66df612Smrg            tb->srcy = -(tb->dsty);
344f66df612Smrg            tb->height = (unsigned) h;
345f66df612Smrg            tb->dsty = 0;
346f66df612Smrg        }
347f66df612Smrg        else {
348f66df612Smrg            tb->srcy = 0;
349f66df612Smrg        }
3503e747e6dSmrg    }
3513e747e6dSmrg}
3523e747e6dSmrg
3533e747e6dSmrgvoid
3543e747e6dSmrgPaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
3553e747e6dSmrg{
3563e747e6dSmrg    int y_offset;
3573e747e6dSmrg    int text_y;
3583e747e6dSmrg    GC gc;
3593e747e6dSmrg
3603e747e6dSmrg#ifdef DEBUG_MENUS
3613e747e6dSmrg    fprintf(stderr, "Paint entry\n");
3623e747e6dSmrg#endif
3633e747e6dSmrg    y_offset = mi->item_num * Scr->EntryHeight;
3643e747e6dSmrg    text_y = y_offset + Scr->MenuFont.y;
3653e747e6dSmrg
366f66df612Smrg    if (mi->func != F_TITLE) {
3673e747e6dSmrg
368f66df612Smrg        if (mi->state) {
369f66df612Smrg            XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
3703e747e6dSmrg
371f66df612Smrg            XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
372f66df612Smrg                           (unsigned) mr->width, (unsigned) Scr->EntryHeight);
3733e747e6dSmrg
374f66df612Smrg            MyFont_ChangeGC(mi->hi_fore, mi->hi_back, &Scr->MenuFont);
3753e747e6dSmrg
376f66df612Smrg            MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x,
377f66df612Smrg                              text_y, mi->item, mi->strlen);
378f66df612Smrg
379f66df612Smrg            gc = Scr->NormalGC;
380f66df612Smrg        }
381f66df612Smrg        else {
382f66df612Smrg            if (mi->user_colors || !exposure) {
383f66df612Smrg                XSetForeground(dpy, Scr->NormalGC, mi->back);
384f66df612Smrg
385f66df612Smrg                XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
386f66df612Smrg                               (unsigned) mr->width,
387f66df612Smrg                               (unsigned) Scr->EntryHeight);
388f66df612Smrg
389f66df612Smrg                MyFont_ChangeGC(mi->fore, mi->back, &Scr->MenuFont);
390f66df612Smrg                gc = Scr->NormalGC;
391f66df612Smrg            }
392f66df612Smrg            else
393f66df612Smrg                gc = Scr->MenuGC;
394f66df612Smrg
395f66df612Smrg            MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, gc,
396f66df612Smrg                              mi->x, text_y, mi->item, mi->strlen);
397f66df612Smrg
398f66df612Smrg        }
399f66df612Smrg
400f66df612Smrg        if (mi->func == F_MENU) {
401f66df612Smrg            int x, y;
402f66df612Smrg
403f66df612Smrg            /* create the pull right pixmap if needed */
404f66df612Smrg            if (Scr->pullPm == None) {
405f66df612Smrg                Scr->pullPm = CreateMenuIcon(Scr->MenuFont.height,
406f66df612Smrg                                             &Scr->pullW, &Scr->pullH);
407f66df612Smrg            }
408f66df612Smrg            x = (int) ((unsigned) mr->width - (Scr->pullW + 5));
409f66df612Smrg            y = (int) ((unsigned) y_offset +
410f66df612Smrg                       (((unsigned) Scr->MenuFont.height - Scr->pullH) / 2));
411f66df612Smrg            XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0, Scr->pullW,
412f66df612Smrg                       Scr->pullH, x, y, 1);
413f66df612Smrg        }
414f66df612Smrg    }
415f66df612Smrg    else {
416f66df612Smrg        XSetForeground(dpy, Scr->NormalGC, mi->back);
417f66df612Smrg
418f66df612Smrg        /* fill the rectangle with the title background color */
419f66df612Smrg        XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
420f66df612Smrg                       (unsigned) mr->width, (unsigned) Scr->EntryHeight);
421f66df612Smrg
422f66df612Smrg        {
423f66df612Smrg            int y;
424f66df612Smrg
425f66df612Smrg            XSetForeground(dpy, Scr->NormalGC, mi->fore);
426f66df612Smrg            /* now draw the dividing lines */
427f66df612Smrg            if (y_offset)
428f66df612Smrg                XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y_offset,
429f66df612Smrg                          mr->width, y_offset);
430f66df612Smrg            y = ((mi->item_num + 1) * Scr->EntryHeight) - 1;
431f66df612Smrg            XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
432f66df612Smrg        }
433f66df612Smrg
434f66df612Smrg        MyFont_ChangeGC(mi->fore, mi->back, &Scr->MenuFont);
435f66df612Smrg        /* finally render the title */
436f66df612Smrg        MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x,
437f66df612Smrg                          text_y, mi->item, mi->strlen);
4383e747e6dSmrg    }
4393e747e6dSmrg}
440ffd25bcaSmrg
4413e747e6dSmrgvoid
4423e747e6dSmrgPaintMenu(MenuRoot *mr, XEvent *e)
4433e747e6dSmrg{
4443e747e6dSmrg    MenuItem *mi;
4453e747e6dSmrg
446f66df612Smrg    for (mi = mr->first; mi != NULL; mi = mi->next) {
447f66df612Smrg        int y_offset = mi->item_num * Scr->EntryHeight;
4483e747e6dSmrg
449f66df612Smrg        /* be smart about handling the expose, redraw only the entries
450f66df612Smrg         * that we need to
451f66df612Smrg         */
452f66df612Smrg        if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
453f66df612Smrg            (e->xexpose.y + e->xexpose.height) > y_offset) {
454f66df612Smrg            PaintEntry(mr, mi, True);
455f66df612Smrg        }
4563e747e6dSmrg    }
4573e747e6dSmrg    XSync(dpy, 0);
4583e747e6dSmrg}
4593e747e6dSmrg
4603e747e6dSmrgstatic Bool fromMenu;
4613e747e6dSmrg
4623e747e6dSmrgvoid
463c2535118SmrgUpdateMenu(void)
4643e747e6dSmrg{
4653e747e6dSmrg    MenuItem *mi;
4663e747e6dSmrg    int i, x, y, x_root, y_root, entry;
4673e747e6dSmrg    int done;
4683e747e6dSmrg    MenuItem *badItem = NULL;
469ffd25bcaSmrg    XPointer context_data;
4706d8e82c3Smrg    unsigned udummy = 0;
4716d8e82c3Smrg    Window wdummy = None;
4723e747e6dSmrg
4733e747e6dSmrg    fromMenu = TRUE;
4743e747e6dSmrg
475f66df612Smrg    while (TRUE) {
476f66df612Smrg        /* block until there is an event */
4773e747e6dSmrg        if (!menuFromFrameOrWindowOrTitlebar) {
478f66df612Smrg            XMaskEvent(dpy,
479f66df612Smrg                       ButtonPressMask | ButtonReleaseMask |
480f66df612Smrg                       EnterWindowMask | ExposureMask |
481f66df612Smrg                       VisibilityChangeMask | LeaveWindowMask |
482f66df612Smrg                       ButtonMotionMask, &Event);
483f66df612Smrg        }
484f66df612Smrg        if (Event.type == MotionNotify) {
485f66df612Smrg            /* discard any extra motion events before a release */
486f66df612Smrg            while (XCheckMaskEvent(dpy,
487f66df612Smrg                                   ButtonMotionMask | ButtonReleaseMask,
488f66df612Smrg                                   &Event))
489f66df612Smrg                if (Event.type == ButtonRelease)
490f66df612Smrg                    break;
491f66df612Smrg        }
492f66df612Smrg
493f66df612Smrg        if (!DispatchEvent())
494f66df612Smrg            continue;
495f66df612Smrg
496f66df612Smrg        if (Event.type == ButtonRelease || Cancel) {
497f66df612Smrg            menuFromFrameOrWindowOrTitlebar = FALSE;
498f66df612Smrg            fromMenu = FALSE;
499f66df612Smrg            return;
500f66df612Smrg        }
501f66df612Smrg
502f66df612Smrg        if (Event.type != MotionNotify)
503ffd25bcaSmrg            continue;
504ffd25bcaSmrg
505f66df612Smrg        if (!ActiveMenu)
506f66df612Smrg            continue;
507f66df612Smrg
508f66df612Smrg        done = FALSE;
5096d8e82c3Smrg        XQueryPointer(dpy, ActiveMenu->w, &wdummy, &wdummy,
5106d8e82c3Smrg                      &x_root, &y_root, &x, &y, &udummy);
511f66df612Smrg
512f66df612Smrg        /* if we haven't received the enter notify yet, wait */
513f66df612Smrg        if (!ActiveMenu->entered)
514f66df612Smrg            continue;
515f66df612Smrg
516f66df612Smrg        if (XFindContext(dpy, ActiveMenu->w, ScreenContext, &context_data) == 0)
517f66df612Smrg            Scr = (struct ScreenInfo *) context_data;
518f66df612Smrg
519f66df612Smrg        if (x < 0 || y < 0 || x >= ActiveMenu->width || y >= ActiveMenu->height) {
520f66df612Smrg            if (ActiveItem && ActiveItem->func != F_TITLE) {
521f66df612Smrg                ActiveItem->state = 0;
522f66df612Smrg                PaintEntry(ActiveMenu, ActiveItem, False);
523f66df612Smrg            }
524f66df612Smrg            ActiveItem = NULL;
525f66df612Smrg            continue;
526f66df612Smrg        }
527f66df612Smrg
528f66df612Smrg        /* look for the entry that the mouse is in */
529f66df612Smrg        entry = y / Scr->EntryHeight;
530f66df612Smrg        for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi = mi->next) {
531f66df612Smrg            if (i == entry)
532f66df612Smrg                break;
533f66df612Smrg        }
534f66df612Smrg
535f66df612Smrg        /* if there is an active item, we might have to turn it off */
536f66df612Smrg        if (ActiveItem) {
537f66df612Smrg            /* is the active item the one we are on ? */
538f66df612Smrg            if (ActiveItem->item_num == entry && ActiveItem->state)
539f66df612Smrg                done = TRUE;
540f66df612Smrg
541f66df612Smrg            /* if we weren't on the active entry, let's turn the old
542f66df612Smrg             * active one off
543f66df612Smrg             */
544f66df612Smrg            if (!done && ActiveItem->func != F_TITLE) {
545f66df612Smrg                ActiveItem->state = 0;
546f66df612Smrg                PaintEntry(ActiveMenu, ActiveItem, False);
547f66df612Smrg            }
548f66df612Smrg        }
549f66df612Smrg
550f66df612Smrg        /* if we weren't on the active item, change the active item and turn
551f66df612Smrg         * it on
552f66df612Smrg         */
553f66df612Smrg        if (!done) {
554f66df612Smrg            ActiveItem = mi;
555f66df612Smrg            if (ActiveItem && ActiveItem->func != F_TITLE && !ActiveItem->state) {
556f66df612Smrg                ActiveItem->state = 1;
557f66df612Smrg                PaintEntry(ActiveMenu, ActiveItem, False);
558f66df612Smrg            }
559f66df612Smrg        }
560f66df612Smrg
561f66df612Smrg        /* now check to see if we were over the arrow of a pull right entry */
562f66df612Smrg        if (ActiveItem && ActiveItem->func == F_MENU &&
563f66df612Smrg            ((ActiveMenu->width - x) < (ActiveMenu->width >> 1))) {
564f66df612Smrg            MenuRoot *save = ActiveMenu;
565f66df612Smrg            int savex = MenuOrigins[MenuDepth - 1].x;
566f66df612Smrg            int savey = MenuOrigins[MenuDepth - 1].y;
567f66df612Smrg
568f66df612Smrg            if (MenuDepth < MAXMENUDEPTH) {
569f66df612Smrg                PopUpMenu(ActiveItem->sub,
570f66df612Smrg                          (savex + (ActiveMenu->width >> 1)),
571f66df612Smrg                          (savey + ActiveItem->item_num * Scr->EntryHeight)
572f66df612Smrg                          /*(savey + ActiveItem->item_num * Scr->EntryHeight +
573f66df612Smrg                             (Scr->EntryHeight >> 1)) */
574f66df612Smrg                          , False);
575f66df612Smrg            }
576f66df612Smrg            else if (!badItem) {
577f66df612Smrg                Bell(XkbBI_MinorError, 0, None);
578f66df612Smrg                badItem = ActiveItem;
579f66df612Smrg            }
580f66df612Smrg
581f66df612Smrg            /* if the menu did get popped up, unhighlight the active item */
582f66df612Smrg            if (save != ActiveMenu && ActiveItem->state) {
583f66df612Smrg                ActiveItem->state = 0;
584f66df612Smrg                PaintEntry(save, ActiveItem, False);
585f66df612Smrg                ActiveItem = NULL;
586f66df612Smrg            }
587f66df612Smrg        }
588f66df612Smrg        if (badItem != ActiveItem)
589f66df612Smrg            badItem = NULL;
590f66df612Smrg        XFlush(dpy);
5913e747e6dSmrg    }
5923e747e6dSmrg
5933e747e6dSmrg}
5943e747e6dSmrg
5953e747e6dSmrg/**
5963e747e6dSmrg * create a new menu root
5973e747e6dSmrg *
5983e747e6dSmrg *  \param name  the name of the menu root
5993e747e6dSmrg */
6003e747e6dSmrgMenuRoot *
601c2535118SmrgNewMenuRoot(const char *name)
6023e747e6dSmrg{
6033e747e6dSmrg    MenuRoot *tmp;
6043e747e6dSmrg
605f66df612Smrg#define UNUSED_PIXEL ((unsigned long) (~0))     /* more than 24 bits */
6063e747e6dSmrg
6076d8e82c3Smrg    tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
6083e747e6dSmrg    tmp->hi_fore = UNUSED_PIXEL;
6093e747e6dSmrg    tmp->hi_back = UNUSED_PIXEL;
6103e747e6dSmrg    tmp->name = name;
6113e747e6dSmrg    tmp->prev = NULL;
6123e747e6dSmrg    tmp->first = NULL;
6133e747e6dSmrg    tmp->last = NULL;
6143e747e6dSmrg    tmp->items = 0;
6153e747e6dSmrg    tmp->width = 0;
6163e747e6dSmrg    tmp->mapped = NEVER_MAPPED;
6173e747e6dSmrg    tmp->pull = FALSE;
6183e747e6dSmrg    tmp->w = None;
6193e747e6dSmrg    tmp->shadow = None;
6203e747e6dSmrg    tmp->real_menu = FALSE;
6213e747e6dSmrg
622f66df612Smrg    if (Scr->MenuList == NULL) {
623f66df612Smrg        Scr->MenuList = tmp;
624f66df612Smrg        Scr->MenuList->next = NULL;
6253e747e6dSmrg    }
6263e747e6dSmrg
627f66df612Smrg    if (Scr->LastMenu == NULL) {
628f66df612Smrg        Scr->LastMenu = tmp;
629f66df612Smrg        Scr->LastMenu->next = NULL;
6303e747e6dSmrg    }
631f66df612Smrg    else {
632f66df612Smrg        Scr->LastMenu->next = tmp;
633f66df612Smrg        Scr->LastMenu = tmp;
634f66df612Smrg        Scr->LastMenu->next = NULL;
6353e747e6dSmrg    }
6363e747e6dSmrg
6373e747e6dSmrg    if (strcmp(name, TWM_WINDOWS) == 0)
638f66df612Smrg        Scr->Windows = tmp;
6393e747e6dSmrg
6403e747e6dSmrg    return (tmp);
6413e747e6dSmrg}
6423e747e6dSmrg
6433e747e6dSmrg/**
6443e747e6dSmrg * add an item to a root menu
6453e747e6dSmrg *
6463e747e6dSmrg *  \param menu   pointer to the root menu to add the item
6473e747e6dSmrg *  \param item   the text to appear in the menu
6483e747e6dSmrg *  \param action the string to possibly execute
6493e747e6dSmrg *  \param sub    the menu root if it is a pull-right entry
6503e747e6dSmrg *  \param func   the numeric function
6513e747e6dSmrg *  \param fore   foreground color string
6523e747e6dSmrg *  \param back   background color string
6533e747e6dSmrg */
6543e747e6dSmrgMenuItem *
655c2535118SmrgAddToMenu(MenuRoot *menu, const char *item, const char *action,
656c2535118Smrg          MenuRoot *sub, int func, const char *fore, const char *back)
6573e747e6dSmrg{
6583e747e6dSmrg    MenuItem *tmp;
6593e747e6dSmrg    int width;
6603e747e6dSmrg
6613e747e6dSmrg#ifdef DEBUG_MENUS
662f66df612Smrg    fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%p, f=%d\n",
663f66df612Smrg            item, action ? action : "<null>", sub, func);
6643e747e6dSmrg#endif
6653e747e6dSmrg
6666d8e82c3Smrg    tmp = (MenuItem *) malloc(sizeof(MenuItem));
6673e747e6dSmrg    tmp->root = menu;
6683e747e6dSmrg
669f66df612Smrg    if (menu->first == NULL) {
670f66df612Smrg        menu->first = tmp;
671f66df612Smrg        tmp->prev = NULL;
6723e747e6dSmrg    }
673f66df612Smrg    else {
674f66df612Smrg        menu->last->next = tmp;
675f66df612Smrg        tmp->prev = menu->last;
6763e747e6dSmrg    }
6773e747e6dSmrg    menu->last = tmp;
6783e747e6dSmrg
6793e747e6dSmrg    tmp->item = item;
680f66df612Smrg    tmp->strlen = (short) strlen(item);
6813e747e6dSmrg    tmp->action = action;
6823e747e6dSmrg    tmp->next = NULL;
6833e747e6dSmrg    tmp->sub = NULL;
6843e747e6dSmrg    tmp->state = 0;
685f66df612Smrg    tmp->func = (short) func;
6863e747e6dSmrg
687f66df612Smrg    if (!Scr->HaveFonts)
688f66df612Smrg        CreateFonts();
6893e747e6dSmrg    width = MyFont_TextWidth(&Scr->MenuFont, item, tmp->strlen);
6903e747e6dSmrg    if (width <= 0)
691f66df612Smrg        width = 1;
6923e747e6dSmrg    if (width > menu->width)
693f66df612Smrg        menu->width = (short) width;
6943e747e6dSmrg
6953e747e6dSmrg    tmp->user_colors = FALSE;
696f66df612Smrg    if (Scr->Monochrome == COLOR && fore != NULL) {
697f66df612Smrg        int save;
698f66df612Smrg
699f66df612Smrg        save = Scr->FirstTime;
700f66df612Smrg        Scr->FirstTime = TRUE;
701f66df612Smrg        GetColor(COLOR, &tmp->fore, fore);
702f66df612Smrg        GetColor(COLOR, &tmp->back, back);
703f66df612Smrg        Scr->FirstTime = (short) save;
704f66df612Smrg        tmp->user_colors = TRUE;
7053e747e6dSmrg    }
706f66df612Smrg    if (sub != NULL) {
707f66df612Smrg        tmp->sub = sub;
708f66df612Smrg        menu->pull = TRUE;
7093e747e6dSmrg    }
7103e747e6dSmrg    tmp->item_num = menu->items++;
7113e747e6dSmrg
7123e747e6dSmrg    return (tmp);
7133e747e6dSmrg}
7143e747e6dSmrg
7153e747e6dSmrgvoid
716c2535118SmrgMakeMenus(void)
7173e747e6dSmrg{
7183e747e6dSmrg    MenuRoot *mr;
7193e747e6dSmrg
720f66df612Smrg    for (mr = Scr->MenuList; mr != NULL; mr = mr->next) {
721f66df612Smrg        if (mr->real_menu == FALSE)
722f66df612Smrg            continue;
7233e747e6dSmrg
724f66df612Smrg        MakeMenu(mr);
7253e747e6dSmrg    }
7263e747e6dSmrg}
7273e747e6dSmrg
728c2535118Smrgstatic void
7293e747e6dSmrgMakeMenu(MenuRoot *mr)
7303e747e6dSmrg{
7313e747e6dSmrg    MenuItem *start, *end, *cur, *tmp;
7323e747e6dSmrg    XColor f1, f2, f3;
7333e747e6dSmrg    XColor b1, b2, b3;
7343e747e6dSmrg    XColor save_fore, save_back;
735f66df612Smrg    int i;
7363e747e6dSmrg    XSetWindowAttributes attributes;
7373e747e6dSmrg    Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
7383e747e6dSmrg
7393e747e6dSmrg    Scr->EntryHeight = Scr->MenuFont.height + 4;
7403e747e6dSmrg
741f66df612Smrg    /* let's first size the window accordingly */
742f66df612Smrg    if (mr->mapped == NEVER_MAPPED) {
743f66df612Smrg        int width;
744f66df612Smrg        unsigned long valuemask;
745f66df612Smrg
746f66df612Smrg        if (mr->pull == TRUE) {
747f66df612Smrg            mr->width = (short) (mr->width + (16 + 10));
748f66df612Smrg        }
749f66df612Smrg
750f66df612Smrg        width = mr->width + 10;
751f66df612Smrg
752f66df612Smrg        for (cur = mr->first; cur != NULL; cur = cur->next) {
753f66df612Smrg            if (cur->func != F_TITLE)
754f66df612Smrg                cur->x = 5;
755f66df612Smrg            else {
756f66df612Smrg                cur->x =
757f66df612Smrg                    (short) (width -
758f66df612Smrg                             MyFont_TextWidth(&Scr->MenuFont, cur->item,
759f66df612Smrg                                              cur->strlen));
760f66df612Smrg                cur->x /= 2;
761f66df612Smrg            }
762f66df612Smrg        }
763f66df612Smrg        mr->height = (short) (mr->items * Scr->EntryHeight);
764f66df612Smrg        mr->width = (short) (mr->width + 10);
765f66df612Smrg
766f66df612Smrg        if (Scr->Shadow) {
767f66df612Smrg            /*
768f66df612Smrg             * Make sure that you don't draw into the shadow window or else
769f66df612Smrg             * the background bits there will get saved
770f66df612Smrg             */
771f66df612Smrg            valuemask = (CWBackPixel | CWBorderPixel);
772f66df612Smrg            attributes.background_pixel = Scr->MenuShadowColor;
773f66df612Smrg            attributes.border_pixel = Scr->MenuShadowColor;
774f66df612Smrg            if (Scr->SaveUnder) {
775f66df612Smrg                valuemask |= CWSaveUnder;
776f66df612Smrg                attributes.save_under = True;
777f66df612Smrg            }
778f66df612Smrg            mr->shadow = XCreateWindow(dpy, Scr->Root, 0, 0,
779f66df612Smrg                                       (unsigned int) mr->width,
780f66df612Smrg                                       (unsigned int) mr->height,
781f66df612Smrg                                       (unsigned int) 0,
782f66df612Smrg                                       CopyFromParent,
783f66df612Smrg                                       (unsigned int) CopyFromParent,
784f66df612Smrg                                       (Visual *) CopyFromParent,
785f66df612Smrg                                       valuemask, &attributes);
786f66df612Smrg        }
787f66df612Smrg
788f66df612Smrg        valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
789f66df612Smrg        attributes.background_pixel = Scr->MenuC.back;
790f66df612Smrg        attributes.border_pixel = Scr->MenuBorderColor;
791f66df612Smrg        attributes.event_mask = (ExposureMask | EnterWindowMask);
792f66df612Smrg        if (Scr->SaveUnder) {
793f66df612Smrg            valuemask |= CWSaveUnder;
794f66df612Smrg            attributes.save_under = True;
795f66df612Smrg        }
796f66df612Smrg        if (Scr->BackingStore) {
797f66df612Smrg            valuemask |= CWBackingStore;
798f66df612Smrg            attributes.backing_store = Always;
799f66df612Smrg        }
800f66df612Smrg        mr->w = XCreateWindow(dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
801f66df612Smrg                              (unsigned int) mr->height,
802f66df612Smrg                              (unsigned int) Scr->MenuBorderWidth,
803f66df612Smrg                              CopyFromParent, (unsigned int) CopyFromParent,
804f66df612Smrg                              (Visual *) CopyFromParent,
805f66df612Smrg                              valuemask, &attributes);
806f66df612Smrg
807f66df612Smrg        XSaveContext(dpy, mr->w, MenuContext, (XPointer) mr);
808f66df612Smrg        XSaveContext(dpy, mr->w, ScreenContext, (XPointer) Scr);
809f66df612Smrg
810f66df612Smrg        mr->mapped = UNMAPPED;
8113e747e6dSmrg    }
8123e747e6dSmrg
8133e747e6dSmrg    /* get the default colors into the menus */
814f66df612Smrg    for (tmp = mr->first; tmp != NULL; tmp = tmp->next) {
815f66df612Smrg        if (!tmp->user_colors) {
816f66df612Smrg            if (tmp->func != F_TITLE) {
817f66df612Smrg                tmp->fore = Scr->MenuC.fore;
818f66df612Smrg                tmp->back = Scr->MenuC.back;
819f66df612Smrg            }
820f66df612Smrg            else {
821f66df612Smrg                tmp->fore = Scr->MenuTitleC.fore;
822f66df612Smrg                tmp->back = Scr->MenuTitleC.back;
823f66df612Smrg            }
824f66df612Smrg        }
825f66df612Smrg
826f66df612Smrg        if (mr->hi_fore != UNUSED_PIXEL) {
827f66df612Smrg            tmp->hi_fore = mr->hi_fore;
828f66df612Smrg            tmp->hi_back = mr->hi_back;
829f66df612Smrg        }
830f66df612Smrg        else {
831f66df612Smrg            tmp->hi_fore = tmp->back;
832f66df612Smrg            tmp->hi_back = tmp->fore;
833f66df612Smrg        }
8343e747e6dSmrg    }
8353e747e6dSmrg
8363e747e6dSmrg    if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
837f66df612Smrg        return;
8383e747e6dSmrg
8393e747e6dSmrg    start = mr->first;
840f66df612Smrg
841f66df612Smrg    while (TRUE) {
842f66df612Smrg        int num;
843f66df612Smrg        int fred, fgreen, fblue;
844f66df612Smrg        int bred, bgreen, bblue;
845f66df612Smrg
846f66df612Smrg        for (; start != NULL; start = start->next) {
847f66df612Smrg            if (start->user_colors)
848f66df612Smrg                break;
849f66df612Smrg        }
850f66df612Smrg        if (start == NULL)
851f66df612Smrg            break;
852f66df612Smrg
853f66df612Smrg        for (end = start->next; end != NULL; end = end->next) {
854f66df612Smrg            if (end->user_colors)
855f66df612Smrg                break;
856f66df612Smrg        }
857f66df612Smrg        if (end == NULL)
858f66df612Smrg            break;
859f66df612Smrg
860f66df612Smrg        /* we have a start and end to interpolate between */
861f66df612Smrg        num = end->item_num - start->item_num;
862f66df612Smrg
863f66df612Smrg        f1.pixel = start->fore;
864f66df612Smrg        XQueryColor(dpy, cmap, &f1);
865f66df612Smrg        f2.pixel = end->fore;
866f66df612Smrg        XQueryColor(dpy, cmap, &f2);
867f66df612Smrg
868f66df612Smrg        b1.pixel = start->back;
869f66df612Smrg        XQueryColor(dpy, cmap, &b1);
870f66df612Smrg        b2.pixel = end->back;
871f66df612Smrg        XQueryColor(dpy, cmap, &b2);
872f66df612Smrg
873f66df612Smrg        fred = ((int) f2.red - (int) f1.red) / num;
874f66df612Smrg        fgreen = ((int) f2.green - (int) f1.green) / num;
875f66df612Smrg        fblue = ((int) f2.blue - (int) f1.blue) / num;
876f66df612Smrg
877f66df612Smrg        bred = ((int) b2.red - (int) b1.red) / num;
878f66df612Smrg        bgreen = ((int) b2.green - (int) b1.green) / num;
879f66df612Smrg        bblue = ((int) b2.blue - (int) b1.blue) / num;
880f66df612Smrg
881f66df612Smrg        f3 = f1;
882f66df612Smrg        f3.flags = DoRed | DoGreen | DoBlue;
883f66df612Smrg
884f66df612Smrg        b3 = b1;
885f66df612Smrg        b3.flags = DoRed | DoGreen | DoBlue;
886f66df612Smrg
887f66df612Smrg        num -= 1;
888f66df612Smrg        for (i = 0, cur = start->next; i < num && cur; i++, cur = cur->next) {
889f66df612Smrg#define AddColor(target,source) target = (unsigned short)(target + source)
890f66df612Smrg            AddColor(f3.red, fred);
891f66df612Smrg            AddColor(f3.green, fgreen);
892f66df612Smrg            AddColor(f3.blue, fblue);
893f66df612Smrg            save_fore = f3;
894f66df612Smrg
895f66df612Smrg            AddColor(b3.red, bred);
896f66df612Smrg            AddColor(b3.green, bgreen);
897f66df612Smrg            AddColor(b3.blue, bblue);
898f66df612Smrg            save_back = b3;
899f66df612Smrg
900f66df612Smrg            XAllocColor(dpy, cmap, &f3);
901f66df612Smrg            XAllocColor(dpy, cmap, &b3);
902f66df612Smrg            cur->hi_back = cur->fore = f3.pixel;
903f66df612Smrg            cur->hi_fore = cur->back = b3.pixel;
904f66df612Smrg            cur->user_colors = True;
905f66df612Smrg
906f66df612Smrg            f3 = save_fore;
907f66df612Smrg            b3 = save_back;
908f66df612Smrg        }
909f66df612Smrg        start = end;
9103e747e6dSmrg    }
9113e747e6dSmrg}
9123e747e6dSmrg
9133e747e6dSmrg/**
9143e747e6dSmrg * pop up a pull down menu.
9153e747e6dSmrg *
9163e747e6dSmrg *  \param menu   the root pointer of the menu to pop up
9173e747e6dSmrg *  \param x,y    location of upper left of menu
9183e747e6dSmrg *  \param center whether or not to center horizontally over position
9193e747e6dSmrg */
920ffd25bcaSmrgBool
921f66df612SmrgPopUpMenu(MenuRoot *menu, int x, int y, Bool center)
9223e747e6dSmrg{
9233e747e6dSmrg    TwmWindow **WindowNames;
924f66df612Smrg    TwmWindow *tmp_win2, *tmp_win3;
925f66df612Smrg    int (*compar) (const char *, const char *) =
926f66df612Smrg        (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
9273e747e6dSmrg
928f66df612Smrg    if (!menu)
929f66df612Smrg        return False;
9303e747e6dSmrg
9313e747e6dSmrg    InstallRootColormap();
9323e747e6dSmrg
933f66df612Smrg    if (menu == Scr->Windows) {
934f66df612Smrg        TwmWindow *tmp_win;
935f66df612Smrg        int WindowNameCount;
9363e747e6dSmrg
937f66df612Smrg        /* this is the twm windows menu,  let's go ahead and build it */
9383e747e6dSmrg
939f66df612Smrg        DestroyMenu(menu);
9403e747e6dSmrg
941f66df612Smrg        menu->first = NULL;
942f66df612Smrg        menu->last = NULL;
943f66df612Smrg        menu->items = 0;
944f66df612Smrg        menu->width = 0;
945f66df612Smrg        menu->mapped = NEVER_MAPPED;
946f66df612Smrg        AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE, NULLSTR,
947f66df612Smrg                  NULLSTR);
948ffd25bcaSmrg
949f66df612Smrg        for (tmp_win = Scr->TwmRoot.next, WindowNameCount = 0;
950f66df612Smrg             tmp_win != NULL; tmp_win = tmp_win->next)
951f66df612Smrg            WindowNameCount++;
952f66df612Smrg
953f66df612Smrg        if (WindowNameCount != 0) {
954f66df612Smrg            int i;
955f66df612Smrg
9566d8e82c3Smrg            WindowNames = (TwmWindow **)
957f66df612Smrg                malloc(sizeof(TwmWindow *) * (size_t) WindowNameCount);
9583e747e6dSmrg            WindowNames[0] = Scr->TwmRoot.next;
959f66df612Smrg
960f66df612Smrg            for (tmp_win = Scr->TwmRoot.next->next, WindowNameCount = 1;
961f66df612Smrg                 tmp_win != NULL; tmp_win = tmp_win->next, WindowNameCount++) {
9623e747e6dSmrg                tmp_win2 = tmp_win;
963f66df612Smrg                for (i = 0; i < WindowNameCount; i++) {
964f66df612Smrg                    if ((*compar) (tmp_win2->name, WindowNames[i]->name) < 0) {
9653e747e6dSmrg                        tmp_win3 = tmp_win2;
9663e747e6dSmrg                        tmp_win2 = WindowNames[i];
9673e747e6dSmrg                        WindowNames[i] = tmp_win3;
9683e747e6dSmrg                    }
9693e747e6dSmrg                }
9703e747e6dSmrg                WindowNames[WindowNameCount] = tmp_win2;
9713e747e6dSmrg            }
972f66df612Smrg            for (i = 0; i < WindowNameCount; i++) {
973f66df612Smrg                AddToMenu(menu, WindowNames[i]->name, (char *) WindowNames[i],
974f66df612Smrg                          NULL, F_POPUP, NULL, NULL);
9753e747e6dSmrg            }
9763e747e6dSmrg            free(WindowNames);
9773e747e6dSmrg        }
9783e747e6dSmrg
979f66df612Smrg        MakeMenu(menu);
9803e747e6dSmrg    }
9813e747e6dSmrg
982f66df612Smrg    if (menu->w == None || menu->items == 0)
983f66df612Smrg        return False;
9843e747e6dSmrg
9853e747e6dSmrg    /* Prevent recursively bringing up menus. */
986f66df612Smrg    if (menu->mapped == MAPPED)
987f66df612Smrg        return False;
9883e747e6dSmrg
9893e747e6dSmrg    /*
9903e747e6dSmrg     * Dynamically set the parent;  this allows pull-ups to also be main
9913e747e6dSmrg     * menus, or to be brought up from more than one place.
9923e747e6dSmrg     */
9933e747e6dSmrg    menu->prev = ActiveMenu;
9943e747e6dSmrg
9953e747e6dSmrg    XGrabPointer(dpy, Scr->Root, True,
996f66df612Smrg                 ButtonPressMask | ButtonReleaseMask |
997f66df612Smrg                 ButtonMotionMask | PointerMotionHintMask,
998f66df612Smrg                 GrabModeAsync, GrabModeAsync,
999f66df612Smrg                 Scr->Root, Scr->MenuCursor, CurrentTime);
10003e747e6dSmrg
10013e747e6dSmrg    ActiveMenu = menu;
10023e747e6dSmrg    menu->mapped = MAPPED;
10033e747e6dSmrg    menu->entered = FALSE;
10043e747e6dSmrg
10053e747e6dSmrg    if (center) {
1006f66df612Smrg        x -= (menu->width / 2);
1007f66df612Smrg        y -= (Scr->EntryHeight / 2);    /* sticky menus would be nice here */
10083e747e6dSmrg    }
10093e747e6dSmrg
10103e747e6dSmrg    /*
10113e747e6dSmrg     * clip to screen
10123e747e6dSmrg     */
10133e747e6dSmrg    if (x + menu->width > Scr->MyDisplayWidth) {
1014f66df612Smrg        x = Scr->MyDisplayWidth - menu->width;
10153e747e6dSmrg    }
1016f66df612Smrg    if (x < 0)
1017f66df612Smrg        x = 0;
10183e747e6dSmrg    if (y + menu->height > Scr->MyDisplayHeight) {
1019f66df612Smrg        y = Scr->MyDisplayHeight - menu->height;
10203e747e6dSmrg    }
1021f66df612Smrg    if (y < 0)
1022f66df612Smrg        y = 0;
10233e747e6dSmrg
10243e747e6dSmrg    MenuOrigins[MenuDepth].x = x;
10253e747e6dSmrg    MenuOrigins[MenuDepth].y = y;
10263e747e6dSmrg    MenuDepth++;
10273e747e6dSmrg
10283e747e6dSmrg    XMoveWindow(dpy, menu->w, x, y);
10293e747e6dSmrg    if (Scr->Shadow) {
1030f66df612Smrg        XMoveWindow(dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
10313e747e6dSmrg    }
10323e747e6dSmrg    if (Scr->Shadow) {
1033f66df612Smrg        XRaiseWindow(dpy, menu->shadow);
10343e747e6dSmrg    }
10353e747e6dSmrg    XMapRaised(dpy, menu->w);
10363e747e6dSmrg    if (Scr->Shadow) {
1037f66df612Smrg        XMapWindow(dpy, menu->shadow);
10383e747e6dSmrg    }
10393e747e6dSmrg    XSync(dpy, 0);
10403e747e6dSmrg    return True;
10413e747e6dSmrg}
10423e747e6dSmrg
10433e747e6dSmrg/**
10443e747e6dSmrg * unhighlight the current menu selection and take down the menus
10453e747e6dSmrg */
10463e747e6dSmrgvoid
1047c2535118SmrgPopDownMenu(void)
10483e747e6dSmrg{
10493e747e6dSmrg    MenuRoot *tmp;
10503e747e6dSmrg
10513e747e6dSmrg    if (ActiveMenu == NULL)
1052f66df612Smrg        return;
10533e747e6dSmrg
1054f66df612Smrg    if (ActiveItem) {
1055f66df612Smrg        ActiveItem->state = 0;
1056f66df612Smrg        PaintEntry(ActiveMenu, ActiveItem, False);
10573e747e6dSmrg    }
10583e747e6dSmrg
1059f66df612Smrg    for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev) {
1060f66df612Smrg        if (Scr->Shadow) {
1061f66df612Smrg            XUnmapWindow(dpy, tmp->shadow);
1062f66df612Smrg        }
1063f66df612Smrg        XUnmapWindow(dpy, tmp->w);
1064f66df612Smrg        tmp->mapped = UNMAPPED;
1065f66df612Smrg        UninstallRootColormap();
10663e747e6dSmrg    }
10673e747e6dSmrg
10683e747e6dSmrg    XFlush(dpy);
10693e747e6dSmrg    ActiveMenu = NULL;
10703e747e6dSmrg    ActiveItem = NULL;
10713e747e6dSmrg    MenuDepth = 0;
10723e747e6dSmrg    if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE)
1073f66df612Smrg        menuFromFrameOrWindowOrTitlebar = TRUE;
10743e747e6dSmrg}
10753e747e6dSmrg
10763e747e6dSmrg/**
10773e747e6dSmrg * look for a menu root
10783e747e6dSmrg *
10793e747e6dSmrg *  \return a pointer to the menu root structure
10803e747e6dSmrg *
10813e747e6dSmrg *  \param name the name of the menu root
10823e747e6dSmrg */
10833e747e6dSmrgMenuRoot *
1084c2535118SmrgFindMenuRoot(const char *name)
10853e747e6dSmrg{
10863e747e6dSmrg    MenuRoot *tmp;
10873e747e6dSmrg
1088f66df612Smrg    for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next) {
1089f66df612Smrg        if (strcmp(name, tmp->name) == 0)
1090f66df612Smrg            return (tmp);
10913e747e6dSmrg    }
10923e747e6dSmrg    return NULL;
10933e747e6dSmrg}
10943e747e6dSmrg
1095ffd25bcaSmrgstatic Bool
1096f66df612Smrgbelongs_to_twm_window(TwmWindow *t, Window w)
10973e747e6dSmrg{
1098f66df612Smrg    if (!t)
1099f66df612Smrg        return False;
11003e747e6dSmrg
11013e747e6dSmrg    if (w == t->frame || w == t->title_w || w == t->hilite_w ||
1102f66df612Smrg        w == t->icon_w || w == t->icon_bm_w)
1103f66df612Smrg        return True;
1104ffd25bcaSmrg
11053e747e6dSmrg    if (t && t->titlebuttons) {
11066d8e82c3Smrg        TBWindow *tbw;
11076d8e82c3Smrg        int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1108f66df612Smrg
1109f66df612Smrg        for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
1110f66df612Smrg            if (tbw->window == w)
1111f66df612Smrg                return True;
1112f66df612Smrg        }
11133e747e6dSmrg    }
11143e747e6dSmrg    return False;
11153e747e6dSmrg}
11163e747e6dSmrg
1117c2535118Smrgstatic void
11183e747e6dSmrgresizeFromCenter(Window w, TwmWindow *tmp_win)
11193e747e6dSmrg{
1120f66df612Smrg    int lastx, lasty, bw2;
1121f66df612Smrg    XEvent event;
11226d8e82c3Smrg    int dummy = 0;
11236d8e82c3Smrg    unsigned udummy = 0;
11246d8e82c3Smrg    Window wdummy = None;
1125f66df612Smrg
1126f66df612Smrg    bw2 = tmp_win->frame_bw * 2;
1127f66df612Smrg    AddingW = tmp_win->attr.width + bw2;
1128f66df612Smrg    AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
11296d8e82c3Smrg    XGetGeometry(dpy, w, &wdummy, &origDragX, &origDragY,
1130f66df612Smrg                 (unsigned int *) &DragWidth, (unsigned int *) &DragHeight,
11316d8e82c3Smrg                 &udummy, &udummy);
1132f66df612Smrg    XWarpPointer(dpy, None, w, 0, 0, 0, 0, DragWidth / 2, DragHeight / 2);
11336d8e82c3Smrg    XQueryPointer(dpy, Scr->Root, &wdummy,
11346d8e82c3Smrg                  &wdummy, &dummy, &dummy, &AddingX, &AddingY, &udummy);
1135f66df612Smrg    lastx = -10000;
1136f66df612Smrg    lasty = -10000;
1137f66df612Smrg    MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
1138f66df612Smrg    while (TRUE) {
1139f66df612Smrg        XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, &event);
1140f66df612Smrg
1141f66df612Smrg        if (event.type == MotionNotify) {
1142f66df612Smrg            /* discard any extra motion events before a release */
1143f66df612Smrg            while (XCheckMaskEvent(dpy,
1144f66df612Smrg                                   ButtonMotionMask | ButtonPressMask, &event))
1145f66df612Smrg                if (event.type == ButtonPress)
1146f66df612Smrg                    break;
1147f66df612Smrg        }
1148f66df612Smrg
1149f66df612Smrg        if (event.type == ButtonPress) {
1150f66df612Smrg            MenuEndResize(tmp_win);
1151f66df612Smrg            XMoveResizeWindow(dpy, w, AddingX, AddingY, (unsigned) AddingW,
1152f66df612Smrg                              (unsigned) AddingH);
1153f66df612Smrg            break;
1154f66df612Smrg        }
1155f66df612Smrg
1156f66df612Smrg        /* if (!DispatchEvent ()) continue; */
1157f66df612Smrg
1158f66df612Smrg        if (event.type != MotionNotify) {
1159f66df612Smrg            continue;
1160f66df612Smrg        }
1161f66df612Smrg
1162f66df612Smrg        /*
1163f66df612Smrg         * XXX - if we are going to do a loop, we ought to consider
1164f66df612Smrg         * using multiple GXxor lines so that we don't need to
1165f66df612Smrg         * grab the server.
1166f66df612Smrg         */
11676d8e82c3Smrg        XQueryPointer(dpy, Scr->Root, &wdummy, &wdummy,
11686d8e82c3Smrg                      &dummy, &dummy, &AddingX, &AddingY, &udummy);
1169f66df612Smrg
1170f66df612Smrg        if (lastx != AddingX || lasty != AddingY) {
1171f66df612Smrg            MenuDoResize(AddingX, AddingY, tmp_win);
1172f66df612Smrg
1173f66df612Smrg            lastx = AddingX;
1174f66df612Smrg            lasty = AddingY;
1175f66df612Smrg        }
1176ffd25bcaSmrg
11773e747e6dSmrg    }
1178ffd25bcaSmrg}
11793e747e6dSmrg
11803e747e6dSmrg/** \fn ExecuteFunction
11813e747e6dSmrg * execute a twm root function.
11823e747e6dSmrg *
11833e747e6dSmrg *  \param func     the function to execute
1184ffd25bcaSmrg *  \param action   the menu action to execute
11853e747e6dSmrg *  \param w        the window to execute this function on
11863e747e6dSmrg *  \param tmp_win  the twm window structure
11873e747e6dSmrg *  \param event    the event that caused the function
11883e747e6dSmrg *  \param context  the context in which the button was pressed
11893e747e6dSmrg *  \param pulldown flag indicating execution from pull down menu
11903e747e6dSmrg *
1191ffd25bcaSmrg *  \return TRUE if should continue with remaining actions,
11923e747e6dSmrg *           else FALSE to abort
11933e747e6dSmrg */
11943e747e6dSmrg
1195c2535118Smrgstatic int
1196ffd25bcaSmrgWarpThere(TwmWindow *t)
11973e747e6dSmrg{
11983e747e6dSmrg    if (Scr->WarpUnmapped || t->mapped) {
1199f66df612Smrg        if (!t->mapped)
1200f66df612Smrg            DeIconify(t);
1201f66df612Smrg        if (!Scr->NoRaiseWarp)
1202f66df612Smrg            XRaiseWindow(dpy, t->frame);
1203f66df612Smrg        WarpToWindow(t);
1204ffd25bcaSmrg        return 1;
1205ffd25bcaSmrg    }
12063e747e6dSmrg    return 0;
12073e747e6dSmrg}
12083e747e6dSmrg
12093e747e6dSmrgint
1210c2535118SmrgExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
12113e747e6dSmrg                XEvent *eventp, int context, int pulldown)
12123e747e6dSmrg{
12133e747e6dSmrg    static Time last_time = 0;
12143e747e6dSmrg    char tmp[200];
12153e747e6dSmrg    char *ptr;
12163e747e6dSmrg    char buff[MAX_FILE_SIZE];
12173e747e6dSmrg    int count, fd;
12183e747e6dSmrg    Window rootw;
12193e747e6dSmrg    int origX, origY;
12203e747e6dSmrg    int do_next_action = TRUE;
12213e747e6dSmrg    int moving_icon = FALSE;
12223e747e6dSmrg    Bool fromtitlebar = False;
12236d8e82c3Smrg    unsigned bw = 0;
12246d8e82c3Smrg    int dummy = 0;
12256d8e82c3Smrg    unsigned udummy = 0;
12266d8e82c3Smrg    Window wdummy = None;
12273e747e6dSmrg
12283e747e6dSmrg    RootFunction = 0;
12293e747e6dSmrg    if (Cancel)
1230f66df612Smrg        return TRUE;            /* XXX should this be FALSE? */
12313e747e6dSmrg
1232f66df612Smrg    switch (func) {
12333e747e6dSmrg    case F_UPICONMGR:
12343e747e6dSmrg    case F_LEFTICONMGR:
12353e747e6dSmrg    case F_RIGHTICONMGR:
12363e747e6dSmrg    case F_DOWNICONMGR:
12373e747e6dSmrg    case F_FORWICONMGR:
12383e747e6dSmrg    case F_BACKICONMGR:
12393e747e6dSmrg    case F_NEXTICONMGR:
12403e747e6dSmrg    case F_PREVICONMGR:
12413e747e6dSmrg    case F_NOP:
12423e747e6dSmrg    case F_TITLE:
12433e747e6dSmrg    case F_DELTASTOP:
12443e747e6dSmrg    case F_RAISELOWER:
12453e747e6dSmrg    case F_WARPTOSCREEN:
12463e747e6dSmrg    case F_WARPTO:
12473e747e6dSmrg    case F_WARPRING:
12483e747e6dSmrg    case F_WARPTOICONMGR:
12493e747e6dSmrg    case F_WARPNEXT:
12503e747e6dSmrg    case F_WARPPREV:
12513e747e6dSmrg    case F_COLORMAP:
1252f66df612Smrg        break;
12533e747e6dSmrg    default:
12543e747e6dSmrg        XGrabPointer(dpy, Scr->Root, True,
1255f66df612Smrg                     ButtonPressMask | ButtonReleaseMask,
1256f66df612Smrg                     GrabModeAsync, GrabModeAsync,
1257f66df612Smrg                     Scr->Root, Scr->WaitCursor, CurrentTime);
1258f66df612Smrg        break;
12593e747e6dSmrg    }
12603e747e6dSmrg
1261f66df612Smrg    switch (func) {
12623e747e6dSmrg    case F_NOP:
12633e747e6dSmrg    case F_TITLE:
1264f66df612Smrg        break;
12653e747e6dSmrg
12663e747e6dSmrg    case F_DELTASTOP:
1267f66df612Smrg        if (WindowMoved)
1268f66df612Smrg            do_next_action = FALSE;
1269f66df612Smrg        break;
12703e747e6dSmrg
12713e747e6dSmrg    case F_RESTART:
12723e747e6dSmrg    {
1273f66df612Smrg        XSync(dpy, 0);
1274f66df612Smrg        Reborder(eventp->xbutton.time);
1275f66df612Smrg        XSync(dpy, 0);
1276f66df612Smrg        if (smcConn)
1277f66df612Smrg            SmcCloseConnection(smcConn, 0, NULL);
1278f66df612Smrg        execvp(*Argv, Argv);
1279f66df612Smrg        twmWarning("unable to restart:  %s", *Argv);
1280f66df612Smrg        break;
12813e747e6dSmrg    }
12823e747e6dSmrg
12833e747e6dSmrg    case F_UPICONMGR:
12843e747e6dSmrg    case F_DOWNICONMGR:
12853e747e6dSmrg    case F_LEFTICONMGR:
12863e747e6dSmrg    case F_RIGHTICONMGR:
12873e747e6dSmrg    case F_FORWICONMGR:
12883e747e6dSmrg    case F_BACKICONMGR:
1289f66df612Smrg        MoveIconManager(func);
12903e747e6dSmrg        break;
12913e747e6dSmrg
12923e747e6dSmrg    case F_NEXTICONMGR:
12933e747e6dSmrg    case F_PREVICONMGR:
1294f66df612Smrg        JumpIconManager(func);
12953e747e6dSmrg        break;
12963e747e6dSmrg
12973e747e6dSmrg    case F_SHOWLIST:
1298f66df612Smrg        if (Scr->NoIconManagers)
1299f66df612Smrg            break;
1300f66df612Smrg        DeIconify(Scr->iconmgr.twm_win);
1301f66df612Smrg        XRaiseWindow(dpy, Scr->iconmgr.twm_win->frame);
1302f66df612Smrg        break;
13033e747e6dSmrg
13043e747e6dSmrg    case F_HIDELIST:
1305f66df612Smrg        if (Scr->NoIconManagers)
1306f66df612Smrg            break;
1307f66df612Smrg        HideIconManager();
1308f66df612Smrg        break;
13093e747e6dSmrg
13103e747e6dSmrg    case F_SORTICONMGR:
1311f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1312f66df612Smrg            return TRUE;
13133e747e6dSmrg
1314f66df612Smrg        {
1315f66df612Smrg            int save_sort;
13163e747e6dSmrg
1317f66df612Smrg            save_sort = Scr->SortIconMgr;
1318f66df612Smrg            Scr->SortIconMgr = TRUE;
13193e747e6dSmrg
1320f66df612Smrg            if (context == C_ICONMGR)
1321f66df612Smrg                SortIconManager((IconMgr *) NULL);
1322f66df612Smrg            else if (tmp_win->iconmgr)
1323f66df612Smrg                SortIconManager(tmp_win->iconmgrp);
1324f66df612Smrg            else
1325f66df612Smrg                Bell(XkbBI_Info, 0, tmp_win->w);
13263e747e6dSmrg
1327f66df612Smrg            Scr->SortIconMgr = (short) save_sort;
1328f66df612Smrg        }
1329f66df612Smrg        break;
13303e747e6dSmrg
13313e747e6dSmrg    case F_IDENTIFY:
1332f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1333f66df612Smrg            return TRUE;
13343e747e6dSmrg
1335f66df612Smrg        Identify(tmp_win);
1336f66df612Smrg        break;
13373e747e6dSmrg
13383e747e6dSmrg    case F_VERSION:
1339f66df612Smrg        Identify((TwmWindow *) NULL);
1340f66df612Smrg        break;
13413e747e6dSmrg
13423e747e6dSmrg    case F_AUTORAISE:
1343f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1344f66df612Smrg            return TRUE;
1345f66df612Smrg
1346f66df612Smrg        tmp_win->auto_raise = !tmp_win->auto_raise;
1347f66df612Smrg        if (tmp_win->auto_raise)
1348f66df612Smrg            ++(Scr->NumAutoRaises);
1349f66df612Smrg        else
1350f66df612Smrg            --(Scr->NumAutoRaises);
1351f66df612Smrg        break;
13523e747e6dSmrg
13533e747e6dSmrg    case F_BEEP:
1354f66df612Smrg        Bell(XkbBI_Info, 0, None);
1355f66df612Smrg        break;
13563e747e6dSmrg
13573e747e6dSmrg    case F_POPUP:
1358f66df612Smrg        tmp_win = (TwmWindow *) action;
1359f66df612Smrg        if (Scr->WindowFunction.func != 0) {
1360f66df612Smrg            ExecuteFunction(Scr->WindowFunction.func,
1361f66df612Smrg                            Scr->WindowFunction.item->action,
1362f66df612Smrg                            w, tmp_win, eventp, C_FRAME, FALSE);
1363f66df612Smrg        }
1364f66df612Smrg        else {
1365f66df612Smrg            DeIconify(tmp_win);
1366f66df612Smrg            XRaiseWindow(dpy, tmp_win->frame);
1367f66df612Smrg        }
1368f66df612Smrg        break;
13693e747e6dSmrg
13703e747e6dSmrg    case F_RESIZE:
1371f66df612Smrg        EventHandler[EnterNotify] = HandleUnknown;
1372f66df612Smrg        EventHandler[LeaveNotify] = HandleUnknown;
1373f66df612Smrg        if (DeferExecution(context, func, Scr->MoveCursor))
1374f66df612Smrg            return TRUE;
1375f66df612Smrg
1376f66df612Smrg        PopDownMenu();
1377f66df612Smrg
1378f66df612Smrg        if (pulldown)
1379f66df612Smrg            XWarpPointer(dpy, None, Scr->Root,
1380f66df612Smrg                         0, 0, 0, 0, eventp->xbutton.x_root,
1381f66df612Smrg                         eventp->xbutton.y_root);
1382f66df612Smrg
1383f66df612Smrg        if (w != tmp_win->icon_w) {     /* can't resize icons */
1384f66df612Smrg
1385f66df612Smrg            if ((Context == C_FRAME || Context == C_WINDOW ||
1386f66df612Smrg                 Context == C_TITLE)
1387f66df612Smrg                && fromMenu)
1388f66df612Smrg                resizeFromCenter(w, tmp_win);
1389f66df612Smrg            else {
1390f66df612Smrg                /*
1391f66df612Smrg                 * see if this is being done from the titlebar
1392f66df612Smrg                 */
1393f66df612Smrg                fromtitlebar =
1394f66df612Smrg                    belongs_to_twm_window(tmp_win, eventp->xbutton.window);
1395f66df612Smrg
1396f66df612Smrg                /* Save pointer position so we can tell if it was moved or
1397f66df612Smrg                   not during the resize. */
1398f66df612Smrg                ResizeOrigX = eventp->xbutton.x_root;
1399f66df612Smrg                ResizeOrigY = eventp->xbutton.y_root;
1400f66df612Smrg
1401f66df612Smrg                StartResize(eventp, tmp_win, fromtitlebar);
1402f66df612Smrg
1403f66df612Smrg                do {
1404f66df612Smrg                    XMaskEvent(dpy,
1405f66df612Smrg                               ButtonPressMask | ButtonReleaseMask |
1406f66df612Smrg                               EnterWindowMask | LeaveWindowMask |
1407f66df612Smrg                               ButtonMotionMask, &Event);
1408f66df612Smrg
1409f66df612Smrg                    if (fromtitlebar && Event.type == ButtonPress) {
1410f66df612Smrg                        fromtitlebar = False;
1411f66df612Smrg                        continue;
1412f66df612Smrg                    }
14133e747e6dSmrg
1414f66df612Smrg                    if (Event.type == MotionNotify) {
1415f66df612Smrg                        /* discard any extra motion events before a release */
1416f66df612Smrg                        while
1417f66df612Smrg                            (XCheckMaskEvent
1418f66df612Smrg                             (dpy, ButtonMotionMask | ButtonReleaseMask,
1419f66df612Smrg                              &Event))
1420f66df612Smrg                            if (Event.type == ButtonRelease)
1421f66df612Smrg                                break;
1422f66df612Smrg                    }
1423f66df612Smrg
1424f66df612Smrg                    if (!DispatchEvent())
1425f66df612Smrg                        continue;
1426f66df612Smrg
1427f66df612Smrg                } while (!(Event.type == ButtonRelease || Cancel));
1428f66df612Smrg                return TRUE;
1429f66df612Smrg            }
1430f66df612Smrg        }
1431f66df612Smrg        break;
14323e747e6dSmrg
14333e747e6dSmrg    case F_ZOOM:
14343e747e6dSmrg    case F_HORIZOOM:
14353e747e6dSmrg    case F_FULLZOOM:
14363e747e6dSmrg    case F_LEFTZOOM:
14373e747e6dSmrg    case F_RIGHTZOOM:
14383e747e6dSmrg    case F_TOPZOOM:
14393e747e6dSmrg    case F_BOTTOMZOOM:
1440f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1441f66df612Smrg            return TRUE;
1442f66df612Smrg        fullzoom(tmp_win, func);
1443f66df612Smrg        break;
14443e747e6dSmrg
14453e747e6dSmrg    case F_MOVE:
14463e747e6dSmrg    case F_FORCEMOVE:
1447f66df612Smrg        if (DeferExecution(context, func, Scr->MoveCursor))
1448f66df612Smrg            return TRUE;
1449f66df612Smrg
1450f66df612Smrg        PopDownMenu();
1451f66df612Smrg        rootw = eventp->xbutton.root;
1452f66df612Smrg        MoveFunction = func;
1453f66df612Smrg
1454f66df612Smrg        if (pulldown)
1455f66df612Smrg            XWarpPointer(dpy, None, Scr->Root,
1456f66df612Smrg                         0, 0, 0, 0, eventp->xbutton.x_root,
1457f66df612Smrg                         eventp->xbutton.y_root);
1458f66df612Smrg
1459f66df612Smrg        EventHandler[EnterNotify] = HandleUnknown;
1460f66df612Smrg        EventHandler[LeaveNotify] = HandleUnknown;
1461f66df612Smrg
1462f66df612Smrg        if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
1463f66df612Smrg            XGrabServer(dpy);
1464f66df612Smrg        }
1465f66df612Smrg        XGrabPointer(dpy, eventp->xbutton.root, True, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | PointerMotionMask,       /* PointerMotionHintMask */
1466f66df612Smrg                     GrabModeAsync, GrabModeAsync,
1467f66df612Smrg                     Scr->Root, Scr->MoveCursor, CurrentTime);
1468f66df612Smrg
1469f66df612Smrg        if (context == C_ICON && tmp_win->icon_w) {
1470f66df612Smrg            w = tmp_win->icon_w;
1471f66df612Smrg            DragX = eventp->xbutton.x;
1472f66df612Smrg            DragY = eventp->xbutton.y;
1473f66df612Smrg            moving_icon = TRUE;
1474f66df612Smrg        }
1475f66df612Smrg
1476f66df612Smrg        else if (w != tmp_win->icon_w) {
1477f66df612Smrg            XTranslateCoordinates(dpy, w, tmp_win->frame,
1478f66df612Smrg                                  eventp->xbutton.x,
1479f66df612Smrg                                  eventp->xbutton.y,
14806d8e82c3Smrg                                  &DragX, &DragY, &wdummy);
1481f66df612Smrg
1482f66df612Smrg            w = tmp_win->frame;
1483f66df612Smrg        }
1484f66df612Smrg
1485f66df612Smrg        DragWindow = None;
1486f66df612Smrg
14876d8e82c3Smrg        XGetGeometry(dpy, w, &wdummy, &origDragX, &origDragY,
1488f66df612Smrg                     (unsigned int *) &DragWidth, (unsigned int *) &DragHeight,
14896d8e82c3Smrg                     &bw, &udummy);
1490f66df612Smrg
1491f66df612Smrg        origX = eventp->xbutton.x_root;
1492f66df612Smrg        origY = eventp->xbutton.y_root;
1493f66df612Smrg        CurrentDragX = origDragX;
1494f66df612Smrg        CurrentDragY = origDragY;
1495f66df612Smrg
1496f66df612Smrg        /*
1497f66df612Smrg         * only do the constrained move if timer is set; need to check it
1498f66df612Smrg         * in case of stupid or wicked fast servers
1499f66df612Smrg         */
1500f66df612Smrg        if (ConstrainedMoveTime &&
1501f66df612Smrg            (eventp->xbutton.time - last_time) < (Time) ConstrainedMoveTime) {
1502f66df612Smrg            int width, height;
1503f66df612Smrg
1504f66df612Smrg            ConstMove = TRUE;
1505f66df612Smrg            ConstMoveDir = MOVE_NONE;
1506f66df612Smrg            ConstMoveX =
1507f66df612Smrg                (int) ((unsigned) eventp->xbutton.x_root - (unsigned) DragX -
15086d8e82c3Smrg                       bw);
1509f66df612Smrg            ConstMoveY =
1510f66df612Smrg                (int) ((unsigned) eventp->xbutton.y_root - (unsigned) DragY -
15116d8e82c3Smrg                       bw);
15126d8e82c3Smrg            width = (int) ((unsigned) DragWidth + 2 * bw);
15136d8e82c3Smrg            height = (int) ((unsigned) DragHeight + 2 * bw);
1514f66df612Smrg            ConstMoveXL = ConstMoveX + width / 3;
1515f66df612Smrg            ConstMoveXR = ConstMoveX + 2 * (width / 3);
1516f66df612Smrg            ConstMoveYT = ConstMoveY + height / 3;
1517f66df612Smrg            ConstMoveYB = ConstMoveY + 2 * (height / 3);
1518f66df612Smrg
1519f66df612Smrg            XWarpPointer(dpy, None, w,
1520f66df612Smrg                         0, 0, 0, 0, DragWidth / 2, DragHeight / 2);
1521f66df612Smrg
15226d8e82c3Smrg            XQueryPointer(dpy, w, &wdummy, &wdummy,
15236d8e82c3Smrg                          &dummy, &dummy, &DragX, &DragY, &udummy);
1524f66df612Smrg        }
1525f66df612Smrg        last_time = eventp->xbutton.time;
1526f66df612Smrg
1527f66df612Smrg        if (!Scr->OpaqueMove) {
1528f66df612Smrg            InstallRootColormap();
1529f66df612Smrg            if (!Scr->MoveDelta) {
1530f66df612Smrg                /*
1531f66df612Smrg                 * Draw initial outline.  This was previously done the
1532f66df612Smrg                 * first time though the outer loop by dropping out of
1533f66df612Smrg                 * the XCheckMaskEvent inner loop down to one of the
1534f66df612Smrg                 * MoveOutline's below.
1535f66df612Smrg                 */
1536f66df612Smrg                MoveOutline(rootw,
15376d8e82c3Smrg                            (int) ((unsigned) origDragX - bw),
15386d8e82c3Smrg                            (int) ((unsigned) origDragY - bw),
15396d8e82c3Smrg                            (int) ((unsigned) DragWidth + 2 * bw),
15406d8e82c3Smrg                            (int) ((unsigned) DragHeight + 2 * bw),
1541f66df612Smrg                            tmp_win->frame_bw,
1542f66df612Smrg                            moving_icon ? 0 : tmp_win->title_height);
1543f66df612Smrg                /*
1544f66df612Smrg                 * This next line causes HandleReleaseNotify to call
1545f66df612Smrg                 * XRaiseWindow().  This is solely to preserve the
1546f66df612Smrg                 * previous behaviour that raises a window being moved
1547f66df612Smrg                 * on button release even if you never actually moved
1548f66df612Smrg                 * any distance (unless you move less than MoveDelta or
1549f66df612Smrg                 * NoRaiseMove is set or OpaqueMove is set).
1550f66df612Smrg                 */
1551f66df612Smrg                DragWindow = w;
1552f66df612Smrg            }
1553f66df612Smrg        }
1554f66df612Smrg
1555f66df612Smrg        /*
1556f66df612Smrg         * see if this is being done from the titlebar
1557f66df612Smrg         */
1558f66df612Smrg        fromtitlebar = belongs_to_twm_window(tmp_win, eventp->xbutton.window);
1559f66df612Smrg
1560f66df612Smrg        if (menuFromFrameOrWindowOrTitlebar) {
1561f66df612Smrg            /* warp the pointer to the middle of the window */
1562f66df612Smrg            XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
1563f66df612Smrg                         origDragX + DragWidth / 2, origDragY + DragHeight / 2);
1564f66df612Smrg            XFlush(dpy);
1565f66df612Smrg        }
1566f66df612Smrg
1567f66df612Smrg        while (TRUE) {
1568f66df612Smrg            long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
1569f66df612Smrg                ButtonPress : ButtonRelease;
1570f66df612Smrg            long movementMask = menuFromFrameOrWindowOrTitlebar ?
1571f66df612Smrg                PointerMotionMask : ButtonMotionMask;
1572f66df612Smrg
1573f66df612Smrg            /* block until there is an interesting event */
1574f66df612Smrg            XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
1575f66df612Smrg                       EnterWindowMask | LeaveWindowMask |
1576f66df612Smrg                       ExposureMask | movementMask |
1577f66df612Smrg                       VisibilityChangeMask, &Event);
1578f66df612Smrg
1579f66df612Smrg            /* throw away enter and leave events until release */
1580f66df612Smrg            if (Event.xany.type == EnterNotify ||
1581f66df612Smrg                Event.xany.type == LeaveNotify)
1582f66df612Smrg                continue;
1583f66df612Smrg
1584f66df612Smrg            if (Event.type == MotionNotify) {
1585f66df612Smrg                /* discard any extra motion events before a logical release */
1586f66df612Smrg                while (XCheckMaskEvent(dpy,
1587f66df612Smrg                                       movementMask | releaseEvent, &Event))
1588f66df612Smrg                    if (Event.type == releaseEvent)
1589f66df612Smrg                        break;
1590f66df612Smrg            }
1591f66df612Smrg
1592f66df612Smrg            /* test to see if we have a second button press to abort move */
1593f66df612Smrg            if (!menuFromFrameOrWindowOrTitlebar && !MovedFromKeyPress) {
1594f66df612Smrg                if (Event.type == ButtonPress && DragWindow != None) {
1595f66df612Smrg                    if (Scr->OpaqueMove)
1596f66df612Smrg                        XMoveWindow(dpy, DragWindow, origDragX, origDragY);
1597f66df612Smrg                    else
1598f66df612Smrg                        MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
1599f66df612Smrg                    DragWindow = None;
16003e747e6dSmrg                }
1601f66df612Smrg            }
1602f66df612Smrg            if (fromtitlebar && Event.type == ButtonPress) {
1603f66df612Smrg                fromtitlebar = False;
1604f66df612Smrg                CurrentDragX = origX = Event.xbutton.x_root;
1605f66df612Smrg                CurrentDragY = origY = Event.xbutton.y_root;
1606f66df612Smrg
1607f66df612Smrg                XTranslateCoordinates(dpy, rootw, tmp_win->frame,
16086d8e82c3Smrg                                      origX, origY, &DragX, &DragY, &wdummy);
1609f66df612Smrg                continue;
1610f66df612Smrg            }
16113e747e6dSmrg
1612f66df612Smrg            if (!DispatchEvent2())
1613f66df612Smrg                continue;
1614f66df612Smrg
1615f66df612Smrg            if (Cancel) {
1616f66df612Smrg                WindowMoved = FALSE;
1617f66df612Smrg                if (!Scr->OpaqueMove)
1618f66df612Smrg                    UninstallRootColormap();
1619f66df612Smrg                return TRUE;    /* XXX should this be FALSE? */
1620f66df612Smrg            }
1621f66df612Smrg            if (Event.type == releaseEvent) {
1622f66df612Smrg                MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
1623f66df612Smrg                if (moving_icon &&
1624f66df612Smrg                    ((CurrentDragX != origDragX || CurrentDragY != origDragY)))
1625f66df612Smrg                    tmp_win->icon_moved = TRUE;
1626f66df612Smrg                if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar)
1627f66df612Smrg                    XMoveWindow(dpy, DragWindow,
1628f66df612Smrg                                Event.xbutton.x_root - DragWidth / 2,
1629f66df612Smrg                                Event.xbutton.y_root - DragHeight / 2);
1630f66df612Smrg                break;
1631f66df612Smrg            }
1632f66df612Smrg
1633f66df612Smrg            /* something left to do only if the pointer moved */
1634f66df612Smrg            if (Event.type != MotionNotify)
1635f66df612Smrg                continue;
1636f66df612Smrg
16376d8e82c3Smrg            XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &wdummy,
1638f66df612Smrg                          &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
16396d8e82c3Smrg                          &dummy, &dummy, &udummy);
1640f66df612Smrg
1641f66df612Smrg            if (DragWindow == None &&
1642f66df612Smrg                abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
1643f66df612Smrg                abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
1644f66df612Smrg                continue;
1645f66df612Smrg
1646f66df612Smrg            WindowMoved = TRUE;
1647f66df612Smrg            DragWindow = w;
1648f66df612Smrg
1649f66df612Smrg            if (!Scr->NoRaiseMove && Scr->OpaqueMove)   /* can't restore... */
1650f66df612Smrg                XRaiseWindow(dpy, DragWindow);
1651f66df612Smrg
1652f66df612Smrg            if (ConstMove) {
1653f66df612Smrg                switch (ConstMoveDir) {
1654f66df612Smrg                case MOVE_NONE:
1655f66df612Smrg                    if (eventp->xmotion.x_root < ConstMoveXL ||
1656f66df612Smrg                        eventp->xmotion.x_root > ConstMoveXR)
1657f66df612Smrg                        ConstMoveDir = MOVE_HORIZ;
1658f66df612Smrg
1659f66df612Smrg                    if (eventp->xmotion.y_root < ConstMoveYT ||
1660f66df612Smrg                        eventp->xmotion.y_root > ConstMoveYB)
1661f66df612Smrg                        ConstMoveDir = MOVE_VERT;
1662f66df612Smrg
16636d8e82c3Smrg                    XQueryPointer(dpy, DragWindow, &wdummy, &wdummy,
16646d8e82c3Smrg                                  &dummy, &dummy, &DragX, &DragY, &udummy);
1665f66df612Smrg                    break;
1666f66df612Smrg
1667f66df612Smrg                case MOVE_VERT:
1668f66df612Smrg                    ConstMoveY =
1669f66df612Smrg                        (int) ((unsigned) eventp->xmotion.y_root -
16706d8e82c3Smrg                               (unsigned) DragY - bw);
1671f66df612Smrg                    break;
1672f66df612Smrg
1673f66df612Smrg                case MOVE_HORIZ:
1674f66df612Smrg                    ConstMoveX =
1675f66df612Smrg                        (int) ((unsigned) eventp->xmotion.x_root -
16766d8e82c3Smrg                               (unsigned) DragX - bw);
1677f66df612Smrg                    break;
1678f66df612Smrg                }
16793e747e6dSmrg
1680f66df612Smrg                if (ConstMoveDir != MOVE_NONE) {
1681f66df612Smrg                    int xl, yt, w2, h;
1682f66df612Smrg
1683f66df612Smrg                    xl = ConstMoveX;
1684f66df612Smrg                    yt = ConstMoveY;
16856d8e82c3Smrg                    w2 = (int) ((unsigned) DragWidth + 2 * bw);
16866d8e82c3Smrg                    h = (int) ((unsigned) DragHeight + 2 * bw);
1687f66df612Smrg
1688f66df612Smrg                    if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
1689f66df612Smrg                        int xr = xl + w2;
1690f66df612Smrg                        int yb = yt + h;
1691f66df612Smrg
1692f66df612Smrg                        if (xl < 0)
1693f66df612Smrg                            xl = 0;
1694f66df612Smrg                        if (xr > Scr->MyDisplayWidth)
1695f66df612Smrg                            xl = Scr->MyDisplayWidth - w2;
1696f66df612Smrg
1697f66df612Smrg                        if (yt < 0)
1698f66df612Smrg                            yt = 0;
1699f66df612Smrg                        if (yb > Scr->MyDisplayHeight)
1700f66df612Smrg                            yt = Scr->MyDisplayHeight - h;
1701f66df612Smrg                    }
1702f66df612Smrg                    CurrentDragX = xl;
1703f66df612Smrg                    CurrentDragY = yt;
1704f66df612Smrg                    if (Scr->OpaqueMove)
1705f66df612Smrg                        XMoveWindow(dpy, DragWindow, xl, yt);
1706f66df612Smrg                    else
1707f66df612Smrg                        MoveOutline(eventp->xmotion.root, xl, yt, w2, h,
1708f66df612Smrg                                    tmp_win->frame_bw,
1709f66df612Smrg                                    moving_icon ? 0 : tmp_win->title_height);
1710f66df612Smrg                }
1711f66df612Smrg            }
1712f66df612Smrg            else if (DragWindow != None) {
1713f66df612Smrg                int xl, yt, w2, h;
1714f66df612Smrg
1715f66df612Smrg                if (!menuFromFrameOrWindowOrTitlebar) {
1716f66df612Smrg                    xl = (int) ((unsigned) eventp->xmotion.x_root -
17176d8e82c3Smrg                                (unsigned) DragX - bw);
1718f66df612Smrg                    yt = (int) ((unsigned) eventp->xmotion.y_root -
17196d8e82c3Smrg                                (unsigned) DragY - bw);
1720f66df612Smrg                }
1721f66df612Smrg                else {
1722f66df612Smrg                    xl = (int) (eventp->xmotion.x_root - (DragWidth / 2));
1723f66df612Smrg                    yt = (int) (eventp->xmotion.y_root - (DragHeight / 2));
1724f66df612Smrg                }
17256d8e82c3Smrg                w2 = (int) ((unsigned) DragWidth + 2 * bw);
17266d8e82c3Smrg                h = (int) ((unsigned) DragHeight + 2 * bw);
1727f66df612Smrg
1728f66df612Smrg                if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
1729f66df612Smrg                    int xr = xl + w2;
1730f66df612Smrg                    int yb = yt + h;
1731f66df612Smrg
1732f66df612Smrg                    if (xl < 0)
1733f66df612Smrg                        xl = 0;
1734f66df612Smrg                    if (xr > Scr->MyDisplayWidth)
1735f66df612Smrg                        xl = Scr->MyDisplayWidth - w2;
1736f66df612Smrg
1737f66df612Smrg                    if (yt < 0)
1738f66df612Smrg                        yt = 0;
1739f66df612Smrg                    if (yb > Scr->MyDisplayHeight)
1740f66df612Smrg                        yt = Scr->MyDisplayHeight - h;
1741f66df612Smrg                }
1742f66df612Smrg
1743f66df612Smrg                CurrentDragX = xl;
1744f66df612Smrg                CurrentDragY = yt;
1745f66df612Smrg                if (Scr->OpaqueMove)
1746f66df612Smrg                    XMoveWindow(dpy, DragWindow, xl, yt);
1747f66df612Smrg                else
1748f66df612Smrg                    MoveOutline(eventp->xmotion.root, xl, yt, w2, h,
1749f66df612Smrg                                tmp_win->frame_bw,
1750f66df612Smrg                                moving_icon ? 0 : tmp_win->title_height);
1751f66df612Smrg            }
1752f66df612Smrg
1753f66df612Smrg        }
1754f66df612Smrg        MovedFromKeyPress = False;
1755f66df612Smrg
1756f66df612Smrg        if (!Scr->OpaqueMove && DragWindow == None)
1757f66df612Smrg            UninstallRootColormap();
17583e747e6dSmrg
17593e747e6dSmrg        break;
17603e747e6dSmrg
17613e747e6dSmrg    case F_FUNCTION:
1762f66df612Smrg    {
1763f66df612Smrg        MenuRoot *mroot;
1764f66df612Smrg        MenuItem *mitem;
1765f66df612Smrg
1766f66df612Smrg        if ((mroot = FindMenuRoot(action)) == NULL) {
1767f66df612Smrg            twmWarning("couldn't find function \"%s\"", action);
1768f66df612Smrg            return TRUE;
1769f66df612Smrg        }
1770f66df612Smrg
1771f66df612Smrg        if (NeedToDefer(mroot) &&
1772f66df612Smrg            DeferExecution(context, func, Scr->SelectCursor))
1773f66df612Smrg            return TRUE;
1774f66df612Smrg        else {
1775f66df612Smrg            for (mitem = mroot->first; mitem != NULL; mitem = mitem->next) {
1776f66df612Smrg                if (!ExecuteFunction(mitem->func, mitem->action, w,
1777f66df612Smrg                                     tmp_win, eventp, context, pulldown))
1778f66df612Smrg                    break;
1779f66df612Smrg            }
1780f66df612Smrg        }
1781f66df612Smrg    }
1782f66df612Smrg        break;
17833e747e6dSmrg
17843e747e6dSmrg    case F_DEICONIFY:
17853e747e6dSmrg    case F_ICONIFY:
1786f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1787f66df612Smrg            return TRUE;
1788f66df612Smrg
1789f66df612Smrg        if (tmp_win->icon) {
1790f66df612Smrg            DeIconify(tmp_win);
1791f66df612Smrg        }
1792f66df612Smrg        else if (func == F_ICONIFY) {
1793f66df612Smrg            Iconify(tmp_win, eventp->xbutton.x_root - 5,
1794f66df612Smrg                    eventp->xbutton.y_root - 5);
1795f66df612Smrg        }
1796f66df612Smrg        break;
17973e747e6dSmrg
17983e747e6dSmrg    case F_RAISELOWER:
1799f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1800f66df612Smrg            return TRUE;
18013e747e6dSmrg
1802f66df612Smrg        if (!WindowMoved) {
1803f66df612Smrg            XWindowChanges xwc;
18043e747e6dSmrg
1805f66df612Smrg            xwc.stack_mode = Opposite;
1806f66df612Smrg            if (w != tmp_win->icon_w)
1807f66df612Smrg                w = tmp_win->frame;
1808f66df612Smrg            XConfigureWindow(dpy, w, CWStackMode, &xwc);
1809f66df612Smrg        }
1810f66df612Smrg        break;
1811ffd25bcaSmrg
18123e747e6dSmrg    case F_RAISE:
1813f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1814f66df612Smrg            return TRUE;
18153e747e6dSmrg
1816f66df612Smrg        /* check to make sure raise is not from the WindowFunction */
1817f66df612Smrg        if (w == tmp_win->icon_w && Context != C_ROOT)
1818f66df612Smrg            XRaiseWindow(dpy, tmp_win->icon_w);
1819f66df612Smrg        else
1820f66df612Smrg            XRaiseWindow(dpy, tmp_win->frame);
18213e747e6dSmrg
1822f66df612Smrg        break;
18233e747e6dSmrg
18243e747e6dSmrg    case F_LOWER:
1825f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1826f66df612Smrg            return TRUE;
18273e747e6dSmrg
1828f66df612Smrg        if (w == tmp_win->icon_w)
1829f66df612Smrg            XLowerWindow(dpy, tmp_win->icon_w);
1830f66df612Smrg        else
1831f66df612Smrg            XLowerWindow(dpy, tmp_win->frame);
18323e747e6dSmrg
1833f66df612Smrg        break;
18343e747e6dSmrg
18353e747e6dSmrg    case F_FOCUS:
1836f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1837f66df612Smrg            return TRUE;
1838f66df612Smrg
1839f66df612Smrg        if (tmp_win->icon == FALSE) {
1840f66df612Smrg            if (!Scr->FocusRoot && Scr->Focus == tmp_win) {
1841f66df612Smrg                FocusOnRoot();
1842f66df612Smrg            }
1843f66df612Smrg            else {
1844f66df612Smrg                if (Scr->Focus != NULL) {
1845f66df612Smrg                    SetBorder(Scr->Focus, False);
1846f66df612Smrg                    if (Scr->Focus->hilite_w)
1847f66df612Smrg                        XUnmapWindow(dpy, Scr->Focus->hilite_w);
1848f66df612Smrg                }
1849f66df612Smrg
1850f66df612Smrg                InstallWindowColormaps(0, tmp_win);
1851f66df612Smrg                if (tmp_win->hilite_w)
1852f66df612Smrg                    XMapWindow(dpy, tmp_win->hilite_w);
1853f66df612Smrg                SetBorder(tmp_win, True);
1854f66df612Smrg                if (!tmp_win->wmhints || tmp_win->wmhints->input)
1855f66df612Smrg                    SetFocus(tmp_win, eventp->xbutton.time);
1856f66df612Smrg                Scr->FocusRoot = FALSE;
1857f66df612Smrg                Scr->Focus = tmp_win;
1858f66df612Smrg            }
1859f66df612Smrg        }
1860f66df612Smrg        break;
18613e747e6dSmrg
18623e747e6dSmrg    case F_DESTROY:
1863f66df612Smrg        if (DeferExecution(context, func, Scr->DestroyCursor))
1864f66df612Smrg            return TRUE;
18653e747e6dSmrg
1866f66df612Smrg        if (tmp_win->iconmgr)
1867f66df612Smrg            Bell(XkbBI_MinorError, 0, tmp_win->w);
1868f66df612Smrg        else
1869f66df612Smrg            XKillClient(dpy, tmp_win->w);
1870f66df612Smrg        break;
18713e747e6dSmrg
18723e747e6dSmrg    case F_DELETE:
1873f66df612Smrg        if (DeferExecution(context, func, Scr->DestroyCursor))
1874f66df612Smrg            return TRUE;
1875f66df612Smrg
1876f66df612Smrg        if (tmp_win->iconmgr)   /* don't send ourself a message */
1877f66df612Smrg            HideIconManager();
1878f66df612Smrg        else if (tmp_win->protocols & DoesWmDeleteWindow)
1879f66df612Smrg            SendDeleteWindowMessage(tmp_win, LastTimestamp());
1880f66df612Smrg        else
1881f66df612Smrg            Bell(XkbBI_MinorError, 0, tmp_win->w);
1882f66df612Smrg        break;
18833e747e6dSmrg
18843e747e6dSmrg    case F_SAVEYOURSELF:
1885f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
1886f66df612Smrg            return TRUE;
18873e747e6dSmrg
1888f66df612Smrg        if (tmp_win->protocols & DoesWmSaveYourself)
1889f66df612Smrg            SendSaveYourselfMessage(tmp_win, LastTimestamp());
1890f66df612Smrg        else
1891f66df612Smrg            Bell(XkbBI_MinorError, 0, tmp_win->w);
1892f66df612Smrg        break;
18933e747e6dSmrg
18943e747e6dSmrg    case F_CIRCLEUP:
1895f66df612Smrg        XCirculateSubwindowsUp(dpy, Scr->Root);
1896f66df612Smrg        break;
18973e747e6dSmrg
18983e747e6dSmrg    case F_CIRCLEDOWN:
1899f66df612Smrg        XCirculateSubwindowsDown(dpy, Scr->Root);
1900f66df612Smrg        break;
19013e747e6dSmrg
19023e747e6dSmrg    case F_EXEC:
1903f66df612Smrg        PopDownMenu();
1904f66df612Smrg        if (!Scr->NoGrabServer) {
1905f66df612Smrg            XUngrabServer(dpy);
1906f66df612Smrg            XSync(dpy, 0);
1907f66df612Smrg        }
1908f66df612Smrg        Execute(action);
1909f66df612Smrg        break;
19103e747e6dSmrg
19113e747e6dSmrg    case F_UNFOCUS:
1912f66df612Smrg        FocusOnRoot();
1913f66df612Smrg        break;
19143e747e6dSmrg
19153e747e6dSmrg    case F_CUT:
1916f66df612Smrg        strcpy(tmp, action);
1917f66df612Smrg        strcat(tmp, "\n");
1918f66df612Smrg        XStoreBytes(dpy, tmp, (int) strlen(tmp));
1919f66df612Smrg        break;
19203e747e6dSmrg
19213e747e6dSmrg    case F_CUTFILE:
1922f66df612Smrg        ptr = XFetchBytes(dpy, &count);
1923f66df612Smrg        if (ptr) {
1924f66df612Smrg            if (sscanf(ptr, "%s", tmp) == 1) {
1925f66df612Smrg                XFree(ptr);
1926f66df612Smrg                ptr = ExpandFilename(tmp);
1927f66df612Smrg                if (ptr) {
1928f66df612Smrg                    fd = open(ptr, O_RDONLY);
1929f66df612Smrg                    if (fd >= 0) {
1930f66df612Smrg                        count = (int) read(fd, buff, MAX_FILE_SIZE - 1);
1931f66df612Smrg                        if (count > 0)
1932f66df612Smrg                            XStoreBytes(dpy, buff, count);
1933f66df612Smrg                        close(fd);
1934f66df612Smrg                    }
1935f66df612Smrg                    else {
1936f66df612Smrg                        twmWarning("unable to open cut file \"%s\"", tmp);
1937f66df612Smrg                    }
1938f66df612Smrg                    free(ptr);
1939f66df612Smrg                }
1940f66df612Smrg            }
1941f66df612Smrg            else {
1942f66df612Smrg                XFree(ptr);
1943f66df612Smrg            }
1944f66df612Smrg        }
1945f66df612Smrg        else {
1946f66df612Smrg            twmWarning("cut buffer is empty");
1947f66df612Smrg        }
1948f66df612Smrg        break;
19493e747e6dSmrg
19503e747e6dSmrg    case F_WARPTOSCREEN:
1951f66df612Smrg    {
1952f66df612Smrg        if (strcmp(action, WARPSCREEN_NEXT) == 0) {
1953f66df612Smrg            WarpToScreen(Scr->screen + 1, 1);
1954f66df612Smrg        }
1955f66df612Smrg        else if (strcmp(action, WARPSCREEN_PREV) == 0) {
1956f66df612Smrg            WarpToScreen(Scr->screen - 1, -1);
1957f66df612Smrg        }
1958f66df612Smrg        else if (strcmp(action, WARPSCREEN_BACK) == 0) {
1959f66df612Smrg            WarpToScreen(PreviousScreen, 0);
1960f66df612Smrg        }
1961f66df612Smrg        else {
1962f66df612Smrg            WarpToScreen(atoi(action), 0);
1963f66df612Smrg        }
1964f66df612Smrg    }
1965f66df612Smrg        break;
19663e747e6dSmrg
19673e747e6dSmrg    case F_COLORMAP:
1968f66df612Smrg    {
1969f66df612Smrg        if (strcmp(action, COLORMAP_NEXT) == 0) {
1970f66df612Smrg            BumpWindowColormap(tmp_win, 1);
1971f66df612Smrg        }
1972f66df612Smrg        else if (strcmp(action, COLORMAP_PREV) == 0) {
1973f66df612Smrg            BumpWindowColormap(tmp_win, -1);
1974f66df612Smrg        }
1975f66df612Smrg        else {
1976f66df612Smrg            BumpWindowColormap(tmp_win, 0);
1977f66df612Smrg        }
1978f66df612Smrg    }
1979f66df612Smrg        break;
19803e747e6dSmrg
19813e747e6dSmrg    case F_WARPPREV:
19823e747e6dSmrg    case F_WARPNEXT:
1983f66df612Smrg    {
19846d8e82c3Smrg        TwmWindow *t;
1985f66df612Smrg        TwmWindow *of, *l, *n;
1986f66df612Smrg        int c = 0;
19873e747e6dSmrg
19883e747e6dSmrg#define wseq(w) (func == F_WARPNEXT ? (w)->next : (w)->prev)
19893e747e6dSmrg#define nwin(w) ((w) && (n=wseq(w)) != NULL && n != &Scr->TwmRoot ? n : l)
19903e747e6dSmrg#define bwin(w) (!(w)||(w)->iconmgr||(w)==of||!(Scr->WarpUnmapped||(w)->mapped))
19913e747e6dSmrg
1992f66df612Smrg        of = (Scr->Focus ? Scr->Focus : &Scr->TwmRoot);
19933e747e6dSmrg
1994f66df612Smrg        for (t = Scr->TwmRoot.next; t; t = t->next)
1995f66df612Smrg            if (!bwin(t))
1996f66df612Smrg                break;
1997f66df612Smrg        if (!t)
1998f66df612Smrg            break;              /* no windows we can use */
19993e747e6dSmrg
2000f66df612Smrg        if (func == F_WARPPREV)
2001f66df612Smrg            for (l = of; l->next; l = l->next);
2002f66df612Smrg        else
2003f66df612Smrg            l = Scr->TwmRoot.next;
20043e747e6dSmrg
2005f66df612Smrg        for (t = of; bwin(t) && c < 2; t = nwin(t))
2006f66df612Smrg            if (t == of)
2007f66df612Smrg                c++;
20083e747e6dSmrg
2009f66df612Smrg        if (bwin(t) || c >= 2) {
2010f66df612Smrg            Bell(XkbBI_MinorError, 0, None);
2011f66df612Smrg        }
2012f66df612Smrg        else {
2013f66df612Smrg            static TwmWindow *savedwarp = NULL;
2014f66df612Smrg
2015f66df612Smrg            if (of && of == savedwarp) {
2016f66df612Smrg                Iconify(of, 0, 0);
2017f66df612Smrg                savedwarp = NULL;
2018f66df612Smrg            }
2019f66df612Smrg            if (!t->mapped)
2020f66df612Smrg                savedwarp = t;
2021f66df612Smrg            else
2022f66df612Smrg                savedwarp = NULL;
2023f66df612Smrg            WarpThere(t);
2024f66df612Smrg        }
2025f66df612Smrg        break;
2026f66df612Smrg    }
20273e747e6dSmrg
20283e747e6dSmrg    case F_WARPTO:
2029f66df612Smrg    {
20306d8e82c3Smrg        TwmWindow *t;
2031f66df612Smrg        int len;
2032f66df612Smrg
2033f66df612Smrg        len = (int) strlen(action);
2034f66df612Smrg
2035f66df612Smrg        for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2036f66df612Smrg            if (!strncmp(action, t->name, (size_t) len))
2037f66df612Smrg                if (WarpThere(t))
2038f66df612Smrg                    break;
2039f66df612Smrg        }
2040f66df612Smrg        if (!t) {
2041f66df612Smrg            for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
20426d8e82c3Smrg                if (!strncmp(action, t->xclass.res_name, (size_t) len))
2043f66df612Smrg                    if (WarpThere(t))
2044f66df612Smrg                        break;
2045f66df612Smrg            }
2046f66df612Smrg            if (!t) {
2047f66df612Smrg                for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
20486d8e82c3Smrg                    if (!strncmp(action, t->xclass.res_class, (size_t) len))
2049f66df612Smrg                        if (WarpThere(t))
2050f66df612Smrg                            break;
2051f66df612Smrg                }
2052f66df612Smrg            }
2053f66df612Smrg        }
2054f66df612Smrg
2055f66df612Smrg        if (!t)
2056f66df612Smrg            Bell(XkbBI_MinorError, 0, None);
2057f66df612Smrg    }
2058f66df612Smrg        break;
20593e747e6dSmrg
20603e747e6dSmrg    case F_WARPTOICONMGR:
2061f66df612Smrg    {
2062f66df612Smrg        TwmWindow *t;
2063f66df612Smrg        int len;
2064f66df612Smrg        Window raisewin = None, iconwin = None;
2065f66df612Smrg
2066f66df612Smrg        len = (int) strlen(action);
2067f66df612Smrg        if (len == 0) {
2068f66df612Smrg            if (tmp_win && tmp_win->list) {
2069f66df612Smrg                raisewin = tmp_win->list->iconmgr->twm_win->frame;
2070f66df612Smrg                iconwin = tmp_win->list->icon;
2071f66df612Smrg            }
2072f66df612Smrg            else if (Scr->iconmgr.active) {
2073f66df612Smrg                raisewin = Scr->iconmgr.twm_win->frame;
2074f66df612Smrg                iconwin = Scr->iconmgr.active->w;
2075f66df612Smrg            }
2076f66df612Smrg        }
2077f66df612Smrg        else {
2078f66df612Smrg            for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2079f66df612Smrg                if (strncmp(action, t->icon_name, (size_t) len) == 0) {
2080f66df612Smrg                    if (t->list && t->list->iconmgr->twm_win->mapped) {
2081f66df612Smrg                        raisewin = t->list->iconmgr->twm_win->frame;
2082f66df612Smrg                        iconwin = t->list->icon;
2083f66df612Smrg                        break;
2084f66df612Smrg                    }
2085f66df612Smrg                }
2086f66df612Smrg            }
2087f66df612Smrg        }
2088f66df612Smrg
2089f66df612Smrg        if (raisewin) {
2090f66df612Smrg            XRaiseWindow(dpy, raisewin);
2091f66df612Smrg            XWarpPointer(dpy, None, iconwin, 0, 0, 0, 0, 5, 5);
2092f66df612Smrg        }
2093f66df612Smrg        else {
2094f66df612Smrg            Bell(XkbBI_MinorError, 0, None);
2095f66df612Smrg        }
2096f66df612Smrg    }
2097f66df612Smrg        break;
2098ffd25bcaSmrg
20993e747e6dSmrg    case F_WARPRING:
2100f66df612Smrg        switch (action[0]) {
2101f66df612Smrg        case 'n':
2102f66df612Smrg            WarpAlongRing(&eventp->xbutton, True);
2103f66df612Smrg            break;
2104f66df612Smrg        case 'p':
2105f66df612Smrg            WarpAlongRing(&eventp->xbutton, False);
2106f66df612Smrg            break;
2107f66df612Smrg        default:
2108f66df612Smrg            Bell(XkbBI_MinorError, 0, None);
2109f66df612Smrg            break;
2110f66df612Smrg        }
2111f66df612Smrg        break;
21123e747e6dSmrg
21133e747e6dSmrg    case F_FILE:
2114f66df612Smrg        ptr = ExpandFilename(action);
2115f66df612Smrg        if (ptr) {
2116f66df612Smrg            fd = open(ptr, O_RDONLY);
2117f66df612Smrg            if (fd >= 0) {
2118f66df612Smrg                count = (int) read(fd, buff, MAX_FILE_SIZE - 1);
2119f66df612Smrg                if (count > 0)
2120f66df612Smrg                    XStoreBytes(dpy, buff, count);
2121f66df612Smrg
2122f66df612Smrg                close(fd);
2123f66df612Smrg            }
2124f66df612Smrg            else {
2125f66df612Smrg                twmWarning("unable to open file \"%s\"", ptr);
2126f66df612Smrg            }
2127f66df612Smrg            free(ptr);
2128f66df612Smrg        }
2129f66df612Smrg        else {
2130f66df612Smrg            twmWarning("error expanding filename");
2131f66df612Smrg        }
2132f66df612Smrg        break;
21333e747e6dSmrg
21343e747e6dSmrg    case F_REFRESH:
2135f66df612Smrg    {
2136f66df612Smrg        XSetWindowAttributes attributes;
2137f66df612Smrg        unsigned long valuemask;
2138f66df612Smrg
2139f66df612Smrg        valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
2140f66df612Smrg        attributes.background_pixel = Scr->Black;
2141f66df612Smrg        attributes.backing_store = NotUseful;
2142f66df612Smrg        attributes.save_under = False;
2143f66df612Smrg        w = XCreateWindow(dpy, Scr->Root, 0, 0,
2144f66df612Smrg                          (unsigned int) Scr->MyDisplayWidth,
2145f66df612Smrg                          (unsigned int) Scr->MyDisplayHeight,
2146f66df612Smrg                          (unsigned int) 0,
2147f66df612Smrg                          CopyFromParent, (unsigned int) CopyFromParent,
2148f66df612Smrg                          (Visual *) CopyFromParent, valuemask, &attributes);
2149f66df612Smrg        XMapWindow(dpy, w);
2150f66df612Smrg        XDestroyWindow(dpy, w);
2151f66df612Smrg        XFlush(dpy);
2152f66df612Smrg    }
2153f66df612Smrg        break;
21543e747e6dSmrg
21553e747e6dSmrg    case F_WINREFRESH:
2156f66df612Smrg        if (DeferExecution(context, func, Scr->SelectCursor))
2157f66df612Smrg            return TRUE;
2158f66df612Smrg
2159f66df612Smrg        if (context == C_ICON && tmp_win->icon_w)
2160f66df612Smrg            w = XCreateSimpleWindow(dpy, tmp_win->icon_w,
2161f66df612Smrg                                    0, 0, 9999, 9999, 0, Scr->Black,
2162f66df612Smrg                                    Scr->Black);
2163f66df612Smrg        else
2164f66df612Smrg            w = XCreateSimpleWindow(dpy, tmp_win->frame,
2165f66df612Smrg                                    0, 0, 9999, 9999, 0, Scr->Black,
2166f66df612Smrg                                    Scr->Black);
2167f66df612Smrg
2168f66df612Smrg        XMapWindow(dpy, w);
2169f66df612Smrg        XDestroyWindow(dpy, w);
2170f66df612Smrg        XFlush(dpy);
2171f66df612Smrg        break;
21723e747e6dSmrg
21733e747e6dSmrg    case F_QUIT:
2174f66df612Smrg        Done(NULL, NULL);
2175f66df612Smrg        break;
21763e747e6dSmrg
21773e747e6dSmrg    case F_PRIORITY:
2178f66df612Smrg        if (HasSync) {
2179f66df612Smrg            if (DeferExecution(context, func, Scr->SelectCursor))
2180f66df612Smrg                return TRUE;
2181f66df612Smrg            (void) XSyncSetPriority(dpy, tmp_win->w, atoi(action));
21823e747e6dSmrg        }
2183f66df612Smrg        break;
2184f66df612Smrg    case F_STARTWM:
2185f66df612Smrg        execlp("/bin/sh", "sh", "-c", action, (void *) NULL);
2186f66df612Smrg        twmWarning("unable to start:  %s", *Argv);
2187f66df612Smrg        break;
21883e747e6dSmrg
21893e747e6dSmrg    }
21903e747e6dSmrg
2191f66df612Smrg    if (ButtonPressed == -1)
2192f66df612Smrg        XUngrabPointer(dpy, CurrentTime);
21933e747e6dSmrg    return do_next_action;
21943e747e6dSmrg}
21953e747e6dSmrg
21963e747e6dSmrg/**
2197ffd25bcaSmrg * defer the execution of a function to the next button press if the context
21983e747e6dSmrg *  is C_ROOT
21993e747e6dSmrg *
22003e747e6dSmrg *  \param context the context in which the mouse button was pressed
2201f66df612Smrg *      \param func    the function to defer
22023e747e6dSmrg *  \param cursor  cursor the cursor to display while waiting
22033e747e6dSmrg */
2204c2535118Smrgstatic int
22053e747e6dSmrgDeferExecution(int context, int func, Cursor cursor)
22063e747e6dSmrg{
2207f66df612Smrg    if (context == C_ROOT) {
2208f66df612Smrg        LastCursor = cursor;
2209f66df612Smrg        XGrabPointer(dpy, Scr->Root, True,
2210f66df612Smrg                     ButtonPressMask | ButtonReleaseMask,
2211f66df612Smrg                     GrabModeAsync, GrabModeAsync,
2212f66df612Smrg                     Scr->Root, cursor, CurrentTime);
22133e747e6dSmrg
2214f66df612Smrg        RootFunction = func;
22153e747e6dSmrg
2216f66df612Smrg        return (TRUE);
22173e747e6dSmrg    }
2218ffd25bcaSmrg
22193e747e6dSmrg    return (FALSE);
22203e747e6dSmrg}
22213e747e6dSmrg
22223e747e6dSmrg/**
22233e747e6dSmrg *regrab the pointer with the LastCursor;
22243e747e6dSmrg */
22253e747e6dSmrgvoid
2226c2535118SmrgReGrab(void)
22273e747e6dSmrg{
22283e747e6dSmrg    XGrabPointer(dpy, Scr->Root, True,
2229f66df612Smrg                 ButtonPressMask | ButtonReleaseMask,
2230f66df612Smrg                 GrabModeAsync, GrabModeAsync,
2231f66df612Smrg                 Scr->Root, LastCursor, CurrentTime);
22323e747e6dSmrg}
22333e747e6dSmrg
22343e747e6dSmrg/**
2235ffd25bcaSmrg * checks each function in the list to see if it is one that needs
22363e747e6dSmrg * to be deferred.
22373e747e6dSmrg *
22383e747e6dSmrg *  \param root the menu root to check
22393e747e6dSmrg */
2240c2535118Smrgstatic Bool
22413e747e6dSmrgNeedToDefer(MenuRoot *root)
22423e747e6dSmrg{
22433e747e6dSmrg    MenuItem *mitem;
22443e747e6dSmrg
2245f66df612Smrg    for (mitem = root->first; mitem != NULL; mitem = mitem->next) {
2246f66df612Smrg        switch (mitem->func) {
2247f66df612Smrg        case F_IDENTIFY:
2248f66df612Smrg        case F_RESIZE:
2249f66df612Smrg        case F_MOVE:
2250f66df612Smrg        case F_FORCEMOVE:
2251f66df612Smrg        case F_DEICONIFY:
2252f66df612Smrg        case F_ICONIFY:
2253f66df612Smrg        case F_RAISELOWER:
2254f66df612Smrg        case F_RAISE:
2255f66df612Smrg        case F_LOWER:
2256f66df612Smrg        case F_FOCUS:
2257f66df612Smrg        case F_DESTROY:
2258f66df612Smrg        case F_WINREFRESH:
2259f66df612Smrg        case F_ZOOM:
2260f66df612Smrg        case F_FULLZOOM:
2261f66df612Smrg        case F_HORIZOOM:
22623e747e6dSmrg        case F_RIGHTZOOM:
22633e747e6dSmrg        case F_LEFTZOOM:
22643e747e6dSmrg        case F_TOPZOOM:
22653e747e6dSmrg        case F_BOTTOMZOOM:
2266f66df612Smrg        case F_AUTORAISE:
2267f66df612Smrg            return TRUE;
2268f66df612Smrg        }
22693e747e6dSmrg    }
22703e747e6dSmrg    return FALSE;
22713e747e6dSmrg}
22723e747e6dSmrg
2273f66df612Smrg/*
2274f66df612Smrg * We cannot safely free a value passed to putenv, but we can cache the most
2275f66df612Smrg * recent value, reducing the memory leaks.
2276f66df612Smrg */
2277f66df612Smrg#define cache_env(saved) \
2278f66df612Smrg    if (saved == NULL || strcmp(saved, update)) { \
2279f66df612Smrg        saved = update; \
2280f66df612Smrg    } else { \
2281f66df612Smrg        free(update); \
2282f66df612Smrg        update = saved; \
2283f66df612Smrg    }
22843e747e6dSmrg
2285c2535118Smrgstatic void
2286c2535118SmrgExecute(const char *s)
22873e747e6dSmrg{
2288f66df612Smrg    static const char display_eqls[] = "DISPLAY=";
2289f66df612Smrg    static char *main_display;
2290f66df612Smrg    static char *exec_display;
2291f66df612Smrg
2292f66df612Smrg    char *ds = DisplayString(dpy);
2293f66df612Smrg    char *colon;
2294f66df612Smrg    char *oldDisplay = NULL;
2295f66df612Smrg    char *value;
2296f66df612Smrg    Bool restorevar = False;
2297f66df612Smrg
2298f66df612Smrg    value = getenv("DISPLAY");
2299f66df612Smrg    oldDisplay = strdup(value ? value : "");
23003e747e6dSmrg
23013e747e6dSmrg    /*
23023e747e6dSmrg     * Build a display string using the current screen number, so that
23033e747e6dSmrg     * X programs which get fired up from a menu come up on the screen
23043e747e6dSmrg     * that they were invoked from, unless specifically overridden on
23053e747e6dSmrg     * their command line.
23063e747e6dSmrg     */
2307f66df612Smrg    colon = strrchr(ds, ':');
2308f66df612Smrg    if (colon) {                /* if host[:]:dpy */
2309f66df612Smrg        size_t need = sizeof(display_eqls) + strlen(ds) + 10;
23106d8e82c3Smrg        char *update = (char *) malloc(need);
2311f66df612Smrg
2312f66df612Smrg        if (update != NULL) {
2313f66df612Smrg            char *dot1;
2314f66df612Smrg
2315f66df612Smrg            strcpy(update, display_eqls);
2316f66df612Smrg            strcat(update, ds);
2317f66df612Smrg            colon = strrchr(update, ':');
2318f66df612Smrg            dot1 = strchr(colon, '.');  /* first period after colon */
2319f66df612Smrg            if (dot1 == NULL)
2320f66df612Smrg                dot1 = colon + strlen(colon);   /* if not there, append */
2321f66df612Smrg            (void) sprintf(dot1, ".%d", Scr->screen);
2322f66df612Smrg            cache_env(exec_display);
2323f66df612Smrg            if (strcmp(update, oldDisplay)) {
2324f66df612Smrg                putenv(update);
2325f66df612Smrg                restorevar = True;
2326f66df612Smrg            }
2327f66df612Smrg        }
23283e747e6dSmrg    }
23293e747e6dSmrg
2330f66df612Smrg    (void) system(s);
2331f66df612Smrg
2332f66df612Smrg    if (restorevar) {
2333f66df612Smrg        size_t need = sizeof(display_eqls) + strlen(oldDisplay);
23346d8e82c3Smrg        char *update = (char *) malloc(need);
23353e747e6dSmrg
2336f66df612Smrg        if (update != NULL) {
23376d8e82c3Smrg            strcat(strcpy(update, display_eqls), oldDisplay);
2338f66df612Smrg            cache_env(main_display);
2339f66df612Smrg            putenv(update);
2340f66df612Smrg        }
23413e747e6dSmrg    }
2342f66df612Smrg    free(oldDisplay);
23433e747e6dSmrg}
23443e747e6dSmrg
23453e747e6dSmrg/**
23463e747e6dSmrg * put input focus on the root window.
23473e747e6dSmrg */
23483e747e6dSmrgvoid
2349c2535118SmrgFocusOnRoot(void)
23503e747e6dSmrg{
2351f66df612Smrg    SetFocus((TwmWindow *) NULL, LastTimestamp());
2352f66df612Smrg    if (Scr->Focus != NULL) {
2353f66df612Smrg        SetBorder(Scr->Focus, False);
2354f66df612Smrg        if (Scr->Focus->hilite_w)
2355f66df612Smrg            XUnmapWindow(dpy, Scr->Focus->hilite_w);
23563e747e6dSmrg    }
23573e747e6dSmrg    InstallWindowColormaps(0, &Scr->TwmRoot);
23583e747e6dSmrg    Scr->Focus = NULL;
23593e747e6dSmrg    Scr->FocusRoot = TRUE;
23603e747e6dSmrg}
23613e747e6dSmrg
23623e747e6dSmrgvoid
23633e747e6dSmrgDeIconify(TwmWindow *tmp_win)
23643e747e6dSmrg{
23653e747e6dSmrg    TwmWindow *t;
23663e747e6dSmrg
23673e747e6dSmrg    /* de-iconify the main window */
2368f66df612Smrg    if (tmp_win->icon) {
2369f66df612Smrg        if (tmp_win->icon_on)
2370f66df612Smrg            Zoom(tmp_win->icon_w, tmp_win->frame);
2371f66df612Smrg        else if (tmp_win->group != (Window) 0) {
2372f66df612Smrg            for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2373f66df612Smrg                if (tmp_win->group == t->w && t->icon_on) {
2374f66df612Smrg                    Zoom(t->icon_w, tmp_win->frame);
2375f66df612Smrg                    break;
2376f66df612Smrg                }
2377f66df612Smrg            }
2378f66df612Smrg        }
23793e747e6dSmrg    }
23803e747e6dSmrg
23813e747e6dSmrg    XMapWindow(dpy, tmp_win->w);
23823e747e6dSmrg    tmp_win->mapped = TRUE;
23833e747e6dSmrg    if (Scr->NoRaiseDeicon)
2384f66df612Smrg        XMapWindow(dpy, tmp_win->frame);
23853e747e6dSmrg    else
2386f66df612Smrg        XMapRaised(dpy, tmp_win->frame);
23873e747e6dSmrg    SetMapStateProp(tmp_win, NormalState);
23883e747e6dSmrg
23893e747e6dSmrg    if (tmp_win->icon_w) {
2390f66df612Smrg        XUnmapWindow(dpy, tmp_win->icon_w);
2391f66df612Smrg        IconDown(tmp_win);
23923e747e6dSmrg    }
23933e747e6dSmrg    if (tmp_win->list)
2394f66df612Smrg        XUnmapWindow(dpy, tmp_win->list->icon);
23953e747e6dSmrg    if ((Scr->WarpCursor ||
23966d8e82c3Smrg         LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->xclass)) &&
2397f66df612Smrg        tmp_win->icon)
2398f66df612Smrg        WarpToWindow(tmp_win);
23993e747e6dSmrg    tmp_win->icon = FALSE;
24003e747e6dSmrg    tmp_win->icon_on = FALSE;
24013e747e6dSmrg
24023e747e6dSmrg    /* now de-iconify transients */
2403f66df612Smrg    for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2404f66df612Smrg        if (t->transient && t->transientfor == tmp_win->w) {
2405f66df612Smrg            if (t->icon_on)
2406f66df612Smrg                Zoom(t->icon_w, t->frame);
2407f66df612Smrg            else
2408f66df612Smrg                Zoom(tmp_win->icon_w, t->frame);
2409f66df612Smrg
2410f66df612Smrg            XMapWindow(dpy, t->w);
2411f66df612Smrg            t->mapped = TRUE;
2412f66df612Smrg            if (Scr->NoRaiseDeicon)
2413f66df612Smrg                XMapWindow(dpy, t->frame);
2414f66df612Smrg            else
2415f66df612Smrg                XMapRaised(dpy, t->frame);
2416f66df612Smrg            SetMapStateProp(t, NormalState);
2417f66df612Smrg
2418f66df612Smrg            if (t->icon_w) {
2419f66df612Smrg                XUnmapWindow(dpy, t->icon_w);
2420f66df612Smrg                IconDown(t);
2421f66df612Smrg            }
2422f66df612Smrg            if (t->list)
2423f66df612Smrg                XUnmapWindow(dpy, t->list->icon);
2424f66df612Smrg            t->icon = FALSE;
2425f66df612Smrg            t->icon_on = FALSE;
2426f66df612Smrg        }
2427f66df612Smrg    }
24283e747e6dSmrg
2429f66df612Smrg    XSync(dpy, 0);
2430f66df612Smrg}
24313e747e6dSmrg
24323e747e6dSmrgvoid
24333e747e6dSmrgIconify(TwmWindow *tmp_win, int def_x, int def_y)
24343e747e6dSmrg{
24353e747e6dSmrg    TwmWindow *t;
24363e747e6dSmrg    int iconify;
24373e747e6dSmrg    XWindowAttributes winattrs;
24383e747e6dSmrg    unsigned long eventMask;
24393e747e6dSmrg
24403e747e6dSmrg    iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
2441f66df612Smrg    if (iconify) {
2442f66df612Smrg        if (tmp_win->icon_w == (Window) 0)
2443f66df612Smrg            CreateIconWindow(tmp_win, def_x, def_y);
2444f66df612Smrg        else
2445f66df612Smrg            IconUp(tmp_win);
2446f66df612Smrg        XMapRaised(dpy, tmp_win->icon_w);
24473e747e6dSmrg    }
24483e747e6dSmrg    if (tmp_win->list)
2449f66df612Smrg        XMapWindow(dpy, tmp_win->list->icon);
24503e747e6dSmrg
24513e747e6dSmrg    XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
2452f66df612Smrg    eventMask = (unsigned long) winattrs.your_event_mask;
24533e747e6dSmrg
24543e747e6dSmrg    /* iconify transients first */
2455f66df612Smrg    for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
2456f66df612Smrg        if (t->transient && t->transientfor == tmp_win->w) {
2457f66df612Smrg            if (iconify) {
2458f66df612Smrg                if (t->icon_on)
2459f66df612Smrg                    Zoom(t->icon_w, tmp_win->icon_w);
2460f66df612Smrg                else
2461f66df612Smrg                    Zoom(t->frame, tmp_win->icon_w);
2462f66df612Smrg            }
2463f66df612Smrg
2464f66df612Smrg            /*
2465f66df612Smrg             * Prevent the receipt of an UnmapNotify, since that would
2466f66df612Smrg             * cause a transition to the Withdrawn state.
2467f66df612Smrg             */
2468f66df612Smrg            t->mapped = FALSE;
2469f66df612Smrg            XSelectInput(dpy, t->w,
2470f66df612Smrg                         (long) (eventMask &
2471f66df612Smrg                                 (unsigned long) (~StructureNotifyMask)));
2472f66df612Smrg            XUnmapWindow(dpy, t->w);
2473f66df612Smrg            XSelectInput(dpy, t->w, (long) eventMask);
2474f66df612Smrg            XUnmapWindow(dpy, t->frame);
2475f66df612Smrg            if (t->icon_w)
2476f66df612Smrg                XUnmapWindow(dpy, t->icon_w);
2477f66df612Smrg            SetMapStateProp(t, IconicState);
2478f66df612Smrg            SetBorder(t, False);
2479f66df612Smrg            if (t == Scr->Focus) {
2480f66df612Smrg                SetFocus((TwmWindow *) NULL, LastTimestamp());
2481f66df612Smrg                Scr->Focus = NULL;
2482f66df612Smrg                Scr->FocusRoot = TRUE;
2483f66df612Smrg            }
2484f66df612Smrg            if (t->list)
2485f66df612Smrg                XMapWindow(dpy, t->list->icon);
2486f66df612Smrg            t->icon = TRUE;
2487f66df612Smrg            t->icon_on = FALSE;
2488f66df612Smrg        }
2489f66df612Smrg    }
2490ffd25bcaSmrg
24913e747e6dSmrg    if (iconify)
2492f66df612Smrg        Zoom(tmp_win->frame, tmp_win->icon_w);
24933e747e6dSmrg
24943e747e6dSmrg    /*
24953e747e6dSmrg     * Prevent the receipt of an UnmapNotify, since that would
24963e747e6dSmrg     * cause a transition to the Withdrawn state.
24973e747e6dSmrg     */
24983e747e6dSmrg    tmp_win->mapped = FALSE;
2499f66df612Smrg    XSelectInput(dpy, tmp_win->w,
2500f66df612Smrg                 (long) (eventMask & (unsigned long) (~StructureNotifyMask)));
25013e747e6dSmrg    XUnmapWindow(dpy, tmp_win->w);
2502f66df612Smrg    XSelectInput(dpy, tmp_win->w, (long) eventMask);
25033e747e6dSmrg    XUnmapWindow(dpy, tmp_win->frame);
25043e747e6dSmrg    SetMapStateProp(tmp_win, IconicState);
25053e747e6dSmrg
2506f66df612Smrg    SetBorder(tmp_win, False);
2507f66df612Smrg    if (tmp_win == Scr->Focus) {
2508f66df612Smrg        SetFocus((TwmWindow *) NULL, LastTimestamp());
2509f66df612Smrg        Scr->Focus = NULL;
2510f66df612Smrg        Scr->FocusRoot = TRUE;
25113e747e6dSmrg    }
25123e747e6dSmrg    tmp_win->icon = TRUE;
25133e747e6dSmrg    if (iconify)
2514f66df612Smrg        tmp_win->icon_on = TRUE;
25153e747e6dSmrg    else
2516f66df612Smrg        tmp_win->icon_on = FALSE;
2517f66df612Smrg    XSync(dpy, 0);
25183e747e6dSmrg}
25193e747e6dSmrg
2520ffd25bcaSmrgstatic void
2521f66df612SmrgIdentify(TwmWindow *t)
25223e747e6dSmrg{
2523f66df612Smrg    int i, n, width, height;
25243e747e6dSmrg    int x, y;
25253e747e6dSmrg    unsigned int wwidth, wheight, bw, depth;
25263e747e6dSmrg    Window junk;
25273e747e6dSmrg    int px, py, dummy;
25283e747e6dSmrg    unsigned udummy;
25296d8e82c3Smrg    Window wdummy = None;
25303e747e6dSmrg
25313e747e6dSmrg    n = 0;
25326d8e82c3Smrg    snprintf(Info[n++], INFO_SIZE, "Twm version:  %s, Release %s",
25336d8e82c3Smrg             XVENDORNAME, APP_VERSION);
25343e747e6dSmrg    Info[n++][0] = '\0';
25353e747e6dSmrg
25363e747e6dSmrg    if (t) {
25376d8e82c3Smrg        XGetGeometry(dpy, t->w, &wdummy, &dummy, &dummy,
2538f66df612Smrg                     &wwidth, &wheight, &bw, &depth);
2539f66df612Smrg        (void) XTranslateCoordinates(dpy, t->w, Scr->Root, 0, 0, &x, &y, &junk);
2540f66df612Smrg        snprintf(Info[n++], INFO_SIZE,
2541f66df612Smrg                 "Name             = \"%s\"", t->full_name);
2542f66df612Smrg        snprintf(Info[n++], INFO_SIZE,
25436d8e82c3Smrg                 "Class.res_name   = \"%s\"", t->xclass.res_name);
2544f66df612Smrg        snprintf(Info[n++], INFO_SIZE,
25456d8e82c3Smrg                 "Class.res_class  = \"%s\"", t->xclass.res_class);
2546f66df612Smrg        Info[n++][0] = '\0';
2547f66df612Smrg        snprintf(Info[n++], INFO_SIZE,
2548f66df612Smrg                 "Geometry/root    = %ux%u+%d+%d", wwidth, wheight, x, y);
2549f66df612Smrg        snprintf(Info[n++], INFO_SIZE, "Border width     = %u", bw);
2550f66df612Smrg        snprintf(Info[n++], INFO_SIZE, "Depth            = %u", depth);
2551f66df612Smrg        if (HasSync) {
2552f66df612Smrg            int priority;
2553f66df612Smrg
2554f66df612Smrg            (void) XSyncGetPriority(dpy, t->w, &priority);
2555f66df612Smrg            snprintf(Info[n++], INFO_SIZE, "Priority         = %d", priority);
2556f66df612Smrg        }
25573e747e6dSmrg    }
25583e747e6dSmrg
25593e747e6dSmrg    Info[n++][0] = '\0';
2560ffd25bcaSmrg    snprintf(Info[n++], INFO_SIZE, "Click to dismiss....");
25613e747e6dSmrg
25623e747e6dSmrg    /* figure out the width and height of the info window */
2563f66df612Smrg    height = n * (Scr->DefaultFont.height + 2);
25643e747e6dSmrg    width = 1;
2565f66df612Smrg    for (i = 0; i < n; i++) {
2566f66df612Smrg        int twidth = MyFont_TextWidth(&Scr->DefaultFont, Info[i],
2567f66df612Smrg                                      (int) strlen(Info[i]));
2568f66df612Smrg
2569f66df612Smrg        if (twidth > width)
2570f66df612Smrg            width = twidth;
2571f66df612Smrg    }
2572f66df612Smrg    if (InfoLines)
2573f66df612Smrg        XUnmapWindow(dpy, Scr->InfoWindow);
2574f66df612Smrg
2575f66df612Smrg    width += 10;                /* some padding */
25766d8e82c3Smrg    if (XQueryPointer(dpy, Scr->Root, &wdummy, &wdummy, &px, &py,
2577f66df612Smrg                      &dummy, &dummy, &udummy)) {
2578f66df612Smrg        px -= (width / 2);
2579f66df612Smrg        py -= (height / 3);
2580f66df612Smrg        if (px + width + BW2 >= Scr->MyDisplayWidth)
2581f66df612Smrg            px = Scr->MyDisplayWidth - width - BW2;
2582f66df612Smrg        if (py + height + BW2 >= Scr->MyDisplayHeight)
2583f66df612Smrg            py = Scr->MyDisplayHeight - height - BW2;
2584f66df612Smrg        if (px < 0)
2585f66df612Smrg            px = 0;
2586f66df612Smrg        if (py < 0)
2587f66df612Smrg            py = 0;
2588f66df612Smrg    }
2589f66df612Smrg    else {
2590f66df612Smrg        px = py = 0;
2591f66df612Smrg    }
2592f66df612Smrg    XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, (unsigned) width,
2593f66df612Smrg                      (unsigned) height);
2594ffd25bcaSmrg    XMapRaised(dpy, Scr->InfoWindow);
25953e747e6dSmrg    InfoLines = n;
25963e747e6dSmrg}
25973e747e6dSmrg
25983e747e6dSmrgvoid
25993e747e6dSmrgSetMapStateProp(TwmWindow *tmp_win, int state)
26003e747e6dSmrg{
2601f66df612Smrg    unsigned long data[2];      /* "suggested" by ICCCM version 1 */
2602ffd25bcaSmrg
26033e747e6dSmrg    data[0] = (unsigned long) state;
2604ffd25bcaSmrg    data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
2605f66df612Smrg                               tmp_win->icon_w);
26063e747e6dSmrg
2607f66df612Smrg    XChangeProperty(dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
2608f66df612Smrg                    PropModeReplace, (unsigned char *) data, 2);
26093e747e6dSmrg}
26103e747e6dSmrg
2611ffd25bcaSmrgBool
2612f66df612SmrgGetWMState(Window w, int *statep, Window *iwp)
26133e747e6dSmrg{
26143e747e6dSmrg    Atom actual_type;
26153e747e6dSmrg    int actual_format;
26163e747e6dSmrg    unsigned long nitems, bytesafter;
2617ffd25bcaSmrg    unsigned char *prop_return = NULL;
26183e747e6dSmrg    Bool retval = False;
26193e747e6dSmrg
2620f66df612Smrg    if (XGetWindowProperty(dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
2621f66df612Smrg                           &actual_type, &actual_format, &nitems, &bytesafter,
2622f66df612Smrg                           &prop_return) != Success || !prop_return)
2623f66df612Smrg        return False;
26243e747e6dSmrg
2625f66df612Smrg    if (nitems <= 2) {          /* "suggested" by ICCCM version 1 */
2626f66df612Smrg        unsigned long *datap = (unsigned long *) prop_return;
2627f66df612Smrg
2628f66df612Smrg        *statep = (int) datap[0];
2629f66df612Smrg        *iwp = (Window) datap[1];
2630f66df612Smrg        retval = True;
26313e747e6dSmrg    }
26323e747e6dSmrg
2633f66df612Smrg    XFree(prop_return);
26343e747e6dSmrg    return retval;
26353e747e6dSmrg}
26363e747e6dSmrg
26373e747e6dSmrgvoid
2638f66df612SmrgWarpToScreen(int n, int inc)
26393e747e6dSmrg{
26403e747e6dSmrg    Window dumwin;
26413e747e6dSmrg    int x, y, dumint;
26423e747e6dSmrg    unsigned int dummask;
26433e747e6dSmrg    ScreenInfo *newscr = NULL;
26443e747e6dSmrg
26453e747e6dSmrg    while (!newscr) {
2646f66df612Smrg        /* wrap around */
2647f66df612Smrg        if (n < 0)
2648f66df612Smrg            n = NumScreens - 1;
2649f66df612Smrg        else if (n >= NumScreens)
2650f66df612Smrg            n = 0;
2651f66df612Smrg
2652f66df612Smrg        newscr = ScreenList[n];
2653f66df612Smrg        if (!newscr) {          /* make sure screen is managed */
2654f66df612Smrg            if (inc) {          /* walk around the list */
2655f66df612Smrg                n += inc;
2656f66df612Smrg                continue;
2657f66df612Smrg            }
2658f66df612Smrg            twmWarning("unable to warp to unmanaged screen %d", n);
2659f66df612Smrg            Bell(XkbBI_MinorError, 0, None);
2660f66df612Smrg            return;
2661f66df612Smrg        }
2662f66df612Smrg    }
2663f66df612Smrg
2664f66df612Smrg    if (Scr->screen == n)
2665f66df612Smrg        return;                 /* already on that screen */
26663e747e6dSmrg
26673e747e6dSmrg    PreviousScreen = Scr->screen;
2668f66df612Smrg    XQueryPointer(dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
2669f66df612Smrg                  &dumint, &dumint, &dummask);
26703e747e6dSmrg
2671f66df612Smrg    XWarpPointer(dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
26723e747e6dSmrg    return;
26733e747e6dSmrg}
26743e747e6dSmrg
26753e747e6dSmrg/**
26763e747e6dSmrg * rotate our internal copy of WM_COLORMAP_WINDOWS
26773e747e6dSmrg */
2678c2535118Smrgstatic void
2679f66df612SmrgBumpWindowColormap(TwmWindow *tmp, int inc)
26803e747e6dSmrg{
26813e747e6dSmrg    ColormapWindow **cwins;
26823e747e6dSmrg
2683f66df612Smrg    if (!tmp)
2684f66df612Smrg        return;
26853e747e6dSmrg
26863e747e6dSmrg    if (inc && tmp->cmaps.number_cwins > 0) {
26876d8e82c3Smrg        cwins = (ColormapWindow **)
2688f66df612Smrg            malloc(sizeof(ColormapWindow *) * (size_t) tmp->cmaps.number_cwins);
2689f66df612Smrg        if (cwins) {
2690f66df612Smrg            int i;
2691f66df612Smrg            int previously_installed;
2692f66df612Smrg
2693f66df612Smrg            /* SUPPRESS 560 */
2694f66df612Smrg            if ((previously_installed = (Scr->cmapInfo.cmaps == &tmp->cmaps &&
2695f66df612Smrg                                         tmp->cmaps.number_cwins))) {
2696f66df612Smrg                for (i = tmp->cmaps.number_cwins; i-- > 0;)
2697f66df612Smrg                    tmp->cmaps.cwins[i]->colormap->state = 0;
2698f66df612Smrg            }
2699f66df612Smrg
2700f66df612Smrg            for (i = 0; i < tmp->cmaps.number_cwins; i++) {
2701f66df612Smrg                int j = i - inc;
2702f66df612Smrg
2703f66df612Smrg                if (j >= tmp->cmaps.number_cwins)
2704f66df612Smrg                    j -= tmp->cmaps.number_cwins;
2705f66df612Smrg                else if (j < 0)
2706f66df612Smrg                    j += tmp->cmaps.number_cwins;
2707f66df612Smrg                cwins[j] = tmp->cmaps.cwins[i];
2708f66df612Smrg            }
2709f66df612Smrg
2710f66df612Smrg            free(tmp->cmaps.cwins);
2711f66df612Smrg
2712f66df612Smrg            tmp->cmaps.cwins = cwins;
2713f66df612Smrg
2714f66df612Smrg            if (tmp->cmaps.number_cwins > 1)
2715f66df612Smrg                bzero(tmp->cmaps.scoreboard,
2716f66df612Smrg                      ColormapsScoreboardLength(&tmp->cmaps));
2717f66df612Smrg
2718f66df612Smrg            if (previously_installed)
2719f66df612Smrg                InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
2720f66df612Smrg        }
2721f66df612Smrg    }
2722f66df612Smrg    else
2723f66df612Smrg        FetchWmColormapWindows(tmp);
27243e747e6dSmrg}
27253e747e6dSmrg
2726c2535118Smrgstatic void
2727f66df612SmrgHideIconManager(void)
27283e747e6dSmrg{
2729f66df612Smrg    SetMapStateProp(Scr->iconmgr.twm_win, WithdrawnState);
27303e747e6dSmrg    XUnmapWindow(dpy, Scr->iconmgr.twm_win->frame);
27313e747e6dSmrg    if (Scr->iconmgr.twm_win->icon_w)
2732f66df612Smrg        XUnmapWindow(dpy, Scr->iconmgr.twm_win->icon_w);
27333e747e6dSmrg    Scr->iconmgr.twm_win->mapped = FALSE;
27343e747e6dSmrg    Scr->iconmgr.twm_win->icon = TRUE;
27353e747e6dSmrg}
27363e747e6dSmrg
27373e747e6dSmrgvoid
2738f66df612SmrgSetBorder(TwmWindow *tmp, Bool onoroff)
27393e747e6dSmrg{
27403e747e6dSmrg    if (tmp->highlight) {
2741f66df612Smrg        if (onoroff) {
2742f66df612Smrg            XSetWindowBorder(dpy, tmp->frame, tmp->border);
2743f66df612Smrg            if (tmp->title_w)
2744f66df612Smrg                XSetWindowBorder(dpy, tmp->title_w, tmp->border);
2745f66df612Smrg        }
2746f66df612Smrg        else {
2747f66df612Smrg            XSetWindowBorderPixmap(dpy, tmp->frame, tmp->gray);
2748f66df612Smrg            if (tmp->title_w)
2749f66df612Smrg                XSetWindowBorderPixmap(dpy, tmp->title_w, tmp->gray);
2750f66df612Smrg        }
27513e747e6dSmrg    }
27523e747e6dSmrg}
27533e747e6dSmrg
2754c2535118Smrgstatic void
2755f66df612SmrgDestroyMenu(MenuRoot *menu)
27563e747e6dSmrg{
27573e747e6dSmrg    MenuItem *item;
27583e747e6dSmrg
27593e747e6dSmrg    if (menu->w) {
2760f66df612Smrg        XDeleteContext(dpy, menu->w, MenuContext);
2761f66df612Smrg        XDeleteContext(dpy, menu->w, ScreenContext);
2762f66df612Smrg        if (Scr->Shadow)
2763f66df612Smrg            XDestroyWindow(dpy, menu->shadow);
2764f66df612Smrg        XDestroyWindow(dpy, menu->w);
27653e747e6dSmrg    }
27663e747e6dSmrg
2767f66df612Smrg    for (item = menu->first; item;) {
2768f66df612Smrg        MenuItem *tmp = item;
2769f66df612Smrg
2770f66df612Smrg        item = item->next;
2771f66df612Smrg        free(tmp);
27723e747e6dSmrg    }
27733e747e6dSmrg}
27743e747e6dSmrg
27753e747e6dSmrg/*
27763e747e6dSmrg * warping routines
27773e747e6dSmrg */
27783e747e6dSmrg
2779c2535118Smrgstatic void
2780f66df612SmrgWarpAlongRing(XButtonEvent *ev, Bool forward)
27813e747e6dSmrg{
27823e747e6dSmrg    TwmWindow *r, *head;
27833e747e6dSmrg
27843e747e6dSmrg    if (Scr->RingLeader)
2785f66df612Smrg        head = Scr->RingLeader;
2786ffd25bcaSmrg    else if (!(head = Scr->Ring))
2787f66df612Smrg        return;
27883e747e6dSmrg
27893e747e6dSmrg    if (forward) {
2790f66df612Smrg        for (r = head->ring.next; r != head; r = r->ring.next) {
2791f66df612Smrg            if (!r || r->mapped)
2792f66df612Smrg                break;
2793f66df612Smrg        }
2794f66df612Smrg    }
2795f66df612Smrg    else {
2796f66df612Smrg        for (r = head->ring.prev; r != head; r = r->ring.prev) {
2797f66df612Smrg            if (!r || r->mapped)
2798f66df612Smrg                break;
2799f66df612Smrg        }
28003e747e6dSmrg    }
28013e747e6dSmrg
28023e747e6dSmrg    if (r && r != head) {
2803f66df612Smrg        TwmWindow *p = Scr->RingLeader, *t;
2804f66df612Smrg        XPointer context_data;
2805f66df612Smrg
2806f66df612Smrg        Scr->RingLeader = r;
2807f66df612Smrg        WarpToWindow(r);
2808f66df612Smrg
2809f66df612Smrg        if (XFindContext(dpy, ev->window, TwmContext, &context_data) == 0)
2810f66df612Smrg            t = (TwmWindow *) context_data;
2811f66df612Smrg        else
2812f66df612Smrg            t = NULL;
2813f66df612Smrg
2814f66df612Smrg        if (p && p->mapped && p == t) {
2815f66df612Smrg            p->ring.cursor_valid = True;
2816f66df612Smrg            p->ring.curs_x = ev->x_root - t->frame_x;
2817f66df612Smrg            p->ring.curs_y = ev->y_root - t->frame_y;
2818f66df612Smrg            if (p->ring.curs_x < -p->frame_bw ||
2819f66df612Smrg                p->ring.curs_x >= p->frame_width + p->frame_bw ||
2820f66df612Smrg                p->ring.curs_y < -p->frame_bw ||
2821f66df612Smrg                p->ring.curs_y >= p->frame_height + p->frame_bw) {
2822f66df612Smrg                /* somehow out of window */
2823f66df612Smrg                p->ring.curs_x = p->frame_width / 2;
2824f66df612Smrg                p->ring.curs_y = p->frame_height / 2;
2825f66df612Smrg            }
2826f66df612Smrg        }
28273e747e6dSmrg    }
28283e747e6dSmrg}
28293e747e6dSmrg
2830c2535118Smrgstatic void
2831f66df612SmrgWarpToWindow(TwmWindow *t)
28323e747e6dSmrg{
28333e747e6dSmrg    int x, y;
28343e747e6dSmrg
2835f66df612Smrg    if (t->auto_raise || !Scr->NoRaiseWarp)
2836f66df612Smrg        AutoRaiseWindow(t);
28373e747e6dSmrg    if (t->ring.cursor_valid) {
2838f66df612Smrg        x = t->ring.curs_x;
2839f66df612Smrg        y = t->ring.curs_y;
28403e747e6dSmrg    }
2841f66df612Smrg    else {
2842f66df612Smrg        x = t->frame_width / 2;
2843f66df612Smrg        y = t->frame_height / 2;
2844f66df612Smrg    }
2845f66df612Smrg    XWarpPointer(dpy, None, t->frame, 0, 0, 0, 0, x, y);
28463e747e6dSmrg}
28473e747e6dSmrg
28483e747e6dSmrg/*
28493e747e6dSmrg * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
28503e747e6dSmrg * client messages will have the following form:
28513e747e6dSmrg *
2852f66df612Smrg *     event type       ClientMessage
2853f66df612Smrg *     message type     _XA_WM_PROTOCOLS
2854f66df612Smrg *     window           tmp->w
2855f66df612Smrg *     format           32
2856f66df612Smrg *     data[0]          message atom
2857f66df612Smrg *     data[1]          time stamp
28583e747e6dSmrg */
2859ffd25bcaSmrgstatic void
2860f66df612Smrgsend_clientmessage(Window w, Atom a, Time timestamp)
28613e747e6dSmrg{
28623e747e6dSmrg    XClientMessageEvent ev;
28636d8e82c3Smrg    memset(&ev, '\0', sizeof(ev));
28643e747e6dSmrg
28653e747e6dSmrg    ev.type = ClientMessage;
28663e747e6dSmrg    ev.window = w;
28673e747e6dSmrg    ev.message_type = _XA_WM_PROTOCOLS;
28683e747e6dSmrg    ev.format = 32;
2869f66df612Smrg    ev.data.l[0] = (long) a;
2870f66df612Smrg    ev.data.l[1] = (long) timestamp;
2871f66df612Smrg    XSendEvent(dpy, w, False, 0L, (XEvent *) &ev);
28723e747e6dSmrg}
28733e747e6dSmrg
28743e747e6dSmrgvoid
2875f66df612SmrgSendDeleteWindowMessage(TwmWindow *tmp, Time timestamp)
28763e747e6dSmrg{
2877f66df612Smrg    send_clientmessage(tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
28783e747e6dSmrg}
28793e747e6dSmrg
28803e747e6dSmrgvoid
2881f66df612SmrgSendSaveYourselfMessage(TwmWindow *tmp, Time timestamp)
28823e747e6dSmrg{
2883f66df612Smrg    send_clientmessage(tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
28843e747e6dSmrg}
28853e747e6dSmrg
28863e747e6dSmrgvoid
2887f66df612SmrgSendTakeFocusMessage(TwmWindow *tmp, Time timestamp)
28883e747e6dSmrg{
2889f66df612Smrg    send_clientmessage(tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
28903e747e6dSmrg}
2891