v00i012: Ardent Window Manager, Part11/13
Mike Wexler
mikew at wyse.wyse.com
Thu Aug 11 08:00:55 AEST 1988
Submitted-by: unido!pcsbst!jkh (Jordan Hubbard)
Posting-number: Volume 0, Issue 12
Archive-name: awm/part11
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 11 (of 13)."
# Contents: awm/menus/menu.c
# Wrapped by mikew at wyse on Mon Aug 8 12:01:48 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f awm/menus/menu.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"awm/menus/menu.c\"
else
echo shar: Extracting \"awm/menus/menu.c\" \(34428 characters\)
sed "s/^X//" >awm/menus/menu.c <<'END_OF_awm/menus/menu.c'
X#ident "%W% %G%"
X
X#ifndef lint
X static char sccs_id[] = "@(#)menu.c 2.1 12/16/87 Siemens Corporate Research and Support, Inc.";
X#endif
X
X
X/*
X RTL Menu Package Version 1.0
X by Joe Camaratta and Mike Berman, Siemens RTL, Princeton NJ, 1987
X
X menu.c: menu utility and support functions.
X
X Originally hacked by Adam J. Richter, based on the menu package for xterm.
X ( misc.c X10/6.6 )
X
X */
X
X/*
X *
X * Changed in various and subtle ways by Jordan Hubbard, Ardent Computer.
X * February 1st, 1988: Removed dependence on oldX by nuking AssocTable
X * stuff in favor of contexts. Added "label" panes, useful for titling
X * purposes. Variable height items, variable fonts, pictoral panes
X * (pixmaps) for cute graphic menus.
X */
X
X/*
X *
X * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca.
X *
X * Copyright 1987 by Jordan Hubbard.
X *
X *
X * All Rights Reserved
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appear in all copies and that
X * both that copyright notice and this permission notice appear in
X * supporting documentation, and that the name of Ardent Computer
X * Corporation or Jordan Hubbard not be used in advertising or publicity
X * pertaining to distribution of the software without specific, written
X * prior permission.
X *
X */
X
X
X/*
X
X Copyright 1987 by
X Siemens Corporate Research and Support, Inc., Princeton, New Jersey
X
X Permission to use, copy, modify, and distribute this software
X and its documentation for any purpose and without fee is
X hereby granted, provided that the above copyright notice
X appear in all copies and that both that copyright notice and
X this permission notice appear in supporting documentation, and
X that the name of Siemens not be used in advertising or
X publicity pertaining to distribution of the software without
X specific, written prior permission. Siemens makes no
X representations about the suitability of this software for any
X purpose. It is provided "as is" without express or implied
X warranty.
X
X */
X
X/*
X
X Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology
X
X Permission to use, copy, modify, and distribute this
X software and its documentation for any purpose and without
X fee is hereby granted, provided that the above copyright
X notice appear in all copies and that both that copyright
X notice and this permission notice appear in supporting
X documentation, and that the name of M.I.T. not be used in
X advertising or publicity pertaining to distribution of the
X software without specific, written prior permission.
X M.I.T. makes no representations about the suitability of
X this software for any purpose. It is provided "as is"
X without express or implied warranty.
X
X */
X
X/*
X * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
X *
X * All Rights Reserved
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appear in all copies and that
X * both that copyright notice and this permission notice appear in
X * supporting documentation, and that the name of Digital Equipment
X * Corporation not be used in advertising or publicity pertaining to
X * distribution of the software without specific, written prior permission.
X *
X *
X * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
X * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
X * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
X * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
X * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
X * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X/* Got that? Good! Now, there is actually some code in here.. */
X
X
X#include <stdio.h>
X#include "X11/Xlib.h"
X#include "X11/cursorfont.h"
X#include "X11/Xutil.h"
X#include "X11/Intrinsic.h"
X
X#include "menu.h"
X#include "menu.def.h"
X#include "gray1.h"
X#include "arrow_icon.h"
X#include "dbug.h"
X
X#define MakeEven(x) ((x%2 == 0)? x : x-1)
X
X
X#define InvertPlane 1
X
Xstatic char Check_MarkBits[] = {
X 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
X 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
X };
X
XMenu MenuDefault;
X
X/*
X * the following have already been set my GetDefaults()
X * by the time we get here.
X */
XXFontStruct *MFontInfo;
XXFontStruct *MBoldFontInfo;
Xint MBorderWidth, MPad, MDelta, MItemBorder;
XPixel MForeground, MBackground, MBorder;
X
Xextern Boolean SaveUnder;
Xextern int Reverse;
Xextern Display *dpy;
Xextern int scr;
X
Xstatic XContext Menu_context;
Xstatic XContext Item_context;
Xstatic contexts_created = FALSE;
X
XMenuItem *AddMenuItem(), *Display_Menu(), *MenuGetItem(),
X *MenuItemByName(), *MenuItemByData(), *GetInitialItem(), *MoveMenu();
Xbool DisposeItem(), SetItemCheck(), SetItemDisable(), Recalc_Menu(),
X SetupItems(), MapMenu(), SetItemText(), SetupMenuWindow();
Xvoid DisposeMenu(), InitMenu(), Undisplay_Menu(), MenuInvert(),
X PlacePointer(), Draw_Menu(), Draw_Item(), SetInitialItem(),
X ClearInitialItem(), Generate_Menu_Entries(), UnmapMenu(),
X SetInputMask();
XMenu *NewMenu(), *MenuGetMenu();
Xint ItemGetMiddleY();
X
X/*
X * AddMenuItem() adds a menu item to an existing menu, at the end of the
X * list, which are number sequentially from zero. The menuitem index is
X * return, or -1 if failed.
X */
X
XMenuItem *AddMenuItem(menu, text, bitmap_file)
XMenu *menu;
Xchar *text;
Xchar *bitmap_file;
X{
X MenuItem *menuitem, **next;
X int junk;
X char *data;
X
X Entry("AddMenuItem")
X
X if (!menu || (!text && !bitmap_file) || (menuitem = allocate(MenuItem, 1))
X == (MenuItem *)0)
X Leave(NULLITEM)
X bzero((char *)menuitem, sizeof(MenuItem));
X ItemText(menuitem) = allocate(char, (strlen(text) + 1));
X strcpy(ItemText(menuitem), text);
X ItemTextLength(menuitem) = strlen(text);
X if (bitmap_file) {
X bitmap_file = (char *)expand_from_path(bitmap_file);
X if (XReadBitmapFileData(bitmap_file,
X &(menuitem->itemTextWidth),
X &(menuitem->itemHeight),
X &data,
X &junk, &junk) != BitmapSuccess) {
X fprintf(stderr, "awm: Can't read bitmap file '%s'\n",
X bitmap_file);
X exit(1);
X }
X menuitem->itemBackground =
X XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X data,
X menuitem->itemTextWidth,
X menuitem->itemHeight,
X MForeground,
X MBackground,
X DefaultDepth(dpy, scr));
X if (!menuitem->itemBackground) {
X fprintf(stderr, "awm: Can't create pixmap for file '%s'\n",
X bitmap_file);
X exit(1);
X }
X free(data);
X free(bitmap_file);
X }
X for(next = &menu->menuItems; *next; next = &(*next)->nextItem);
X
X *next = menuitem;
X
X SetMenuFlag(menu, menuChanged);
X Leave(menuitem)
X}
X
X/*
X * DisposeItem() releases the memory allocated for the given indexed
X * menuitem. Nonzero is returned if an item was actual disposed of.
X * It also checks to see whether the item we're disposing is the
X * initial item for the menu -- if so, null out the initial item.
X */
Xbool DisposeItem(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X MenuItem **next, **last, *menuitem;
X
X Entry("DisposeItem")
X
X if (MenuIsNull(menu) || ItemIsNull(item))
X Leave(FALSE)
X next = &MenuItems(menu);
X do {
X if(!*next)
X Leave(FALSE)
X last = next;
X next = &(*next)->nextItem;
X } while((*last != item) && !ItemIsNull(*next));
X menuitem = *last;
X *last = *next;
X if (ItemWindow(menuitem)) {
X XDeleteContext(dpy, ItemWindow(menuitem), Item_context);
X XDestroyWindow(dpy, ItemWindow(menuitem));
X }
X if (ItemIsInitialItem(menu, menuitem))
X ClearInitialItem(menu);
X
X if (ItemText(menuitem))
X free((char*)ItemText(menuitem));
X free((char*)menuitem);
X
X SetMenuFlag(menu, menuChanged);
X Leave(TRUE)
X}
X
X/*
X * DisposeMenu() releases the memory allocated for the given menu.
X */
Xvoid DisposeMenu(menu)
XMenu *menu;
X{
X Entry("DisposeMenu")
X
X if(!menu)
X Leave_void
X if (TestMenuFlag(menu, menuMapped))
X UnmapMenu(menu);
X while(DisposeItem(menu, MenuItems(menu)));
X if(MenuWindow(menu)) {
X XDeleteContext(dpy, MenuWindow(menu), Menu_context);
X XDestroyWindow(dpy, MenuWindow(menu));
X }
X XFreePixmap (dpy, MenuGreyPixmap(menu));
X XFreePixmap (dpy, MenuArrowPixmap(menu));
X XFreePixmap (dpy, MenuCheckmarkPixmap(menu));
X XFreeGC (dpy, MenuNormalGC(menu));
X XFreeGC (dpy, MenuInvertGC(menu));
X XFreeGC (dpy, MenuHighlightedGC(menu));
X XFreeGC (dpy, menu->boldGC);
X
X if (MenuHasInitialItem(menu))
X ClearInitialItem(menu);
X free((char*) menu);
X Leave_void
X}
X
Xstatic char *Name;
X
Xvoid InitMenu(name, options)
Xchar *name;
Xunsigned int options;
X{
X char *cp;
X
X Entry("InitMenu")
X
X Name = name;
X MenuDefault.menuFlags = menuChanged;
X
X MenuDefault.menuInitialItemText = (char *) NULL;
X MenuDefault.display = dpy;
X MenuDefault.screen = scr;
X MenuDefault.menuOptions = options;
X Leave_void
X}
X
X/*
X * ItemText changes the text of item of the menu.
X */
Xbool SetItemText(menu, item, text)
XMenu *menu;
XMenuItem *item;
Xchar *text;
X{
X Entry("SetItemText")
X
X if (strcmp (ItemText(item), text) == 0)
X Leave (True)
X
X if(ItemText(item))
X free((char *) ItemText(item));
X
X ItemText(item) = allocate(char, (strlen(text) + 1));
X strcpy(ItemText(item), text);
X
X ItemTextLength(item) = strlen (text);
X SetMenuFlag(menu, menuChanged);
X
X (void) Recalc_Menu (menu);
X Leave(TRUE)
X}
X
X/*
X * NewMenu() returns a pointer to an initialized new Menu structure, or NULL
X * if failed.
X *
X * The Menu structure _menuDefault contains the default menu settings.
X */
XMenu *NewMenu()
X{
X extern Pixmap MakeGreyStipple ();
X Menu *menu = 0;
X
X XGCValues gcValues, invertGCValues;
X
X static unsigned long gcMask =
X GCFunction | GCForeground | GCBackground | GCFont | GCStipple;
X static unsigned long invertgcMask = GCFont | GCFunction;
X char *cp;
X
X Entry("NewMenu")
X
X /*
X * Allocate the memory for the menu structure.
X */
X if(MenuIsNull((menu = allocate(Menu, 1))))
X Leave(NULLMENU)
X
X /*
X * Initialize to default values.
X */
X *menu = MenuDefault;
X gcValues.font = MFontInfo->fid;
X
X /*
X * If the menu cursor hasn't been given, make a default one.
X */
X
X MenuCursor(menu) = XCreateFontCursor (dpy, XC_right_ptr);
X MenuArrowPixmap(menu) = XCreatePixmapFromBitmapData(dpy,
X RootWindow(dpy, scr),
X arrow_bits,
X arrow_width,
X arrow_height,
X MForeground,
X MBackground,
X DefaultDepth(dpy, scr));
X
X MenuGreyPixmap(menu) = XCreateBitmapFromData(dpy,
X RootWindow(dpy, scr),
X gray1_bits,
X gray1_width, gray1_height);
X
X MenuCheckmarkPixmap(menu) = XCreatePixmapFromBitmapData(dpy,
X RootWindow(dpy, scr),
X Check_MarkBits,
X checkMarkWidth,
X checkMarkHeight,
X MForeground,
X MBackground,
X DefaultDepth(dpy, scr));
X
X gcValues.foreground = MForeground;
X gcValues.background = MBackground;
X
X gcValues.stipple = MenuGreyPixmap(menu);
X gcValues.function = GXcopy;
X gcValues.subwindow_mode = IncludeInferiors;
X gcValues.graphics_exposures = False;
X MenuNormalGC(menu) =
X XCreateGC (dpy, RootWindow(dpy, scr),
X gcMask | GCSubwindowMode | GCGraphicsExposures, &gcValues);
X
X invertGCValues = gcValues;
X invertGCValues.foreground = MBackground;
X invertGCValues.background = MForeground;
X MenuHighlightedGC(menu) = XCreateGC (dpy, RootWindow (dpy, scr),
X gcMask, &invertGCValues);
X gcValues.function = GXinvert;
X MenuInvertGC(menu) = XCreateGC (dpy, RootWindow (dpy, scr),
X invertgcMask, &gcValues);
X gcValues.function = GXcopy;
X gcValues.font = MBoldFontInfo->fid;
X menu->boldGC = XCreateGC(dpy, RootWindow(dpy, scr),
X gcMask | GCSubwindowMode | GCGraphicsExposures, &gcValues);
X Leave(menu)
X}
X
X
X/*
X * SetItemCheck sets the check state of item of the menu to "state".
X */
Xbool SetItemCheck(menu, item, state)
XMenu *menu;
XMenuItem *item;
Xint state;
X{
X Entry("SetItemCheck")
X
X if (TestItemFlag(item,itemChecked) == state) /* Exit if unchanged */
X Leave (True)
X
X if (state)
X SetItemFlag(item, itemChecked);
X else
X ResetItemFlag(item, itemChecked);
X
X SetItemFlag(item, itemChanged);
X SetMenuFlag(menu, menuItemChanged);
X
X Leave(TRUE)
X}
X/*
X * SetItemDeaf sets the "deaf" state of item of the menu to "state".
X * "deaf" means that the item is display only and not sensitive to input.
X */
Xbool SetItemDeaf(menu, item, state)
XMenu *menu;
XMenuItem *item;
Xint state;
X{
X Entry("SetItemDeaf")
X
X if (TestItemFlag(item,itemDeaf) == state) /* Exit if unchanged */
X Leave (True)
X
X if (state)
X SetItemFlag(item, itemDeaf);
X else
X ResetItemFlag(item, itemDeaf);
X
X SetItemFlag(item, itemChanged);
X SetMenuFlag(menu, menuItemChanged);
X if (ItemIsInitialItem(menu, item))
X ClearInitialItem(menu);
X Leave(TRUE)
X}
X
X/*
X * SetItemDisable sets the disable state of item "n" of the menu to "state".
X */
Xbool SetItemDisable(menu, item, state)
XMenu *menu;
XMenuItem *item;
Xint state;
X{
X Entry("SetItemDisable")
X
X if (TestItemFlag(item,itemDisabled) == state) /* Exit if unchanged */
X Leave (True)
X
X if(state)
X {
X SetItemFlag(item, itemDisabled);
X /* if disabled item is currently initial item, null initial item */
X if (ItemIsInitialItem(menu, item))
X ClearInitialItem(menu);
X }
X else
X ResetItemFlag(item, itemDisabled);
X
X SetItemFlag(item, itemChanged);
X SetMenuFlag(menu, menuItemChanged);
X
X Leave(TRUE)
X}
X
XMenuItem *Display_Menu(menu, parent, x, y)
XMenu *menu;
XMenu *parent;
Xint x;
Xint y;
X{
X MenuItem *item;
X
X Entry("Display_Menu")
X
X if (MenuIsNull(menu))
X Leave(FALSE)
X
X MenuParent(menu) = parent;
X
X if (MenuIsNull(parent))
X MenuNested(menu) = 0;
X else
X MenuNested(menu) = MenuNested(parent) + 1;
X if (!MenuWindow(menu) || TestMenuFlag(menu,
X (menuChanged | menuItemChanged))) {
X if (!SetupMenuWindow(menu))
X Leave(NULL)
X Generate_Menu_Entries(menu);
X }
X if (TestOptionFlag(menu,savebits) &&
X (MenuSavedPixmap(menu) != (Pixmap) 0))
X SetInputMask(menu, MenuIgnoreMask);
X else
X SetInputMask(menu, ExposureMask);
X if (!(item = MoveMenu(menu, x, y)) || !MapMenu(menu))
X Leave(FALSE)
X Draw_Menu(menu);
X
X Leave(item)
X}
X
Xvoid Undisplay_Menu(menu)
XMenu *menu;
X{
X Entry("Undisplay_Menu")
X
X if (MenuIsNull(menu))
X Leave_void
X
X MenuParent(menu) = NULLMENU;
X MenuNested(menu) = 0;
X
X UnmapMenu(menu);
X Leave_void
X}
X
Xvoid MenuInvert(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X Entry("MenuInvert")
X
X XFillRectangle (dpy,
X ItemWindow(item),
X MenuInvertGC(menu),
X 0, 0,
X MenuWidth(menu),
X item->itemHeight);
X Leave_void
X}
X
X/*
X * Recalculate all of the various menu and item variables.
X */
Xbool Recalc_Menu(menu)
XMenu *menu;
X{
X MenuItem *item;
X int max, height, fontheight, boldfontheight, nitems;
X /* Gets set to false first time we see an item with text */
X unsigned int menuIsPictures = TRUE;
X
X Entry("Recalc_Menu")
X
X /*
X * We must have already gotten the menu font.
X */
X if(!MFontInfo)
X Leave(FALSE)
X /*
X * Initialize the various max width variables.
X */
X fontheight = MFontInfo->ascent + MFontInfo->descent + 2;
X boldfontheight = MBoldFontInfo->ascent + MBoldFontInfo->descent + 2;
X height = nitems = 0;
X MenuMaxTextWidth(menu) = 0;
X /*
X * The item height is the maximum of the font height and the
X * checkbox height, unless we find out that it's a pixmap (in which
X * case, most of these values are overridden).
X */
X max = fontheight;
X if(checkMarkHeight > max)
X max = checkMarkHeight;
X
X max += 2*MItemBorder;
X max = MakeEven(max);
X
X /*
X * Go through the menu item list.
X */
X for(item = MenuItems(menu) ; item ; item = ItemNext(item)) {
X if (item->itemBackground) /* pixmap is static size */
X max = item->itemHeight;
X else {
X if (ItemIsDeaf(item)) /* It's a label, use bold info */
X max = boldfontheight;
X else
X max = fontheight;
X }
X if (checkMarkHeight > max)
X max = checkMarkHeight;
X if (!item->itemBackground) {
X max += 2 * MItemBorder;
X max = MakeEven(max);
X item->itemHeight = max;
X }
X height += max;
X nitems++;
X /*
X * Check the text width with the max value stored in
X * menu.
X */
X if (!item->itemBackground) {
X if ((ItemTextWidth(item) = XTextWidth(ItemIsDeaf(item) ?
X MBoldFontInfo
X : MFontInfo,
X ItemText(item),
X strlen (ItemText(item))))
X > MenuMaxTextWidth(menu))
X MenuMaxTextWidth(menu) = ItemTextWidth(item);
X menuIsPictures = FALSE;
X }
X /* ItemTextWidth is really pixmap size. Yick. */
X else {
X if (ItemTextWidth(item) > MenuMaxTextWidth(menu))
X MenuMaxTextWidth(menu) = ItemTextWidth(item);
X }
X
X }
X /*
X * Set the menu height and then set the menu width.
X */
X MenuHeight(menu) = height;
X menu->avgHeight = height / nitems;
X
X if (menuIsPictures == TRUE)
X MenuWidth(menu) = MenuMaxTextWidth(menu) + (2 * MItemBorder);
X else {
X MenuWidth(menu) = 4 * MenuItemPad(menu) + MenuMaxTextWidth(menu) +
X checkMarkWidth + arrow_width + (2 * MItemBorder);
X }
X MenuItemWidth(menu) = MenuWidth(menu) - (2 * MItemBorder);
X Leave(TRUE)
X}
X
X/*
X * Figure out where to popup the menu, relative to the where the button was
X * pressed.
X * Returns pointer to initial item to warp to.
X */
Xstatic MenuItem *MoveMenu(menu, ev_x, ev_y)
XMenu *menu;
Xint ev_x, ev_y;
X{
X int x, y;
X int total_width, total_height;
X int offset;
X MenuItem *item;
X Window junk;
X int r_x, foo, state;
X
X Entry("MoveMenu")
X
X /*
X * Get the coordinates of the mouse when the button was pressed.
X */
X
X total_width = MenuWidth(menu) + 2 * MenuBorderWidth(menu);
X total_height = MenuHeight(menu) + 2 * MenuBorderWidth(menu);
X
X XQueryPointer(dpy, RootWindow(dpy, scr), &junk, &junk, &r_x, &y,
X &foo, &foo, &state);
X x = ev_x - MenuItemPad(menu);
X if (x < 0)
X x = 0;
X else if (TestOptionFlag(menu, rightoffset) &&
X !MenuIsNull(MenuParent(menu)))
X {
X /* check whether parent is close to right edge... */
X /* "too close" means that child would leave < delta of its parent */
X /* visible to its left. */
X if (TestOptionFlag(menu, bigoffset))
X {
X if (MenuX(MenuParent(menu)) + MenuWidth(MenuParent(menu)) >
X DisplayWidth(dpy, scr) - total_width)
X x = MenuX(MenuParent(menu))
X - total_width + 2*MenuBorderWidth(menu);
X }
X else
X {
X if (MenuX(MenuParent(menu)) + MenuDelta(MenuParent(menu)) >
X DisplayWidth(dpy, scr) - total_width)
X {
X x = (MenuX(MenuParent(menu)) + MenuWidth(MenuParent(menu)) +
X 2 * MenuBorderWidth(MenuParent(menu))
X - total_width - MenuDelta(menu));
X }
X }
X }
X if (x + total_width >
X DisplayWidth(dpy, scr))
X x = DisplayWidth(dpy, scr)
X - total_width;
X
X /*
X * If we have an initial item, try to popup the menu centered
X * vertically within this item.
X */
X if(MenuHasInitialItem(menu)) {
X int tmp_y;
X
X /*
X * Look through the item list. "y" is the vertical position
X * of the top of the current item and "n" is the item number.
X */
X offset = MenuBorderWidth(menu);
X for(item = MenuItems(menu) ; ;) {
X /*
X * On finding the initial item, center within this item.
X */
X if (ItemIsInitialItem(menu, item)) {
X y -= offset;
X break;
X }
X else
X offset += item->itemHeight;
X /*
X * If we run out of items, turn off the initial item
X * and treat this as if no initial item.
X */
X if(!(item = ItemNext(item))) {
X ClearInitialItem(menu);
X break;
X }
X }
X }
X
X if (y < 0)
X y = 0;
X else if (y + total_height >
X DisplayHeight(dpy, scr))
X {
X y = DisplayHeight(dpy, scr)
X - (total_height + 1);
X }
X y = MakeEven(y) + 1;
X XMoveWindow(dpy, MenuWindow(menu), x, y);
X MenuX(menu) = x;
X MenuY(menu) = y;
X
X if (!ItemIsInitialItem(menu, item))
X item = MenuItems(menu);
X Leave(item)
X}
X
X
Xvoid PlacePointer(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X int y;
X
X Entry("PlacePointer")
X
X y = ItemGetMiddleY(item);
X
X XWarpPointer(dpy, None,
X RootWindow(dpy, scr),
X 0, 0, 0, 0,
X MenuX(menu) + MPad + (MenuWidth(menu) / 2), y);
X Leave_void
X}
X
X/*
X * Map the menu window.
X */
Xstatic bool MapMenu(menu)
XMenu *menu;
X{
X Entry("MapMenu")
X
X if (!TestMenuFlag(menu, menuMapped))
X MenuItemHighlighted(menu) = NULLITEM;
X
X /*
X * Actually map the window.
X */
X
X if (TestOptionFlag(menu,savebits))
X {
X if ((MenuSavedPixmap(menu) == (Pixmap) 0) ||
X (MenuOldWidth(menu) != MenuWidth(menu)) ||
X (MenuOldHeight(menu) != MenuHeight(menu)) ||
X (MenuOldBorderWidth(menu) != MenuBorderWidth(menu)))
X {
X if (MenuSavedPixmap(menu) != (Pixmap) 0)
X XFreePixmap(dpy, MenuSavedPixmap(menu));
X
X MenuSavedPixmap(menu) =
X XCreatePixmap(dpy,
X RootWindow(dpy, scr),
X MenuWidth(menu) + 2*MenuBorderWidth(menu),
X MenuHeight(menu) + 2*MenuBorderWidth(menu),
X DefaultDepth(dpy, scr));
X DBUG_5("Pixmaps","Created pixmap: width %d, height %d, depth %d\n",
X MenuWidth(menu) + 2*MenuBorderWidth(menu),
X MenuHeight(menu) + 2*MenuBorderWidth(menu),
X DefaultDepth(dpy, scr));
X MenuOldWidth(menu) = MenuWidth(menu);
X MenuOldHeight(menu) = MenuHeight(menu);
X MenuOldBorderWidth(menu) = MenuBorderWidth(menu);
X }
X else
X SetInputMask(menu, ExposureMask);
X
X if (MenuSavedPixmap(menu) != (Pixmap) 0) {
X /* XFillRectangle(dpy,
X MenuSavedPixmap(menu),
X SaveGC,
X 0,0,
X MenuWidth(menu) + 2*MenuBorderWidth(menu),
X MenuHeight(menu) + 2*MenuBorderWidth(menu)); */
X SetInputMask(menu, MenuIgnoreMask);
X XCopyArea(dpy,
X RootWindow(dpy, scr),
X MenuSavedPixmap(menu),
X MenuNormalGC(menu),
X MenuX(menu),
X MenuY(menu),
X (unsigned int) (MenuWidth(menu) + 2*MenuBorderWidth(menu)),
X (unsigned int) (MenuHeight(menu) + 2*MenuBorderWidth(menu)),
X 0, 0);
X }
X else
X SetInputMask(menu, ExposureMask);
X
X }
X
X XRaiseWindow(dpy, MenuWindow(menu));
X XMapWindow(dpy, MenuWindow(menu));
X SetMenuFlag(menu, menuMapped);
X Leave(TRUE)
X}
X
Xstatic void Generate_Menu_Entries (menu)
XMenu *menu;
X{
X MenuItem *item;
X
X Entry("Generate_Menu_Entries")
X
X for (item = MenuItems(menu); item; (item = ItemNext(item))) {
X
X if (ItemGenerator(item)) {
X char *newText;
X
X (ItemGenerator(item)) (&newText, &ItemCallback(item));
X SetItemText (menu, item, newText);
X }
X
X if (ItemCheckproc(item))
X SetItemCheck (menu, item, (ItemCheckproc(item))(menu,item));
X }
X Leave_void
X}
X
X/*
X * Draw the entire menu in the blank window.
X */
Xvoid Draw_Menu(menu)
XMenu *menu;
X{
X MenuItem *item;
X
X Entry("Draw_Menu")
X
X ResetMenuFlag(menu, menuChanged);
X /*
X * For each item in the list, first draw any check mark and then
X * draw the rest of it.
X */
X for(item = MenuItems(menu) ; item ; item = ItemNext(item)) {
X if (TestOptionFlag(menu, savebits))
X {
X /* go ahead and draw it, don't wait for exposes */
X Draw_Item(menu, item, 0, 0, MenuWidth(menu), item->itemHeight);
X }
X }
X Leave_void
X}
X
X/*
X * Draw the item at vertical position y.
X */
Xvoid Draw_Item(menu, item, fill_x, fill_y, fill_width, fill_height)
XMenu *menu;
XMenuItem *item;
Xint fill_x, fill_y, fill_width, fill_height;
X{
X int y; /* baseline */
X int x = MenuItemPad(menu);
X int x1 = 2 * MenuItemPad(menu) + checkMarkWidth;
X int pad;
X int high;
X XGCValues gcValues;
X
X Entry("Draw_Item")
X
X if (TestItemFlag(item, itemDisabled))
X {
X gcValues.fill_style = FillOpaqueStippled;
X XChangeGC(dpy, MenuNormalGC(menu),
X (GCFillStyle), &gcValues);
X }
X
X high = (MenuItemHighlighted(menu) == item);
X if (!item->itemBackground) {
X if (high && !TestItemFlag(item, itemDeaf))
X {
X XSetFunction(dpy, MenuNormalGC(menu), GXset);
X XFillRectangle(dpy, ItemWindow(item),
X MenuNormalGC(menu), fill_x, fill_y,
X fill_width, fill_height);
X XSetFunction(dpy, MenuNormalGC(menu), GXcopyInverted);
X }
X else
X XClearArea(dpy, ItemWindow(item),
X fill_x, fill_y, fill_width, fill_height, False);
X
X /*
X * Draw the check mark, possibly dimmed, wherever is necessary.
X */
X }
X if(TestItemFlag(item, itemChecked)){
X XCopyArea (dpy, MenuCheckmarkPixmap(menu),
X ItemWindow(item),
X MenuNormalGC(menu),
X 0, 0, checkMarkWidth, checkMarkHeight,
X (int) x, (item->itemHeight - checkMarkHeight) / 2);
X }
X /* Draw submenu indicator arrow */
X if(ItemSubmenu(item)) {
X XCopyArea (dpy, MenuArrowPixmap(menu),
X ItemWindow(item),
X MenuNormalGC(menu),
X 0, 0,
X arrow_width, arrow_height,
X (int) (x + MenuItemWidth(menu) -
X arrow_width - MenuItemPad(menu)),
X (item->itemHeight - arrow_height) / 2 - 1);
X }
X /*
X * Draw the text, centered vertically.
X */
X if (!item->itemBackground) {
X if (!TestItemFlag(item, itemDeaf)) {
X pad = (item->itemHeight -
X (MFontInfo->ascent + MFontInfo->descent)) / 2;
X y = item->itemHeight - pad - MFontInfo->descent;
X
X XDrawString (dpy, ItemWindow(item),
X (high? MenuHighlightedGC(menu) : MenuNormalGC(menu)),
X x1, y, ItemText(item), ItemTextLength(item));
X if (high)
X XSetFunction(dpy, MenuNormalGC(menu), GXcopy);
X if (TestItemFlag(item, itemDisabled))
X {
X gcValues.fill_style = FillSolid;
X XChangeGC(dpy, MenuNormalGC(menu),
X (GCFillStyle), &gcValues);
X }
X
X }
X else {
X pad = (item->itemHeight - (MBoldFontInfo->ascent +
X MBoldFontInfo->descent)) / 2;
X y = item->itemHeight - pad - MBoldFontInfo->descent;
X XDrawString(dpy, ItemWindow(item), menu->boldGC, x1, y,
X ItemText(item), ItemTextLength(item));
X }
X }
X Leave_void
X}
X
X
X/*
X * UnmapMenu() unmaps a menu, if it is currently mapped.
X */
Xstatic void UnmapMenu(menu)
XMenu *menu;
X{
X Entry("UnmapMenu")
X
X if(!menu || !(TestMenuFlag(menu, menuMapped)))
X Leave_void
X XUnmapWindow(dpy, MenuWindow(menu));
X /* XClearWindow (dpy, MenuWindow(menu));*/
X
X if (TestOptionFlag(menu, savebits))
X {
X if (MenuSavedPixmap(menu))
X XCopyArea (dpy,
X MenuSavedPixmap(menu),
X RootWindow (dpy, scr),
X MenuNormalGC(menu),
X 0, 0,
X MenuWidth(menu) + 2*MenuBorderWidth(menu),
X MenuHeight(menu) + 2*MenuBorderWidth(menu),
X MenuX(menu), MenuY(menu));
X
X }
X ResetMenuFlag(menu, menuMapped);
X Leave_void
X}
X
Xstatic bool SetupMenuWindow (menu)
XMenu *menu;
X{
X int changed = TestMenuFlag(menu, (menuChanged | menuItemChanged));
X
X Entry("SetupMenuWindow")
X
X if (contexts_created == FALSE) {
X contexts_created = TRUE;
X Menu_context = XUniqueContext();
X Item_context = XUniqueContext();
X }
X
X /*
X * If the entire menu has changed, throw away any saved pixmap and
X * then call RecalcMenu().
X */
X
X if(changed & menuChanged) {
X if(!Recalc_Menu(menu))
X Leave(FALSE)
X changed &= ~menuItemChanged;
X }
X
X if(!MenuWindow(menu)) {
X static unsigned long valuemask =
X CWOverrideRedirect | CWBorderPixel | CWBackPixel;
X XSetWindowAttributes attributes;
X
X attributes.override_redirect = True;
X attributes.border_pixel = MBorder;
X attributes.background_pixel = MBackground;
X if (SaveUnder) {
X attributes.save_under = True;
X valuemask |= CWSaveUnder;
X }
X
X if((MenuWindow(menu) =
X XCreateWindow(dpy,
X RootWindow(dpy, scr),
X 0, 0,
X MenuWidth(menu), MenuHeight(menu),
X MenuBorderWidth(menu),
X DefaultDepth(dpy, scr),
X InputOutput,
X DefaultVisual(dpy, scr),
X valuemask, &attributes)
X ) == (Window)0)
X Leave(FALSE)
X else if (SetupItems(menu) == FALSE)
X Leave(FALSE)
X
X XSaveContext(dpy, MenuWindow(menu), Menu_context, (char *) menu);
X XMapSubwindows(dpy, MenuWindow(menu));
X
X XDefineCursor(dpy, MenuWindow(menu), MenuCursor(menu));
X }
X else if(changed & menuChanged) {
X XResizeWindow(dpy, MenuWindow(menu),
X MenuWidth(menu), MenuHeight(menu));
X if (SetupItems(menu) == FALSE)
X Leave(FALSE)
X XMapSubwindows(dpy, MenuWindow(menu));
X }
X Leave(TRUE)
X}
X
Xstatic bool SetupItems(menu)
XMenu *menu;
X{
X int y;
X MenuItem *item;
X int changed = TestMenuFlag(menu, (menuChanged | menuItemChanged));
X
X Entry("SetupItems")
X
X for (item = MenuItems(menu), y = 0; item;
X y += item->itemHeight, item = ItemNext(item)) {
X if (!ItemWindow(item)) {
X static unsigned long valuemask =
X (CWOverrideRedirect | CWBorderPixel | CWBackPixel);
X XSetWindowAttributes attributes;
X
X attributes.override_redirect = True;
X attributes.border_pixel = MBorder;
X attributes.background_pixel = MBackground;
X
X if((ItemWindow(item) =
X XCreateWindow(dpy,
X MenuWindow(menu),
X 0, y,
X MenuItemWidth(menu),
X item->itemHeight - (2 * MItemBorder),
X MItemBorder,
X DefaultDepth(dpy, scr),
X InputOutput,
X DefaultVisual(dpy, scr),
X valuemask, &attributes)
X ) == (Window) 0)
X Leave(FALSE)
X if (item->itemBackground) {
X XSetWindowBackgroundPixmap(dpy, ItemWindow(item),
X item->itemBackground);
X XFreePixmap(dpy, item->itemBackground);
X }
X ItemMenu(item) = menu;
X XSaveContext(dpy, ItemWindow(item), Item_context,
X (char *) item);
X XDefineCursor(dpy, ItemWindow(item),
X MenuCursor(menu));
X }
X
X else if (changed & menuChanged) {
X XResizeWindow(dpy, ItemWindow(item),
X MenuItemWidth(menu),
X item->itemHeight - (2 * MItemBorder));
X XMoveWindow(dpy, ItemWindow(item), 0, y);
X }
X }
X Leave(TRUE)
X}
X
Xstatic void SetInputMask(menu, mask)
XMenu *menu;
Xunsigned int mask;
X{
X MenuItem *item;
X
X Entry("SetInputMask")
X
X XSelectInput(dpy, MenuWindow(menu),
X (mask | MenuEventMask));
X for(item = MenuItems(menu) ; item ; item = ItemNext(item))
X {
X if (TestItemFlag(item, itemDisabled) || TestItemFlag(item, itemDeaf))
X XSelectInput(dpy, ItemWindow(item),
X (mask | MenuIgnoreMask));
X else if (ItemIsLeaf(item))
X XSelectInput(dpy, ItemWindow(item),
X (mask | NormalItemEventMask));
X else
X XSelectInput(dpy, ItemWindow(item),
X (mask | SubmenuItemEventMask));
X }
X Leave_void
X}
X
XMenuItem *MenuItemByData(menu, data)
XMenu* menu;
Xpointer data;
X{
X MenuItem *item;
X
X Entry("MenuItemByData")
X
X for (item = MenuItems(menu);
X !ItemIsNull(item) && (ItemData(item) != data);
X item = ItemNext(item));
X
X Leave(item)
X}
X
XMenuItem *MenuItemByName (menu, name)
XMenu *menu;
Xchar *name;
X{
X MenuItem *item;
X
X Entry("MenuItemByName")
X
X for (item = MenuItems(menu); item; item = ItemNext(item))
X if (strcmp (name, ItemText(item)) == 0)
X Leave(item)
X Leave(NULLITEM)
X}
X
XMenuItem *MenuGetItem(menu, window)
XMenu *menu;
XWindow window;
X{
X MenuItem *foo = 0;
X
X Entry("MenuGetItem")
X
X XFindContext(dpy, window, Item_context, &foo);
X Leave(foo)
X}
X
XMenu *MenuGetMenu(menu, window)
XMenu *menu;
XWindow window;
X{
X Menu *bar = 0;
X
X Entry("MenuGetMenu")
X
X XFindContext(dpy, window, Menu_context, &bar);
X Leave(bar)
X}
X
Xint ItemGetMiddleY(item)
XMenuItem *item;
X{
X Window child;
X XWindowAttributes attributes;
X int x, y;
X
X Entry("ItemGetMiddleY")
X
X XGetWindowAttributes(dpy, ItemWindow(item), &attributes);
X XTranslateCoordinates(dpy,
X MenuWindow(ItemMenu(item)),
X RootWindow(dpy, scr),
X attributes.x, attributes.y,
X &x, &y, &child);
X Leave((item->itemHeight / 2) + y)
X}
X
Xvoid SetInitialItem(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X extern char *realloc();
X
X Entry("SetInitialItem")
X
X if (MenuHasInitialItem(menu)) {
X if (strlen(MenuInitialItemText(menu)) < strlen(ItemText(item)))
X MenuInitialItemText(menu) =
X realloc(MenuInitialItemText(menu),
X strlen(ItemText(item)) + 1);
X }
X else
X MenuInitialItemText(menu) =
X allocate(char,(strlen(ItemText(item)) + 1));
X strcpy(MenuInitialItemText(menu), ItemText(item));
X Leave_void
X}
X
Xvoid ClearInitialItem(menu)
XMenu *menu;
X{
X Entry("ClearInitialItem")
X
X if (MenuHasInitialItem(menu)) {
X free(MenuInitialItemText(menu));
X MenuInitialItemText(menu) = (char *) NULL;
X }
X Leave_void
X}
X
XMenuItem *GetInitialItem(menu)
XMenu *menu;
X{
X MenuItem *item;
X
X Entry("GetInitialItem")
X
X if (MenuHasInitialItem(menu)) {
X for(item = MenuItems(menu) ; item ; item = ItemNext(item)) {
X if (ItemIsInitialItem(menu, item))
X Leave(item)
X }
X }
X Leave((MenuItem *) NULL)
X}
X
X
X/* Some utility functions */
X
Xvoid Retch(s, p1, p2, p3, p4)
Xchar *s;
Xlong p1, p2, p3, p4;
X{
X char buffer[1024];
X
X sprintf(buffer, s, p1, p2, p3, p4);
X fprintf(stderr, "Error in %s %s\n", curr_rtn(), buffer);
X return;
X}
END_OF_awm/menus/menu.c
if test 34428 -ne `wc -c <awm/menus/menu.c`; then
echo shar: \"awm/menus/menu.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 11 \(of 13\).
cp /dev/null ark11isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 13 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
Mike Wexler(wyse!mikew) Phone: (408)433-1000 x1330
More information about the Comp.sources.x
mailing list