[comp.sources.x] v09i005: TWM with a virtual root window, Part04/09

toml@marvin.Solbourne.COM (Tom LaStrange) (08/30/90)

Submitted-by: toml@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@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.