Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

glut_win.c

Go to the documentation of this file.
00001 
00002 /* Copyright (c) Mark J. Kilgard, 1994, 1997.  */
00003 
00004 /* This program is freely distributable without licensing fees
00005    and is provided without guarantee or warrantee expressed or
00006    implied. This program is -not- in the public domain. */
00007 
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include <assert.h>
00012 #if !defined(_WIN32)
00013 #include <X11/Xlib.h>
00014 #include <X11/Xatom.h>
00015 #endif
00016 
00017 #include "glutint.h"
00018 
00019 GLUTwindow *__glutCurrentWindow = NULL;
00020 GLUTwindow **__glutWindowList = NULL;
00021 int __glutWindowListSize = 0;
00022 #if !defined(_WIN32)
00023 GLUTstale *__glutStaleWindowList = NULL;
00024 #endif
00025 GLUTwindow *__glutMenuWindow = NULL;
00026 
00027 void (*__glutFreeOverlayFunc) (GLUToverlay *);
00028 XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
00029   Criterion * requiredCriteria, int nRequired, int requiredMask, void** fbc) = NULL;
00030 
00031 static Criterion requiredWindowCriteria[] =
00032 {
00033   {LEVEL, EQ, 0},
00034   {TRANSPARENT, EQ, 0}
00035 };
00036 static int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
00037 static int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
00038 
00039 static void
00040 cleanWindowWorkList(GLUTwindow * window)
00041 {
00042   GLUTwindow **pEntry = &__glutWindowWorkList;
00043   GLUTwindow *entry = __glutWindowWorkList;
00044 
00045   /* Tranverse singly-linked window work list look for the
00046      window. */
00047   while (entry) {
00048     if (entry == window) {
00049       /* Found it; delete it. */
00050       *pEntry = entry->prevWorkWin;
00051       return;
00052     } else {
00053       pEntry = &entry->prevWorkWin;
00054       entry = *pEntry;
00055     }
00056   }
00057 }
00058 
00059 #if !defined(_WIN32)
00060 
00061 static void
00062 cleanStaleWindowList(GLUTwindow * window)
00063 {
00064   GLUTstale **pEntry = &__glutStaleWindowList;
00065   GLUTstale *entry = __glutStaleWindowList;
00066 
00067   /* Tranverse singly-linked stale window list look for the
00068      window ID. */
00069   while (entry) {
00070     if (entry->window == window) {
00071       /* Found it; delete it. */
00072       *pEntry = entry->next;
00073       free(entry);
00074       return;
00075     } else {
00076       pEntry = &entry->next;
00077       entry = *pEntry;
00078     }
00079   }
00080 }
00081 
00082 #endif
00083 
00084 static GLUTwindow *__glutWindowCache = NULL;
00085 
00086 GLUTwindow *
00087 __glutGetWindow(Window win)
00088 {
00089   int i;
00090 
00091   /* Does win belong to the last window ID looked up? */
00092   if (__glutWindowCache && (win == __glutWindowCache->win ||
00093       (__glutWindowCache->overlay && win ==
00094         __glutWindowCache->overlay->win))) {
00095     return
00096       __glutWindowCache;
00097   }
00098   /* Otherwise scan the window list looking for the window ID. */
00099   for (i = 0; i < __glutWindowListSize; i++) {
00100     if (__glutWindowList[i]) {
00101       if (win == __glutWindowList[i]->win) {
00102         __glutWindowCache = __glutWindowList[i];
00103         return __glutWindowCache;
00104       }
00105       if (__glutWindowList[i]->overlay) {
00106         if (win == __glutWindowList[i]->overlay->win) {
00107           __glutWindowCache = __glutWindowList[i];
00108           return __glutWindowCache;
00109         }
00110       }
00111     }
00112   }
00113 #if !defined(_WIN32)
00114   {
00115     GLUTstale *entry;
00116 
00117     /* Scan through destroyed overlay window IDs for which no
00118        DestroyNotify has yet been received. */
00119     for (entry = __glutStaleWindowList; entry; entry = entry->next) {
00120       if (entry->win == win)
00121         return entry->window;
00122     }
00123   }
00124 #endif
00125   return NULL;
00126 }
00127 
00128 /* CENTRY */
00129 int APIENTRY
00130 glutGetWindow(void)
00131 {
00132   if (__glutCurrentWindow) {
00133     return __glutCurrentWindow->num + 1;
00134   } else {
00135     return 0;
00136   }
00137 }
00138 /* ENDCENTRY */
00139 
00140 void
00141 __glutSetWindow(GLUTwindow * window)
00142 {
00143   /* It is tempting to try to short-circuit the call to
00144      glXMakeCurrent if we "know" we are going to make current
00145      to a window we are already current to.  In fact, this
00146      assumption breaks when GLUT is expected to integrated with
00147      other OpenGL windowing APIs that also make current to
00148      OpenGL contexts.  Since glXMakeCurrent short-circuits the
00149      "already bound" case, GLUT avoids the temptation to do so
00150      too. */
00151   __glutCurrentWindow = window;
00152 
00153   MAKE_CURRENT_LAYER(__glutCurrentWindow);
00154 
00155 #if !defined(_WIN32)
00156   /* We should be careful to force a finish between each
00157      iteration through the GLUT main loop if indirect OpenGL 
00158      contexts are in use; indirect contexts tend to have  much
00159      longer latency because lots of OpenGL extension requests
00160      can queue up in the X protocol stream.  We accomplish this
00161      by posting GLUT_FINISH_WORK to be done. */
00162   if (!__glutCurrentWindow->isDirect)
00163     __glutPutOnWorkList(__glutCurrentWindow, GLUT_FINISH_WORK);
00164 #endif
00165 
00166   /* If debugging is enabled, we'll want to check this window
00167      for any OpenGL errors every iteration through the GLUT
00168      main loop.  To accomplish this, we post the
00169      GLUT_DEBUG_WORK to be done on this window. */
00170   if (__glutDebug) {
00171     __glutPutOnWorkList(__glutCurrentWindow, GLUT_DEBUG_WORK);
00172   }
00173 }
00174 
00175 /* CENTRY */
00176 void APIENTRY
00177 glutSetWindow(int win)
00178 {
00179   GLUTwindow *window;
00180 
00181   if (win < 1 || win > __glutWindowListSize) {
00182     __glutWarning("glutSetWindow attempted on bogus window.");
00183     return;
00184   }
00185   window = __glutWindowList[win - 1];
00186   if (!window) {
00187     __glutWarning("glutSetWindow attempted on bogus window.");
00188     return;
00189   }
00190   __glutSetWindow(window);
00191 }
00192 /* ENDCENTRY */
00193 
00194 static int
00195 getUnusedWindowSlot(void)
00196 {
00197   int i;
00198 
00199   /* Look for allocated, unused slot. */
00200   for (i = 0; i < __glutWindowListSize; i++) {
00201     if (!__glutWindowList[i]) {
00202       return i;
00203     }
00204   }
00205   /* Allocate a new slot. */
00206   __glutWindowListSize++;
00207   if (__glutWindowList) {
00208     __glutWindowList = (GLUTwindow **)
00209       realloc(__glutWindowList,
00210       __glutWindowListSize * sizeof(GLUTwindow *));
00211   } else {
00212     /* XXX Some realloc's do not correctly perform a malloc
00213        when asked to perform a realloc on a NULL pointer,
00214        though the ANSI C library spec requires this. */
00215     __glutWindowList = (GLUTwindow **)
00216       malloc(sizeof(GLUTwindow *));
00217   }
00218   if (!__glutWindowList)
00219     __glutFatalError("out of memory.");
00220   __glutWindowList[__glutWindowListSize - 1] = NULL;
00221   return __glutWindowListSize - 1;
00222 }
00223 
00224 static XVisualInfo *
00225 getVisualInfoCI(unsigned int mode)
00226 {
00227   static int bufSizeList[] =
00228   {16, 12, 8, 4, 2, 1, 0};
00229   XVisualInfo *vi;
00230   int list[32];
00231   int i, n = 0;
00232 
00233   /* Should not be looking at display mode mask if
00234      __glutDisplayString is non-NULL. */
00235   assert(!__glutDisplayString);
00236 
00237   list[n++] = GLX_BUFFER_SIZE;
00238   list[n++] = 1;
00239   if (GLUT_WIND_IS_DOUBLE(mode)) {
00240     list[n++] = GLX_DOUBLEBUFFER;
00241   }
00242   if (GLUT_WIND_IS_STEREO(mode)) {
00243     list[n++] = GLX_STEREO;
00244   }
00245   if (GLUT_WIND_HAS_DEPTH(mode)) {
00246     list[n++] = GLX_DEPTH_SIZE;
00247     list[n++] = 1;
00248   }
00249   if (GLUT_WIND_HAS_STENCIL(mode)) {
00250     list[n++] = GLX_STENCIL_SIZE;
00251     list[n++] = 1;
00252   }
00253   list[n] = (int) None; /* terminate list */
00254 
00255   /* glXChooseVisual specify GLX_BUFFER_SIZE prefers the
00256      "smallest index buffer of at least the specified size".
00257      This would be reasonable if GLUT allowed the user to
00258      specify the required buffe size, but GLUT's display mode
00259      is too simplistic (easy to use?). GLUT should try to find
00260      the "largest".  So start with a large buffer size and
00261      shrink until we find a matching one that exists. */
00262 
00263   for (i = 0; bufSizeList[i]; i++) {
00264     /* XXX Assumes list[1] is where GLX_BUFFER_SIZE parameter
00265        is. */
00266     list[1] = bufSizeList[i];
00267     vi = glXChooseVisual(__glutDisplay,
00268       __glutScreen, list);
00269     if (vi)
00270       return vi;
00271   }
00272   return NULL;
00273 }
00274 
00275 static XVisualInfo *
00276 getVisualInfoRGB(unsigned int mode)
00277 {
00278   int list[32];
00279   int n = 0;
00280 
00281   /* Should not be looking at display mode mask if
00282      __glutDisplayString is non-NULL. */
00283   assert(!__glutDisplayString);
00284 
00285   /* XXX Would a caching mechanism to minize the calls to
00286      glXChooseVisual? You'd have to reference count
00287      XVisualInfo* pointers.  Would also have to properly
00288      interact with glutInitDisplayString. */
00289 
00290   list[n++] = GLX_RGBA;
00291   list[n++] = GLX_RED_SIZE;
00292   list[n++] = 1;
00293   list[n++] = GLX_GREEN_SIZE;
00294   list[n++] = 1;
00295   list[n++] = GLX_BLUE_SIZE;
00296   list[n++] = 1;
00297   if (GLUT_WIND_HAS_ALPHA(mode)) {
00298     list[n++] = GLX_ALPHA_SIZE;
00299     list[n++] = 1;
00300   }
00301   if (GLUT_WIND_IS_DOUBLE(mode)) {
00302     list[n++] = GLX_DOUBLEBUFFER;
00303   }
00304   if (GLUT_WIND_IS_STEREO(mode)) {
00305     list[n++] = GLX_STEREO;
00306   }
00307   if (GLUT_WIND_HAS_DEPTH(mode)) {
00308     list[n++] = GLX_DEPTH_SIZE;
00309     list[n++] = 1;
00310   }
00311   if (GLUT_WIND_HAS_STENCIL(mode)) {
00312     list[n++] = GLX_STENCIL_SIZE;
00313     list[n++] = 1;
00314   }
00315   if (GLUT_WIND_HAS_ACCUM(mode)) {
00316     list[n++] = GLX_ACCUM_RED_SIZE;
00317     list[n++] = 1;
00318     list[n++] = GLX_ACCUM_GREEN_SIZE;
00319     list[n++] = 1;
00320     list[n++] = GLX_ACCUM_BLUE_SIZE;
00321     list[n++] = 1;
00322     if (GLUT_WIND_HAS_ALPHA(mode)) {
00323       list[n++] = GLX_ACCUM_ALPHA_SIZE;
00324       list[n++] = 1;
00325     }
00326   }
00327 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
00328   if (GLUT_WIND_IS_MULTISAMPLE(mode)) {
00329     if (!__glutIsSupportedByGLX("GLX_SGIS_multisample"))
00330       return NULL;
00331     list[n++] = GLX_SAMPLES_SGIS;
00332     /* XXX Is 4 a reasonable minimum acceptable number of
00333        samples? */
00334     list[n++] = 4;
00335   }
00336 #endif
00337   list[n] = (int) None; /* terminate list */
00338 
00339   return glXChooseVisual(__glutDisplay,
00340     __glutScreen, list);
00341 }
00342 
00343 XVisualInfo *
00344 __glutGetVisualInfo(unsigned int mode)
00345 {
00346   /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
00347   if (GLUT_WIND_IS_LUMINANCE(mode))
00348     return NULL;
00349 
00350   if (GLUT_WIND_IS_RGB(mode))
00351     return getVisualInfoRGB(mode);
00352   else
00353     return getVisualInfoCI(mode);
00354 }
00355 
00356 XVisualInfo *
00357 __glutDetermineVisual(
00358   unsigned int displayMode,
00359   Bool * treatAsSingle,
00360   XVisualInfo * (getVisualInfo) (unsigned int))
00361 {
00362   XVisualInfo *vis;
00363 
00364   /* Should not be looking at display mode mask if
00365      __glutDisplayString is non-NULL. */
00366   assert(!__glutDisplayString);
00367 
00368   *treatAsSingle = GLUT_WIND_IS_SINGLE(displayMode);
00369   vis = getVisualInfo(displayMode);
00370   if (!vis) {
00371     /* Fallback cases when can't get exactly what was asked
00372        for... */
00373     if (GLUT_WIND_IS_SINGLE(displayMode)) {
00374       /* If we can't find a single buffered visual, try looking
00375          for a double buffered visual.  We can treat a double
00376          buffered visual as a single buffer visual by changing
00377          the draw buffer to GL_FRONT and treating any swap
00378          buffers as no-ops. */
00379       displayMode |= GLUT_DOUBLE;
00380       vis = getVisualInfo(displayMode);
00381       *treatAsSingle = True;
00382     }
00383     if (!vis && GLUT_WIND_IS_MULTISAMPLE(displayMode)) {
00384       /* If we can't seem to get multisampling (ie, not Reality
00385          Engine class graphics!), go without multisampling.  It
00386          is up to the application to query how many multisamples
00387          were allocated (0 equals no multisampling) if the
00388          application is going to use multisampling for more than
00389          just antialiasing. */
00390       displayMode &= ~GLUT_MULTISAMPLE;
00391       vis = getVisualInfo(displayMode);
00392     }
00393   }
00394   return vis;
00395 }
00396 
00397 void
00398 __glutDefaultDisplay(void)
00399 {
00400   /* XXX Remove the warning after GLUT 3.0. */
00401   __glutWarning("The following is a new check for GLUT 3.0; update your code.");
00402   __glutFatalError(
00403     "redisplay needed for window %d, but no display callback.",
00404     __glutCurrentWindow->num + 1);
00405 }
00406 
00407 void
00408 __glutDefaultReshape(int width, int height)
00409 {
00410   GLUToverlay *overlay;
00411 
00412   /* Adjust the viewport of the window (and overlay if one
00413      exists). */
00414   MAKE_CURRENT_WINDOW(__glutCurrentWindow);
00415   glViewport(0, 0, (GLsizei) width, (GLsizei) height);
00416   overlay = __glutCurrentWindow->overlay;
00417   if (overlay) {
00418     MAKE_CURRENT_OVERLAY(overlay);
00419     glViewport(0, 0, (GLsizei) width, (GLsizei) height);
00420   }
00421   /* Make sure we are current to the current layer (application
00422      should be able to count on the current layer not changing
00423      unless the application explicitly calls glutUseLayer). */
00424   MAKE_CURRENT_LAYER(__glutCurrentWindow);
00425 }
00426 
00427 XVisualInfo *
00428 __glutDetermineWindowVisual(Bool * treatAsSingle, Bool * visAlloced, void **fbc)
00429 {
00430   if (__glutDisplayString) {
00431 
00432     /* __glutDisplayString should be NULL except if
00433        glutInitDisplayString has been called to register a
00434        different display string.  Calling glutInitDisplayString
00435        means using a string instead of an integer mask determine
00436        the visual to use. Using the function pointer variable
00437        __glutDetermineVisualFromString below avoids linking in
00438        the code for implementing glutInitDisplayString (ie,
00439        glut_dstr.o) unless glutInitDisplayString gets called by
00440        the application. */
00441 
00442     assert(__glutDetermineVisualFromString);
00443     *visAlloced = False;
00444     *fbc = NULL;
00445     return __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
00446       requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, fbc);
00447   } else {
00448     *visAlloced = True;
00449     *fbc = NULL;
00450     return __glutDetermineVisual(__glutDisplayMode,
00451       treatAsSingle, __glutGetVisualInfo);
00452   }
00453 }
00454 
00455 /* ARGSUSED5 */  /* Only Win32 uses gameMode parameter. */
00456 GLUTwindow *
00457 __glutCreateWindow(GLUTwindow * parent,
00458   int x, int y, int width, int height, int gameMode)
00459 {
00460   GLUTwindow *window;
00461   XSetWindowAttributes wa;
00462   unsigned long attribMask;
00463   int winnum;
00464   int i;
00465 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
00466   GLXFBConfigSGIX fbc;
00467 #else
00468   void *fbc;
00469 #endif
00470 
00471 #if defined(_WIN32)
00472   WNDCLASS wc;
00473   int style;
00474 
00475   if (!GetClassInfo(GetModuleHandle(NULL), "GLUT", &wc)) {
00476     __glutOpenWin32Connection(NULL);
00477   }
00478 #else
00479   if (!__glutDisplay) {
00480     __glutOpenXConnection(NULL);
00481   }
00482 #endif
00483   if (__glutGameModeWindow) {
00484     __glutFatalError("cannot create windows in game mode.");
00485   }
00486   winnum = getUnusedWindowSlot();
00487   window = (GLUTwindow *) malloc(sizeof(GLUTwindow));
00488   if (!window) {
00489     __glutFatalError("out of memory.");
00490   }
00491   window->num = winnum;
00492 
00493 #if !defined(_WIN32)
00494   window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
00495     &window->visAlloced, (void**) &fbc);
00496   if (!window->vis) {
00497     __glutFatalError(
00498       "visual with necessary capabilities not found.");
00499   }
00500   __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
00501 #endif
00502   window->eventMask = StructureNotifyMask | ExposureMask;
00503 
00504   attribMask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
00505   wa.background_pixmap = None;
00506   wa.border_pixel = 0;
00507   wa.colormap = window->cmap;
00508   wa.event_mask = window->eventMask;
00509   if (parent) {
00510     if (parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
00511       wa.event_mask |= GLUT_HACK_STOP_PROPAGATE_MASK;
00512     attribMask |= CWDontPropagate;
00513     wa.do_not_propagate_mask = parent->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
00514   } else {
00515     wa.do_not_propagate_mask = 0;
00516   }
00517 
00518   /* Stash x, y, width and height before Win32's __glutAdjustCoords
00519      possibly overwrites the values. */
00520   window->x = x;
00521   window->y = y;
00522   window->width = width;
00523   window->height = height;
00524   window->forceReshape = True;
00525   window->ignoreKeyRepeat = False;
00526 
00527 #if defined(_WIN32)
00528   __glutAdjustCoords(parent ? parent->win : NULL,
00529     &x, &y, &width, &height);
00530   if (parent) {
00531     style = WS_CHILD;
00532   } else {
00533     if (gameMode) {
00534       /* Game mode window should be a WS_POPUP window to
00535          ensure that the taskbar is hidden by it.  A standard
00536          WS_OVERLAPPEDWINDOW does not hide the task bar. */
00537       style = WS_POPUP | WS_MAXIMIZE;
00538     } else {
00539       /* A standard toplevel window with borders and such. */
00540       style = WS_OVERLAPPEDWINDOW;
00541     }
00542   }
00543   window->win = CreateWindow("GLUT", "GLUT",
00544     WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
00545     x, y, width, height, parent ? parent->win : __glutRoot,
00546     NULL, GetModuleHandle(NULL), 0);
00547   window->hdc = GetDC(window->win);
00548   /* Must set the XHDC for fake glXChooseVisual & fake
00549      glXCreateContext & fake XAllocColorCells. */
00550   XHDC = window->hdc;
00551   window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
00552     &window->visAlloced, &fbc);
00553   if (!window->vis) {
00554     __glutFatalError(
00555       "pixel format with necessary capabilities not found.");
00556   }
00557   if (!SetPixelFormat(window->hdc,
00558       ChoosePixelFormat(window->hdc, window->vis),
00559       window->vis)) {
00560     __glutFatalError("SetPixelFormat failed during window create.");
00561   }
00562   __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
00563   /* Make sure subwindows get a windowStatus callback. */
00564   if (parent) {
00565     PostMessage(parent->win, WM_ACTIVATE, 0, 0);
00566   }
00567   window->renderDc = window->hdc;
00568 #else
00569   window->win = XCreateWindow(__glutDisplay,
00570     parent == NULL ? __glutRoot : parent->win,
00571     x, y, width, height, 0,
00572     window->vis->depth, InputOutput, window->vis->visual,
00573     attribMask, &wa);
00574 #endif
00575   window->renderWin = window->win;
00576 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig) && defined(__sgi)
00577   if (fbc) {
00578     window->ctx = glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
00579       GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
00580   } else
00581 #endif
00582   {
00583     window->ctx = glXCreateContext(__glutDisplay, window->vis,
00584       None, __glutTryDirect);
00585   }
00586   if (!window->ctx) {
00587     __glutFatalError(
00588       "failed to create OpenGL rendering context.");
00589   }
00590   window->renderCtx = window->ctx;
00591 #if !defined(_WIN32)
00592   window->isDirect = glXIsDirect(__glutDisplay, window->ctx);
00593   if (__glutForceDirect) {
00594     if (!window->isDirect)
00595       __glutFatalError("direct rendering not possible.");
00596   }
00597 #endif
00598 
00599   window->parent = parent;
00600   if (parent) {
00601     window->siblings = parent->children;
00602     parent->children = window;
00603   } else {
00604     window->siblings = NULL;
00605   }
00606   window->overlay = NULL;
00607   window->children = NULL;
00608   window->display = __glutDefaultDisplay;
00609   window->reshape = __glutDefaultReshape;
00610   window->mouse = NULL;
00611   window->motion = NULL;
00612   window->passive = NULL;
00613   window->entry = NULL;
00614   window->keyboard = NULL;
00615   window->keyboardUp = NULL;
00616   window->windowStatus = NULL;
00617   window->visibility = NULL;
00618   window->special = NULL;
00619   window->specialUp = NULL;
00620   window->buttonBox = NULL;
00621   window->dials = NULL;
00622   window->spaceMotion = NULL;
00623   window->spaceRotate = NULL;
00624   window->spaceButton = NULL;
00625   window->tabletMotion = NULL;
00626   window->tabletButton = NULL;
00627   window->wacomMotion = NULL;
00628   window->wacomButton = NULL;
00629   window->move = NULL;
00630 #ifdef _WIN32
00631   window->joystick = NULL;
00632   window->joyPollInterval = 0;
00633 #endif
00634   window->tabletPos[0] = -1;
00635   window->tabletPos[1] = -1;
00636   window->shownState = 0;
00637   window->visState = -1;  /* not VisibilityUnobscured,
00638                              VisibilityPartiallyObscured, or
00639                              VisibilityFullyObscured */
00640   window->entryState = -1;  /* not EnterNotify or LeaveNotify */
00641 
00642   window->desiredConfMask = 0;
00643   window->buttonUses = 0;
00644   window->cursor = GLUT_CURSOR_INHERIT;
00645 
00646   /* Setup window to be mapped when glutMainLoop starts. */
00647   window->workMask = GLUT_MAP_WORK;
00648 #ifdef _WIN32
00649   if (gameMode) {
00650     /* When mapping a game mode window, just show
00651        the window.  We have already created the game
00652        mode window with a maximize flag at creation
00653        time.  Doing a ShowWindow(window->win, SW_SHOWNORMAL)
00654        would be wrong for a game mode window since it
00655        would unmaximize the window. */
00656     window->desiredMapState = GameModeState;
00657   } else {
00658     window->desiredMapState = NormalState;
00659   }
00660 #else
00661   window->desiredMapState = NormalState;
00662 #endif
00663   window->prevWorkWin = __glutWindowWorkList;
00664   __glutWindowWorkList = window;
00665 
00666   /* Initially, no menus attached. */
00667   for (i = 0; i < GLUT_MAX_MENUS; i++) {
00668     window->menu[i] = 0;
00669   }
00670 
00671   /* Add this new window to the window list. */
00672   __glutWindowList[winnum] = window;
00673 
00674   /* Make the new window the current window. */
00675   __glutSetWindow(window);
00676 
00677   __glutDetermineMesaSwapHackSupport();
00678 
00679   if (window->treatAsSingle) {
00680     /* We do this because either the window really is single
00681        buffered (in which case this is redundant, but harmless,
00682        because this is the initial single-buffered context
00683        state); or we are treating a double buffered window as a
00684        single-buffered window because the system does not appear
00685        to export any suitable single- buffered visuals (in which
00686        the following are necessary). */
00687     glDrawBuffer(GL_FRONT);
00688     glReadBuffer(GL_FRONT);
00689   }
00690   return window;
00691 }
00692 
00693 /* CENTRY */
00694 int APIENTRY
00695 glutCreateWindow(const char *title)
00696 {
00697   static int firstWindow = 1;
00698   GLUTwindow *window;
00699 #if !defined(_WIN32)
00700   XWMHints *wmHints;
00701 #endif
00702   Window win;
00703   XTextProperty textprop;
00704 
00705   if (__glutGameModeWindow) {
00706     __glutFatalError("cannot create windows in game mode.");
00707   }
00708   window = __glutCreateWindow(NULL,
00709     __glutSizeHints.x, __glutSizeHints.y,
00710     __glutInitWidth, __glutInitHeight,
00711     /* not game mode */ 0);
00712   win = window->win;
00713   /* Setup ICCCM properties. */
00714   textprop.value = (unsigned char *) title;
00715   textprop.encoding = XA_STRING;
00716   textprop.format = 8;
00717   textprop.nitems = strlen(title);
00718 #if defined(_WIN32)
00719   SetWindowText(win, title);
00720   if (__glutIconic) {
00721     window->desiredMapState = IconicState;
00722   }
00723 #else
00724   wmHints = XAllocWMHints();
00725   wmHints->initial_state =
00726     __glutIconic ? IconicState : NormalState;
00727   wmHints->flags = StateHint;
00728   XSetWMProperties(__glutDisplay, win, &textprop, &textprop,
00729   /* Only put WM_COMMAND property on first window. */
00730     firstWindow ? __glutArgv : NULL,
00731     firstWindow ? __glutArgc : 0,
00732     &__glutSizeHints, wmHints, NULL);
00733   XFree(wmHints);
00734   XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
00735 #endif
00736   firstWindow = 0;
00737   return window->num + 1;
00738 }
00739 
00740 int APIENTRY
00741 glutCreateSubWindow(int win, int x, int y, int width, int height)
00742 {
00743   GLUTwindow *window;
00744 
00745   window = __glutCreateWindow(__glutWindowList[win - 1],
00746     x, y, width, height, /* not game mode */ 0);
00747 #if !defined(_WIN32)
00748   {
00749     GLUTwindow *toplevel;
00750 
00751     toplevel = __glutToplevelOf(window);
00752     if (toplevel->cmap != window->cmap) {
00753       __glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
00754     }
00755   }
00756 #endif
00757   return window->num + 1;
00758 }
00759 /* ENDCENTRY */
00760 
00761 void
00762 __glutDestroyWindow(GLUTwindow * window,
00763   GLUTwindow * initialWindow)
00764 {
00765   GLUTwindow **prev, *cur, *parent, *siblings;
00766 
00767   /* Recursively destroy any children. */
00768   cur = window->children;
00769   while (cur) {
00770     siblings = cur->siblings;
00771     __glutDestroyWindow(cur, initialWindow);
00772     cur = siblings;
00773   }
00774   /* Remove from parent's children list (only necessary for
00775      non-initial windows and subwindows!). */
00776   parent = window->parent;
00777   if (parent && parent == initialWindow->parent) {
00778     prev = &parent->children;
00779     cur = parent->children;
00780     while (cur) {
00781       if (cur == window) {
00782         *prev = cur->siblings;
00783         break;
00784       }
00785       prev = &(cur->siblings);
00786       cur = cur->siblings;
00787     }
00788   }
00789   /* Unbind if bound to this window. */
00790   if (window == __glutCurrentWindow) {
00791     UNMAKE_CURRENT();
00792     __glutCurrentWindow = NULL;
00793   }
00794   /* Begin tearing down window itself. */
00795   if (window->overlay) {
00796     __glutFreeOverlayFunc(window->overlay);
00797   }
00798   XDestroyWindow(__glutDisplay, window->win);
00799   glXDestroyContext(__glutDisplay, window->ctx);
00800   if (window->colormap) {
00801     /* Only color index windows have colormap data structure. */
00802     __glutFreeColormap(window->colormap);
00803   }
00804   /* NULLing the __glutWindowList helps detect is a window
00805      instance has been destroyed, given a window number. */
00806   __glutWindowList[window->num] = NULL;
00807 
00808   /* Cleanup data structures that might contain window. */
00809   cleanWindowWorkList(window);
00810 #if !defined(_WIN32)
00811   cleanStaleWindowList(window);
00812 #endif
00813   /* Remove window from the "get window cache" if it is there. */
00814   if (__glutWindowCache == window)
00815     __glutWindowCache = NULL;
00816 
00817   if (window->visAlloced) {
00818     /* Only free XVisualInfo* gotten from glXChooseVisual. */
00819     XFree(window->vis);
00820   }
00821 
00822   if (window == __glutGameModeWindow) {
00823     /* Destroying the game mode window should implicitly
00824        have GLUT leave game mode. */
00825     __glutCloseDownGameMode();
00826   }
00827 
00828   free(window);
00829 }
00830 
00831 /* CENTRY */
00832 void APIENTRY
00833 glutDestroyWindow(int win)
00834 {
00835   GLUTwindow *window = __glutWindowList[win - 1];
00836 
00837   if (__glutMappedMenu && __glutMenuWindow == window) {
00838     __glutFatalUsage("destroying menu window not allowed while menus in use");
00839   }
00840 #if !defined(_WIN32)
00841   /* If not a toplevel window... */
00842   if (window->parent) {
00843     /* Destroying subwindows may change colormap requirements;
00844        recalculate toplevel window's WM_COLORMAP_WINDOWS
00845        property. */
00846     __glutPutOnWorkList(__glutToplevelOf(window->parent),
00847       GLUT_COLORMAP_WORK);
00848   }
00849 #endif
00850   __glutDestroyWindow(window, window);
00851 }
00852 /* ENDCENTRY */
00853 
00854 void
00855 __glutChangeWindowEventMask(long eventMask, Bool add)
00856 {
00857   if (add) {
00858     /* Add eventMask to window's event mask. */
00859     if ((__glutCurrentWindow->eventMask & eventMask) !=
00860       eventMask) {
00861       __glutCurrentWindow->eventMask |= eventMask;
00862       __glutPutOnWorkList(__glutCurrentWindow,
00863         GLUT_EVENT_MASK_WORK);
00864     }
00865   } else {
00866     /* Remove eventMask from window's event mask. */
00867     if (__glutCurrentWindow->eventMask & eventMask) {
00868       __glutCurrentWindow->eventMask &= ~eventMask;
00869       __glutPutOnWorkList(__glutCurrentWindow,
00870         GLUT_EVENT_MASK_WORK);
00871     }
00872   }
00873 }
00874 
00875 void APIENTRY
00876 glutDisplayFunc(GLUTdisplayCB displayFunc)
00877 {
00878   /* XXX Remove the warning after GLUT 3.0. */
00879   if (!displayFunc)
00880     __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
00881   __glutCurrentWindow->display = displayFunc;
00882 }
00883 
00884 void APIENTRY
00885 glutMouseFunc(GLUTmouseCB mouseFunc)
00886 {
00887   if (__glutCurrentWindow->mouse) {
00888     if (!mouseFunc) {
00889       /* Previous mouseFunc being disabled. */
00890       __glutCurrentWindow->buttonUses--;
00891       __glutChangeWindowEventMask(
00892         ButtonPressMask | ButtonReleaseMask,
00893         __glutCurrentWindow->buttonUses > 0);
00894     }
00895   } else {
00896     if (mouseFunc) {
00897       /* Previously no mouseFunc, new one being installed. */
00898       __glutCurrentWindow->buttonUses++;
00899       __glutChangeWindowEventMask(
00900         ButtonPressMask | ButtonReleaseMask, True);
00901     }
00902   }
00903   __glutCurrentWindow->mouse = mouseFunc;
00904 }
00905 
00906 void APIENTRY
00907 glutMotionFunc(GLUTmotionCB motionFunc)
00908 {
00909   /* Hack.  Some window managers (4Dwm by default) will mask
00910      motion events if the client is not selecting for button
00911      press and release events. So we select for press and
00912      release events too (being careful to use reference
00913      counting).  */
00914   if (__glutCurrentWindow->motion) {
00915     if (!motionFunc) {
00916       /* previous mouseFunc being disabled */
00917       __glutCurrentWindow->buttonUses--;
00918       __glutChangeWindowEventMask(
00919         ButtonPressMask | ButtonReleaseMask,
00920         __glutCurrentWindow->buttonUses > 0);
00921     }
00922   } else {
00923     if (motionFunc) {
00924       /* Previously no mouseFunc, new one being installed. */
00925       __glutCurrentWindow->buttonUses++;
00926       __glutChangeWindowEventMask(
00927         ButtonPressMask | ButtonReleaseMask, True);
00928     }
00929   }
00930   /* Real work of selecting for passive mouse motion.  */
00931   __glutChangeWindowEventMask(
00932     Button1MotionMask | Button2MotionMask | Button3MotionMask,
00933     motionFunc != NULL);
00934   __glutCurrentWindow->motion = motionFunc;
00935 }
00936 
00937 void APIENTRY
00938 glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc)
00939 {
00940   __glutChangeWindowEventMask(PointerMotionMask,
00941     passiveMotionFunc != NULL);
00942 
00943   /* Passive motion also requires watching enters and leaves so
00944      that a fake passive motion event can be generated on an
00945      enter. */
00946   __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
00947     __glutCurrentWindow->entry != NULL || passiveMotionFunc != NULL);
00948 
00949   __glutCurrentWindow->passive = passiveMotionFunc;
00950 }
00951 
00952 void APIENTRY
00953 glutEntryFunc(GLUTentryCB entryFunc)
00954 {
00955   __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
00956     entryFunc != NULL || __glutCurrentWindow->passive);
00957   __glutCurrentWindow->entry = entryFunc;
00958   if (!entryFunc) {
00959     __glutCurrentWindow->entryState = -1;
00960   }
00961 }
00962 
00963 void APIENTRY
00964 glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc)
00965 {
00966   __glutChangeWindowEventMask(VisibilityChangeMask,
00967     windowStatusFunc != NULL);
00968   __glutCurrentWindow->windowStatus = windowStatusFunc;
00969   if (!windowStatusFunc) {
00970     /* Make state invalid. */
00971     __glutCurrentWindow->visState = -1;
00972   }
00973 }
00974 
00975 static void
00976 visibilityHelper(int status)
00977 {
00978   if (status == GLUT_HIDDEN || status == GLUT_FULLY_COVERED)
00979     __glutCurrentWindow->visibility(GLUT_NOT_VISIBLE);
00980   else
00981     __glutCurrentWindow->visibility(GLUT_VISIBLE);
00982 }
00983 
00984 void APIENTRY
00985 glutVisibilityFunc(GLUTvisibilityCB visibilityFunc)
00986 {
00987   __glutCurrentWindow->visibility = visibilityFunc;
00988   if (visibilityFunc)
00989     glutWindowStatusFunc(visibilityHelper);
00990   else
00991     glutWindowStatusFunc(NULL);
00992 }
00993 
00994 void APIENTRY
00995 glutReshapeFunc(GLUTreshapeCB reshapeFunc)
00996 {
00997   if (reshapeFunc) {
00998     __glutCurrentWindow->reshape = reshapeFunc;
00999   } else {
01000     __glutCurrentWindow->reshape = __glutDefaultReshape;
01001   }
01002 }
01003 
01004 void APIENTRY
01005 glutMoveFunc(GLUTmoveCB moveFunc)
01006 {
01007   __glutCurrentWindow->move = moveFunc;
01008   /* StructureNotifyMask is added to window's event mask
01009      by __glutCreateWindow() */
01010 }

Generated on Mon Sep 18 11:39:31 2006 for jot by  doxygen 1.4.4