|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 25624 (0x6418) Types: TextFile Names: »menu.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦526ad3590⟧ »EUUGD11/gnu-31mar87/X.V10.R4.tar.Z« └─⟦2109abc41⟧ └─⟦this⟧ »./X.V10R4/xterm/menu.c«
/* * $Source: /u1/X/xterm/RCS/menu.c,v $ * $Header: menu.c,v 10.101 86/12/01 17:52:43 swick Rel $ */ #ifdef MODEMENU #include "X/Xlib.h" #include "menu.h" #ifndef lint static char sccs_id[] = "@(#)menu.c\tX10/6.6\t11/3/86"; #endif lint #define FALSE 0 #define TRUE 1 #define InvertPlane 1 #define SetStateFlags(item) item->itemFlags = (item->itemFlags &\ ~(itemStateMask | itemChanged)) |\ ((item->itemFlags & itemSetMask) >>\ itemSetMaskShift) static short Check_MarkBits[] = { 0x0100, 0x0180, 0x00c0, 0x0060, 0x0031, 0x001b, 0x000e, 0x0004 }; static short Check_GrayBits[] = { 0x0100, 0x0080, 0x0040, 0x0020, 0x0011, 0x000a, 0x0004, 0x0000 }; static short Default_CursorBits[] = { 0x0000, 0x0002, 0x0006, 0x000e, 0x001e, 0x003e, 0x007e, 0x00fe, 0x01fe, 0x003e, 0x0036, 0x0062, 0x0060, 0x00c0, 0x00c0, 0x0000 }; static short Default_GrayBits[] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, }; static short Default_MaskBits[] = { 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x007f, 0x00f7, 0x00f3, 0x01e1, 0x01e0, 0x01c0 }; static char def_menu_font[] = "vtsingle"; Pixmap Gray_Tile; Menu Menu_Default; Cursor Menu_DefaultCursor; char *Menu_DefaultFont; FontInfo *Menu_DefaultFontInfo; /* * AddMenuItem() adds a menu item to an existing menu, at the end of the * list, which are number sequentially from zero. The menuitem index is * return, or -1 if failed. */ AddMenuItem(menu, text) register Menu *menu; register char *text; { register MenuItem *menuitem, **next; register int i; extern char *malloc(); if(!menu || !text || (menuitem = (MenuItem *)malloc(sizeof(MenuItem))) == (MenuItem *)0) return(-1); bzero((char *)menuitem, sizeof(MenuItem)); menuitem->itemText = text; menuitem->itemTextLength = strlen(text); for(i = 0, next = &menu->menuItems ; *next ; i++) next = &(*next)->nextItem; *next = menuitem; menu->menuFlags |= menuChanged; return(i); } /* * DisposeItem() releases the memory allocated for the given indexed * menuitem. Nonzero is returned if an item was actual disposed of. */ DisposeItem(menu, i) register Menu *menu; register int i; { register MenuItem **next, **last, *menuitem; if(!menu || i < 0) return(0); next = &menu->menuItems; do { if(!*next) return(0); last = next; next = &(*next)->nextItem; } while(i-- > 0); menuitem = *last; *last = *next; free(menuitem); return(1); } /* * DisposeMenu() releases the memory allocated for the given menu. */ DisposeMenu(menu) register Menu *menu; { static Unmap_Menu(); if(!menu) return; if(menu->menuFlags & menuMapped) Unmap_Menu(menu); while(DisposeItem(menu, 0)); if(menu->menuWindow) XDestroyWindow(menu->menuWindow); if(menu->menuSaved) XFreePixmap(menu->menuSaved); free(menu); } InitMenu(name) register char *name; { register char *cp; register Bitmap bit; /* * If the gray tile hasn't been set up, do it now. */ if(!Gray_Tile) { if(!(bit = XStoreBitmap(grayWidth, grayHeight, Default_GrayBits))) return; Gray_Tile = XMakePixmap(bit, WhitePixel, BlackPixel); XFreeBitmap(bit); } Menu_Default.menuFlags = menuChanged; if((cp = XGetDefault(name, "MenuFreeze")) && strcmp(cp, "on") == 0) Menu_Default.menuFlags |= menuFreeze; if((cp = XGetDefault(name, "MenuSave")) && strcmp(cp, "on") == 0) Menu_Default.menuFlags |= menuSaveMenu; Menu_Default.menuInitialItem = -1; Menu_Default.menuBorderWidth = (cp = XGetDefault(name, "MenuBorder")) ? atoi(cp) : 2; Menu_Default.menuItemPad = (cp = XGetDefault(name, "MenuPad")) ? atoi(cp) : 3; Menu_DefaultFont = (cp = XGetDefault(name, "MenuFont")) ? cp : def_menu_font; }; /* * ItemFlags returns the state of item "n" of the menu. */ ItemFlags(menu, n) register Menu *menu; register int n; { register MenuItem *item; if(!menu || !menu->menuItems || n < 0) return(-1); for(item = menu->menuItems ; n > 0 ; n--) if(!(item = item->nextItem)) return(0); return((item->itemFlags & itemSetMask) >> itemSetMaskShift); } /* * ItemText changes the text of item "n" of the menu. */ ItemText(menu, n, text) register Menu *menu; register int n; char *text; { register MenuItem *item; if(!menu || !menu->menuItems || n < 0 || !text) return(0); for(item = menu->menuItems ; n > 0 ; n--) if(!(item = item->nextItem)) return(0); item->itemText = text; menu->menuFlags |= menuChanged; return(1); } /* * NewMenu() returns a pointer to an initialized new Menu structure, or NULL * if failed. * * The Menu structure _menuDefault contains the default menu settings. */ Menu *NewMenu(name, reverse) char *name; int reverse; { register Menu *menu; register int fg, bg; extern char *malloc(); /* * If the GrayTile hasn't been defined, InitMenu() was never * run, so exit. */ if(!Gray_Tile) return((Menu *)0); /* * Allocate the memory for the menu structure. */ if((menu = (Menu *)malloc(sizeof(Menu))) == (Menu *)0) return((Menu *)0); /* * Initialize to default values. */ *menu = Menu_Default; /* * If the menu font hasn't yet been gotten, go get it. */ if(!menu->menuFontInfo) { if(!Menu_DefaultFontInfo && !(Menu_DefaultFontInfo = XOpenFont(Menu_DefaultFont))) return((Menu *)0); menu->menuFontInfo = Menu_DefaultFontInfo; } /* * If the menu cursor hasn't been given, make a default one. */ if(!menu->menuCursor) { if(!Menu_DefaultCursor) { if(reverse) { fg = WhitePixel; bg = BlackPixel; } else { fg = BlackPixel; bg = WhitePixel; } if(!(Menu_DefaultCursor = XCreateCursor(defaultCursorWidth, defaultCursorHeight, Default_CursorBits, Default_MaskBits, defaultCursorX, defaultCursorY, fg, bg, GXcopy))) return((Menu *)0); } menu->menuCursor = Menu_DefaultCursor; } /* * Initialze the default background and border pixmaps and foreground * and background colors (black and white). */ if(reverse) { menu->menuBgTile = BlackPixmap; menu->menuFgColor = WhitePixel; menu->menuBgColor = BlackPixel; } else { menu->menuBgTile = WhitePixmap; menu->menuFgColor = BlackPixel; menu->menuBgColor = WhitePixel; } /* * Set the menu title. If name is NULL or is an empty string, no * title will be displayed. */ if(name && *name) { menu->menuTitleLength = strlen(menu->menuTitle = name); menu->menuTitleWidth = XStringWidth(name, menu->menuFontInfo, 0, 0); menu->menuItemTop = menu->menuFontInfo->height + 2 * menu->menuItemPad + 1; } else menu->menuTitleLength = menu->menuTitleWidth = menu->menuItemTop = 0; return(menu); } /* * SetItemCheck sets the check state of item "n" of the menu to "state". */ SetItemCheck(menu, n, state) register Menu *menu; register int n; int state; { register MenuItem *item; if(!menu || !menu->menuItems || n < 0) return(0); for(item = menu->menuItems ; n > 0 ; n--) if(!(item = item->nextItem)) return(0); if(state) item->itemFlags |= itemSetChecked; else item->itemFlags &= ~itemSetChecked; if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) != (item->itemFlags & itemStateMask)) { item->itemFlags |= itemChanged; menu->menuFlags |= menuItemChanged; } else item->itemFlags &= ~itemChanged; return(1); } /* * SetItemDisable sets the disable state of item "n" of the menu to "state". */ SetItemDisable(menu, n, state) register Menu *menu; register int n; int state; { register MenuItem *item; if(!menu || !menu->menuItems || n < 0) return(0); for(item = menu->menuItems ; n > 0 ; n--) if(!(item = item->nextItem)) return(0); if(state) item->itemFlags |= itemSetDisabled; else item->itemFlags &= ~itemSetDisabled; if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) != (item->itemFlags & itemStateMask)) { item->itemFlags |= itemChanged; menu->menuFlags |= menuItemChanged; } else item->itemFlags &= ~itemChanged; return(1); } /* * TrackMenu does most of the work of displaying the menu and tracking the * mouse. */ TrackMenu(menu, event) register Menu *menu; register XButtonPressedEvent *event; { register MenuItem *item; register int i, button; register MenuItem *hilited_item = (MenuItem *)0; register int drawn; XButtonReleasedEvent ev; register int changed; int y, n, hilited_y, hilited_n, in_window; static MenuItem *Mouse_InItem(), *Y_InItem(); static Unmap_Menu(); /* * Check that things are reasonable. */ if(!menu || !event || !menu->menuItems || event->type != ButtonPressed) return(-1); /* * Set the changed flag and clear the menu changed flags. */ changed = menu->menuFlags & (menuChanged | menuItemChanged); /* * If the entire menu has changed, throw away any saved pixmap and * then call RecalcMenu(). */ if(changed & menuChanged) { if(menu->menuSaved) XFreePixmap(menu->menuSaved); menu->menuSaved = (Pixmap)0; if(!Recalc_Menu(menu)) return(-1); changed &= ~menuItemChanged; } /* * Now if the window was never created, go ahead and make it. Otherwise * if the menu has changed, resize the window. */ if(!menu->menuWindow) { if((menu->menuWindow = XCreateWindow(RootWindow, 0, 0, menu->menuWidth, menu->menuHeight, menu->menuBorderWidth, Gray_Tile, menu->menuBgTile)) == (Window)0) return(-1); XDefineCursor(menu->menuWindow, menu->menuCursor); XSelectInput(menu->menuWindow, ExposeWindow | EnterWindow | LeaveWindow | MouseMoved | ButtonReleased); } else if(changed & menuChanged) XChangeWindow(menu->menuWindow, menu->menuWidth, menu->menuHeight); /* * Figure out where the menu is supposed to go, from the initial button * press, and move the window there. Then map the menu. */ if(!Move_Menu(menu, event) || !Map_Menu(menu)) return(-1); /* * Try to grab the mouse, over a period of 10 seconds. */ for(i = 10 ; ; ) { if(XGrabMouse(menu->menuWindow, menu->menuCursor, ButtonReleased | EnterWindow | LeaveWindow | MouseMoved)) break; if(--i <= 0) { Unmap_Menu(menu); return(-1); } sleep(1); } /* * Save away the button that was pressed and use it to match a * corresponding ButtonReleased event. */ button = event->detail & 03; /* * Now process events for the menu window. */ drawn = 0; for( ; ; ) { XNextEvent(&ev); if(ev.type != ButtonReleased && ev.window != menu->menuWindow) { if(menu->menuEventHandler) (*menu->menuEventHandler)(&ev); continue; } switch(ev.type) { case ExposeWindow: /* * If we have a saved pixmap, display it. Otherwise * redraw the menu and save it away. */ if(menu->menuSaved) { XPixmapPut(menu->menuWindow, 0, 0, 0, 0, menu->menuWidth, menu->menuHeight, menu->menuSaved, GXcopy, AllPlanes); /* * If the menuItemChanged flag is still set, * then we need to redraw certain menu items. * ("i" is the vertical position of the top * of the current item.) */ if(changed & menuItemChanged) { i = menu->menuItemTop; for(item = menu->menuItems ; item ; item = item->nextItem) { if(item->itemFlags & itemChanged) Modify_Item(menu, item, i); i += item->itemHeight; } } } else Draw_Menu(menu); /* * If the menu has changed in any way and we want to * save the menu, throw away any existing save menu * image and make a new one. */ XFlush(); if(changed && (menu->menuFlags & menuSaveMenu)) { if(menu->menuSaved) XFreePixmap(menu->menuSaved); menu->menuSaved = XPixmapSave(menu->menuWindow, 0, 0, menu->menuWidth, menu->menuHeight); } /* * See which item the cursor may currently be in. If * it is in a non-disabled item, hilite it. */ if(hilited_item = Mouse_InItem(menu, &hilited_y, &hilited_n, &in_window)) XPixFill(menu->menuWindow, 0, hilited_y, menu->menuWidth, hilited_item->itemHeight, BlackPixmap, (Bitmap)0, GXinvert, InvertPlane); drawn++; break; case EnterWindow: in_window = TRUE; /* drop through */ case MouseMoved: if(!drawn || !in_window) break; /* * See which item the cursor may currently be in. If * the item has changed, unhilite the old one and * then hilited the new one. */ y = ((XEnterWindowEvent *)&ev)->y; if((item = Y_InItem(menu, &y, &n)) != hilited_item) { if(hilited_item) XPixFill(menu->menuWindow, 0, hilited_y, menu->menuWidth, hilited_item->itemHeight, BlackPixmap, (Bitmap)0, GXinvert, InvertPlane); if(hilited_item = item) { XPixFill(menu->menuWindow, 0, hilited_y = y, menu->menuWidth, item->itemHeight, BlackPixmap, (Bitmap)0, GXinvert, InvertPlane); hilited_n = n; } } break; case LeaveWindow: if(!drawn) break; /* * Unhilite any window that is currently hilited. */ if(hilited_item) { XPixFill(menu->menuWindow, 0, hilited_y, menu->menuWidth, hilited_item->itemHeight, BlackPixmap, (Bitmap)0, GXinvert, InvertPlane); hilited_item = (MenuItem *)0; } in_window = FALSE; break; case ButtonReleased: /* * If the correct button was released, ungrab the mouse * and return the index number of any selected menu * item. */ if((ev.detail & 0x3) == button) { if(in_window) { y = ((XButtonReleasedEvent *)&ev)->y; if((item = Y_InItem(menu, &y, &n)) != hilited_item) { if(hilited_item) XPixFill(menu->menuWindow, 0, hilited_y, menu->menuWidth, hilited_item->itemHeight, BlackPixmap, (Bitmap)0, GXinvert, InvertPlane); if(hilited_item = item) { XPixFill(menu->menuWindow, 0, hilited_y = y, menu->menuWidth, hilited_item->itemHeight, BlackPixmap, (Bitmap)0, GXinvert, InvertPlane); hilited_n = n; } } } XUngrabMouse(); menu->menuFlags &= ~(menuChanged | menuItemChanged); Unmap_Menu(menu); XFlush(); if(hilited_item) return(menu->menuInitialItem = hilited_n); return(-1); } break; } } } /* * Recalculate all of the various menu and item variables. */ static Recalc_Menu(menu) register Menu *menu; { register MenuItem *item; register int max, i, height, fontheight; /* * We must have already gotten the menu font. */ if(!menu->menuFontInfo) return(0); /* * Initialize the various max width variables. */ fontheight = menu->menuFontInfo->height; height = menu->menuItemTop; menu->menuMaxTextWidth = menu->menuTitleWidth; /* * The item height is the maximum of the font height and the * checkbox height. */ max = fontheight; if(checkMarkHeight > max) max = checkMarkHeight; /* * Go through the menu item list. */ for(item = menu->menuItems ; item ; item = item->nextItem) { /* * If the item text is a single dash, we assume this is * a line separator and treat it special. */ if(strcmp(item->itemText, "-") == 0) height += (item->itemHeight = lineSeparatorHeight); else { height += (item->itemHeight = max); /* * Check the text width with the max value stored in * menu. */ if((item->itemTextWidth = XStringWidth(item->itemText, menu->menuFontInfo, 0, 0)) > menu->menuMaxTextWidth) menu->menuMaxTextWidth = item->itemTextWidth; } /* * If the itemChanged flag is set, set the state bits. */ if(item->itemFlags & itemChanged) { item->itemFlags = (item->itemFlags & ~itemStateMask) | ((item->itemFlags & itemSetMask) >> itemSetMaskShift); item->itemFlags &= ~itemChanged; } } /* * Set the menu height and then set the menu width. */ menu->menuHeight = height; menu->menuWidth = 3 * menu->menuItemPad + menu->menuMaxTextWidth + checkMarkWidth; return(1); } /* * Figure out where to popup the menu, relative to the where the button was * pressed. */ static Move_Menu(menu, ev) register Menu *menu; XButtonPressedEvent *ev; { register MenuItem *item; register int n, x, y; int ev_x, ev_y; int total_width; Window subw; /* * Get the coordinates of the mouse when the button was pressed. */ XInterpretLocator(RootWindow, &ev_x, &ev_y, &subw, ev->location); /* * Try to popup the menu so that the cursor is centered within the * width of the menu, but compensate if that would run it outside * the display area. */ total_width = menu->menuWidth + 2 * menu->menuBorderWidth; if((x = ev_x - total_width / 2) < 0) x = 0; else if(x + total_width > DisplayWidth()) x = DisplayWidth() - total_width; #ifdef DROPMENUS y = 0; #else DROPMENUS /* * If we have an inital item, try to popup the menu centered * vertically within this item. */ if(menu->menuInitialItem >= 0) { /* * Look through the item list. "y" is the vertical position * of the top of the current item and "n" is the item number. */ y = menu->menuItemTop + menu->menuBorderWidth; for(n = 0, item = menu->menuItems ; ; n++) { /* * On finding the intial item, center within this item. */ if(n == menu->menuInitialItem) { y += item->itemHeight / 2; break; } y += item->itemHeight; /* * If we run out of items, turn off the initial item * and treat this as if no initial item. */ if(!(item = item->nextItem)) { menu->menuInitialItem = -1; goto noInitial; } } /* * If no initial item, try to popup the menu centered in the item * nearest the center of the menu. */ } else { noInitial: /* * Look through the item list. "y" is the vertical position * of the top of the current item and "n" is the vertical * position of the center of the menu. */ y = menu->menuItemTop + menu->menuBorderWidth; for(n = menu->menuHeight / 2, item = menu->menuItems ; item ; item = item->nextItem) /* * If the center of the menu is in this item, we * center within this item. */ if((y += item->itemHeight) > n) { y -= item->itemHeight / 2; break; } } #endif DROPMENU /* * If the menu extends above outside of the display, warp * the mouse vertically so the menu will all show up. */ if((y = ev_y - y) < 0) { XWarpMouse(RootWindow, ev_x, ev_y - y); y = 0; } else if((n = y + menu->menuHeight + 2 * menu->menuBorderWidth - DisplayHeight()) > 0) { XWarpMouse(RootWindow, ev_x, ev_y - n); y -= n; } XMoveWindow(menu->menuWindow, x, y); /* * If we are in freeze mode, save what will be the coordinates of * the save image. */ if(menu->menuFlags & menuFreeze) { menu->menuSavedImageX = x; menu->menuSavedImageY = y; } return(1); } /* * Map the menu window. */ static Map_Menu(menu) register Menu *menu; { register int i; /* * If we are in freeze mode, save the pixmap underneath where the menu * will be (including the border). */ if(menu->menuFlags & menuFreeze) { XGrabServer(); i = 2 * menu->menuBorderWidth; if((menu->menuSavedImage = XPixmapSave(RootWindow, menu->menuSavedImageX, menu->menuSavedImageY, menu->menuWidth + i, menu->menuHeight + i)) == (Pixmap)0) return(0); } /* * Actually map the window. */ XMapWindow(menu->menuWindow); menu->menuFlags |= menuMapped; return(1); } /* * Draw the entire menu in the blank window. */ static Draw_Menu(menu) register Menu *menu; { register MenuItem *item; register int top = menu->menuItemTop; register int x = menu->menuItemPad; register int y, dim; /* * If we have a menu title, draw it first, centered and hilited. */ if(menu->menuTitleLength) { XPixSet(menu->menuWindow, 0, 0, menu->menuWidth, top - 1, menu->menuFgColor); XText(menu->menuWindow, (menu->menuWidth - menu->menuTitleWidth) / 2, menu->menuItemPad, menu->menuTitle, menu->menuTitleLength, menu->menuFontInfo->id, menu->menuBgColor, menu->menuFgColor); } /* * For each item in the list, first draw any check mark and then * draw the rest of it. */ for(item = menu->menuItems ; item ; item = item->nextItem) { SetStateFlags(item); dim = (item->itemFlags & itemDisabled); /* * Draw the check mark, possibly dimmed, wherever is necessary. */ if(item->itemFlags & itemChecked) { XBitmapBitsPut(menu->menuWindow, x, y = top + (item->itemHeight - checkMarkHeight) / 2, checkMarkWidth, checkMarkHeight, dim ? Check_GrayBits : Check_MarkBits, menu->menuFgColor, menu->menuBgColor, (Bitmap)0, GXcopy, AllPlanes); } /* * Draw the item, possibly dimmed. */ Draw_Item(menu, item, top, dim); top += item->itemHeight; } } /* * Modify the item at vertical position y. This routine is table driven and * the state and set bits are each 2 bits long, contiguous, the least * significant bits in the flag word and with the state bits in bits 0 & 1. */ #define drawCheck 0x10 #define removeCheck 0x08 #define dimCheck 0x04 #define drawItem 0x02 #define dimItem 0x01 static char Modify_Table[] = { 0x00, 0x02, 0x08, 0x0a, 0x01, 0x00, 0x09, 0x08, 0x10, 0x12, 0x00, 0x12, 0x15, 0x14, 0x05, 0x00 }; static Modify_Item(menu, item, top) register Menu *menu; register MenuItem *item; int top; { register int x = menu->menuItemPad; register int y; register int center = top + item->itemHeight / 2; register int func = Modify_Table[item->itemFlags & (itemStateMask | itemSetMask)]; /* * If we really won't be making a change, return. */ if(func == 0) return; /* * Draw the check mark if needed, possibly dimmed. */ y = center - (checkMarkHeight / 2); if(func & (drawCheck | dimCheck)) XBitmapBitsPut(menu->menuWindow, x, y, checkMarkWidth, checkMarkHeight, (func & dimCheck) ? Check_GrayBits : Check_MarkBits, menu->menuFgColor, menu->menuBgColor, (Bitmap)0, GXcopy, AllPlanes); /* * Remove the check mark if needed. */ if(func & removeCheck) XTileSet(menu->menuWindow, x, y, checkMarkWidth, checkMarkHeight, menu->menuBgTile); /* * Call Draw_Item if we need to draw or dim the item. */ if((x = func & dimItem) || (func & drawItem)) Draw_Item(menu, item, top, x); /* * Update state flags. */ SetStateFlags(item); } /* * Draw the item (less check mark) at vertical position y. * Dim the item if "dim" is set. */ static Draw_Item(menu, item, y, dim) register Menu *menu; register MenuItem *item; register int y; int dim; { register int x = 2 * menu->menuItemPad + checkMarkWidth; register int center = y + item->itemHeight / 2; /* * If the item text is a single dash, draw a separating line. */ if(strcmp(item->itemText, "-") == 0) { XLine(menu->menuWindow, 0, center, menu->menuWidth, center, 1, 1, menu->menuFgColor, GXcopy, AllPlanes); return; } /* * Draw and/or dim the text, centered vertically. */ y = center - (menu->menuFontInfo->height / 2); if(dim) { XTileSet(menu->menuWindow, x, y, item->itemTextWidth, menu->menuFontInfo->height, Gray_Tile); XTextPad(menu->menuWindow, x, y, item->itemText, item->itemTextLength, menu->menuFontInfo->id, 0, 0, menu->menuFgColor, menu->menuBgColor, menu->menuFgColor ? GXand : GXor, AllPlanes); } else XText(menu->menuWindow, x, y, item->itemText, item->itemTextLength, menu->menuFontInfo->id, menu->menuFgColor, menu->menuBgColor); } /* * Determine which enabled menu item the mouse is currently in. Return the * top position of this item and its item number. Set inwindow to whether * we are or not. */ static MenuItem *Mouse_InItem(menu, top, n, inwindow) register Menu *menu; int *top, *n, *inwindow; { int x, y; Window subw; static MenuItem *Y_InItem(); /* * Find out where the mouse is. If its not in the menu window, * return NULL. */ XQueryMouse(RootWindow, &x, &y, &subw); if(subw != menu->menuWindow) { *inwindow = FALSE; return((MenuItem *)0); } *inwindow = TRUE; /* * Now get the coordinates relative to the menu window. */ XInterpretLocator(menu->menuWindow, &x, &y, &subw, (x << 16) | y); /* * Call Y_InItem(). */ *top = y; return(Y_InItem(menu, top, n)); } /* * Return which enabled item the locator is in. Also return the * top position of this item and its item number. Initial y passed * in top. */ static MenuItem *Y_InItem(menu, top, n) register Menu *menu; int *top, *n; { register MenuItem *item; register int t, i; register int y = *top; Window subw; /* * Go through the item list. "t" is the vertical position of the * current item and "i" is its item number. */ t = menu->menuItemTop; /* * If the mouse is before the first item, return. */ if(y < t) return((MenuItem *)0); for(i = 0, item = menu->menuItems ; item ; i++, item = item->nextItem) { /* * If the y coordinate is within this menu item, then return. * But don't return disable items. */ if(t + item->itemHeight > y) { if(item->itemFlags & itemDisabled) return((MenuItem *)0); *top = t; *n = i; return(item); } t += item->itemHeight; } /* * Should never get here. */ return((MenuItem *)0); } /* * Unmap_Menu() unmaps a menu, if it is currently mapped. */ static Unmap_Menu(menu) register Menu *menu; { register int i; if(!menu || !(menu->menuFlags & menuMapped)) return; if(menu->menuFlags & menuFreeze) { XUnmapTransparent(menu->menuWindow); i = 2 * menu->menuBorderWidth; XPixmapPut(RootWindow, 0, 0, menu->menuSavedImageX, menu->menuSavedImageY, menu->menuWidth + i, menu->menuHeight + i, menu->menuSavedImage, GXcopy, AllPlanes); XFreePixmap(menu->menuSavedImage); XUngrabServer(); } else XUnmapWindow(menu->menuWindow); menu->menuFlags &= ~menuMapped; } #endif MODEMENU