diff options
Diffstat (limited to 'src/glut/glx/glut_menu.c')
-rw-r--r-- | src/glut/glx/glut_menu.c | 1023 |
1 files changed, 0 insertions, 1023 deletions
diff --git a/src/glut/glx/glut_menu.c b/src/glut/glx/glut_menu.c deleted file mode 100644 index d136823c54..0000000000 --- a/src/glut/glx/glut_menu.c +++ /dev/null @@ -1,1023 +0,0 @@ - -/* Copyright (c) Mark J. Kilgard, 1994, 1997. */ - -/* This program is freely distributable without licensing fees - and is provided without guarantee or warrantee expressed or - implied. This program is -not- in the public domain. */ - -/* The Win32 GLUT file win32_menu.c completely re-implements all - the menuing functionality implemented. This file is used only by - the X Window System version of GLUT. */ - -#ifdef __VMS -#include <GL/vms_x_fix.h> -#endif - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <assert.h> - -#include <unistd.h> -#include <X11/Xlib.h> -#include <X11/cursorfont.h> /* for XC_arrow */ - -#include "glutint.h" -#include "layerutil.h" - -void (CDECL *__glutMenuStatusFunc) (int, int, int); -GLUTmenuItem *__glutItemSelected; -GLUTmenu **__glutMenuList = NULL; - -static int menuListSize = 0; -static XFontStruct *menuFont = NULL; -static Cursor menuCursor; -static Colormap menuColormap; -static Visual *menuVisual; -static int menuDepth; -static int fontHeight; -static GC blackGC, grayGC, whiteGC; -static unsigned long menuBlack, menuWhite, menuGray; -static unsigned long useSaveUnders; - -/* A replacement for XAllocColor (originally by Brian Paul). - This function should never fail to allocate a color. When - XAllocColor fails, we return the nearest matching color. If - we have to allocate many colors this function isn't a great - solution; the XQueryColors() could be done just once. */ -static void -noFaultXAllocColor(Display * dpy, Colormap cmap, int cmapSize, - XColor * color) -{ - XColor *ctable, subColor; - int i, bestmatch; - double mindist; /* 3*2^16^2 exceeds 32-bit long int - precision. */ - - for (;;) { - /* First try just using XAllocColor. */ - if (XAllocColor(dpy, cmap, color)) { - return; - } - - /* Retrieve color table entries. */ - /* XXX alloca canidate. */ - ctable = (XColor *) malloc(cmapSize * sizeof(XColor)); - for (i = 0; i < cmapSize; i++) - ctable[i].pixel = i; - XQueryColors(dpy, cmap, ctable, cmapSize); - - /* Find best match. */ - bestmatch = -1; - mindist = 0.0; - for (i = 0; i < cmapSize; i++) { - double dr = (double) color->red - (double) ctable[i].red; - double dg = (double) color->green - (double) ctable[i].green; - double db = (double) color->blue - (double) ctable[i].blue; - double dist = dr * dr + dg * dg + db * db; - if (bestmatch < 0 || dist < mindist) { - bestmatch = i; - mindist = dist; - } - } - - /* Return result. */ - subColor.red = ctable[bestmatch].red; - subColor.green = ctable[bestmatch].green; - subColor.blue = ctable[bestmatch].blue; - free(ctable); - if (XAllocColor(dpy, cmap, &subColor)) { - *color = subColor; - return; - } - /* Extremely unlikely, but possibly color was deallocated - and reallocated by someone else before we could - XAllocColor the color cell we located. If so, loop - again... */ - } -} - -static int -ifSunCreator(void) -{ - char *xvendor, *glvendor, *renderer; - int isSunCreator = 0; /* Until proven that it is. */ - int savedDisplayMode = 0; - char *savedDisplayString = 0; - GLUTwindow *window; - -#define VENDOR_SUN "Sun Microsystems" -#define RENDERER_CREATOR "Creator" - - /* Check the X vendor string first. It is easier to check - than the OpenGL vendor and renderer strings since it - doesn't require a valid OpenGL rendering context. Bail - early if not connected to a Sun. */ - xvendor = ServerVendor(__glutDisplay); - if (!strncmp(xvendor, VENDOR_SUN, sizeof(VENDOR_SUN) - 1)) { - - /* We need a valid current OpenGL rendering context to be - able to call glGetString successfully. If there is not - a current window, set up a temporary one just to call - glGetString with (gag, expensive). */ - if (__glutCurrentWindow) { - window = NULL; - } else { - savedDisplayMode = __glutDisplayMode; - savedDisplayString = __glutDisplayString; - __glutDisplayMode = GLUT_RGB | GLUT_SINGLE; - __glutDisplayString = NULL; - window = __glutCreateWindow(NULL, 0, 0, 1, 1, 0); - } - - glvendor = (char *) glGetString(GL_VENDOR); - if (!strncmp(glvendor, VENDOR_SUN, sizeof(VENDOR_SUN) - 1)) { - renderer = (char *) glGetString(GL_RENDERER); - if (!strncmp(renderer, RENDERER_CREATOR, sizeof(RENDERER_CREATOR) - 1)) { - isSunCreator = 1; - } - } - /* Destroy the temporary window for glGetString if one - needed to be created. */ - if (window) { - __glutDestroyWindow(window, window); - __glutDisplayMode = savedDisplayMode; - __glutDisplayString = savedDisplayString; - } - } - return isSunCreator; -} - -static void -menuVisualSetup(void) -{ - XLayerVisualInfo template, *visual, *overlayVisuals; - XColor color; - Status status; - Bool presumablyMesa; - int layer, nVisuals, i, dummy; - unsigned long *placeHolders = NULL; - int numPlaceHolders = 0; - Bool allocateHigh; - - allocateHigh = ifSunCreator(); - - /* Start with the highest overlay layer and work down. I - don't think any hardware has more than 3 overlay layers. */ - for (layer = 3; layer > 0; layer--) { - template.layer = layer; - template.vinfo.screen = __glutScreen; - overlayVisuals = __glutXGetLayerVisualInfo(__glutDisplay, - VisualScreenMask | VisualLayerMask, &template, &nVisuals); - if (overlayVisuals) { - /* First, check if the default visual is in this layer. - If the default visual is in this layer, we try to use - it since it has pre-defined black and white pixels and - - using the default visual will probably minimize - colormap flashing problems. Suggested by Thomas Roell - (thomas@xig.com). */ - for (i = 0; i < nVisuals; i++) { - visual = &overlayVisuals[i]; - if (visual->vinfo.colormap_size >= 3) { - /* Compare visual IDs just to be safe. */ - if (visual->vinfo.visual->visualid == DefaultVisual(__glutDisplay, __glutScreen)->visualid) { - /* Settle for default visual. */ - menuVisual = DefaultVisual(__glutDisplay, __glutScreen); - menuDepth = DefaultDepth(__glutDisplay, __glutScreen); - menuColormap = DefaultColormap(__glutDisplay, __glutScreen); - menuBlack = BlackPixel(__glutDisplay, __glutScreen); - menuWhite = WhitePixel(__glutDisplay, __glutScreen); - color.red = color.green = color.blue = 0xaa00; - noFaultXAllocColor(__glutDisplay, menuColormap, - menuVisual->map_entries, &color); - menuGray = color.pixel; - useSaveUnders = 0; - XFree(overlayVisuals); - return; - } - } - } - for (i = 0; i < nVisuals; i++) { - visual = &overlayVisuals[i]; - if (visual->vinfo.colormap_size >= 3) { - if (allocateHigh) { - /* For Sun's Creator graphics, try to force the - read-only colors to the high end of the colormap - by first allocating read-write place-holder cells - for all but the last three cells. This helps - avoid colormap flashing problems. */ - numPlaceHolders = visual->vinfo.colormap_size - 3; - if (numPlaceHolders > 0) { - placeHolders = (unsigned long *) - malloc(numPlaceHolders * sizeof(unsigned long)); - /* A malloc failure would be harmless. */ - } - } - menuColormap = XCreateColormap(__glutDisplay, __glutRoot, - visual->vinfo.visual, AllocNone); - if (placeHolders) { - /* Again for Sun's Creator graphics, do the actual - read-write place-holder cell allocation. */ - status = XAllocColorCells(__glutDisplay, menuColormap, False, 0, 0, - placeHolders, numPlaceHolders); - if (!status) { - XFreeColormap(__glutDisplay, menuColormap); - free(placeHolders); - placeHolders = NULL; - continue; - } - } - /* Allocate overlay colormap cells in defined order: - gray, black, white to match the IRIS GL allocation - scheme. Increases likelihood of less overlay - colormap flashing. */ - /* XXX Nice if these 3 AllocColor's could be done in - one protocol round-trip. */ - color.red = color.green = color.blue = 0xaa00; - status = XAllocColor(__glutDisplay, - menuColormap, &color); - if (!status) { - XFreeColormap(__glutDisplay, menuColormap); - if (placeHolders) { - free(placeHolders); - placeHolders = NULL; - } - continue; - } - menuGray = color.pixel; - color.red = color.green = color.blue = 0x0000; - status = XAllocColor(__glutDisplay, - menuColormap, &color); - if (!status) { - XFreeColormap(__glutDisplay, menuColormap); - if (placeHolders) { - free(placeHolders); - placeHolders = NULL; - } - continue; - } - menuBlack = color.pixel; - color.red = color.green = color.blue = 0xffff; - status = XAllocColor(__glutDisplay, - menuColormap, &color); - if (!status) { - XFreeColormap(__glutDisplay, menuColormap); - if (placeHolders) { - free(placeHolders); - placeHolders = NULL; - } - continue; - } - if (placeHolders) { - /* Now free the placeholder cells. */ - XFreeColors(__glutDisplay, menuColormap, - placeHolders, numPlaceHolders, 0); - free(placeHolders); - placeHolders = NULL; - } - menuWhite = color.pixel; - menuVisual = visual->vinfo.visual; - menuDepth = visual->vinfo.depth; - /* If using overlays, do not request "save unders". */ - useSaveUnders = 0; - XFree(overlayVisuals); - return; - } - } - XFree(overlayVisuals); - } - } - /* Settle for default visual. */ - menuVisual = DefaultVisual(__glutDisplay, __glutScreen); - menuDepth = DefaultDepth(__glutDisplay, __glutScreen); - menuColormap = DefaultColormap(__glutDisplay, __glutScreen); - menuBlack = BlackPixel(__glutDisplay, __glutScreen); - menuWhite = WhitePixel(__glutDisplay, __glutScreen); - color.red = color.green = color.blue = 0xaa00; - noFaultXAllocColor(__glutDisplay, menuColormap, - menuVisual->map_entries, &color); - menuGray = color.pixel; - - /* When no overlays are supported, we would like to use X - "save unders" to avoid exposes to windows obscured by - pop-up menus. However, OpenGL's direct rendering support - means OpenGL interacts poorly with X backing store and - save unders. X servers do not (in implementation - practice) redirect OpenGL rendering destined to obscured - window regions into backing store. - - Implementation solutions exist for this problem, but they - are expensive and high-end OpenGL implementations - typically provide fast rendering and/or overlays to - obviate the problem associated of user interfaces (pop-up - menus) forcing redraws of complex normal plane scenes. - (See support for overlays pop-up menus above.) - - Mesa 3D, however, does not support direct rendering. - Overlays are often unavailable to Mesa, and Mesa is also - relatively slow. For these reasons, Mesa-rendering GLUT - programs can and should use X save unders. - - Look for the GLX extension. If _not_ supported, we are - presumably using Mesa so enable save unders. */ - - presumablyMesa = !XQueryExtension(__glutDisplay, "GLX", - &dummy, &dummy, &dummy); - - if (presumablyMesa) { - useSaveUnders = CWSaveUnder; - } else { - useSaveUnders = 0; - } -} - -static void -menuSetup(void) -{ - if (menuFont) { - /* MenuFont overload to indicate menu initalization. */ - return; - } - menuFont = XLoadQueryFont(__glutDisplay, - "-*-helvetica-bold-o-normal--14-*-*-*-p-*-iso8859-1"); - if (!menuFont) { - /* Try back up font. */ - menuFont = XLoadQueryFont(__glutDisplay, "fixed"); - } - if (!menuFont) { - __glutFatalError("could not load font."); - } - menuVisualSetup(); - fontHeight = menuFont->ascent + menuFont->descent; - menuCursor = XCreateFontCursor(__glutDisplay, XC_arrow); -} - -static void -menuGraphicsContextSetup(Window win) -{ - XGCValues gcvals; - - if (blackGC != None) { - return; - } - gcvals.font = menuFont->fid; - gcvals.foreground = menuBlack; - blackGC = XCreateGC(__glutDisplay, win, - GCFont | GCForeground, &gcvals); - gcvals.foreground = menuGray; - grayGC = XCreateGC(__glutDisplay, win, GCForeground, &gcvals); - gcvals.foreground = menuWhite; - whiteGC = XCreateGC(__glutDisplay, win, GCForeground, &gcvals); -} - -void -__glutSetMenu(GLUTmenu * menu) -{ - __glutCurrentMenu = menu; -} - -static void -unmapMenu(GLUTmenu * menu) -{ - if (menu->cascade) { - unmapMenu(menu->cascade); - menu->cascade = NULL; - } - menu->anchor = NULL; - menu->highlighted = NULL; - XUnmapWindow(__glutDisplay, menu->win); -} - -static void -finishMenu(Window win, int x, int y) -{ - Window dummy; - int rc; - - unmapMenu(__glutMappedMenu); - XUngrabPointer(__glutDisplay, CurrentTime); - - /* Popping up an overlay popup menu will install its own - colormap. If the window associated with the menu has an - overlay, install that window's overlay colormap so the - overlay isn't left using the popup menu's colormap. */ - if (__glutMenuWindow->overlay) { - XInstallColormap(__glutDisplay, - __glutMenuWindow->overlay->colormap->cmap); - } - - /* This XFlush is needed to to make sure the pointer is - really ungrabbed when the application's menu callback is - called. Otherwise, a deadlock might happen because the - application may try to read from an terminal window, but - yet the ungrab hasn't really happened since it hasn't been - flushed out. */ - XFlush(__glutDisplay); - - if (__glutMenuStatusFunc) { - if (win != __glutMenuWindow->win) { - /* The button release may have occurred in a window other - than the window requesting the pop-up menu (for - example, one of the submenu windows). In this case, we - need to translate the coordinates into the coordinate - system of the window associated with the window. */ - rc = XTranslateCoordinates(__glutDisplay, win, __glutMenuWindow->win, - x, y, &x, &y, &dummy); - assert(rc != False); /* Will always be on same screen. */ - } - __glutSetWindow(__glutMenuWindow); - __glutSetMenu(__glutMappedMenu); - - /* Setting __glutMappedMenu to NULL permits operations that - change menus or destroy the menu window again. */ - __glutMappedMenu = NULL; - - __glutMenuStatusFunc(GLUT_MENU_NOT_IN_USE, x, y); - } - /* Setting __glutMappedMenu to NULL permits operations that - change menus or destroy the menu window again. */ - __glutMappedMenu = NULL; - - /* If an item is selected and it is not a submenu trigger, - generate menu callback. */ - if (__glutItemSelected && !__glutItemSelected->isTrigger) { - __glutSetWindow(__glutMenuWindow); - /* When menu callback is triggered, current menu should be - set to the callback menu. */ - __glutSetMenu(__glutItemSelected->menu); - __glutItemSelected->menu->select( - __glutItemSelected->value); - } - __glutMenuWindow = NULL; -} - -#define MENU_BORDER 1 -#define MENU_GAP 2 -#define MENU_ARROW_GAP 6 -#define MENU_ARROW_WIDTH 8 - -static void -mapMenu(GLUTmenu * menu, int x, int y) -{ - XWindowChanges changes; - unsigned int mask; - int subMenuExtension, num; - - /* If there are submenus, we need to provide extra space for - the submenu pull arrow. */ - if (menu->submenus > 0) { - subMenuExtension = MENU_ARROW_GAP + MENU_ARROW_WIDTH; - } else { - subMenuExtension = 0; - } - - changes.stack_mode = Above; - mask = CWStackMode | CWX | CWY; - /* If the menu isn't managed (ie, validated so all the - InputOnly subwindows are the right size), do so. */ - if (!menu->managed) { - GLUTmenuItem *item; - - item = menu->list; - num = menu->num; - while (item) { - XWindowChanges itemupdate; - - itemupdate.y = (num - 1) * fontHeight + MENU_GAP; - itemupdate.width = menu->pixwidth; - itemupdate.width += subMenuExtension; - XConfigureWindow(__glutDisplay, item->win, - CWWidth | CWY, &itemupdate); - item = item->next; - num--; - } - menu->pixheight = MENU_GAP + - fontHeight * menu->num + MENU_GAP; - changes.height = menu->pixheight; - changes.width = MENU_GAP + - menu->pixwidth + subMenuExtension + MENU_GAP; - mask |= CWWidth | CWHeight; - menu->managed = True; - } - /* Make sure menu appears fully on screen. */ - if (y + menu->pixheight >= __glutScreenHeight) { - changes.y = __glutScreenHeight - menu->pixheight; - } else { - changes.y = y; - } - if (x + menu->pixwidth + subMenuExtension >= - __glutScreenWidth) { - changes.x = __glutScreenWidth - - menu->pixwidth + subMenuExtension; - } else { - changes.x = x; - } - - /* Rember where the menu is placed so submenus can be - properly placed relative to it. */ - menu->x = changes.x; - menu->y = changes.y; - - XConfigureWindow(__glutDisplay, menu->win, mask, &changes); - XInstallColormap(__glutDisplay, menuColormap); - /* XXX The XRaiseWindow below should not be necessary because - the XConfigureWindow requests an Above stack mode (same as - XRaiseWindow), but some Sun users complained this was still - necessary. Probably some window manager or X server bug on - these machines?? */ - XRaiseWindow(__glutDisplay, menu->win); - XMapWindow(__glutDisplay, menu->win); -} - -static void -startMenu(GLUTmenu * menu, GLUTwindow * window, - int x, int y, int x_win, int y_win) -{ - int grab; - - assert(__glutMappedMenu == NULL); - grab = XGrabPointer(__glutDisplay, __glutRoot, True, - ButtonPressMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, - __glutRoot, menuCursor, CurrentTime); - if (grab != GrabSuccess) { - /* Somebody else has pointer grabbed, ignore menu - activation. */ - return; - } - __glutMappedMenu = menu; - __glutMenuWindow = window; - __glutItemSelected = NULL; - if (__glutMenuStatusFunc) { - __glutSetMenu(menu); - __glutSetWindow(window); - __glutMenuStatusFunc(GLUT_MENU_IN_USE, x_win, y_win); - } - mapMenu(menu, x, y); -} - -static void -paintSubMenuArrow(Window win, int x, int y) -{ - XPoint p[5]; - - p[0].x = p[4].x = x; - p[0].y = p[4].y = y - menuFont->ascent + 1; - p[1].x = p[0].x + MENU_ARROW_WIDTH - 1; - p[1].y = p[0].y + (menuFont->ascent / 2) - 1; - p[2].x = p[1].x; - p[2].y = p[1].y + 1; - p[3].x = p[0].x; - p[3].y = p[0].y + menuFont->ascent - 2; - XFillPolygon(__glutDisplay, win, - whiteGC, p, 4, Convex, CoordModeOrigin); - XDrawLines(__glutDisplay, win, blackGC, p, 5, CoordModeOrigin); -} - -static void -paintMenuItem(GLUTmenuItem * item, int num) -{ - Window win = item->menu->win; - GC gc; - int y; - int subMenuExtension; - - if (item->menu->submenus > 0) { - subMenuExtension = MENU_ARROW_GAP + MENU_ARROW_WIDTH; - } else { - subMenuExtension = 0; - } - if (item->menu->highlighted == item) { - gc = whiteGC; - } else { - gc = grayGC; - } - y = MENU_GAP + fontHeight * num - menuFont->descent; - XFillRectangle(__glutDisplay, win, gc, - MENU_GAP, y - fontHeight + menuFont->descent, - item->menu->pixwidth + subMenuExtension, fontHeight); - XDrawString(__glutDisplay, win, blackGC, - MENU_GAP, y, item->label, item->len); - if (item->isTrigger) { - paintSubMenuArrow(win, - item->menu->pixwidth + MENU_ARROW_GAP + 1, y); - } -} - -static void -paintMenu(GLUTmenu * menu) -{ - GLUTmenuItem *item; - int i = menu->num; - int y = MENU_GAP + fontHeight * i - menuFont->descent; - - item = menu->list; - while (item) { - if (item->menu->highlighted == item) { - paintMenuItem(item, i); - } else { - /* Quick render of the menu item; assume background - already cleared to gray. */ - XDrawString(__glutDisplay, menu->win, blackGC, - 2, y, item->label, item->len); - if (item->isTrigger) { - paintSubMenuArrow(menu->win, - menu->pixwidth + MENU_ARROW_GAP + 1, y); - } - } - i--; - y -= fontHeight; - item = item->next; - } -} - -static GLUTmenuItem * -getMenuItem(GLUTmenu * menu, Window win, int *which) -{ - GLUTmenuItem *item; - int i; - - if (menu->searched) { - __glutFatalError("submenu infinite loop detected"); - } - menu->searched = True; - i = menu->num; - item = menu->list; - while (item) { - if (item->win == win) { - *which = i; - menu->searched = False; - return item; - } - if (item->isTrigger) { - GLUTmenuItem *subitem; - - subitem = __glutGetMenuItem(__glutMenuList[item->value], - win, which); - if (subitem) { - menu->searched = False; - return subitem; - } - } - i--; - item = item->next; - } - menu->searched = False; - return NULL; -} - -static int -getMenuItemIndex(GLUTmenuItem * item) -{ - int count = 0; - - while (item) { - count++; - item = item->next; - } - return count; -} - -static GLUTmenu * -getMenu(Window win) -{ - GLUTmenu *menu; - - menu = __glutMappedMenu; - while (menu) { - if (win == menu->win) { - return menu; - } - menu = menu->cascade; - } - return NULL; -} - -static GLUTmenu * -getMenuByNum(int menunum) -{ - if (menunum < 1 || menunum > menuListSize) { - return NULL; - } - return __glutMenuList[menunum - 1]; -} - -static int -getUnusedMenuSlot(void) -{ - int i; - - /* Look for allocated, unused slot. */ - for (i = 0; i < menuListSize; i++) { - if (!__glutMenuList[i]) { - return i; - } - } - /* Allocate a new slot. */ - menuListSize++; - if (__glutMenuList) { - __glutMenuList = (GLUTmenu **) - realloc(__glutMenuList, menuListSize * sizeof(GLUTmenu *)); - } else { - /* XXX Some realloc's do not correctly perform a malloc - when asked to perform a realloc on a NULL pointer, - though the ANSI C library spec requires this. */ - __glutMenuList = (GLUTmenu **) malloc(sizeof(GLUTmenu *)); - } - if (!__glutMenuList) { - __glutFatalError("out of memory."); - } - __glutMenuList[menuListSize - 1] = NULL; - return menuListSize - 1; -} - -void -__glutMenuModificationError(void) -{ - /* XXX Remove the warning after GLUT 3.0. */ - __glutWarning("The following is a new check for GLUT 3.0; update your code."); - __glutFatalError("menu manipulation not allowed while menus in use."); -} - - -static void -menuItemEnterOrLeave(GLUTmenuItem * item, - int num, int type) -{ - int alreadyUp = 0; - - if (type == EnterNotify) { - GLUTmenuItem *prevItem = item->menu->highlighted; - - if (prevItem && prevItem != item) { - /* If there's an already higlighted item in this menu - that is different from this one (we could be - re-entering an item with an already cascaded - submenu!), unhighlight the previous item. */ - item->menu->highlighted = NULL; - paintMenuItem(prevItem, getMenuItemIndex(prevItem)); - } - item->menu->highlighted = item; - __glutItemSelected = item; - if (item->menu->cascade) { - if (!item->isTrigger) { - /* Entered a menu item that is not a submenu trigger, - so pop down the current submenu cascade of this - menu. */ - unmapMenu(item->menu->cascade); - item->menu->cascade = NULL; - } else { - GLUTmenu *submenu = __glutMenuList[item->value]; - - if (submenu->anchor == item) { - /* We entered the submenu trigger for the submenu - that is already up, so don't take down the - submenu. */ - alreadyUp = 1; - } else { - /* Submenu already popped up for some other submenu - item of this menu; need to pop down that other - submenu cascade. */ - unmapMenu(item->menu->cascade); - item->menu->cascade = NULL; - } - } - } - if (!alreadyUp) { - /* Make sure the menu item gets painted with - highlighting. */ - paintMenuItem(item, num); - } else { - /* If already up, should already be highlighted. */ - } - } else { - /* LeaveNotify: Handle leaving a menu item... */ - if (item->menu->cascade && - item->menu->cascade->anchor == item) { - /* If there is a submenu casacaded from this item, do not - change the highlighting on this item upon leaving. */ - } else { - /* Unhighlight this menu item. */ - item->menu->highlighted = NULL; - paintMenuItem(item, num); - } - __glutItemSelected = NULL; - } - if (item->isTrigger) { - if (type == EnterNotify && !alreadyUp) { - GLUTmenu *submenu = __glutMenuList[item->value]; - - mapMenu(submenu, - item->menu->x + item->menu->pixwidth + - MENU_ARROW_GAP + MENU_ARROW_WIDTH + - MENU_GAP + MENU_BORDER, - item->menu->y + fontHeight * (num - 1) + MENU_GAP); - item->menu->cascade = submenu; - submenu->anchor = item; - } - } -} - -/* Installs callback functions for use by glut_event.c The point - of this is so that GLUT's menu code only gets linked into - GLUT binaries (assuming a static library) if the GLUT menu - API is used. */ -static void -installMenuCallbacks(void) -{ - __glutMenuItemEnterOrLeave = menuItemEnterOrLeave; - __glutFinishMenu = finishMenu; - __glutPaintMenu = paintMenu; - __glutStartMenu = startMenu; - __glutGetMenuByNum = getMenuByNum; - __glutGetMenu = getMenu; - __glutGetMenuItem = getMenuItem; -} - -int GLUTAPIENTRY -glutCreateMenu(GLUTselectCB selectFunc) -{ - XSetWindowAttributes wa; - GLUTmenu *menu; - int menuid; - - if (__glutMappedMenu) { - __glutMenuModificationError(); - } - if (!__glutDisplay) { - __glutOpenXConnection(NULL); - } - - installMenuCallbacks(); - - menuid = getUnusedMenuSlot(); - menu = (GLUTmenu *) malloc(sizeof(GLUTmenu)); - if (!menu) { - __glutFatalError("out of memory."); - } - menu->id = menuid; - menu->num = 0; - menu->submenus = 0; - menu->managed = False; - menu->searched = False; - menu->pixwidth = 0; - menu->select = selectFunc; - menu->list = NULL; - menu->cascade = NULL; - menu->highlighted = NULL; - menu->anchor = NULL; - menuSetup(); - wa.override_redirect = True; - wa.background_pixel = menuGray; - wa.border_pixel = menuBlack; - wa.colormap = menuColormap; - wa.event_mask = StructureNotifyMask | ExposureMask | - ButtonPressMask | ButtonReleaseMask | - EnterWindowMask | LeaveWindowMask; - /* Save unders really only enabled if useSaveUnders is set to - CWSaveUnder, ie. using Mesa 3D. See earlier comments. */ - wa.save_under = True; - menu->win = XCreateWindow(__glutDisplay, __glutRoot, - /* Real position determined when mapped. */ - 0, 0, - /* Real size will be determined when menu is manged. */ - 1, 1, - MENU_BORDER, menuDepth, InputOutput, menuVisual, - CWOverrideRedirect | CWBackPixel | CWBorderPixel | - CWEventMask | CWColormap | useSaveUnders, - &wa); - menuGraphicsContextSetup(menu->win); - __glutMenuList[menuid] = menu; - __glutSetMenu(menu); - return menuid + 1; -} - -/* CENTRY */ -int GLUTAPIENTRY -glutGetMenu(void) -{ - if (__glutCurrentMenu) { - return __glutCurrentMenu->id + 1; - } else { - return 0; - } -} - -void GLUTAPIENTRY -glutSetMenu(int menuid) -{ - GLUTmenu *menu; - - if (menuid < 1 || menuid > menuListSize) { - __glutWarning("glutSetMenu attempted on bogus menu."); - return; - } - menu = __glutMenuList[menuid - 1]; - if (!menu) { - __glutWarning("glutSetMenu attempted on bogus menu."); - return; - } - __glutSetMenu(menu); -} -/* ENDCENTRY */ - -void -__glutSetMenuItem(GLUTmenuItem * item, const char *label, - int value, Bool isTrigger) -{ - GLUTmenu *menu; - - menu = item->menu; - item->label = __glutStrdup(label); - if (!item->label) { - __glutFatalError("out of memory."); - } - item->isTrigger = isTrigger; - item->len = (int) strlen(label); - item->value = value; - item->pixwidth = XTextWidth(menuFont, label, item->len) + 4; - if (item->pixwidth > menu->pixwidth) { - menu->pixwidth = item->pixwidth; - } - menu->managed = False; -} - -/* CENTRY */ -void GLUTAPIENTRY -glutAddMenuEntry(const char *label, int value) -{ - XSetWindowAttributes wa; - GLUTmenuItem *entry; - - if (__glutMappedMenu) { - __glutMenuModificationError(); - } - entry = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem)); - if (!entry) { - __glutFatalError("out of memory."); - } - entry->menu = __glutCurrentMenu; - __glutSetMenuItem(entry, label, value, False); - wa.event_mask = EnterWindowMask | LeaveWindowMask; - entry->win = XCreateWindow(__glutDisplay, - __glutCurrentMenu->win, MENU_GAP, - __glutCurrentMenu->num * fontHeight + MENU_GAP, /* x & y */ - entry->pixwidth, fontHeight, /* width & height */ - 0, CopyFromParent, InputOnly, CopyFromParent, - CWEventMask, &wa); - XMapWindow(__glutDisplay, entry->win); - __glutCurrentMenu->num++; - entry->next = __glutCurrentMenu->list; - __glutCurrentMenu->list = entry; -} - -void GLUTAPIENTRY -glutAddSubMenu(const char *label, int menu) -{ - XSetWindowAttributes wa; - GLUTmenuItem *submenu; - - if (__glutMappedMenu) { - __glutMenuModificationError(); - } - submenu = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem)); - if (!submenu) { - __glutFatalError("out of memory."); - } - __glutCurrentMenu->submenus++; - submenu->menu = __glutCurrentMenu; - __glutSetMenuItem(submenu, label, /* base 0 */ menu - 1, True); - wa.event_mask = EnterWindowMask | LeaveWindowMask; - submenu->win = XCreateWindow(__glutDisplay, - __glutCurrentMenu->win, MENU_GAP, - __glutCurrentMenu->num * fontHeight + MENU_GAP, /* x & y */ - submenu->pixwidth, fontHeight, /* width & height */ - 0, CopyFromParent, InputOnly, CopyFromParent, - CWEventMask, &wa); - XMapWindow(__glutDisplay, submenu->win); - __glutCurrentMenu->num++; - submenu->next = __glutCurrentMenu->list; - __glutCurrentMenu->list = submenu; -} - -void GLUTAPIENTRY -glutAttachMenu(int button) -{ - /* if button >= GLUT_MAX_MENUS, we'll go out of array bounds below */ - if (button >= GLUT_MAX_MENUS) { - return; - } - if (__glutMappedMenu) { - __glutMenuModificationError(); - } - installMenuCallbacks(); - if (__glutCurrentWindow->menu[button] < 1) { - __glutCurrentWindow->buttonUses++; - } - __glutChangeWindowEventMask( - ButtonPressMask | ButtonReleaseMask, True); - __glutCurrentWindow->menu[button] = __glutCurrentMenu->id + 1; -} -/* ENDCENTRY */ |