jkh@ardent.UUCP (Jordan K. Hubbard) (06/16/88)
#! /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 15 (of 17)." # Contents: awm/menus/menu.c # Wrapped by jkh@ardent on Thu Jun 16 00:44:25 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'awm/menus/menu.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'awm/menus/menu.c'\" else echo shar: Extracting \"'awm/menus/menu.c'\" \(34427 characters\) sed "s/^X//" >'awm/menus/menu.c' <<'END_OF_FILE' 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 static char Check_MarkBits[] = { X 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00, X 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00 X }; X Menu MenuDefault; X X/* X * the following have already been set my GetDefaults() X * by the time we get here. X */ XXFontStruct *MFontInfo; XXFontStruct *MBoldFontInfo; int MBorderWidth, MPad, MDelta, MItemBorder; Pixel MForeground, MBackground, MBorder; X extern Boolean SaveUnder; extern int Reverse; extern Display *dpy; extern int scr; X static XContext Menu_context; static XContext Item_context; static contexts_created = FALSE; X MenuItem *AddMenuItem(), *Display_Menu(), *MenuGetItem(), X *MenuItemByName(), *MenuItemByData(), *GetInitialItem(), *MoveMenu(); bool DisposeItem(), SetItemCheck(), SetItemDisable(), Recalc_Menu(), X SetupItems(), MapMenu(), SetItemText(), SetupMenuWindow(); void DisposeMenu(), InitMenu(), Undisplay_Menu(), MenuInvert(), X PlacePointer(), Draw_Menu(), Draw_Item(), SetInitialItem(), X ClearInitialItem(), Generate_Menu_Entries(), UnmapMenu(), X SetInputMask(); Menu *NewMenu(), *MenuGetMenu(); int 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 MenuItem *AddMenuItem(menu, text, bitmap_file) Menu *menu; char *text; char *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 */ bool DisposeItem(menu, item) Menu *menu; MenuItem *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 */ void DisposeMenu(menu) Menu *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 static char *Name; X void InitMenu(name, options) char *name; unsigned 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 */ bool SetItemText(menu, item, text) Menu *menu; MenuItem *item; char *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 */ Menu *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 */ bool SetItemCheck(menu, item, state) Menu *menu; MenuItem *item; int 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 */ bool SetItemDeaf(menu, item, state) Menu *menu; MenuItem *item; int 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 */ bool SetItemDisable(menu, item, state) Menu *menu; MenuItem *item; int 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 MenuItem *Display_Menu(menu, parent, x, y) Menu *menu; Menu *parent; int x; int 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 void Undisplay_Menu(menu) Menu *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 void MenuInvert(menu, item) Menu *menu; MenuItem *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 */ bool Recalc_Menu(menu) Menu *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 */ static MenuItem *MoveMenu(menu, ev_x, ev_y) Menu *menu; int 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 void PlacePointer(menu, item) Menu *menu; MenuItem *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 */ static bool MapMenu(menu) Menu *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 static void Generate_Menu_Entries (menu) Menu *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 */ void Draw_Menu(menu) Menu *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 */ void Draw_Item(menu, item, fill_x, fill_y, fill_width, fill_height) Menu *menu; MenuItem *item; int 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 */ static void UnmapMenu(menu) Menu *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 static bool SetupMenuWindow (menu) Menu *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 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 static bool SetupItems(menu) Menu *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 static void SetInputMask(menu, mask) Menu *menu; unsigned 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 MenuItem *MenuItemByData(menu, data) Menu* menu; pointer 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 MenuItem *MenuItemByName (menu, name) Menu *menu; char *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 MenuItem *MenuGetItem(menu, window) Menu *menu; Window window; X{ X MenuItem *foo = 0; X X Entry("MenuGetItem") X X XFindContext(dpy, window, Item_context, &foo); X Leave(foo) X} X Menu *MenuGetMenu(menu, window) Menu *menu; Window window; X{ X Menu *bar = 0; X X Entry("MenuGetMenu") X X XFindContext(dpy, window, Menu_context, &bar); X Leave(bar) X} X int ItemGetMiddleY(item) MenuItem *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 void SetInitialItem(menu, item) Menu *menu; MenuItem *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 void ClearInitialItem(menu) Menu *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 MenuItem *GetInitialItem(menu) Menu *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 void Retch(s, p1, p2, p3, p4) char *s; long 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_FILE if test 34427 -ne `wc -c <'awm/menus/menu.c'`; then echo shar: \"'awm/menus/menu.c'\" unpacked with wrong size! fi # end of 'awm/menus/menu.c' fi echo shar: End of archive 15 \(of 17\). cp /dev/null ark15isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 17 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