v09i005: TWM with a virtual root window, Part04/09
Tom LaStrange
toml at marvin.Solbourne.COM
Thu Aug 30 05:33:24 AEST 1990
Submitted-by: toml at marvin.Solbourne.COM (Tom LaStrange)
Posting-number: Volume 9, Issue 5
Archive-name: tvtwm/part04
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting test in a file
# 3. Execute the file with /bin/sh (not csh) to create the files:
#
#menus.c
#
# Created by toml () on Wed Aug 29 08:43:33 MDT 1990
#
if test -f 'menus.c'
then
echo shar: will not over-write existing file "menus.c"
else
echo extracting "menus.c"
sed 's/^X//' >menus.c <<'SHAR_EOF'
X/*****************************************************************************/
X/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
X/** Salt Lake City, Utah **/
X/** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
X/** Cambridge, Massachusetts **/
X/** **/
X/** All Rights Reserved **/
X/** **/
X/** Permission to use, copy, modify, and distribute this software and **/
X/** its documentation for any purpose and without fee is hereby **/
X/** granted, provided that the above copyright notice appear in all **/
X/** copies and that both that copyright notice and this permis- **/
X/** sion notice appear in supporting documentation, and that the **/
X/** names of Evans & Sutherland and M.I.T. not be used in advertising **/
X/** in publicity pertaining to distribution of the software without **/
X/** specific, written prior permission. **/
X/** **/
X/** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
X/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
X/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
X/** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
X/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
X/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
X/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
X/** OR PERFORMANCE OF THIS SOFTWARE. **/
X/*****************************************************************************/
X
X
X/***********************************************************************
X *
X * $XConsortium: menus.c,v 1.156 90/03/23 13:30:49 jim Exp $
X *
X * twm menu code
X *
X * 17-Nov-87 Thomas E. LaStrange File created
X *
X ***********************************************************************/
X
X#if !defined(lint) && !defined(SABER)
Xstatic char RCSinfo[] =
X"$XConsortium: menus.c,v 1.156 90/03/23 13:30:49 jim Exp $";
X#endif
X
X#include <stdio.h>
X#include <signal.h>
X#include <X11/Xos.h>
X#include "twm.h"
X#include "gc.h"
X#include "menus.h"
X#include "resize.h"
X#include "events.h"
X#include "util.h"
X#include "parse.h"
X#include "gram.h"
X#include "screen.h"
X#include <X11/bitmaps/menu12>
X#include "version.h"
X#include "vdt.h"
X#include "add_window.h"
X#include "patchlevel.h"
X
Xextern XEvent Event;
X
Xint RootFunction = NULL;
XMenuRoot *ActiveMenu = NULL; /* the active menu */
XMenuItem *ActiveItem = NULL; /* the active menu item */
Xint MoveFunction; /* either F_MOVE or F_FORCEMOVE */
Xint WindowMoved = FALSE;
X
Xint ConstMove = FALSE; /* constrained move variables */
Xint ConstMoveDir;
Xint ConstMoveX;
Xint ConstMoveY;
Xint ConstMoveXL;
Xint ConstMoveXR;
Xint ConstMoveYT;
Xint ConstMoveYB;
X
Xint MenuDepth = 0; /* number of menus up */
Xstatic struct {
X int x;
X int y;
X} MenuOrigins[MAXMENUDEPTH];
Xstatic Cursor LastCursor;
X
Xvoid WarpAlongRing(), WarpToWindow();
X
Xextern char *Action;
Xextern int Context;
Xextern TwmWindow *ButtonWindow, *Tmp_win;
Xextern XEvent Event, ButtonEvent;
Xextern char *InitFile;
Xstatic void Identify();
X
X#define SHADOWWIDTH 5 /* in pixels */
X
X/***********************************************************************
X *
X * Procedure:
X * InitMenus - initialize menu roots
X *
X ***********************************************************************
X */
X
Xvoid
XInitMenus()
X{
X int i, j, k;
X FuncKey *key, *tmp;
X
X for (i = 0; i < MAX_BUTTONS+1; i++)
X for (j = 0; j < NUM_CONTEXTS; j++)
X for (k = 0; k < MOD_SIZE; k++)
X {
X Scr->Mouse[i][j][k].func = NULL;
X Scr->Mouse[i][j][k].item = NULL;
X }
X
X Scr->DefaultFunction.func = NULL;
X Scr->WindowFunction.func = NULL;
X
X if (FirstScreen)
X {
X for (key = Scr->FuncKeyRoot.next; key != NULL;)
X {
X free(key->name);
X tmp = key;
X key = key->next;
X free((char *) tmp);
X }
X Scr->FuncKeyRoot.next = NULL;
X }
X
X}
X
X/***********************************************************************
X *
X * Procedure:
X * AddFuncKey - add a function key to the list
X *
X * Inputs:
X * name - the name of the key
X * cont - the context to look for the key press in
X * mods - modifier keys that need to be pressed
X * func - the function to perform
X * win_name- the window name (if any)
X * action - the action string associated with the function (if any)
X *
X ***********************************************************************
X */
X
XBool AddFuncKey (name, cont, mods, func, win_name, action)
X char *name;
X int cont, mods, func;
X char *win_name;
X char *action;
X{
X FuncKey *tmp;
X KeySym keysym;
X KeyCode keycode;
X
X /*
X * Don't let a 0 keycode go through, since that means AnyKey to the
X * XGrabKey call in GrabKeys().
X */
X if ((keysym = XStringToKeysym(name)) == NoSymbol ||
X (keycode = XKeysymToKeycode(dpy, keysym)) == 0)
X {
X return False;
X }
X
X /* see if there already is a key defined for this context */
X for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
X {
X if (tmp->keysym == keysym &&
X tmp->cont == cont &&
X tmp->mods == mods)
X break;
X }
X
X if (tmp == NULL)
X {
X tmp = (FuncKey *) malloc(sizeof(FuncKey));
X tmp->next = Scr->FuncKeyRoot.next;
X Scr->FuncKeyRoot.next = tmp;
X }
X
X tmp->name = name;
X tmp->keysym = keysym;
X tmp->keycode = keycode;
X tmp->cont = cont;
X tmp->mods = mods;
X tmp->func = func;
X tmp->win_name = win_name;
X tmp->action = action;
X
X return True;
X}
X
Xint CreateTitleButton (name, func, action, menuroot, rightside, append)
X char *name;
X int func;
X char *action;
X MenuRoot *menuroot;
X Bool rightside;
X Bool append;
X{
X TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton));
X
X if (!tb) {
X fprintf (stderr,
X "%s: unable to allocate %d bytes for title button\n",
X ProgramName, sizeof(TitleButton));
X return 0;
X }
X
X tb->next = NULL;
X tb->name = name; /* note that we are not copying */
X tb->bitmap = None; /* WARNING, values not set yet */
X tb->width = 0; /* see InitTitlebarButtons */
X tb->height = 0; /* ditto */
X tb->func = func;
X tb->action = action;
X tb->menuroot = menuroot;
X tb->rightside = rightside;
X if (rightside) {
X Scr->TBInfo.nright++;
X } else {
X Scr->TBInfo.nleft++;
X }
X
X /*
X * Cases for list:
X *
X * 1. empty list, prepend left put at head of list
X * 2. append left, prepend right put in between left and right
X * 3. append right put at tail of list
X *
X * Do not refer to widths and heights yet since buttons not created
X * (since fonts not loaded and heights not known).
X */
X if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) { /* 1 */
X tb->next = Scr->TBInfo.head;
X Scr->TBInfo.head = tb;
X } else if (append && rightside) { /* 3 */
X register TitleButton *t;
X for (t = Scr->TBInfo.head; t->next; t = t->next) ;
X t->next = tb;
X tb->next = NULL;
X } else { /* 2 */
X register TitleButton *t, *prev = NULL;
X for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
X prev = t;
X }
X if (prev) {
X tb->next = prev->next;
X prev->next = tb;
X } else {
X tb->next = Scr->TBInfo.head;
X Scr->TBInfo.head = tb;
X }
X }
X
X return 1;
X}
X
X
X/*
X * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
X * button. If we can't find the button, then put in a question; if we can't
X * find the question mark, something is wrong and we are probably going to be
X * in trouble later on.
X */
Xvoid InitTitlebarButtons ()
X{
X TitleButton *tb;
X int h;
X
X /*
X * initialize dimensions
X */
X Scr->TBInfo.width = (Scr->TitleHeight -
X 2 * (Scr->FramePadding + Scr->ButtonIndent));
X Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
X ? ((Scr->TitlePadding + 1) / 2) : 1);
X h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
X
X /*
X * add in some useful buttons and bindings so that novices can still
X * use the system.
X */
X if (!Scr->NoDefaults) {
X /* insert extra buttons */
X if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
X False, False)) {
X fprintf (stderr, "%s: unable to add iconify button\n",
X ProgramName);
X }
X if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
X True, True)) {
X fprintf (stderr, "%s: unable to add resize button\n",
X ProgramName);
X }
X AddDefaultBindings ();
X }
X ComputeCommonTitleOffsets ();
X
X /*
X * load in images and do appropriate centering
X */
X
X for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
X tb->bitmap = FindBitmap (tb->name, &tb->width, &tb->height);
X if (!tb->bitmap) {
X tb->bitmap = FindBitmap (TBPM_QUESTION, &tb->width, &tb->height);
X if (!tb->bitmap) { /* cannot happen (see util.c) */
X fprintf (stderr,
X "%s: unable to add titlebar button \"%s\"\n",
X ProgramName, tb->name);
X }
X }
X
X tb->dstx = (h - tb->width + 1) / 2;
X if (tb->dstx < 0) { /* clip to minimize copying */
X tb->srcx = -(tb->dstx);
X tb->width = h;
X tb->dstx = 0;
X } else {
X tb->srcx = 0;
X }
X tb->dsty = (h - tb->height + 1) / 2;
X if (tb->dsty < 0) {
X tb->srcy = -(tb->dsty);
X tb->height = h;
X tb->dsty = 0;
X } else {
X tb->srcy = 0;
X }
X }
X}
X
X
XPaintEntry(mr, mi, exposure)
XMenuRoot *mr;
XMenuItem *mi;
Xint exposure;
X{
X int y_offset;
X int text_y;
X GC gc;
X
X#ifdef DEBUG_MENUS
X fprintf(stderr, "Paint entry\n");
X#endif
X y_offset = mi->item_num * Scr->EntryHeight;
X text_y = y_offset + Scr->MenuFont.y;
X
X if (mi->func != F_TITLE)
X {
X int x, y;
X
X if (mi->state)
X {
X XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
X
X XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
X mr->width, Scr->EntryHeight);
X
X FBF(mi->hi_fore, mi->hi_back, Scr->MenuFont.font->fid);
X
X XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
X text_y, mi->item, mi->strlen);
X
X gc = Scr->NormalGC;
X }
X else
X {
X if (mi->user_colors || !exposure)
X {
X XSetForeground(dpy, Scr->NormalGC, mi->back);
X
X XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
X mr->width, Scr->EntryHeight);
X
X FBF(mi->fore, mi->back, Scr->MenuFont.font->fid);
X gc = Scr->NormalGC;
X }
X else
X gc = Scr->MenuGC;
X
X XDrawString(dpy, mr->w, gc, mi->x,
X text_y, mi->item, mi->strlen);
X }
X
X if (mi->func == F_MENU)
X {
X
X /* create the pull right pixmap if needed */
X if (Scr->pullPm == None)
X {
X Scr->pullPm = XCreatePixmapFromBitmapData(dpy, Scr->Root,
X menu12_bits, menu12_width, menu12_height, 1, 0, 1);
X }
X x = mr->width - menu12_width - 5;
X y = y_offset + ((Scr->MenuFont.height - menu12_height) / 2);
X XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
X menu12_width, menu12_height, x, y, 1);
X }
X }
X else
X {
X int y;
X
X XSetForeground(dpy, Scr->NormalGC, mi->back);
X
X /* fill the rectangle with the title background color */
X XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
X mr->width, Scr->EntryHeight);
X
X {
X XSetForeground(dpy, Scr->NormalGC, mi->fore);
X /* now draw the dividing lines */
X if (y_offset)
X XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
X mr->width, y_offset);
X y = ((mi->item_num+1) * Scr->EntryHeight)-1;
X XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
X }
X
X FBF(mi->fore, mi->back, Scr->MenuFont.font->fid);
X /* finally render the title */
X XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
X text_y, mi->item, mi->strlen);
X }
X}
X
X
XPaintMenu(mr, e)
XMenuRoot *mr;
XXEvent *e;
X{
X MenuItem *mi;
X
X for (mi = mr->first; mi != NULL; mi = mi->next)
X {
X int y_offset = mi->item_num * Scr->EntryHeight;
X
X /* be smart about handling the expose, redraw only the entries
X * that we need to
X */
X if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
X (e->xexpose.y + e->xexpose.height) > y_offset)
X {
X PaintEntry(mr, mi, True);
X }
X }
X XSync(dpy, 0);
X}
X
X
XUpdateMenu()
X{
X MenuItem *mi;
X int i, x, y, x_root, y_root, entry;
X int done;
X MenuItem *badItem = NULL;
X
X while (TRUE)
X {
X while (XCheckMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
X EnterWindowMask | ExposureMask, &Event))
X {
X if (!DispatchEvent ()) continue;
X if (Event.type == ButtonRelease || Cancel)
X return;
X }
X
X /* if we haven't recieved the enter notify yet, wait */
X if (ActiveMenu && !ActiveMenu->entered)
X continue;
X
X done = FALSE;
X XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
X &x_root, &y_root, &x, &y, &JunkMask);
X
X XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *)&Scr);
X
X if (x < 0 || y < 0 ||
X x >= ActiveMenu->width || y >= ActiveMenu->height)
X {
X if (ActiveItem && ActiveItem->func != F_TITLE)
X {
X ActiveItem->state = 0;
X PaintEntry(ActiveMenu, ActiveItem, False);
X }
X ActiveItem = NULL;
X continue;
X }
X
X /* look for the entry that the mouse is in */
X entry = y / Scr->EntryHeight;
X for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
X {
X if (i == entry)
X break;
X }
X
X /* if there is an active item, we might have to turn it off */
X if (ActiveItem)
X {
X /* is the active item the one we are on ? */
X if (ActiveItem->item_num == entry && ActiveItem->state)
X done = TRUE;
X
X /* if we weren't on the active entry, let's turn the old
X * active one off
X */
X if (!done && ActiveItem->func != F_TITLE)
X {
X ActiveItem->state = 0;
X PaintEntry(ActiveMenu, ActiveItem, False);
X }
X }
X
X /* if we weren't on the active item, change the active item and turn
X * it on
X */
X if (!done)
X {
X ActiveItem = mi;
X if (ActiveItem->func != F_TITLE && !ActiveItem->state)
X {
X ActiveItem->state = 1;
X PaintEntry(ActiveMenu, ActiveItem, False);
X }
X }
X
X /* now check to see if we were over the arrow of a pull right entry */
X if (ActiveItem->func == F_MENU &&
X ((ActiveMenu->width - x) < (ActiveMenu->width >> 1)))
X {
X MenuRoot *save = ActiveMenu;
X int savex = MenuOrigins[MenuDepth - 1].x;
X int savey = MenuOrigins[MenuDepth - 1].y;
X
X if (MenuDepth < MAXMENUDEPTH) {
X PopUpMenu (ActiveItem->sub, (savex + (ActiveMenu->width >> 1)),
X (savey + ActiveItem->item_num * Scr->EntryHeight +
X (Scr->EntryHeight >> 1)), False);
X } else if (!badItem) {
X XBell (dpy, 0);
X badItem = ActiveItem;
X }
X
X /* if the menu did get popped up, unhighlight the active item */
X if (save != ActiveMenu && ActiveItem->state)
X {
X ActiveItem->state = 0;
X PaintEntry(save, ActiveItem, False);
X ActiveItem = NULL;
X }
X }
X if (badItem != ActiveItem) badItem = NULL;
X XFlush(dpy);
X }
X}
X
X/***********************************************************************
X *
X * Procedure:
X * NewMenuRoot - create a new menu root
X *
X * Returned Value:
X * (MenuRoot *)
X *
X * Inputs:
X * name - the name of the menu root
X *
X ***********************************************************************
X */
X
XMenuRoot *
XNewMenuRoot(name)
X char *name;
X{
X MenuRoot *tmp;
X
X tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
X tmp->hi_fore = -1;
X tmp->hi_back = -1;
X tmp->name = name;
X tmp->prev = NULL;
X tmp->first = NULL;
X tmp->last = NULL;
X tmp->items = 0;
X tmp->width = 0;
X tmp->mapped = NEVER_MAPPED;
X tmp->pull = FALSE;
X tmp->w = None;
X tmp->shadow = None;
X tmp->real_menu = FALSE;
X
X if (Scr->MenuList == NULL)
X {
X Scr->MenuList = tmp;
X Scr->MenuList->next = NULL;
X }
X
X if (Scr->LastMenu == NULL)
X {
X Scr->LastMenu = tmp;
X Scr->LastMenu->next = NULL;
X }
X else
X {
X Scr->LastMenu->next = tmp;
X Scr->LastMenu = tmp;
X Scr->LastMenu->next = NULL;
X }
X
X if (strcmp(name, TWM_WINDOWS) == 0)
X Scr->Windows = tmp;
X
X return (tmp);
X}
X
X/***********************************************************************
X *
X * Procedure:
X * AddToMenu - add an item to a root menu
X *
X * Returned Value:
X * (MenuItem *)
X *
X * Inputs:
X * menu - pointer to the root menu to add the item
X * item - the text to appear in the menu
X * action - the string to possibly execute
X * sub - the menu root if it is a pull-right entry
X * func - the numeric function
X * fore - foreground color string
X * back - background color string
X *
X ***********************************************************************
X */
X
XMenuItem *
XAddToMenu(menu, item, action, sub, func, fore, back)
X MenuRoot *menu;
X char *item, *action;
X MenuRoot *sub;
X int func;
X char *fore, *back;
X{
X MenuItem *tmp;
X int width;
X
X#ifdef DEBUG_MENUS
X fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
X item, action, sub, func);
X#endif
X
X tmp = (MenuItem *) malloc(sizeof(MenuItem));
X tmp->root = menu;
X
X if (menu->first == NULL)
X {
X menu->first = tmp;
X tmp->prev = NULL;
X }
X else
X {
X menu->last->next = tmp;
X tmp->prev = menu->last;
X }
X menu->last = tmp;
X
X tmp->item = item;
X tmp->strlen = strlen(item);
X tmp->action = action;
X tmp->next = NULL;
X tmp->sub = NULL;
X tmp->state = 0;
X tmp->func = func;
X
X if (!Scr->HaveFonts) CreateFonts();
X width = XTextWidth(Scr->MenuFont.font, item, tmp->strlen);
X if (width <= 0)
X width = 1;
X if (width > menu->width)
X menu->width = width;
X
X tmp->user_colors = FALSE;
X if (Scr->Monochrome == COLOR && fore != NULL)
X {
X int save;
X
X save = Scr->FirstTime;
X Scr->FirstTime = TRUE;
X GetColor(COLOR, &tmp->fore, fore);
X GetColor(COLOR, &tmp->back, back);
X Scr->FirstTime = save;
X tmp->user_colors = TRUE;
X }
X if (sub != NULL)
X {
X tmp->sub = sub;
X menu->pull = TRUE;
X }
X tmp->item_num = menu->items++;
X
X return (tmp);
X}
X
XMakeMenus()
X{
X MenuRoot *mr;
X
X for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
X {
X if (mr->real_menu == FALSE)
X continue;
X
X MakeMenu(mr);
X }
X}
X
XMakeMenu(mr)
XMenuRoot *mr;
X{
X MenuItem *start, *end, *cur, *tmp;
X XColor f1, f2, f3;
X XColor b1, b2, b3;
X XColor save_fore, save_back;
X int num, i;
X int fred, fgreen, fblue;
X int bred, bgreen, bblue;
X int width;
X unsigned long valuemask;
X XSetWindowAttributes attributes;
X Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
X
X Scr->EntryHeight = Scr->MenuFont.height + 4;
X
X /* lets first size the window accordingly */
X if (mr->mapped == NEVER_MAPPED)
X {
X if (mr->pull == TRUE)
X {
X mr->width += 16 + 10;
X }
X
X width = mr->width + 10;
X
X for (cur = mr->first; cur != NULL; cur = cur->next)
X {
X if (cur->func != F_TITLE)
X cur->x = 5;
X else
X {
X cur->x = width - XTextWidth(Scr->MenuFont.font, cur->item,
X cur->strlen);
X cur->x /= 2;
X }
X }
X mr->height = mr->items * Scr->EntryHeight;
X mr->width += 10;
X
X if (Scr->Shadow)
X {
X /*
X * Make sure that you don't draw into the shadow window or else
X * the background bits there will get saved
X */
X valuemask = (CWBackPixel | CWBorderPixel);
X attributes.background_pixel = Scr->MenuShadowColor;
X attributes.border_pixel = Scr->MenuShadowColor;
X if (Scr->SaveUnder) {
X valuemask |= CWSaveUnder;
X attributes.save_under = True;
X }
X mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
X (unsigned int) mr->width,
X (unsigned int) mr->height,
X (unsigned int)0,
X CopyFromParent,
X (unsigned int) CopyFromParent,
X (Visual *) CopyFromParent,
X valuemask, &attributes);
X }
X
X valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
X attributes.background_pixel = Scr->MenuC.back;
X attributes.border_pixel = Scr->MenuC.fore;
X attributes.event_mask = (ExposureMask | EnterWindowMask);
X if (Scr->SaveUnder) {
X valuemask |= CWSaveUnder;
X attributes.save_under = True;
X }
X if (Scr->BackingStore) {
X valuemask |= CWBackingStore;
X attributes.backing_store = Always;
X }
X mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
X (unsigned int) mr->height, (unsigned int) 1,
X CopyFromParent, (unsigned int) CopyFromParent,
X (Visual *) CopyFromParent,
X valuemask, &attributes);
X
X
X XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
X XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
X
X mr->mapped = UNMAPPED;
X }
X
X /* get the default colors into the menus */
X for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
X {
X if (!tmp->user_colors) {
X if (tmp->func != F_TITLE) {
X tmp->fore = Scr->MenuC.fore;
X tmp->back = Scr->MenuC.back;
X } else {
X tmp->fore = Scr->MenuTitleC.fore;
X tmp->back = Scr->MenuTitleC.back;
X }
X }
X
X if (mr->hi_fore != -1)
X {
X tmp->hi_fore = mr->hi_fore;
X tmp->hi_back = mr->hi_back;
X }
X else
X {
X tmp->hi_fore = tmp->back;
X tmp->hi_back = tmp->fore;
X }
X }
X
X if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
X return;
X
X start = mr->first;
X while (TRUE)
X {
X for (; start != NULL; start = start->next)
X {
X if (start->user_colors)
X break;
X }
X if (start == NULL)
X break;
X
X for (end = start->next; end != NULL; end = end->next)
X {
X if (end->user_colors)
X break;
X }
X if (end == NULL)
X break;
X
X /* we have a start and end to interpolate between */
X num = end->item_num - start->item_num;
X
X f1.pixel = start->fore;
X XQueryColor(dpy, cmap, &f1);
X f2.pixel = end->fore;
X XQueryColor(dpy, cmap, &f2);
X
X b1.pixel = start->back;
X XQueryColor(dpy, cmap, &b1);
X b2.pixel = end->back;
X XQueryColor(dpy, cmap, &b2);
X
X fred = ((int)f2.red - (int)f1.red) / num;
X fgreen = ((int)f2.green - (int)f1.green) / num;
X fblue = ((int)f2.blue - (int)f1.blue) / num;
X
X bred = ((int)b2.red - (int)b1.red) / num;
X bgreen = ((int)b2.green - (int)b1.green) / num;
X bblue = ((int)b2.blue - (int)b1.blue) / num;
X
X f3 = f1;
X f3.flags = DoRed | DoGreen | DoBlue;
X
X b3 = b1;
X b3.flags = DoRed | DoGreen | DoBlue;
X
X num -= 1;
X for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
X {
X f3.red += fred;
X f3.green += fgreen;
X f3.blue += fblue;
X save_fore = f3;
X
X b3.red += bred;
X b3.green += bgreen;
X b3.blue += bblue;
X save_back = b3;
X
X XAllocColor(dpy, cmap, &f3);
X XAllocColor(dpy, cmap, &b3);
X cur->fore = f3.pixel;
X cur->back = b3.pixel;
X cur->user_colors = True;
X
X f3 = save_fore;
X b3 = save_back;
X }
X start = end;
X }
X}
X
X/***********************************************************************
X *
X * Procedure:
X * PopUpMenu - pop up a pull down menu
X *
X * Inputs:
X * menu - the root pointer of the menu to pop up
X * x, y - location of upper left of menu
X * center - whether or not to center horizontally over position
X *
X ***********************************************************************
X */
X
XBool PopUpMenu (menu, x, y, center)
X MenuRoot *menu;
X int x, y;
X Bool center;
X{
X if (!menu) return False;
X
X InstallRootColormap();
X
X if (menu == Scr->Windows)
X {
X TwmWindow *tmp_win;
X
X /* this is the twm windows menu, let's go ahead and build it */
X
X DestroyMenu (menu);
X
X menu->first = NULL;
X menu->last = NULL;
X menu->items = 0;
X menu->width = 0;
X menu->mapped = NEVER_MAPPED;
X
X AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
X for (tmp_win = Scr->TwmRoot.next;
X tmp_win != NULL;
X tmp_win = tmp_win->next)
X {
X AddToMenu (menu, tmp_win->name, (char *) tmp_win, NULL, F_POPUP,
X NULLSTR, NULLSTR);
X }
X MakeMenu(menu);
X }
X
X if (menu->w == None || menu->items == 0) return False;
X
X /* Prevent recursively bringing up menus. */
X if (menu->mapped == MAPPED) return False;
X
X /*
X * Dynamically set the parent; this allows pull-ups to also be main
X * menus, or to be brought up from more than one place.
X */
X menu->prev = ActiveMenu;
X
X XGrabPointer(dpy, Scr->Root, True,
X ButtonPressMask | ButtonReleaseMask,
X GrabModeAsync, GrabModeAsync,
X Scr->Root, Scr->MenuCursor, CurrentTime);
X
X ActiveMenu = menu;
X menu->mapped = MAPPED;
X menu->entered = FALSE;
X
X if (center) {
X x -= (menu->width / 2);
X y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */
X }
X
X /*
X * clip to screen
X */
X if (x + menu->width > Scr->MyDisplayWidth) {
X x = Scr->MyDisplayWidth - menu->width;
X }
X if (x < 0) x = 0;
X if (y + menu->height > Scr->MyDisplayHeight) {
X y = Scr->MyDisplayHeight - menu->height;
X }
X if (y < 0) y = 0;
X
X MenuOrigins[MenuDepth].x = x;
X MenuOrigins[MenuDepth].y = y;
X MenuDepth++;
X
X XMoveWindow(dpy, menu->w, x, y);
X if (Scr->Shadow) {
X XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
X }
X if (Scr->Shadow) {
X XRaiseWindow (dpy, menu->shadow);
X }
X XMapRaised(dpy, menu->w);
X if (Scr->Shadow) {
X XMapWindow (dpy, menu->shadow);
X }
X XSync(dpy, 0);
X return True;
X}
X
X/***********************************************************************
X *
X * Procedure:
X * PopDownMenu - unhighlight the current menu selection and
X * take down the menus
X *
X ***********************************************************************
X */
X
XPopDownMenu()
X{
X MenuRoot *tmp;
X
X if (ActiveMenu == NULL)
X return;
X
X if (ActiveItem)
X {
X ActiveItem->state = 0;
X PaintEntry(ActiveMenu, ActiveItem, False);
X }
X
X for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
X {
X if (Scr->Shadow) {
X XUnmapWindow (dpy, tmp->shadow);
X }
X XUnmapWindow(dpy, tmp->w);
X tmp->mapped = UNMAPPED;
X UninstallRootColormap();
X }
X
X XFlush(dpy);
X ActiveMenu = NULL;
X ActiveItem = NULL;
X MenuDepth = 0;
X}
X
X/***********************************************************************
X *
X * Procedure:
X * FindMenuRoot - look for a menu root
X *
X * Returned Value:
X * (MenuRoot *) - a pointer to the menu root structure
X *
X * Inputs:
X * name - the name of the menu root
X *
X ***********************************************************************
X */
X
XMenuRoot *
XFindMenuRoot(name)
X char *name;
X{
X MenuRoot *tmp;
X
X for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
X {
X if (strcmp(name, tmp->name) == 0)
X return (tmp);
X }
X return NULL;
X}
X
X
X/***********************************************************************
X *
X * Procedure:
X * ExecuteFunction - execute a twm root function
X *
X * Inputs:
X * func - the function to execute
X * action - the menu action to execute
X * w - the window to execute this function on
X * tmp_win - the twm window structure
X * event - the event that caused the function
X * context - the context in which the button was pressed
X * pulldown- flag indicating execution from pull down menu
X *
X * Returns:
X * TRUE if should continue with remaining actions else FALSE to abort
X *
X ***********************************************************************
X */
X
Xint
XExecuteFunction(func, action, w, tmp_win, eventp, context, pulldown)
X int func;
X char *action;
X Window w;
X TwmWindow *tmp_win;
X XEvent *eventp;
X int context;
X int pulldown;
X{
X static Time last_time = 0;
X
X char tmp[200];
X char *ptr;
X char buff[MAX_FILE_SIZE];
X int count, fd;
X Window rootw;
X int origX, origY;
X int do_next_action = TRUE;
X int moving_icon = FALSE;
X extern int ConstrainedMoveTime;
X
X RootFunction = NULL;
X if (Cancel)
X return TRUE; /* XXX should this be FALSE? */
X
X switch (func)
X {
X case F_UPICONMGR:
X case F_LEFTICONMGR:
X case F_RIGHTICONMGR:
X case F_DOWNICONMGR:
X case F_FORWICONMGR:
X case F_BACKICONMGR:
X case F_NEXTICONMGR:
X case F_PREVICONMGR:
X case F_NOP:
X case F_TITLE:
X case F_DELTASTOP:
X case F_RAISELOWER:
X case F_WARPTOSCREEN:
X case F_WARPTO:
X case F_WARPRING:
X case F_WARPTOICONMGR:
X case F_COLORMAP:
X break;
X default:
X XGrabPointer(dpy, Scr->Root, True,
X ButtonPressMask | ButtonReleaseMask,
X GrabModeAsync, GrabModeAsync,
X Scr->Root, Scr->WaitCursor, CurrentTime);
X break;
X }
X
X switch (func)
X {
X case F_NOP:
X case F_TITLE:
X break;
X
X case F_PANNER:
X if (Scr->Panner) {
X if (XFindContext (dpy, Scr->Panner, TwmContext, (caddr_t *)&tmp_win) != XCSUCCESS)
X tmp_win = AddWindow(Scr->Panner, FALSE, NULL);
X if (tmp_win->mapped) {
X UnmapFrame(tmp_win);
X tmp_win->mapped = FALSE;
X }
X else {
X if (tmp_win->icon)
X DeIconify(tmp_win);
X else
X MapFrame(tmp_win);
X tmp_win->mapped = TRUE;
X }
X }
X break;
X
X case F_SCROLLHOME:
X case F_SCROLLLEFT:
X case F_SCROLLRIGHT:
X case F_SCROLLUP:
X case F_SCROLLDOWN:
X ScrollDesktop(func);
X break;
X
X case F_DELTASTOP:
X if (WindowMoved) do_next_action = FALSE;
X break;
X
X case F_RESTART:
X XSync (dpy, 0);
X Reborder ();
X XSync (dpy, 0);
X execvp(*Argv, Argv);
X fprintf (stderr, "%s: unable to restart: %s\n", ProgramName, *Argv);
X break;
X
X case F_UPICONMGR:
X case F_DOWNICONMGR:
X case F_LEFTICONMGR:
X case F_RIGHTICONMGR:
X case F_FORWICONMGR:
X case F_BACKICONMGR:
X MoveIconManager(func);
X break;
X
X case F_NEXTICONMGR:
X case F_PREVICONMGR:
X JumpIconManager(func);
X break;
X
X case F_SHOWLIST:
X if (Scr->NoIconManagers)
X break;
X DeIconify(Scr->iconmgr.twm_win);
X RaiseFrame(Scr->iconmgr.twm_win);
X break;
X
X case F_HIDELIST:
X if (Scr->NoIconManagers)
X break;
X HideIconManager ();
X break;
X
X case F_STICK:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X if (Scr->VirtualDesktop) {
X int x, y;
X Window junkChild;
X
X if (tmp_win->sticky) {
X XReparentWindow(dpy, tmp_win->frame, Scr->VirtualDesktop,
X tmp_win->frame_x + Scr->vdtPositionX,
X tmp_win->frame_y + Scr->vdtPositionY);
X if (tmp_win->icon_w) {
X XReparentWindow(dpy, tmp_win->icon_w, Scr->VirtualDesktop,
X tmp_win->icon_loc_x + Scr->vdtPositionX,
X tmp_win->icon_loc_y + Scr->vdtPositionY);
X tmp_win->icon_loc_x += Scr->vdtPositionX;
X tmp_win->icon_loc_y += Scr->vdtPositionY;
X }
X if (!tmp_win->icon)
X XMapRaised(dpy, tmp_win->virtualWindow);
X else if (tmp_win->virtualIcon)
X XMapRaised(dpy, tmp_win->virtualIcon);
X tmp_win->root = Scr->VirtualDesktop;
X tmp_win->frame_x += Scr->vdtPositionX;
X tmp_win->frame_y += Scr->vdtPositionY;
X tmp_win->sticky = False;
X SetSWM_ROOT(tmp_win);
X SetTWM_FLAGS(tmp_win);
X }
X else {
X XReparentWindow(dpy, tmp_win->frame, Scr->Root,
X tmp_win->frame_x - Scr->vdtPositionX,
X tmp_win->frame_y - Scr->vdtPositionY);
X if (tmp_win->icon_w) {
X XReparentWindow(dpy, tmp_win->icon_w, Scr->Root,
X tmp_win->icon_loc_x - Scr->vdtPositionX,
X tmp_win->icon_loc_y - Scr->vdtPositionY);
X tmp_win->icon_loc_x -= Scr->vdtPositionX;
X tmp_win->icon_loc_y -= Scr->vdtPositionY;
X }
X XUnmapWindow(dpy, tmp_win->virtualWindow);
X if (tmp_win->virtualIcon)
X XUnmapWindow(dpy, tmp_win->virtualIcon);
X tmp_win->root = Scr->Root;
X tmp_win->frame_x -= Scr->vdtPositionX;
X tmp_win->frame_y -= Scr->vdtPositionY;
X tmp_win->sticky = True;
X SetSWM_ROOT(tmp_win);
X SetTWM_FLAGS(tmp_win);
X }
X }
X break;
X
X case F_SORTICONMGR:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X {
X int save_sort;
X
X save_sort = Scr->SortIconMgr;
X Scr->SortIconMgr = TRUE;
X
X if (context == C_ICONMGR)
X SortIconManager((IconMgr *) NULL);
X else if (tmp_win->iconmgr)
X SortIconManager(tmp_win->iconmgrp);
X else
X XBell(dpy, 0);
X
X Scr->SortIconMgr = save_sort;
X }
X break;
X
X case F_IDENTIFY:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X Identify(tmp_win);
X break;
X
X case F_VERSION:
X Identify ((TwmWindow *) NULL);
X break;
X
X case F_AUTORAISE:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X tmp_win->auto_raise = !tmp_win->auto_raise;
X break;
X
X case F_BEEP:
X XBell(dpy, 0);
X break;
X
X case F_POPUP:
X tmp_win = (TwmWindow *)action;
X if (Scr->WindowFunction.func != NULL)
X {
X ExecuteFunction(Scr->WindowFunction.func,
X Scr->WindowFunction.item->action,
X w, tmp_win, eventp, C_FRAME, FALSE);
X }
X else
X {
X DeIconify(tmp_win);
X if (Scr->VirtualDesktop)
X ScrollToQuadrant(tmp_win);
X RaiseFrame (tmp_win);
X }
X break;
X
X case F_RESIZE:
X EventHandler[EnterNotify] = HandleUnknown;
X EventHandler[LeaveNotify] = HandleUnknown;
X if (DeferExecution(context, func, Scr->MoveCursor))
X return TRUE;
X
X PopDownMenu();
X
X if (pulldown)
X XWarpPointer(dpy, None, Scr->Root,
X 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
X
X if (w != tmp_win->icon_w) { /* can't resize icons */
X Bool fromtitlebar = False; /* controls AutoRelativeResizing */
X
X /*
X * see if this is being done from the titlebar
X */
X if (tmp_win && tmp_win->titlebuttons) {
X register TBWindow *tbw;
X register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
X for (tbw = tmp_win->titlebuttons; nb > 0; tbw++, nb--) {
X if (tbw->window == w) {
X fromtitlebar = True;
X break;
X }
X }
X }
X
X StartResize (eventp, tmp_win, fromtitlebar);
X return TRUE;
X }
X break;
X
X
X case F_ZOOM:
X case F_HORIZOOM:
X case F_FULLZOOM:
X case F_LEFTZOOM:
X case F_RIGHTZOOM:
X case F_TOPZOOM:
X case F_BOTTOMZOOM:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X fullzoom(tmp_win, func);
X break;
X
X case F_MOVE:
X case F_FORCEMOVE:
X if (DeferExecution(context, func, Scr->MoveCursor))
X return TRUE;
X
X PopDownMenu();
X rootw = eventp->xbutton.root;
X MoveFunction = func;
X
X if (pulldown)
X XWarpPointer(dpy, None, Scr->Root,
X 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
X
X if (context == C_ICON && tmp_win->icon_w)
X {
X DragIcon(tmp_win, eventp, pulldown);
X }
X else if (w != tmp_win->icon_w)
X {
X DragFrame(tmp_win, eventp, pulldown);
X }
X#ifdef OLD_MOVE
X if (DeferExecution(context, func, Scr->MoveCursor))
X return TRUE;
X
X PopDownMenu();
X rootw = eventp->xbutton.root;
X MoveFunction = func;
X
X if (pulldown)
X XWarpPointer(dpy, None, Scr->Root,
X 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
X
X EventHandler[EnterNotify] = HandleUnknown;
X EventHandler[LeaveNotify] = HandleUnknown;
X
X if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
X XGrabServer(dpy);
X }
X XGrabPointer(dpy, eventp->xbutton.root, True,
X ButtonPressMask | ButtonReleaseMask,
X GrabModeAsync, GrabModeAsync,
X Scr->Root, Scr->MoveCursor, CurrentTime);
X
X if (context == C_ICON && tmp_win->icon_w)
X {
X w = tmp_win->icon_w;
X DragVirtual = tmp_win->virtualIcon;
X DragX = eventp->xbutton.x;
X DragY = eventp->xbutton.y;
X moving_icon = TRUE;
X }
X else if (w != tmp_win->icon_w)
X {
X XTranslateCoordinates(dpy, w, tmp_win->frame,
X eventp->xbutton.x,
X eventp->xbutton.y,
X &DragX, &DragY, &JunkChild);
X
X w = tmp_win->frame;
X DragVirtual = tmp_win->virtualWindow;
X }
X
X DragWindow = None;
X
X XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
X (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW,
X &JunkDepth);
X
X origX = eventp->xbutton.x_root;
X origY = eventp->xbutton.y_root;
X CurrentDragX = origDragX;
X CurrentDragY = origDragY;
X
X /*
X * only do the constrained move if timer is set; need to check it
X * in case of stupid or wicked fast servers
X */
X if (ConstrainedMoveTime &&
X (eventp->xbutton.time - last_time) < ConstrainedMoveTime)
X {
X int width, height;
X
X ConstMove = TRUE;
X ConstMoveDir = MOVE_NONE;
X ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
X ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
X width = DragWidth + 2 * JunkBW;
X height = DragHeight + 2 * JunkBW;
X ConstMoveXL = ConstMoveX + width/3;
X ConstMoveXR = ConstMoveX + 2*(width/3);
X ConstMoveYT = ConstMoveY + height/3;
X ConstMoveYB = ConstMoveY + 2*(height/3);
X
X XWarpPointer(dpy, None, w,
X 0, 0, 0, 0, DragWidth/2, DragHeight/2);
X
X XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
X &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
X }
X last_time = eventp->xbutton.time;
X
X if (!Scr->OpaqueMove)
X InstallRootColormap();
X
X while (TRUE)
X {
X int done;
X
X done = FALSE;
X while (XCheckMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
X EnterWindowMask | LeaveWindowMask |
X ExposureMask, &Event))
X {
X /* throw away enter and leave events until release */
X if (Event.xany.type == EnterNotify ||
X Event.xany.type == LeaveNotify) continue;
X
X if (!DispatchEvent ()) continue;
X
X if (Cancel)
X {
X WindowMoved = FALSE;
X if (!Scr->OpaqueMove)
X UninstallRootColormap();
X return TRUE; /* XXX should this be FALSE? */
X }
X if (Event.type == ButtonRelease)
X {
X MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
X done = TRUE;
X if (moving_icon &&
X ((CurrentDragX != origDragX ||
X CurrentDragY != origDragY)))
X tmp_win->icon_moved = TRUE;
X break;
X }
X }
X
X if (done)
X break;
X
X /*
X * WARNING - mashing event
X */
X XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
X &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
X &JunkX, &JunkY, &JunkMask);
X
X if (DragWindow == None &&
X abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
X abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
X continue;
X
X WindowMoved = TRUE;
X DragWindow = w;
X
X if (!Scr->NoRaiseMove && Scr->OpaqueMove) /* can't restore... */
X XRaiseWindow(dpy, DragWindow);
X
X if (ConstMove)
X {
X switch (ConstMoveDir)
X {
X case MOVE_NONE:
X if (eventp->xmotion.x_root < ConstMoveXL ||
X eventp->xmotion.x_root > ConstMoveXR)
X ConstMoveDir = MOVE_HORIZ;
X
X if (eventp->xmotion.y_root < ConstMoveYT ||
X eventp->xmotion.y_root > ConstMoveYB)
X ConstMoveDir = MOVE_VERT;
X
X XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
X &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
X break;
X
X case MOVE_VERT:
X ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
X break;
X
X case MOVE_HORIZ:
X ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
X break;
X }
X
X if (ConstMoveDir != MOVE_NONE)
X {
X int xl, yt, xr, yb, w, h;
X
X xl = ConstMoveX;
X yt = ConstMoveY;
X w = DragWidth + 2 * JunkBW;
X h = DragHeight + 2 * JunkBW;
X
X if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
X {
X xr = xl + w;
X yb = yt + h;
X
X if (xl < 0)
X xl = 0;
X if (xr > Scr->MyDisplayWidth)
X xl = Scr->MyDisplayWidth - w;
X
X if (yt < 0)
X yt = 0;
X if (yb > Scr->MyDisplayHeight)
X yt = Scr->MyDisplayHeight - h;
X }
X CurrentDragX = xl;
X CurrentDragY = yt;
X if (Scr->OpaqueMove)
X XMoveWindow(dpy, DragWindow, xl, yt);
X else
X MoveOutline(eventp->xmotion.root, xl, yt, w, h,
X tmp_win->frame_bw,
X moving_icon ? 0 : tmp_win->title_height);
X }
X }
X else if (DragWindow != None)
X {
X int xl, yt, xr, yb, w, h;
X
X xl = eventp->xmotion.x_root - DragX - JunkBW;
X yt = eventp->xmotion.y_root - DragY - JunkBW;
X w = DragWidth + 2 * JunkBW;
X h = DragHeight + 2 * JunkBW;
X
X if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
X {
X xr = xl + w;
X yb = yt + h;
X
X if (xl < 0)
X xl = 0;
X if (xr > Scr->MyDisplayWidth)
X xl = Scr->MyDisplayWidth - w;
X
X if (yt < 0)
X yt = 0;
X if (yb > Scr->MyDisplayHeight)
X yt = Scr->MyDisplayHeight - h;
X }
X
X CurrentDragX = xl;
X CurrentDragY = yt;
X if (Scr->OpaqueMove)
X XMoveWindow(dpy, DragWindow, xl, yt);
X else
X MoveOutline(eventp->xmotion.root, xl, yt, w, h,
X tmp_win->frame_bw,
X moving_icon ? 0 : tmp_win->title_height);
X }
X
X }
X
X if (!Scr->OpaqueMove && DragWindow == None)
X UninstallRootColormap();
X#endif /* OLD_MOVE */
X break;
X
X case F_FUNCTION:
X {
X MenuRoot *mroot;
X MenuItem *mitem;
X
X if ((mroot = FindMenuRoot(action)) == NULL)
X {
X fprintf (stderr, "%s: couldn't find function \"%s\"\n",
X ProgramName, action);
X return TRUE;
X }
X
X if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X else
X {
X for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
X {
X if (!ExecuteFunction (mitem->func, mitem->action, w,
X tmp_win, eventp, context, pulldown))
X break;
X }
X }
X }
X break;
X
X case F_DEICONIFY:
X case F_ICONIFY:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X if (tmp_win->icon)
X {
X DeIconify(tmp_win);
X }
X else if (func == F_ICONIFY)
X {
X Iconify (tmp_win, eventp->xbutton.x_root - 5,
X eventp->xbutton.y_root - 5);
X }
X break;
X
X case F_RAISELOWER:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X if (!WindowMoved) {
X Window virtual;
X XWindowChanges xwc;
X
X xwc.stack_mode = Opposite;
X virtual = tmp_win->virtualIcon;
X if (w != tmp_win->icon_w) {
X w = tmp_win->frame;
X virtual = tmp_win->virtualWindow;
X }
X XConfigureWindow (dpy, w, CWStackMode, &xwc);
X if (tmp_win->sticky && Scr->VirtualDesktop)
X XLowerWindow(dpy, Scr->VirtualDesktop);
X if (virtual)
X XConfigureWindow (dpy, virtual, CWStackMode, &xwc);
X }
X break;
X
X case F_RAISE:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X if (w == tmp_win->icon_w)
X RaiseIcon(tmp_win);
X else
X RaiseFrame(tmp_win);
X
X break;
X
X case F_LOWER:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X if (w == tmp_win->icon_w)
X LowerIcon(tmp_win);
X else
X LowerFrame(tmp_win);
X
X break;
X
X case F_FOCUS:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X if (tmp_win->icon == FALSE)
X {
X if (!Scr->FocusRoot && Scr->Focus == tmp_win)
X {
X FocusOnRoot();
X }
X else
X {
X if (Scr->Focus != NULL) {
X SetBorder (Scr->Focus, False);
X if (Scr->Focus->hilite_w)
X XUnmapWindow (dpy, Scr->Focus->hilite_w);
X }
X
X InstallWindowColormaps (0, tmp_win);
X if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w);
X SetBorder (tmp_win, True);
X SetFocus (tmp_win);
X Scr->FocusRoot = FALSE;
X Scr->Focus = tmp_win;
X }
X }
X break;
X
X case F_DESTROY:
X if (DeferExecution(context, func, Scr->DestroyCursor))
X return TRUE;
X
X if (tmp_win->iconmgr)
X XBell(dpy, 0);
X else if (tmp_win->w == Scr->Panner) {
X UnmapFrame(tmp_win);
X tmp_win->mapped = FALSE;
X }
X else
X XKillClient(dpy, tmp_win->w);
X break;
X
X case F_DELETE:
X if (DeferExecution(context, func, Scr->DestroyCursor))
X return TRUE;
X
X if (tmp_win->iconmgr) /* don't send ourself a message */
X HideIconManager ();
X else if (tmp_win->protocols & DoesWmDeleteWindow)
X SendDeleteWindowMessage (tmp_win, LastTimestamp());
X else
X XBell (dpy, 0);
X break;
X
X case F_SAVEYOURSELF:
X if (DeferExecution (context, func, Scr->SelectCursor))
X return TRUE;
X
X if (tmp_win->protocols & DoesWmSaveYourself)
X SendSaveYourselfMessage (tmp_win, LastTimestamp());
X else
X XBell (dpy, 0);
X break;
X
X case F_CIRCLEUP:
X XCirculateSubwindowsUp(dpy, Scr->Root);
X break;
X
X case F_CIRCLEDOWN:
X XCirculateSubwindowsDown(dpy, Scr->Root);
X break;
X
X case F_EXEC:
X PopDownMenu();
X if (!Scr->NoGrabServer) {
X XUngrabServer (dpy);
X XSync (dpy, 0);
X }
X Execute(action);
X break;
X
X case F_UNFOCUS:
X FocusOnRoot();
X break;
X
X case F_CUT:
X strcpy(tmp, action);
X strcat(tmp, "\n");
X XStoreBytes(dpy, tmp, strlen(tmp));
X break;
X
X case F_CUTFILE:
X ptr = XFetchBytes(dpy, &count);
X if (ptr) {
X if (sscanf (ptr, "%s", tmp) == 1) {
X XFree (ptr);
X ptr = ExpandFilename(tmp);
X if (ptr) {
X fd = open (ptr, 0);
X if (fd >= 0) {
X count = read (fd, buff, MAX_FILE_SIZE - 1);
X if (count > 0) XStoreBytes (dpy, buff, count);
X close(fd);
X } else {
X fprintf (stderr,
X "%s: unable to open cut file \"%s\"\n",
X ProgramName, tmp);
X }
X if (ptr != tmp) free (ptr);
X }
X } else {
X XFree(ptr);
X }
X } else {
X fprintf(stderr, "%s: cut buffer is empty\n", ProgramName);
X }
X break;
X
X case F_WARPTOSCREEN:
X {
X if (strcmp (action, WARPSCREEN_NEXT) == 0) {
X WarpToScreen (Scr->screen + 1, 1);
X } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
X WarpToScreen (Scr->screen - 1, -1);
X } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
X WarpToScreen (PreviousScreen, 0);
X } else {
X WarpToScreen (atoi (action), 0);
X }
X }
X break;
X
X case F_COLORMAP:
X {
X if (strcmp (action, COLORMAP_NEXT) == 0) {
X BumpWindowColormap (tmp_win, 1);
X } else if (strcmp (action, COLORMAP_PREV) == 0) {
X BumpWindowColormap (tmp_win, -1);
X } else {
X BumpWindowColormap (tmp_win, 0);
X }
X }
X break;
X
X case F_WARPTO:
X {
X register TwmWindow *t;
X int len;
X
X len = strlen(action);
X
X for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
X if (!strncmp(action, t->name, len)) break;
X }
X if (!t) {
X for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
X if (!strncmp(action, t->class.res_name, len)) break;
X }
X if (!t) {
X for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
X if (!strncmp(action, t->class.res_class, len)) break;
X }
X }
X }
X
X if (t) {
X if (Scr->WarpUnmapped || t->mapped) {
X if (!t->mapped) DeIconify (t);
X RaiseFrame (t);
X WarpToWindow (t);
X }
X } else {
X XBell (dpy, 0);
X }
X }
X break;
X
X case F_WARPTOICONMGR:
X {
X TwmWindow *t;
X int len;
X Window raisewin = None, iconwin = None;
X TwmWindow *raiseFrame;
X
X len = strlen(action);
X if (len == 0) {
X if (tmp_win && tmp_win->list) {
X raisewin = tmp_win->list->iconmgr->twm_win->frame;
X raiseFrame = tmp_win->list->iconmgr->twm_win;
X iconwin = tmp_win->list->icon;
X } else if (Scr->iconmgr.active) {
X raisewin = Scr->iconmgr.twm_win->frame;
X raiseFrame = Scr->iconmgr.twm_win;
X iconwin = Scr->iconmgr.active->w;
X }
X } else {
X for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
X if (strncmp (action, t->icon_name, len) == 0) {
X if (t->list && t->list->iconmgr->twm_win->mapped) {
X raisewin = t->list->iconmgr->twm_win->frame;
X raiseFrame = t->list->iconmgr->twm_win;
X iconwin = t->list->icon;
X break;
X }
X }
X }
X }
X
X if (raisewin) {
X RaiseFrame (raiseFrame);
X XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
X } else {
X XBell (dpy, 0);
X }
X }
X break;
X
X case F_WARPRING:
X switch (action[0]) {
X case 'n':
X WarpAlongRing (&eventp->xbutton, True);
X break;
X case 'p':
X WarpAlongRing (&eventp->xbutton, False);
X break;
X default:
X XBell (dpy, 0);
X break;
X }
X break;
X
X case F_FILE:
X action = ExpandFilename(action);
X fd = open(action, 0);
X if (fd >= 0)
X {
X count = read(fd, buff, MAX_FILE_SIZE - 1);
X if (count > 0)
X XStoreBytes(dpy, buff, count);
X
X close(fd);
X }
X else
X {
X fprintf (stderr, "%s: unable to open file \"%s\"\n",
X ProgramName, action);
X }
X break;
X
X case F_REFRESH:
X {
X XSetWindowAttributes attributes;
X unsigned long valuemask;
X
X valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
X attributes.background_pixel = Scr->Black;
X attributes.backing_store = NotUseful;
X attributes.save_under = False;
X w = XCreateWindow (dpy, Scr->Root, 0, 0,
X (unsigned int) Scr->MyDisplayWidth,
X (unsigned int) Scr->MyDisplayHeight,
X (unsigned int) 0,
X CopyFromParent, (unsigned int) CopyFromParent,
X (Visual *) CopyFromParent, valuemask,
X &attributes);
X XMapWindow (dpy, w);
X XDestroyWindow (dpy, w);
X XFlush (dpy);
X }
X break;
X
X case F_WINREFRESH:
X if (DeferExecution(context, func, Scr->SelectCursor))
X return TRUE;
X
X if (context == C_ICON && tmp_win->icon_w)
X w = XCreateSimpleWindow(dpy, tmp_win->icon_w,
X 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
X else
X w = XCreateSimpleWindow(dpy, tmp_win->frame,
X 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
X
X XMapWindow(dpy, w);
X XDestroyWindow(dpy, w);
X XFlush(dpy);
X break;
X
X case F_QUIT:
X Done();
X break;
X }
X
X if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
X return do_next_action;
X}
X
X/***********************************************************************
X *
X * Procedure:
X * DeferExecution - defer the execution of a function to the
X * next button press if the context is C_ROOT
X *
X * Inputs:
X * context - the context in which the mouse button was pressed
X * func - the function to defer
X * cursor - the cursor to display while waiting
X *
X ***********************************************************************
X */
X
Xint
XDeferExecution(context, func, cursor)
Xint context, func;
XCursor cursor;
X{
X if (context == C_ROOT)
X {
X LastCursor = cursor;
X XGrabPointer(dpy, Scr->Root, True,
X ButtonPressMask | ButtonReleaseMask,
X GrabModeAsync, GrabModeAsync,
X Scr->Root, cursor, CurrentTime);
X
X RootFunction = func;
X
X return (TRUE);
X }
X
X return (FALSE);
X}
X
X
X/***********************************************************************
X *
X * Procedure:
X * ReGrab - regrab the pointer with the LastCursor;
X *
X ***********************************************************************
X */
X
XReGrab()
X{
X XGrabPointer(dpy, Scr->Root, True,
X ButtonPressMask | ButtonReleaseMask,
X GrabModeAsync, GrabModeAsync,
X Scr->Root, LastCursor, CurrentTime);
X}
X
X/***********************************************************************
X *
X * Procedure:
X * NeedToDefer - checks each function in the list to see if it
X * is one that needs to be defered.
X *
X * Inputs:
X * root - the menu root to check
X *
X ***********************************************************************
X */
X
XNeedToDefer(root)
XMenuRoot *root;
X{
X MenuItem *mitem;
X
X for (mitem = root->first; mitem != NULL; mitem = mitem->next)
X {
X switch (mitem->func)
X {
X case F_IDENTIFY:
X case F_RESIZE:
X case F_MOVE:
X case F_FORCEMOVE:
X case F_DEICONIFY:
X case F_ICONIFY:
X case F_RAISELOWER:
X case F_RAISE:
X case F_LOWER:
X case F_FOCUS:
X case F_DESTROY:
X case F_WINREFRESH:
X case F_ZOOM:
X case F_FULLZOOM:
X case F_HORIZOOM:
X case F_RIGHTZOOM:
X case F_LEFTZOOM:
X case F_TOPZOOM:
X case F_BOTTOMZOOM:
X case F_AUTORAISE:
X return TRUE;
X }
X }
X return FALSE;
X}
X
X/***********************************************************************
X *
X * Procedure:
X * Execute - execute the string by /bin/sh
X *
X * Inputs:
X * s - the string containing the command
X *
X ***********************************************************************
X */
X
Xvoid
XExecute(s)
X char *s;
X{
X static char buf[256];
X char *ds = DisplayString (dpy);
X char *colon, *dot1;
X char oldDisplay[256];
X char *doisplay;
X int restorevar = 0;
X
X oldDisplay[0] = '\0';
X doisplay=getenv("DISPLAY");
X if (doisplay)
X strcpy (oldDisplay, doisplay);
X
X /*
X * Build a display string using the current screen number, so that
X * X programs which get fired up from a menu come up on the screen
X * that they were invoked from, unless specifically overridden on
X * their command line.
X */
X colon = rindex (ds, ':');
X if (colon) { /* if host[:]:dpy */
X strcpy (buf, "DISPLAY=");
X strcat (buf, ds);
X colon = buf + 8 + (colon - ds); /* use version in buf */
X dot1 = index (colon, '.'); /* first period after colon */
X if (!dot1) dot1 = colon + strlen (colon); /* if not there, append */
X (void) sprintf (dot1, ".%d", Scr->screen);
X putenv (buf);
X restorevar = 1;
X }
X
X (void) system (s);
X
X if (restorevar) { /* why bother? */
X (void) sprintf (buf, "DISPLAY=%s", oldDisplay);
X putenv (buf);
X }
X}
X
X/***********************************************************************
X *
X * Procedure:
X * FocusOnRoot - put input focus on the root window
X *
X ***********************************************************************
X */
X
Xvoid
XFocusOnRoot()
X{
X SetFocus ((TwmWindow *) NULL);
X if (Scr->Focus != NULL)
X {
X SetBorder (Scr->Focus, False);
X if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w);
X }
X InstallWindowColormaps(0, &Scr->TwmRoot);
X Scr->Focus = NULL;
X Scr->FocusRoot = TRUE;
X}
X
XDeIconify(tmp_win)
XTwmWindow *tmp_win;
X{
X TwmWindow *t;
X
X /* de-iconify group members (if any) */
X if (tmp_win->group == tmp_win->w)
X {
X for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
X {
X if (tmp_win->group == t->group &&
X tmp_win->group != t->w && t->icon)
X {
X if (t->icon_on)
X Zoom(t->icon_w, t->frame);
X else
X Zoom(tmp_win->icon_w, t->frame);
X
X t->mapped = TRUE;
X if (!Scr->NoRaiseDeicon)
X RaiseFrame(t);
X MapFrame(t);
X SetMapStateProp(t, NormalState);
X
X if (t->icon_w) {
X UnmapIcon(t);
X IconDown (t);
X }
X if (t->list) XUnmapWindow(dpy, t->list->icon);
X t->icon = FALSE;
X t->icon_on = FALSE;
X }
X }
X }
X
X /* now de-iconify the main window */
X if (tmp_win->icon)
X {
X if (tmp_win->icon_on)
X Zoom(tmp_win->icon_w, tmp_win->frame);
X else if (tmp_win->group != NULL)
X {
X for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
X {
X if (tmp_win->group == t->w && t->icon_on)
X {
X Zoom(t->icon_w, tmp_win->frame);
X break;
X }
X }
X }
X }
X
X
X tmp_win->mapped = TRUE;
X if (!Scr->NoRaiseDeicon)
X RaiseFrame(tmp_win);
X MapFrame(tmp_win);
X SetMapStateProp(tmp_win, NormalState);
X
X if (tmp_win->icon_w) {
X UnmapIcon(tmp_win);
X IconDown (tmp_win);
X }
X if (tmp_win->list)
X XUnmapWindow(dpy, tmp_win->list->icon);
X if ((Scr->WarpCursor ||
X LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)) &&
X tmp_win->icon)
X WarpToWindow (tmp_win);
X tmp_win->icon = FALSE;
X tmp_win->icon_on = FALSE;
X XSync (dpy, 0);
X}
X
XIconify(tmp_win, def_x, def_y)
XTwmWindow *tmp_win;
Xint def_x, def_y;
X{
X TwmWindow *t;
X int iconify;
X XWindowAttributes winattrs;
X unsigned long eventMask;
X
X iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
X if (iconify)
X {
X if (tmp_win->icon_w == NULL)
X CreateIconWindow(tmp_win, def_x, def_y);
X else
X IconUp(tmp_win);
X MapIcon(tmp_win);
X }
X if (tmp_win->list)
X XMapWindow(dpy, tmp_win->list->icon);
X
X XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
X eventMask = winattrs.your_event_mask;
X
X /* iconify group members first */
X if (tmp_win->group == tmp_win->w)
X {
X for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
X {
X if (tmp_win->group == t->group && tmp_win->group != t->w)
X {
X if (iconify)
X {
X if (t->icon_on)
X Zoom(t->icon_w, tmp_win->icon_w);
X else
X Zoom(t->frame, tmp_win->icon_w);
X }
X
X /*
X * Prevent the receipt of an UnmapNotify, since that would
X * cause a transition to the Withdrawn state.
X */
X t->mapped = FALSE;
X XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
X UnmapFrame(t);
X XSelectInput(dpy, t->w, eventMask);
X if (t->icon_w)
X UnmapIcon(t);
X SetMapStateProp(t, IconicState);
X SetBorder (t, False);
X if (t == Scr->Focus)
X {
X SetFocus ((TwmWindow *) NULL);
X Scr->Focus = NULL;
X Scr->FocusRoot = TRUE;
X }
X if (t->list) XMapWindow(dpy, t->list->icon);
X t->icon = TRUE;
X t->icon_on = FALSE;
X }
X }
X }
X
X if (iconify)
X Zoom(tmp_win->frame, tmp_win->icon_w);
X
X /*
X * Prevent the receipt of an UnmapNotify, since that would
X * cause a transition to the Withdrawn state.
X */
X tmp_win->mapped = FALSE;
X XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
X UnmapFrame(tmp_win);
X XSelectInput(dpy, tmp_win->w, eventMask);
X SetMapStateProp(tmp_win, IconicState);
X
X SetBorder (tmp_win, False);
X if (tmp_win == Scr->Focus)
X {
X SetFocus ((TwmWindow *) NULL);
X Scr->Focus = NULL;
X Scr->FocusRoot = TRUE;
X }
X tmp_win->icon = TRUE;
X if (iconify)
X tmp_win->icon_on = TRUE;
X else
X tmp_win->icon_on = FALSE;
X XSync (dpy, 0);
X}
X
Xstatic void Identify (t)
XTwmWindow *t;
X{
X int i, n, twidth, width, height;
X int x, y;
X unsigned int wwidth, wheight, bw, depth;
X Window junk;
X int px, py, dummy;
X unsigned udummy;
X
X n = 0;
X (void) sprintf(Info[n++], "tvtwm version: %s", Version);
X (void) sprintf(Info[n++], "Patchlevel %d", PATCHLEVEL);
X Info[n++][0] = '\0';
X
X if (t) {
X XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
X &wwidth, &wheight, &bw, &depth);
X (void) XTranslateCoordinates (dpy, t->w, Scr->Root, JunkX, JunkY,
X &x, &y, &junk);
X (void) sprintf(Info[n++], "Name = \"%s\"", t->full_name);
X (void) sprintf(Info[n++], "Class.res_name = \"%s\"", t->class.res_name);
X (void) sprintf(Info[n++], "Class.res_class = \"%s\"", t->class.res_class);
X Info[n++][0] = '\0';
X (void) sprintf(Info[n++], "Geometry/root = %dx%d+%d+%d", wwidth, wheight,
X x, y);
X (void) sprintf(Info[n++], "Border width = %d", bw);
X (void) sprintf(Info[n++], "Depth = %d", depth);
X }
X
X Info[n++][0] = '\0';
X (void) sprintf(Info[n++], "Click to dismiss....");
X
X /* figure out the width and height of the info window */
X height = n * (Scr->DefaultFont.height+2);
X width = 1;
X for (i = 0; i < n; i++)
X {
X twidth = XTextWidth(Scr->DefaultFont.font, Info[i],
X strlen(Info[i]));
X if (twidth > width)
X width = twidth;
X }
X if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
X
X width += 10; /* some padding */
X if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py,
X &dummy, &dummy, &udummy)) {
X px -= (width / 2);
X py -= (height / 3);
X if (px + width + BW2 >= Scr->MyDisplayWidth)
X px = Scr->MyDisplayWidth - width - BW2;
X if (py + height + BW2 >= Scr->MyDisplayHeight)
X py = Scr->MyDisplayHeight - height - BW2;
X if (px < 0) px = 0;
X if (py < 0) py = 0;
X } else {
X px = py = 0;
X }
X XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
X XMapRaised(dpy, Scr->InfoWindow);
X InfoLines = n;
X}
X
XSetMapStateProp(tmp_win, state)
XTwmWindow *tmp_win;
Xint state;
X{
X unsigned long data[2]; /* "suggested" by ICCCM version 1 */
X
X data[0] = (unsigned long) state;
X data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
X tmp_win->icon_w);
X
X XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
X PropModeReplace, (unsigned char *) data, 2);
X}
X
XBool GetWMState (w, statep, iwp)
X Window w;
X int *statep;
X Window *iwp;
X{
X Atom actual_type;
X int actual_format;
X unsigned long nitems, bytesafter;
X unsigned long *datap = NULL;
X Bool retval = False;
X
X if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
X &actual_type, &actual_format, &nitems, &bytesafter,
X (unsigned char **) &datap) != Success || !datap)
X return False;
X
X if (nitems <= 2) { /* "suggested" by ICCCM version 1 */
X *statep = (int) datap[0];
X *iwp = (Window) datap[1];
X retval = True;
X }
X
X XFree ((char *) datap);
X return retval;
X}
X
X
XWarpToScreen (n, inc)
X int n, inc;
X{
X Window dumwin;
X int x, y, dumint;
X unsigned int dummask;
X ScreenInfo *newscr = NULL;
X
X while (!newscr) {
X /* wrap around */
X if (n < 0)
X n = NumScreens - 1;
X else if (n >= NumScreens)
X n = 0;
X
X newscr = ScreenList[n];
X if (!newscr) { /* make sure screen is managed */
X if (inc) { /* walk around the list */
X n += inc;
X continue;
X }
X fprintf (stderr, "%s: unable to warp to unmanaged screen %d\n",
X ProgramName, n);
X XBell (dpy, 0);
X return;
X }
X }
X
X if (Scr->screen == n) return; /* already on that screen */
X
X PreviousScreen = Scr->screen;
X XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
X &dumint, &dumint, &dummask);
X
X XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
X return;
X}
X
X
X/*
X * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
X */
X
XBumpWindowColormap (tmp, inc)
X TwmWindow *tmp;
X int inc;
X{
X int i, j, previously_installed;
X ColormapWindow **cwins;
X
X if (!tmp) return;
X
X if (inc && tmp->cmaps.number_cwins > 0) {
X cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
X tmp->cmaps.number_cwins);
X if (cwins) {
X if (previously_installed = (Scr->cmapInfo.cmaps == &tmp->cmaps &&
X tmp->cmaps.number_cwins)) {
X for (i = tmp->cmaps.number_cwins; i-- > 0; )
X tmp->cmaps.cwins[i]->colormap->state = 0;
X }
X
X for (i = 0; i < tmp->cmaps.number_cwins; i++) {
X j = i - inc;
X if (j >= tmp->cmaps.number_cwins)
X j -= tmp->cmaps.number_cwins;
X else if (j < 0)
X j += tmp->cmaps.number_cwins;
X cwins[j] = tmp->cmaps.cwins[i];
X }
X
X free((char *) tmp->cmaps.cwins);
X
X tmp->cmaps.cwins = cwins;
X
X if (tmp->cmaps.number_cwins > 1)
X bzero (tmp->cmaps.scoreboard,
X ColormapsScoreboardLength(&tmp->cmaps));
X
X if (previously_installed)
X InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
X }
X } else
X FetchWmColormapWindows (tmp);
X}
X
XHideIconManager ()
X{
X SetMapStateProp (Scr->iconmgr.twm_win, WithdrawnState);
X UnmapFrame(Scr->iconmgr.twm_win);
X if (Scr->iconmgr.twm_win->icon_w)
X UnmapIcon(Scr->iconmgr.twm_win);
X Scr->iconmgr.twm_win->mapped = FALSE;
X Scr->iconmgr.twm_win->icon = TRUE;
X}
X
X
XSetBorder (tmp, onoroff)
X TwmWindow *tmp;
X Bool onoroff;
X{
X if (tmp->highlight) {
X if (onoroff) {
X XSetWindowBorder (dpy, tmp->frame, tmp->border);
X if (tmp->title_w)
X XSetWindowBorder (dpy, tmp->title_w, tmp->border);
X } else {
X XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray);
X if (tmp->title_w)
X XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray);
X }
X }
X}
X
XDestroyMenu (menu)
X MenuRoot *menu;
X{
X MenuItem *item;
X
X if (menu->w) {
X XDeleteContext (dpy, menu->w, MenuContext);
X XDeleteContext (dpy, menu->w, ScreenContext);
X if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
X XDestroyWindow(dpy, menu->w);
X }
X
X for (item = menu->first; item; ) {
X MenuItem *tmp = item;
X item = item->next;
X free ((char *) tmp);
X }
X}
X
X/*
X * warping routines
X */
Xvoid WarpAlongRing (ev, forward)
X XButtonEvent *ev;
X Bool forward;
X{
X TwmWindow *r, *head;
X
X if (Scr->RingLeader)
X head = Scr->RingLeader;
X else if (!(head = Scr->Ring))
X return;
X
X if (forward) {
X for (r = head->ring.next; r != head; r = r->ring.next) {
X if (!r || r->mapped) break;
X }
X } else {
X for (r = head->ring.prev; r != head; r = r->ring.prev) {
X if (!r || r->mapped) break;
X }
X }
X
X if (r && r != head) {
X TwmWindow *p = Scr->RingLeader, *t;
X
X Scr->RingLeader = r;
X WarpToWindow (r);
X
X if (p && p->mapped &&
X XFindContext (dpy, ev->window, TwmContext, (caddr_t *)&t) == XCSUCCESS &&
X p == t) {
X p->ring.cursor_valid = True;
X p->ring.curs_x = ev->x_root - t->frame_x;
X p->ring.curs_y = ev->y_root - t->frame_y;
X if (p->ring.curs_x < -p->frame_bw ||
X p->ring.curs_x >= p->frame_width + p->frame_bw ||
X p->ring.curs_y < -p->frame_bw ||
X p->ring.curs_y >= p->frame_height + p->frame_bw) {
X /* somehow out of window */
X p->ring.curs_x = p->frame_width / 2;
X p->ring.curs_y = p->frame_height / 2;
X }
X }
X }
X}
X
Xvoid WarpToWindow (t)
X TwmWindow *t;
X{
X int x, y;
X
X /* if we have the virtual desktop, attempt to make the window
X * somewhat visible
X */
X if (Scr->VirtualDesktop)
X ScrollToQuadrant(t);
X
X if (t->auto_raise || !Scr->NoRaiseWarp) AutoRaiseWindow (t);
X if (t->ring.cursor_valid) {
X x = t->ring.curs_x;
X y = t->ring.curs_y;
X } else {
X x = t->frame_width / 2;
X y = t->frame_height / 2;
X }
X XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y);
X}
X
X
X/*
X * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
X * client messages will have the following form:
X *
X * event type ClientMessage
X * message type _XA_WM_PROTOCOLS
X * window tmp->w
X * format 32
X * data[0] message atom
X * data[1] time stamp
X */
Xstatic void send_clientmessage (w, a, timestamp)
X Window w;
X Atom a;
X Time timestamp;
X{
X XClientMessageEvent ev;
X
X ev.type = ClientMessage;
X ev.window = w;
X ev.message_type = _XA_WM_PROTOCOLS;
X ev.format = 32;
X ev.data.l[0] = a;
X ev.data.l[1] = timestamp;
X XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
X}
X
XSendDeleteWindowMessage (tmp, timestamp)
X TwmWindow *tmp;
X Time timestamp;
X{
X send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
X}
X
XSendSaveYourselfMessage (tmp, timestamp)
X TwmWindow *tmp;
X Time timestamp;
X{
X send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
X}
X
X
XSendTakeFocusMessage (tmp, timestamp)
X TwmWindow *tmp;
X Time timestamp;
X{
X send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
X}
SHAR_EOF
if test 64620 -ne "`wc -c < menus.c`"
then
echo shar: error transmitting "menus.c" '(should have been 64620 characters)'
fi
fi
# end of shell archive
exit 0
dan
----------------------------------------------------
O'Reilly && Associates argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.
More information about the Comp.sources.x
mailing list