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