Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

glut_win.c

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

Powered by Plone

This site conforms to the following standards: