home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) Mark J. Kilgard, 1994. */
-
- /* 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. */
-
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <errno.h>
- #include <assert.h>
-
- #include <GL/glut.h>
- #include "glutint.h"
-
- GLUTmenu *__glutCurrentMenu = NULL;
- void (*__glutMenuStatusFunc) (int, int, int);
- GLUTmenu *__glutMappedMenu;
- GLUTwindow *__glutMenuWindow;
- GLUTmenuItem *__glutItemSelected;
- unsigned __glutMenuButton;
-
- static GLUTmenu **menuList = 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;
-
- #if 0
- /* 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 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 void
- menuVisualSetup(void)
- {
- XLayerVisualInfo template, *visual, *overlayVisuals;
- XColor color;
- Status status;
- Bool presumablyMesa;
- int layer, nVisuals, i, dummy;
-
- for (layer = 3; layer > 0; layer--) {
- template.layer = layer;
- template.vinfo.screen = __glutScreen;
- overlayVisuals = __glutXGetLayerVisualInfo(__glutDisplay,
- VisualScreenMask | VisualLayerMask, &template, &nVisuals);
- if (overlayVisuals) {
- for (i = 0; i < nVisuals; i++) {
- visual = &overlayVisuals[i];
- if (visual->vinfo.colormap_size >= 3) {
- menuColormap = XCreateColormap(__glutDisplay, __glutRoot,
- visual->vinfo.visual, AllocNone);
- /* 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);
- continue;
- }
- menuGray = color.pixel;
- color.red = color.green = color.blue = 0x0000;
- status = XAllocColor(__glutDisplay,
- menuColormap, &color);
- if (!status) {
- XFreeColormap(__glutDisplay, menuColormap);
- continue;
- }
- menuBlack = color.pixel;
- color.red = color.green = color.blue = 0xffff;
- status = XAllocColor(__glutDisplay,
- menuColormap, &color);
- if (!status) {
- XFreeColormap(__glutDisplay, menuColormap);
- continue;
- }
- menuWhite = color.pixel;
- menuVisual = visual->vinfo.visual;
- menuDepth = visual->vinfo.depth;
- /* If using overlays, avoid requesting "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);
- }
- #endif
-
- /* DEPRICATED, use glutMenuStatusFunc instead. */
- void APIENTRY
- glutMenuStateFunc(GLUTmenuStateCB menuStateFunc)
- {
- __glutMenuStatusFunc = (GLUTmenuStatusCB) menuStateFunc;
- }
-
- void APIENTRY
- glutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc)
- {
- __glutMenuStatusFunc = menuStatusFunc;
- }
-
- 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);
- }
-
- void
- __glutFinishMenu(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. */
- GdiFlush(); // put in a GdiFlush() just in case
-
- 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)
- {
- TrackPopupMenu(menu->win, TPM_LEFTALIGN |
- __glutMenuButton == TPM_RIGHTBUTTON ?
- TPM_RIGHTBUTTON : TPM_LEFTBUTTON,
- x, y, 0, __glutCurrentWindow->win, NULL);
- // 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);
- }
-
- void
- __glutStartMenu(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);
- }
-
- #if 0
- 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)
- {
- HWND 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);
- }
- }
-
- void
- __glutPaintMenu(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;
- }
- }
- #endif
-
- GLUTmenuItem *
- __glutGetUniqueMenuItem(GLUTmenu * menu, int unique)
- {
- GLUTmenuItem *item;
- int i;
-
- i = menu->num;
- item = menu->list;
- while (item) {
- if (item->unique == unique)
- return item;
- if (item->isTrigger) {
- GLUTmenuItem *subitem;
- subitem = __glutGetUniqueMenuItem(menuList[item->value], unique);
- if (subitem)
- return subitem;
- }
- i--;
- item = item->next;
- }
- return NULL;
- }
-
- GLUTmenuItem *
- __glutGetMenuItem(GLUTmenu * menu, Window win, int *which)
- {
- GLUTmenuItem *item;
- int i;
-
- i = menu->num;
- item = menu->list;
- while (item) {
- if (item->win == win) {
- *which = i;
- return item;
- }
- if (item->isTrigger) {
- GLUTmenuItem *subitem;
-
- subitem = __glutGetMenuItem(menuList[item->value],
- win, which);
- if (subitem) {
- return subitem;
- }
- }
- i--;
- item = item->next;
- }
- return NULL;
- }
-
- static int
- getMenuItemIndex(GLUTmenuItem * item)
- {
- int count = 0;
-
- while (item) {
- count++;
- item = item->next;
- }
- return count;
- }
-
- GLUTmenu *
- __glutGetMenu(Window win)
- {
- GLUTmenu *menu;
-
- menu = __glutMappedMenu;
- while (menu) {
- if (win == menu->win) {
- return menu;
- }
- menu = menu->cascade;
- }
- return NULL;
- }
-
- GLUTmenu *
- __glutGetMenuByNum(int menunum)
- {
- if (menunum < 1 || menunum > menuListSize) {
- return NULL;
- }
- return menuList[menunum - 1];
- }
-
- static int
- getUnusedMenuSlot(void)
- {
- int i;
-
- /* Look for allocated, unused slot. */
- for (i = 0; i < menuListSize; i++) {
- if (!menuList[i]) {
- return i;
- }
- }
- /* Allocate a new slot. */
- menuListSize++;
- if (menuList) {
- menuList = (GLUTmenu **)
- realloc(menuList, 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. */
- menuList = (GLUTmenu **) malloc(sizeof(GLUTmenu *));
- }
- if (!menuList)
- __glutFatalError("out of memory.");
- menuList[menuListSize - 1] = NULL;
- return menuListSize - 1;
- }
-
- static void
- menuModificationError(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.");
- }
-
- int APIENTRY
- glutCreateMenu(GLUTselectCB selectFunc)
- {
- // XSetWindowAttributes wa;
- GLUTmenu *menu;
- int menuid;
-
- if (__glutMappedMenu)
- menuModificationError();
- 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->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 = CreatePopupMenu();
- // 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);
- menuList[menuid] = menu;
- __glutSetMenu(menu);
- return menuid + 1;
- }
-
- /* CENTRY */
- void APIENTRY
- glutDestroyMenu(int menunum)
- {
- GLUTmenu *menu = __glutGetMenuByNum(menunum);
- GLUTmenuItem *item, *next;
-
- if (__glutMappedMenu)
- menuModificationError();
- assert(menu->id == menunum - 1);
- DestroyMenu(menu->win);
- // XDestroySubwindows(__glutDisplay, menu->win);
- // XDestroyWindow(__glutDisplay, menu->win);
- menuList[menunum - 1] = NULL;
- /* free all menu entries */
- item = menu->list;
- while (item) {
- assert(item->menu == menu);
- next = item->next;
- free(item->label);
- free(item);
- item = next;
- }
- if (__glutCurrentMenu == menu) {
- __glutCurrentMenu = NULL;
- }
- free(menu);
- }
-
- int APIENTRY
- glutGetMenu(void)
- {
- if (__glutCurrentMenu) {
- return __glutCurrentMenu->id + 1;
- } else {
- return 0;
- }
- }
-
- void APIENTRY
- glutSetMenu(int menuid)
- {
- GLUTmenu *menu;
-
- if (menuid < 1 || menuid > menuListSize) {
- __glutWarning("glutSetMenu attempted on bogus menu.");
- return;
- }
- menu = menuList[menuid - 1];
- if (!menu) {
- __glutWarning("glutSetMenu attempted on bogus menu.");
- return;
- }
- __glutSetMenu(menu);
- }
- /* ENDCENTRY */
-
- static void
- setMenuItem(GLUTmenuItem * item, const char *label,
- int value, Bool isTrigger)
- {
- GLUTmenu *menu;
- static unsigned int unique = 1;
-
- 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->unique = unique++;
- if (isTrigger) {
- AppendMenu(menu->win, MF_POPUP, (UINT)item->win, label);
- } else {
- AppendMenu(menu->win, MF_STRING, (UINT)item->unique, label);
- }
- // item->pixwidth = XTextWidth(menuFont, label, item->len) + 4;
- // if (item->pixwidth > menu->pixwidth) {
- // menu->pixwidth = item->pixwidth;
- // }
- menu->managed = FALSE;
- }
-
- /* CENTRY */
- void APIENTRY
- glutAddMenuEntry(const char *label, int value)
- {
- // XSetWindowAttributes wa;
- GLUTmenuItem *entry;
-
- if (__glutMappedMenu)
- menuModificationError();
- entry = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
- if (!entry)
- __glutFatalError("out of memory.");
- entry->menu = __glutCurrentMenu;
- setMenuItem(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 APIENTRY
- glutAddSubMenu(const char *label, int menu)
- {
- // XSetWindowAttributes wa;
- GLUTmenuItem *submenu;
- GLUTmenu *popupmenu;
-
- if (__glutMappedMenu)
- menuModificationError();
- submenu = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
- if (!submenu)
- __glutFatalError("out of memory.");
- __glutCurrentMenu->submenus++;
- submenu->menu = __glutCurrentMenu;
- popupmenu = __glutGetMenuByNum(menu);
- if (popupmenu)
- submenu->win = popupmenu->win;
- setMenuItem(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 APIENTRY
- glutChangeToMenuEntry(int num, const char *label, int value)
- {
- GLUTmenuItem *item;
- int i;
-
- if (__glutMappedMenu)
- menuModificationError();
- i = __glutCurrentMenu->num;
- item = __glutCurrentMenu->list;
- while (item) {
- if (i == num) {
- if (item->isTrigger) {
- /* If changing a submenu trigger to a menu entry, we
- need to account for submenus. */
- item->menu->submenus--;
- DestroyMenu(item->win); // nuke the Win32 menu
- }
- free(item->label);
- ModifyMenu(__glutCurrentMenu->win, (UINT)item, MF_BYCOMMAND, (UINT)item, label);
- // setMenuItem(item, label, value, FALSE);
- return;
- }
- i--;
- item = item->next;
- }
- __glutWarning("Current menu has no %d item.", num);
- }
-
- void APIENTRY
- glutChangeToSubMenu(int num, const char *label, int menu)
- {
- GLUTmenuItem *item;
- int i;
-
- if (__glutMappedMenu)
- menuModificationError();
- i = __glutCurrentMenu->num;
- item = __glutCurrentMenu->list;
- while (item) {
- if (i == num) {
- if (!item->isTrigger) {
- /* If changing a menu entry to as submenu trigger, we
- need to account for submenus. */
- item->menu->submenus++;
- item->win = CreatePopupMenu();
- }
- free(item->label);
- setMenuItem(item, label, /* base 0 */ menu - 1, TRUE);
- return;
- }
- i--;
- item = item->next;
- }
- __glutWarning("Current menu has no %d item.", num);
- }
-
- void APIENTRY
- glutRemoveMenuItem(int num)
- {
- GLUTmenuItem *item, **prev, *remaining;
- int pixwidth, i;
-
- if (__glutMappedMenu)
- menuModificationError();
- i = __glutCurrentMenu->num;
- prev = &__glutCurrentMenu->list;
- item = __glutCurrentMenu->list;
- /* If menu item is removed, the menu's pixwidth may need to
- be recomputed. */
- pixwidth = 1;
- while (item) {
- if (i == num) {
- /* If this menu item's pixwidth is as wide as the menu's
- pixwidth, removing this menu item will necessitate
- shrinking the menu's pixwidth. */
- if (item->pixwidth >= __glutCurrentMenu->pixwidth) {
- /* Continue recalculating menu pixwidth, first skipping
- the removed item. */
- remaining = item->next;
- while (remaining) {
- if (remaining->pixwidth > pixwidth) {
- pixwidth = remaining->pixwidth;
- }
- remaining = remaining->next;
- }
- __glutCurrentMenu->pixwidth = pixwidth;
- }
- __glutCurrentMenu->num--;
- __glutCurrentMenu->managed = FALSE;
-
- /* Patch up menu's item list. */
- *prev = item->next;
-
- RemoveMenu(__glutCurrentMenu->win, (UINT)item, MF_BYCOMMAND);
-
- free(item->label);
- free(item);
- return;
- }
- if (item->pixwidth > pixwidth) {
- pixwidth = item->pixwidth;
- }
- i--;
- prev = &item->next;
- item = item->next;
- }
- __glutWarning("Current menu has no %d item.", num);
- }
-
- void APIENTRY
- glutAttachMenu(int button)
- {
- if (__glutMappedMenu)
- menuModificationError();
- if (__glutCurrentWindow->menu[button] < 1) {
- __glutCurrentWindow->buttonUses++;
- }
- // __glutChangeWindowEventMask(
- // ButtonPressMask | ButtonReleaseMask, True);
- __glutCurrentWindow->menu[button] = __glutCurrentMenu->id + 1;
- }
-
- void APIENTRY
- glutDetachMenu(int button)
- {
- if (__glutMappedMenu)
- menuModificationError();
- if (__glutCurrentWindow->menu[button] > 0) {
- __glutCurrentWindow->buttonUses--;
- // __glutChangeWindowEventMask(ButtonPressMask | ButtonReleaseMask,
- // __glutCurrentWindow->buttonUses > 0);
- __glutCurrentWindow->menu[button] = 0;
- }
- }
- /* ENDCENTRY */
-
- #if 0
- void
- __glutMenuItemEnterOrLeave(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 = menuList[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 = menuList[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;
- }
- }
- }
- #endif
-