glut_win.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:29k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /* Copyright (c) Mark J. Kilgard, 1994, 1997.  */
  2. /* This program is freely distributable without licensing fees
  3.    and is provided without guarantee or warrantee expressed or
  4.    implied. This program is -not- in the public domain. */
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <assert.h>
  9. #if !defined(_WIN32)
  10. #include <X11/Xlib.h>
  11. #include <X11/Xatom.h>
  12. #endif
  13. #include "glutint.h"
  14. GLUTwindow *__glutCurrentWindow = NULL;
  15. GLUTwindow **__glutWindowList = NULL;
  16. int __glutWindowListSize = 0;
  17. #if !defined(_WIN32)
  18. GLUTstale *__glutStaleWindowList = NULL;
  19. #endif
  20. GLUTwindow *__glutMenuWindow = NULL;
  21. void (*__glutFreeOverlayFunc) (GLUToverlay *);
  22. XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
  23.   Criterion * requiredCriteria, int nRequired, int requiredMask, void** fbc) = NULL;
  24. static Criterion requiredWindowCriteria[] =
  25. {
  26.   {LEVEL, EQ, 0},
  27.   {TRANSPARENT, EQ, 0}
  28. };
  29. static int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
  30. static int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
  31. static void
  32. cleanWindowWorkList(GLUTwindow * window)
  33. {
  34.   GLUTwindow **pEntry = &__glutWindowWorkList;
  35.   GLUTwindow *entry = __glutWindowWorkList;
  36.   /* Tranverse singly-linked window work list look for the
  37.      window. */
  38.   while (entry) {
  39.     if (entry == window) {
  40.       /* Found it; delete it. */
  41.       *pEntry = entry->prevWorkWin;
  42.       return;
  43.     } else {
  44.       pEntry = &entry->prevWorkWin;
  45.       entry = *pEntry;
  46.     }
  47.   }
  48. }
  49. #if !defined(_WIN32)
  50. static void
  51. cleanStaleWindowList(GLUTwindow * window)
  52. {
  53.   GLUTstale **pEntry = &__glutStaleWindowList;
  54.   GLUTstale *entry = __glutStaleWindowList;
  55.   /* Tranverse singly-linked stale window list look for the
  56.      window ID. */
  57.   while (entry) {
  58.     if (entry->window == window) {
  59.       /* Found it; delete it. */
  60.       *pEntry = entry->next;
  61.       free(entry);
  62.       return;
  63.     } else {
  64.       pEntry = &entry->next;
  65.       entry = *pEntry;
  66.     }
  67.   }
  68. }
  69. #endif
  70. static GLUTwindow *__glutWindowCache = NULL;
  71. GLUTwindow *
  72. __glutGetWindow(Window win)
  73. {
  74.   int i;
  75.   /* Does win belong to the last window ID looked up? */
  76.   if (__glutWindowCache && (win == __glutWindowCache->win ||
  77.       (__glutWindowCache->overlay && win ==
  78.         __glutWindowCache->overlay->win))) {
  79.     return
  80.       __glutWindowCache;
  81.   }
  82.   /* Otherwise scan the window list looking for the window ID. */
  83.   for (i = 0; i < __glutWindowListSize; i++) {
  84.     if (__glutWindowList[i]) {
  85.       if (win == __glutWindowList[i]->win) {
  86.         __glutWindowCache = __glutWindowList[i];
  87.         return __glutWindowCache;
  88.       }
  89.       if (__glutWindowList[i]->overlay) {
  90.         if (win == __glutWindowList[i]->overlay->win) {
  91.           __glutWindowCache = __glutWindowList[i];
  92.           return __glutWindowCache;
  93.         }
  94.       }
  95.     }
  96.   }
  97. #if !defined(_WIN32)
  98.   {
  99.     GLUTstale *entry;
  100.     /* Scan through destroyed overlay window IDs for which no
  101.        DestroyNotify has yet been received. */
  102.     for (entry = __glutStaleWindowList; entry; entry = entry->next) {
  103.       if (entry->win == win)
  104.         return entry->window;
  105.     }
  106.   }
  107. #endif
  108.   return NULL;
  109. }
  110. /* CENTRY */
  111. int APIENTRY
  112. glutGetWindow(void)
  113. {
  114.   if (__glutCurrentWindow) {
  115.     return __glutCurrentWindow->num + 1;
  116.   } else {
  117.     return 0;
  118.   }
  119. }
  120. /* ENDCENTRY */
  121. void
  122. __glutSetWindow(GLUTwindow * window)
  123. {
  124.   /* It is tempting to try to short-circuit the call to
  125.      glXMakeCurrent if we "know" we are going to make current
  126.      to a window we are already current to.  In fact, this
  127.      assumption breaks when GLUT is expected to integrated with
  128.      other OpenGL windowing APIs that also make current to
  129.      OpenGL contexts.  Since glXMakeCurrent short-circuits the
  130.      "already bound" case, GLUT avoids the temptation to do so
  131.      too. */
  132.   __glutCurrentWindow = window;
  133.   MAKE_CURRENT_LAYER(__glutCurrentWindow);
  134. #if !defined(_WIN32)
  135.   /* We should be careful to force a finish between each
  136.      iteration through the GLUT main loop if indirect OpenGL 
  137.      contexts are in use; indirect contexts tend to have  much
  138.      longer latency because lots of OpenGL extension requests
  139.      can queue up in the X protocol stream.  We accomplish this
  140.      by posting GLUT_FINISH_WORK to be done. */
  141.   if (!__glutCurrentWindow->isDirect)
  142.     __glutPutOnWorkList(__glutCurrentWindow, GLUT_FINISH_WORK);
  143. #endif
  144.   /* If debugging is enabled, we'll want to check this window
  145.      for any OpenGL errors every iteration through the GLUT
  146.      main loop.  To accomplish this, we post the
  147.      GLUT_DEBUG_WORK to be done on this window. */
  148.   if (__glutDebug) {
  149.     __glutPutOnWorkList(__glutCurrentWindow, GLUT_DEBUG_WORK);
  150.   }
  151. }
  152. /* CENTRY */
  153. void APIENTRY
  154. glutSetWindow(int win)
  155. {
  156.   GLUTwindow *window;
  157.   if (win < 1 || win > __glutWindowListSize) {
  158.     __glutWarning("glutSetWindow attempted on bogus window.");
  159.     return;
  160.   }
  161.   window = __glutWindowList[win - 1];
  162.   if (!window) {
  163.     __glutWarning("glutSetWindow attempted on bogus window.");
  164.     return;
  165.   }
  166.   __glutSetWindow(window);
  167. }
  168. /* ENDCENTRY */
  169. static int
  170. getUnusedWindowSlot(void)
  171. {
  172.   int i;
  173.   /* Look for allocated, unused slot. */
  174.   for (i = 0; i < __glutWindowListSize; i++) {
  175.     if (!__glutWindowList[i]) {
  176.       return i;
  177.     }
  178.   }
  179.   /* Allocate a new slot. */
  180.   __glutWindowListSize++;
  181.   if (__glutWindowList) {
  182.     __glutWindowList = (GLUTwindow **)
  183.       realloc(__glutWindowList,
  184.       __glutWindowListSize * sizeof(GLUTwindow *));
  185.   } else {
  186.     /* XXX Some realloc's do not correctly perform a malloc
  187.        when asked to perform a realloc on a NULL pointer,
  188.        though the ANSI C library spec requires this. */
  189.     __glutWindowList = (GLUTwindow **)
  190.       malloc(sizeof(GLUTwindow *));
  191.   }
  192.   if (!__glutWindowList)
  193.     __glutFatalError("out of memory.");
  194.   __glutWindowList[__glutWindowListSize - 1] = NULL;
  195.   return __glutWindowListSize - 1;
  196. }
  197. static XVisualInfo *
  198. getVisualInfoCI(unsigned int mode)
  199. {
  200.   static int bufSizeList[] =
  201.   {16, 12, 8, 4, 2, 1, 0};
  202.   XVisualInfo *vi;
  203.   int list[32];
  204.   int i, n = 0;
  205.   /* Should not be looking at display mode mask if
  206.      __glutDisplayString is non-NULL. */
  207.   assert(!__glutDisplayString);
  208.   list[n++] = GLX_BUFFER_SIZE;
  209.   list[n++] = 1;
  210.   if (GLUT_WIND_IS_DOUBLE(mode)) {
  211.     list[n++] = GLX_DOUBLEBUFFER;
  212.   }
  213.   if (GLUT_WIND_IS_STEREO(mode)) {
  214.     list[n++] = GLX_STEREO;
  215.   }
  216.   if (GLUT_WIND_HAS_DEPTH(mode)) {
  217.     list[n++] = GLX_DEPTH_SIZE;
  218.     list[n++] = 1;
  219.   }
  220.   if (GLUT_WIND_HAS_STENCIL(mode)) {
  221.     list[n++] = GLX_STENCIL_SIZE;
  222.     list[n++] = 1;
  223.   }
  224.   list[n] = (int) None; /* terminate list */
  225.   /* glXChooseVisual specify GLX_BUFFER_SIZE prefers the
  226.      "smallest index buffer of at least the specified size".
  227.      This would be reasonable if GLUT allowed the user to
  228.      specify the required buffe size, but GLUT's display mode
  229.      is too simplistic (easy to use?). GLUT should try to find
  230.      the "largest".  So start with a large buffer size and
  231.      shrink until we find a matching one that exists. */
  232.   for (i = 0; bufSizeList[i]; i++) {
  233.     /* XXX Assumes list[1] is where GLX_BUFFER_SIZE parameter
  234.        is. */
  235.     list[1] = bufSizeList[i];
  236.     vi = glXChooseVisual(__glutDisplay,
  237.       __glutScreen, list);
  238.     if (vi)
  239.       return vi;
  240.   }
  241.   return NULL;
  242. }
  243. static XVisualInfo *
  244. getVisualInfoRGB(unsigned int mode)
  245. {
  246.   int list[32];
  247.   int n = 0;
  248.   /* Should not be looking at display mode mask if
  249.      __glutDisplayString is non-NULL. */
  250.   assert(!__glutDisplayString);
  251.   /* XXX Would a caching mechanism to minize the calls to
  252.      glXChooseVisual? You'd have to reference count
  253.      XVisualInfo* pointers.  Would also have to properly
  254.      interact with glutInitDisplayString. */
  255.   list[n++] = GLX_RGBA;
  256.   list[n++] = GLX_RED_SIZE;
  257.   list[n++] = 1;
  258.   list[n++] = GLX_GREEN_SIZE;
  259.   list[n++] = 1;
  260.   list[n++] = GLX_BLUE_SIZE;
  261.   list[n++] = 1;
  262.   if (GLUT_WIND_HAS_ALPHA(mode)) {
  263.     list[n++] = GLX_ALPHA_SIZE;
  264.     list[n++] = 1;
  265.   }
  266.   if (GLUT_WIND_IS_DOUBLE(mode)) {
  267.     list[n++] = GLX_DOUBLEBUFFER;
  268.   }
  269.   if (GLUT_WIND_IS_STEREO(mode)) {
  270.     list[n++] = GLX_STEREO;
  271.   }
  272.   if (GLUT_WIND_HAS_DEPTH(mode)) {
  273.     list[n++] = GLX_DEPTH_SIZE;
  274.     list[n++] = 1;
  275.   }
  276.   if (GLUT_WIND_HAS_STENCIL(mode)) {
  277.     list[n++] = GLX_STENCIL_SIZE;
  278.     list[n++] = 1;
  279.   }
  280.   if (GLUT_WIND_HAS_ACCUM(mode)) {
  281.     list[n++] = GLX_ACCUM_RED_SIZE;
  282.     list[n++] = 1;
  283.     list[n++] = GLX_ACCUM_GREEN_SIZE;
  284.     list[n++] = 1;
  285.     list[n++] = GLX_ACCUM_BLUE_SIZE;
  286.     list[n++] = 1;
  287.     if (GLUT_WIND_HAS_ALPHA(mode)) {
  288.       list[n++] = GLX_ACCUM_ALPHA_SIZE;
  289.       list[n++] = 1;
  290.     }
  291.   }
  292. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
  293.   if (GLUT_WIND_IS_MULTISAMPLE(mode)) {
  294.     if (!__glutIsSupportedByGLX("GLX_SGIS_multisample"))
  295.       return NULL;
  296.     list[n++] = GLX_SAMPLES_SGIS;
  297.     /* XXX Is 4 a reasonable minimum acceptable number of
  298.        samples? */
  299.     list[n++] = 4;
  300.   }
  301. #endif
  302.   list[n] = (int) None; /* terminate list */
  303.   return glXChooseVisual(__glutDisplay,
  304.     __glutScreen, list);
  305. }
  306. XVisualInfo *
  307. __glutGetVisualInfo(unsigned int mode)
  308. {
  309.   /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
  310.   if (GLUT_WIND_IS_LUMINANCE(mode))
  311.     return NULL;
  312.   if (GLUT_WIND_IS_RGB(mode))
  313.     return getVisualInfoRGB(mode);
  314.   else
  315.     return getVisualInfoCI(mode);
  316. }
  317. XVisualInfo *
  318. __glutDetermineVisual(
  319.   unsigned int displayMode,
  320.   Bool * treatAsSingle,
  321.   XVisualInfo * (getVisualInfo) (unsigned int))
  322. {
  323.   XVisualInfo *vis;
  324.   /* Should not be looking at display mode mask if
  325.      __glutDisplayString is non-NULL. */
  326.   assert(!__glutDisplayString);
  327.   *treatAsSingle = GLUT_WIND_IS_SINGLE(displayMode);
  328.   vis = getVisualInfo(displayMode);
  329.   if (!vis) {
  330.     /* Fallback cases when can't get exactly what was asked
  331.        for... */
  332.     if (GLUT_WIND_IS_SINGLE(displayMode)) {
  333.       /* If we can't find a single buffered visual, try looking
  334.          for a double buffered visual.  We can treat a double
  335.          buffered visual as a single buffer visual by changing
  336.          the draw buffer to GL_FRONT and treating any swap
  337.          buffers as no-ops. */
  338.       displayMode |= GLUT_DOUBLE;
  339.       vis = getVisualInfo(displayMode);
  340.       *treatAsSingle = True;
  341.     }
  342.     if (!vis && GLUT_WIND_IS_MULTISAMPLE(displayMode)) {
  343.       /* If we can't seem to get multisampling (ie, not Reality
  344.          Engine class graphics!), go without multisampling.  It
  345.          is up to the application to query how many multisamples
  346.          were allocated (0 equals no multisampling) if the
  347.          application is going to use multisampling for more than
  348.          just antialiasing. */
  349.       displayMode &= ~GLUT_MULTISAMPLE;
  350.       vis = getVisualInfo(displayMode);
  351.     }
  352.   }
  353.   return vis;
  354. }
  355. void GLUTCALLBACK
  356. __glutDefaultDisplay(void)
  357. {
  358.   /* XXX Remove the warning after GLUT 3.0. */
  359.   __glutWarning("The following is a new check for GLUT 3.0; update your code.");
  360.   __glutFatalError(
  361.     "redisplay needed for window %d, but no display callback.",
  362.     __glutCurrentWindow->num + 1);
  363. }
  364. void GLUTCALLBACK
  365. __glutDefaultReshape(int width, int height)
  366. {
  367.   GLUToverlay *overlay;
  368.   /* Adjust the viewport of the window (and overlay if one
  369.      exists). */
  370.   MAKE_CURRENT_WINDOW(__glutCurrentWindow);
  371.   glViewport(0, 0, (GLsizei) width, (GLsizei) height);
  372.   overlay = __glutCurrentWindow->overlay;
  373.   if (overlay) {
  374.     MAKE_CURRENT_OVERLAY(overlay);
  375.     glViewport(0, 0, (GLsizei) width, (GLsizei) height);
  376.   }
  377.   /* Make sure we are current to the current layer (application
  378.      should be able to count on the current layer not changing
  379.      unless the application explicitly calls glutUseLayer). */
  380.   MAKE_CURRENT_LAYER(__glutCurrentWindow);
  381. }
  382. XVisualInfo *
  383. __glutDetermineWindowVisual(Bool * treatAsSingle, Bool * visAlloced, void **fbc)
  384. {
  385.   if (__glutDisplayString) {
  386.     /* __glutDisplayString should be NULL except if
  387.        glutInitDisplayString has been called to register a
  388.        different display string.  Calling glutInitDisplayString
  389.        means using a string instead of an integer mask determine
  390.        the visual to use. Using the function pointer variable
  391.        __glutDetermineVisualFromString below avoids linking in
  392.        the code for implementing glutInitDisplayString (ie,
  393.        glut_dstr.o) unless glutInitDisplayString gets called by
  394.        the application. */
  395.     assert(__glutDetermineVisualFromString);
  396.     *visAlloced = False;
  397.     *fbc = NULL;
  398.     return __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
  399.       requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, fbc);
  400.   } else {
  401.     *visAlloced = True;
  402.     *fbc = NULL;
  403.     return __glutDetermineVisual(__glutDisplayMode,
  404.       treatAsSingle, __glutGetVisualInfo);
  405.   }
  406. }
  407. /* ARGSUSED5 */  /* Only Win32 uses gameMode parameter. */
  408. GLUTwindow *
  409. __glutCreateWindow(GLUTwindow * parent,
  410.   int x, int y, int width, int height, int gameMode)
  411. {
  412.   GLUTwindow *window;
  413.   XSetWindowAttributes wa;
  414.   unsigned long attribMask;
  415.   int winnum;
  416.   int i;
  417. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  418.   GLXFBConfigSGIX fbc;
  419. #else
  420.   void *fbc;
  421. #endif
  422. #if defined(_WIN32)
  423.   WNDCLASS wc;
  424.   int style;
  425.   if (!GetClassInfo(GetModuleHandle(NULL), "GLUT", &wc)) {
  426.     __glutOpenWin32Connection(NULL);
  427.   }
  428. #else
  429.   if (!__glutDisplay) {
  430.     __glutOpenXConnection(NULL);
  431.   }
  432. #endif
  433.   if (__glutGameModeWindow) {
  434.     __glutFatalError("cannot create windows in game mode.");
  435.   }
  436.   winnum = getUnusedWindowSlot();
  437.   window = (GLUTwindow *) malloc(sizeof(GLUTwindow));
  438.   if (!window) {
  439.     __glutFatalError("out of memory.");
  440.   }
  441.   window->num = winnum;
  442. #if !defined(_WIN32)
  443.   window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
  444.     &window->visAlloced, (void**) &fbc);
  445.   if (!window->vis) {
  446.     __glutFatalError(
  447.       "visual with necessary capabilities not found.");
  448.   }
  449.   __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
  450. #else
  451.   window->cmap = 0;
  452. #endif
  453.   window->eventMask = StructureNotifyMask | ExposureMask;
  454.   attribMask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
  455.   wa.background_pixmap = None;
  456.   wa.border_pixel = 0;
  457.   wa.colormap = window->cmap;
  458.   wa.event_mask = window->eventMask;
  459.   if (parent) {
  460.     if (parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
  461.       wa.event_mask |= GLUT_HACK_STOP_PROPAGATE_MASK;
  462.     attribMask |= CWDontPropagate;
  463.     wa.do_not_propagate_mask = parent->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
  464.   } else {
  465.     wa.do_not_propagate_mask = 0;
  466.   }
  467.   /* Stash width and height before Win32's __glutAdjustCoords
  468.      possibly overwrites the values. */
  469.   window->width = width;
  470.   window->height = height;
  471.   window->forceReshape = True;
  472.   window->ignoreKeyRepeat = False;
  473. #if defined(_WIN32)
  474.   __glutAdjustCoords(parent ? parent->win : NULL,
  475.     &x, &y, &width, &height);
  476.   if (parent) {
  477.     style = WS_CHILD;
  478.   } else {
  479.     if (gameMode) {
  480.       /* Game mode window should be a WS_POPUP window to
  481.          ensure that the taskbar is hidden by it.  A standard
  482.          WS_OVERLAPPEDWINDOW does not hide the task bar. */
  483.       style = WS_POPUP | WS_MAXIMIZE;
  484.     } else {
  485.       /* A standard toplevel window with borders and such. */
  486.       style = WS_OVERLAPPEDWINDOW;
  487.     }
  488.   }
  489.   window->win = CreateWindow("GLUT", "GLUT",
  490.     WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
  491.     x, y, width, height, parent ? parent->win : __glutRoot,
  492.     NULL, GetModuleHandle(NULL), 0);
  493.   window->hdc = GetDC(window->win);
  494.   /* Must set the XHDC for fake glXChooseVisual & fake
  495.      glXCreateContext & fake XAllocColorCells. */
  496.   XHDC = window->hdc;
  497.   window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
  498.     &window->visAlloced, &fbc);
  499.   if (!window->vis) {
  500.     __glutFatalError(
  501.       "pixel format with necessary capabilities not found.");
  502.   }
  503.   if (!SetPixelFormat(window->hdc,
  504.       ChoosePixelFormat(window->hdc, window->vis),
  505.       window->vis)) {
  506.     __glutFatalError("SetPixelFormat failed during window create.");
  507.   }
  508.   __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
  509.   /* Make sure subwindows get a windowStatus callback. */
  510.   if (parent) {
  511.     PostMessage(parent->win, WM_ACTIVATE, 0, 0);
  512.   }
  513.   window->renderDc = window->hdc;
  514. #else
  515.   window->win = XCreateWindow(__glutDisplay,
  516.     parent == NULL ? __glutRoot : parent->win,
  517.     x, y, width, height, 0,
  518.     window->vis->depth, InputOutput, window->vis->visual,
  519.     attribMask, &wa);
  520. #endif
  521.   window->renderWin = window->win;
  522. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  523.   if (fbc) {
  524.     window->ctx = glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
  525.       GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
  526.   } else
  527. #endif
  528.   {
  529.     window->ctx = glXCreateContext(__glutDisplay, window->vis,
  530.       None, __glutTryDirect);
  531.   }
  532.   if (!window->ctx) {
  533.     __glutFatalError(
  534.       "failed to create OpenGL rendering context.");
  535.   }
  536.   window->renderCtx = window->ctx;
  537. #if !defined(_WIN32)
  538.   window->isDirect = glXIsDirect(__glutDisplay, window->ctx);
  539.   if (__glutForceDirect) {
  540.     if (!window->isDirect)
  541.       __glutFatalError("direct rendering not possible.");
  542.   }
  543. #endif
  544.   window->parent = parent;
  545.   if (parent) {
  546.     window->siblings = parent->children;
  547.     parent->children = window;
  548.   } else {
  549.     window->siblings = NULL;
  550.   }
  551.   window->overlay = NULL;
  552.   window->children = NULL;
  553.   window->display = __glutDefaultDisplay;
  554.   window->reshape = __glutDefaultReshape;
  555.   window->mouse = NULL;
  556.   window->motion = NULL;
  557.   window->passive = NULL;
  558.   window->entry = NULL;
  559.   window->keyboard = NULL;
  560.   window->keyboardUp = NULL;
  561.   window->windowStatus = NULL;
  562.   window->visibility = NULL;
  563.   window->special = NULL;
  564.   window->specialUp = NULL;
  565.   window->buttonBox = NULL;
  566.   window->dials = NULL;
  567.   window->spaceMotion = NULL;
  568.   window->spaceRotate = NULL;
  569.   window->spaceButton = NULL;
  570.   window->tabletMotion = NULL;
  571.   window->tabletButton = NULL;
  572. #ifdef _WIN32
  573.   window->joystick = NULL;
  574.   window->joyPollInterval = 0;
  575. #endif
  576.   window->tabletPos[0] = -1;
  577.   window->tabletPos[1] = -1;
  578.   window->shownState = 0;
  579.   window->visState = -1;  /* not VisibilityUnobscured,
  580.                              VisibilityPartiallyObscured, or
  581.                              VisibilityFullyObscured */
  582.   window->entryState = -1;  /* not EnterNotify or LeaveNotify */
  583.   window->desiredConfMask = 0;
  584.   window->buttonUses = 0;
  585.   window->cursor = GLUT_CURSOR_INHERIT;
  586.   /* Setup window to be mapped when glutMainLoop starts. */
  587.   window->workMask = GLUT_MAP_WORK;
  588. #ifdef _WIN32
  589.   if (gameMode) {
  590.     /* When mapping a game mode window, just show
  591.        the window.  We have already created the game
  592.        mode window with a maximize flag at creation
  593.        time.  Doing a ShowWindow(window->win, SW_SHOWNORMAL)
  594.        would be wrong for a game mode window since it
  595.        would unmaximize the window. */
  596.     window->desiredMapState = GameModeState;
  597.   } else {
  598.     window->desiredMapState = NormalState;
  599.   }
  600. #else
  601.   window->desiredMapState = NormalState;
  602. #endif
  603.   window->prevWorkWin = __glutWindowWorkList;
  604.   __glutWindowWorkList = window;
  605.   /* Initially, no menus attached. */
  606.   for (i = 0; i < GLUT_MAX_MENUS; i++) {
  607.     window->menu[i] = 0;
  608.   }
  609.   /* Add this new window to the window list. */
  610.   __glutWindowList[winnum] = window;
  611.   /* Make the new window the current window. */
  612.   __glutSetWindow(window);
  613.   __glutDetermineMesaSwapHackSupport();
  614.   if (window->treatAsSingle) {
  615.     /* We do this because either the window really is single
  616.        buffered (in which case this is redundant, but harmless,
  617.        because this is the initial single-buffered context
  618.        state); or we are treating a double buffered window as a
  619.        single-buffered window because the system does not appear
  620.        to export any suitable single- buffered visuals (in which
  621.        the following are necessary). */
  622.     glDrawBuffer(GL_FRONT);
  623.     glReadBuffer(GL_FRONT);
  624.   }
  625.   #ifdef WIN32
  626.   if (gameMode) {
  627.   glutFullScreen();
  628.   }
  629.   #endif
  630.   return window;
  631. }
  632. /* CENTRY */
  633. int APIENTRY
  634. glutCreateWindow(const char *title)
  635. {
  636.   static int firstWindow = 1;
  637.   GLUTwindow *window;
  638. #if !defined(_WIN32)
  639.   XWMHints *wmHints;
  640. #endif
  641.   Window win;
  642.   XTextProperty textprop;
  643.   if (__glutGameModeWindow) {
  644.     __glutFatalError("cannot create windows in game mode.");
  645.   }
  646.   window = __glutCreateWindow(NULL,
  647.     __glutSizeHints.x, __glutSizeHints.y,
  648.     __glutInitWidth, __glutInitHeight,
  649.     /* not game mode */ 0);
  650.   win = window->win;
  651.   /* Setup ICCCM properties. */
  652.   textprop.value = (unsigned char *) title;
  653.   textprop.encoding = XA_STRING;
  654.   textprop.format = 8;
  655.   textprop.nitems = strlen(title);
  656. #if defined(_WIN32)
  657.   SetWindowText(win, title);
  658.   if (__glutIconic) {
  659.     window->desiredMapState = IconicState;
  660.   }
  661. #else
  662.   wmHints = XAllocWMHints();
  663.   wmHints->initial_state =
  664.     __glutIconic ? IconicState : NormalState;
  665.   wmHints->flags = StateHint;
  666.   XSetWMProperties(__glutDisplay, win, &textprop, &textprop,
  667.   /* Only put WM_COMMAND property on first window. */
  668.     firstWindow ? __glutArgv : NULL,
  669.     firstWindow ? __glutArgc : 0,
  670.     &__glutSizeHints, wmHints, NULL);
  671.   XFree(wmHints);
  672.   XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
  673. #endif
  674.   firstWindow = 0;
  675.   return window->num + 1;
  676. }
  677. #ifdef _WIN32
  678. int APIENTRY
  679. __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int))
  680. {
  681.   __glutExitFunc = exitfunc;
  682.   return glutCreateWindow(title);
  683. }
  684. #endif
  685. int APIENTRY
  686. glutCreateSubWindow(int win, int x, int y, int width, int height)
  687. {
  688.   GLUTwindow *window;
  689.   window = __glutCreateWindow(__glutWindowList[win - 1],
  690.     x, y, width, height, /* not game mode */ 0);
  691. #if !defined(_WIN32)
  692.   {
  693.     GLUTwindow *toplevel;
  694.     toplevel = __glutToplevelOf(window);
  695.     if (toplevel->cmap != window->cmap) {
  696.       __glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
  697.     }
  698.   }
  699. #endif
  700.   return window->num + 1;
  701. }
  702. /* ENDCENTRY */
  703. void
  704. __glutDestroyWindow(GLUTwindow * window,
  705.   GLUTwindow * initialWindow)
  706. {
  707.   GLUTwindow **prev, *cur, *parent, *siblings;
  708.   /* Recursively destroy any children. */
  709.   cur = window->children;
  710.   while (cur) {
  711.     siblings = cur->siblings;
  712.     __glutDestroyWindow(cur, initialWindow);
  713.     cur = siblings;
  714.   }
  715.   /* Remove from parent's children list (only necessary for
  716.      non-initial windows and subwindows!). */
  717.   parent = window->parent;
  718.   if (parent && parent == initialWindow->parent) {
  719.     prev = &parent->children;
  720.     cur = parent->children;
  721.     while (cur) {
  722.       if (cur == window) {
  723.         *prev = cur->siblings;
  724.         break;
  725.       }
  726.       prev = &(cur->siblings);
  727.       cur = cur->siblings;
  728.     }
  729.   }
  730.   /* Unbind if bound to this window. */
  731.   if (window == __glutCurrentWindow) {
  732.     UNMAKE_CURRENT();
  733.     __glutCurrentWindow = NULL;
  734.   }
  735.   /* Begin tearing down window itself. */
  736.   if (window->overlay) {
  737.     __glutFreeOverlayFunc(window->overlay);
  738.   }
  739.   XDestroyWindow(__glutDisplay, window->win);
  740.   glXDestroyContext(__glutDisplay, window->ctx);
  741.   if (window->colormap) {
  742.     /* Only color index windows have colormap data structure. */
  743.     __glutFreeColormap(window->colormap);
  744.   }
  745.   /* NULLing the __glutWindowList helps detect is a window
  746.      instance has been destroyed, given a window number. */
  747.   __glutWindowList[window->num] = NULL;
  748.   /* Cleanup data structures that might contain window. */
  749.   cleanWindowWorkList(window);
  750. #if !defined(_WIN32)
  751.   cleanStaleWindowList(window);
  752. #endif
  753.   /* Remove window from the "get window cache" if it is there. */
  754.   if (__glutWindowCache == window)
  755.     __glutWindowCache = NULL;
  756.   if (window->visAlloced) {
  757.     /* Only free XVisualInfo* gotten from glXChooseVisual. */
  758.     XFree(window->vis);
  759.   }
  760.   if (window == __glutGameModeWindow) {
  761.     /* Destroying the game mode window should implicitly
  762.        have GLUT leave game mode. */
  763.     __glutCloseDownGameMode();
  764.   }
  765.   free(window);
  766. }
  767. /* CENTRY */
  768. void APIENTRY
  769. glutDestroyWindow(int win)
  770. {
  771.   GLUTwindow *window = __glutWindowList[win - 1];
  772.   if (__glutMappedMenu && __glutMenuWindow == window) {
  773.     __glutFatalUsage("destroying menu window not allowed while menus in use");
  774.   }
  775. #if !defined(_WIN32)
  776.   /* If not a toplevel window... */
  777.   if (window->parent) {
  778.     /* Destroying subwindows may change colormap requirements;
  779.        recalculate toplevel window's WM_COLORMAP_WINDOWS
  780.        property. */
  781.     __glutPutOnWorkList(__glutToplevelOf(window->parent),
  782.       GLUT_COLORMAP_WORK);
  783.   }
  784. #endif
  785.   __glutDestroyWindow(window, window);
  786.   XFlush(__glutDisplay);
  787. }
  788. /* ENDCENTRY */
  789. void
  790. __glutChangeWindowEventMask(long eventMask, Bool add)
  791. {
  792.   if (add) {
  793.     /* Add eventMask to window's event mask. */
  794.     if ((__glutCurrentWindow->eventMask & eventMask) !=
  795.       eventMask) {
  796.       __glutCurrentWindow->eventMask |= eventMask;
  797.       __glutPutOnWorkList(__glutCurrentWindow,
  798.         GLUT_EVENT_MASK_WORK);
  799.     }
  800.   } else {
  801.     /* Remove eventMask from window's event mask. */
  802.     if (__glutCurrentWindow->eventMask & eventMask) {
  803.       __glutCurrentWindow->eventMask &= ~eventMask;
  804.       __glutPutOnWorkList(__glutCurrentWindow,
  805.         GLUT_EVENT_MASK_WORK);
  806.     }
  807.   }
  808. }
  809. void APIENTRY
  810. glutDisplayFunc(GLUTdisplayCB displayFunc)
  811. {
  812.   /* XXX Remove the warning after GLUT 3.0. */
  813.   if (!displayFunc)
  814.     __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
  815.   __glutCurrentWindow->display = displayFunc;
  816. }
  817. void APIENTRY
  818. glutMouseFunc(GLUTmouseCB mouseFunc)
  819. {
  820.   if (__glutCurrentWindow->mouse) {
  821.     if (!mouseFunc) {
  822.       /* Previous mouseFunc being disabled. */
  823.       __glutCurrentWindow->buttonUses--;
  824.       __glutChangeWindowEventMask(
  825.         ButtonPressMask | ButtonReleaseMask,
  826.         __glutCurrentWindow->buttonUses > 0);
  827.     }
  828.   } else {
  829.     if (mouseFunc) {
  830.       /* Previously no mouseFunc, new one being installed. */
  831.       __glutCurrentWindow->buttonUses++;
  832.       __glutChangeWindowEventMask(
  833.         ButtonPressMask | ButtonReleaseMask, True);
  834.     }
  835.   }
  836.   __glutCurrentWindow->mouse = mouseFunc;
  837. }
  838. void APIENTRY
  839. glutMotionFunc(GLUTmotionCB motionFunc)
  840. {
  841.   /* Hack.  Some window managers (4Dwm by default) will mask
  842.      motion events if the client is not selecting for button
  843.      press and release events. So we select for press and
  844.      release events too (being careful to use reference
  845.      counting).  */
  846.   if (__glutCurrentWindow->motion) {
  847.     if (!motionFunc) {
  848.       /* previous mouseFunc being disabled */
  849.       __glutCurrentWindow->buttonUses--;
  850.       __glutChangeWindowEventMask(
  851.         ButtonPressMask | ButtonReleaseMask,
  852.         __glutCurrentWindow->buttonUses > 0);
  853.     }
  854.   } else {
  855.     if (motionFunc) {
  856.       /* Previously no mouseFunc, new one being installed. */
  857.       __glutCurrentWindow->buttonUses++;
  858.       __glutChangeWindowEventMask(
  859.         ButtonPressMask | ButtonReleaseMask, True);
  860.     }
  861.   }
  862.   /* Real work of selecting for passive mouse motion.  */
  863.   __glutChangeWindowEventMask(
  864.     Button1MotionMask | Button2MotionMask | Button3MotionMask,
  865.     motionFunc != NULL);
  866.   __glutCurrentWindow->motion = motionFunc;
  867. }
  868. void APIENTRY
  869. glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc)
  870. {
  871.   __glutChangeWindowEventMask(PointerMotionMask,
  872.     passiveMotionFunc != NULL);
  873.   /* Passive motion also requires watching enters and leaves so
  874.      that a fake passive motion event can be generated on an
  875.      enter. */
  876.   __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
  877.     __glutCurrentWindow->entry != NULL || passiveMotionFunc != NULL);
  878.   __glutCurrentWindow->passive = passiveMotionFunc;
  879. }
  880. void APIENTRY
  881. glutEntryFunc(GLUTentryCB entryFunc)
  882. {
  883.   __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
  884.     entryFunc != NULL || __glutCurrentWindow->passive);
  885.   __glutCurrentWindow->entry = entryFunc;
  886.   if (!entryFunc) {
  887.     __glutCurrentWindow->entryState = -1;
  888.   }
  889. }
  890. void APIENTRY
  891. glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc)
  892. {
  893.   __glutChangeWindowEventMask(VisibilityChangeMask,
  894.     windowStatusFunc != NULL);
  895.   __glutCurrentWindow->windowStatus = windowStatusFunc;
  896.   if (!windowStatusFunc) {
  897.     /* Make state invalid. */
  898.     __glutCurrentWindow->visState = -1;
  899.   }
  900. }
  901. static void GLUTCALLBACK
  902. visibilityHelper(int status)
  903. {
  904.   if (status == GLUT_HIDDEN || status == GLUT_FULLY_COVERED)
  905.     __glutCurrentWindow->visibility(GLUT_NOT_VISIBLE);
  906.   else
  907.     __glutCurrentWindow->visibility(GLUT_VISIBLE);
  908. }
  909. void APIENTRY
  910. glutVisibilityFunc(GLUTvisibilityCB visibilityFunc)
  911. {
  912.   __glutCurrentWindow->visibility = visibilityFunc;
  913.   if (visibilityFunc)
  914.     glutWindowStatusFunc(visibilityHelper);
  915.   else
  916.     glutWindowStatusFunc(NULL);
  917. }
  918. void APIENTRY
  919. glutReshapeFunc(GLUTreshapeCB reshapeFunc)
  920. {
  921.   if (reshapeFunc) {
  922.     __glutCurrentWindow->reshape = reshapeFunc;
  923.   } else {
  924.     __glutCurrentWindow->reshape = __glutDefaultReshape;
  925.   }
  926. }