//tex \section{Basic Data Structures: glutint.h} \label{iglut_glutint_h} The {\tt glutint.h} header file declares GLUT internal data structures and internal functions and variables used across GLUT implementation source files. This header is included by all the GLUT implementation source code. Because it defines internal information about GLUT's implementation which is not part of the GLUT API, it should not be included by source files using the GLUT API. The library uses the {\tt \_\_glut} prefix for all internal symbols (functions and variables) that might have external linkage. Where internal symbols are isolated to a single source file, such symbols are declared static to avoid external linkage. For such static symbols, the {\tt \_\_glut} prefix is unnecessary. This convention sets up a clean namespace for GLUT internal symbols to avoid clashing with application symbols. //dead #ifndef __glutint_h__ #define __glutint_h__ /* Copyright (c) Mark J. Kilgard, 1994. */ /* This program is freely distributable without licensing fees and is provided without guarantee or warrantee expressed or implied. This program is -not- in the public domain. */ #ifdef __sgi #define SUPPORT_FORTRAN #endif //tex Unix, X11, OpenGL, and GLX data types are used throughout this header. //code #include #include #include #ifdef __vms struct timeval { __int64 val; }; extern int sys$gettim(struct timeval *); #else #include #include #endif //tex \subsection{Time Management} GLUT's {\tt glutTimerFunc} allows GLUT to generate callbacks in response to the passage of time. The bulk of the code to manage timer callbacks is found in {\tt glut\_event.c}'s event processing code. To manage time related calculations a number of time related macros are helpful. {\tt GETTIMEOFDAY} is specified as a macro because the Berkeley Unix and AT\&T Unix variants have conflicting interfaces for {\tt gettimeofday}. The BSD variant of {\tt gettimeofday} takes a second parameter to return timezone information (that is not used by GLUT). Using {\tt GETTIMEOFDAY} helps hide this differences in the two interfaces. //code #if defined(__vms) /* One TICK on VMS is 100 nanoseconds; 0.1 microseconds or 0.0001 milliseconds. This means that there are 0.01 ticks/ns, 10 ticks/us, 10,000 ticks/ms and 10,000,000 ticks/second. */ #define TICKS_PER_MILLISECOND 10000 #define TICKS_PER_SECOND 10000000 #define GETTIMEOFDAY(_x) (void) sys$gettim (_x); #define ADD_TIME(dest, src1, src2) { \ (dest).val = (src1).val + (src2).val; \ } #define TIMEDELTA(dest, src1, src2) { \ (dest).val = (src1).val - (src2).val; \ } #define IS_AFTER(t1, t2) ((t2).val > (t1).val) #define IS_AT_OR_AFTER(t1, t2) ((t2).val >= (t1).val) #else #ifdef SVR4 #define GETTIMEOFDAY(_x) gettimeofday(_x) #else #define GETTIMEOFDAY(_x) gettimeofday(_x, NULL) #endif //tex \noindent The {\tt GETTIMEOFDAY} updates a {\tt timeval} structure with the current time. The structure is defined as follows: \begin{verbatim} struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; \end{verbatim} While the {\tt timeval} structure specifies the time to microsecond accuracy, most Unix implementations do not provide time to that accuracy. The timer callbacks registered with {\tt glutTimerFunc} are only specified to millisecond accuracy. Because time is not represented with a single integer, the macros below permit arithmetic and comparison operations using {\tt timeval} structures. (These macros do assume the microsecond filed of the {\tt timeval} structures are normalized between 0 and 1,000,000.) {\tt ADD\_TIME} adds two {\tt timeval} structures together, correctly handling microsecond overflow. This macro is used by {\tt glutTimerFunc} in {\tt glut\_event.c} to calculate the absolute time when the timer callback being registered should be called. //code #define ADD_TIME(dest, src1, src2) { \ if(((dest).tv_usec = \ (src1).tv_usec + (src2).tv_usec) >= 1000000) { \ (dest).tv_usec -= 1000000; \ (dest).tv_sec = (src1).tv_sec + (src2).tv_sec + 1; \ } else { \ (dest).tv_sec = (src1).tv_sec + (src2).tv_sec; \ if(((dest).tv_sec >= 1) && (((dest).tv_usec <0))) { \ (dest).tv_sec --;(dest).tv_usec += 1000000; \ } \ } \ } //tex \noindent {\tt TIMEDELTA} subtracts one {\tt timeval} structure from another, correctly handling microsecond underflow. This macro is used by {\tt waitForSomething} in {\tt glut\_event.c} to determine the time between current time and the next pending timer callback to know the maximum time to block waiting for input. //code #define TIMEDELTA(dest, src1, src2) { \ if(((dest).tv_usec = (src1).tv_usec - (src2).tv_usec) < 0) { \ (dest).tv_usec += 1000000; \ (dest).tv_sec = (src1).tv_sec - (src2).tv_sec - 1; \ } else { \ (dest).tv_sec = (src1).tv_sec - (src2).tv_sec; \ } \ } //tex \noindent {\tt IS\_AFTER} determines if the first {\tt timeval} structure is temporally after the second. This macro is used by {\tt glutTimerFunc} to order the timer callback being registered temporally on the list of timer callbacks. It is also used by {\tt waitForSomething} to determine if the next timer callback should already have been called. //code #define IS_AFTER(t1, t2) \ (((t2).tv_sec > (t1).tv_sec) || \ (((t2).tv_sec == (t1).tv_sec) && \ ((t2).tv_usec > (t1).tv_usec))) //tex \noindent {\tt IS\_AT\_OR\_AFTER} determines if the first {\tt timeval} structure is temporally at or after the second. This macro is used by {\tt handleTimeouts} in {\tt glut\_event.c} while traversing the timer callback list to call any timer callbacks that need to be called. //code #define IS_AT_OR_AFTER(t1, t2) \ (((t2).tv_sec > (t1).tv_sec) || \ (((t2).tv_sec == (t1).tv_sec) && \ ((t2).tv_usec >= (t1).tv_usec))) #endif //tex \subsection{Display Mode Macros} The {\tt GLUT\_WIND\_IS} family of macros decode GLUT's display mode to determine what frame buffer capabilities a given display mode mask requests. These macros help {\tt \_\_glutGetVisualInfo} in {\tt glut\_win.c} determine the correct X visual to use when creating a GLUT window or when determining if the current display mode is possible. //code #define GLUT_WIND_IS_RGB(x) (((x) & GLUT_INDEX) == 0) #define GLUT_WIND_IS_INDEX(x) (((x) & GLUT_INDEX) != 0) #define GLUT_WIND_IS_SINGLE(x) (((x) & GLUT_DOUBLE) == 0) #define GLUT_WIND_IS_DOUBLE(x) (((x) & GLUT_DOUBLE) != 0) #define GLUT_WIND_HAS_ACCUM(x) (((x) & GLUT_ACCUM) != 0) #define GLUT_WIND_HAS_ALPHA(x) (((x) & GLUT_ALPHA) != 0) #define GLUT_WIND_HAS_DEPTH(x) (((x) & GLUT_DEPTH) != 0) #define GLUT_WIND_HAS_STENCIL(x) (((x) & GLUT_STENCIL) != 0) #define GLUT_WIND_IS_MULTISAMPLE(x) (((x) & GLUT_MULTISAMPLE) != 0) #define GLUT_WIND_IS_STEREO(x) (((x) & GLUT_STEREO) != 0) #define GLUT_WIND_IS_LUMINANCE(x) (((x) & GLUT_LUMINANCE) != 0) //tex \subsection{Work List Management} \label{iglut_mask_bits} GLUT services requests resulting from either events or GLUT API calls by the application. Servicing these requests is supported (and optimized) by maintaining a {\em work list}. The work list contains windows needing requests serviced and the work pending for each window. The work list permits requests to be batched for more efficient execution. For example, if several GLUT API requests will result in the updating of the X event mask, these multiple requests will be batched as a single X request to update event mask (combining all the independent update request). Also, multiple requests to redisplay the window before the next opportunity to redraw the window will trigger only a single display callback. The constants below are masks that are OR-ed together into a work mask maintained for each GLUT window. Work is added to the work list by calling {\tt \_\_glutPutOnWorkList} in {\tt glut\_event.c} (see Section \ref{iglut_glut_event_c}). The routine {\tt processWindowWorkList} also in {\tt glut\_event.c} is called to process any pending work. Windows are removed from the work list once all their pending work has been processed. //code #define GLUT_MAP_WORK (1 << 0) #define GLUT_EVENT_MASK_WORK (1 << 1) #define GLUT_REDISPLAY_WORK (1 << 2) #define GLUT_CONFIGURE_WORK (1 << 3) #define GLUT_COLORMAP_WORK (1 << 4) #define GLUT_DEVICE_MASK_WORK (1 << 5) #define GLUT_FINISH_WORK (1 << 6) #define GLUT_DEBUG_WORK (1 << 7) #define GLUT_DUMMY_WORK (1 << 8) #define GLUT_FULL_SCREEN_WORK (1 << 9) #define GLUT_OVERLAY_REDISPLAY_WORK (1 << 10) //tex \noindent {\tt GLUT\_MAP\_WORK} indicates the window needs to be shown, hidden, or iconified. {\tt GLUT\_EVENT\_MASK\_WORK} indicates the window needs its X event mask updated. {\tt GLUT\_REDISPLAY\_WORK} indicates the window needs to be redisplayed. {\tt GLUT\_CONFIGURE\_WORK} indicates the size, position, or stacking order needs to be updated. {\tt GLUT\_COLORMAP\_WORK} indicates the top-level window's ICCCM {\tt WM\_COLORMAP\_WINDOWS} property needs to be changed or removed. {\tt GLUT\_DEVICE\_MASK\_WORK} indicates the window needs its X Input extension event mask updated. {\tt GLUT\_FINISH\_WORK} indicates a {\tt glFinish} should be done on this window. {\tt GLUT\_DEBUG\_WORK} indicates that OpenGL errors should be queried for the rendering context associated with this context. {\tt GLUT\_DUMMY\_WORK} is for accounting purposes within {\tt processWindowWorkList}. The work list facility is used throughout GLUT's implementation to efficiently handle pending work. \subsection{Callback Prototypes} Each possible GLUT callback function has an associated {\tt typedef} used to prototype the callback. //dead /* GLUT callback function types */ //code typedef void (*GLUTdisplayCB) (void); typedef void (*GLUTreshapeCB) (int, int); typedef void (*GLUTkeyboardCB) (unsigned char, int, int); typedef void (*GLUTmouseCB) (int, int, int, int); typedef void (*GLUTmotionCB) (int, int); typedef void (*GLUTpassiveCB) (int, int); typedef void (*GLUTentryCB) (int); typedef void (*GLUTvisibilityCB) (int); typedef void (*GLUTidleCB) (void); typedef void (*GLUTtimerCB) (int); typedef void (*GLUTmenuStateCB) (int); /* DEPRICATED. */ typedef void (*GLUTmenuStatusCB) (int, int, int); typedef void (*GLUTselectCB) (int); typedef void (*GLUTspecialCB) (int, int, int); typedef void (*GLUTspaceMotionCB) (int, int, int); typedef void (*GLUTspaceRotateCB) (int, int, int); typedef void (*GLUTspaceButtonCB) (int, int); typedef void (*GLUTdialsCB) (int, int); typedef void (*GLUTbuttonBoxCB) (int, int); typedef void (*GLUTtabletMotionCB) (int, int); typedef void (*GLUTtabletButtonCB) (int, int, int, int); //dead #ifdef SUPPORT_FORTRAN typedef void (*GLUTdisplayFCB) (void); typedef void (*GLUTreshapeFCB) (int *, int *); /* NOTE the pressed key is int, not unsigned char for Fortran! */ typedef void (*GLUTkeyboardFCB) (int *, int *, int *); typedef void (*GLUTmouseFCB) (int *, int *, int *, int *); typedef void (*GLUTmotionFCB) (int *, int *); typedef void (*GLUTpassiveFCB) (int *, int *); typedef void (*GLUTentryFCB) (int *); typedef void (*GLUTvisibilityFCB) (int *); typedef void (*GLUTidleFCB) (void); typedef void (*GLUTtimerFCB) (int *); typedef void (*GLUTmenuStateFCB) (int *); /* DEPRICATED. */ typedef void (*GLUTmenuStatusFCB) (int *, int *, int *); typedef void (*GLUTselectFCB) (int *); typedef void (*GLUTspecialFCB) (int *, int *, int *); typedef void (*GLUTspaceMotionFCB) (int *, int *, int *); typedef void (*GLUTspaceRotateFCB) (int *, int *, int *); typedef void (*GLUTspaceButtonFCB) (int *, int *); typedef void (*GLUTdialsFCB) (int *, int *); typedef void (*GLUTbuttonBoxFCB) (int *, int *); typedef void (*GLUTtabletMotionFCB) (int *, int *); typedef void (*GLUTtabletButtonFCB) (int *, int *, int *, int *); #endif //code //tex \subsection{Internal Data Objects} The three major types of data objects internal to GLUT are the windows, menus, and colormaps. Windows also have an associated overlay object when an overlay is established. Each menu object has an associated list of menu item objects. Each color index (but not RGBA) window colormap has an associated array of color cell objects. \subsubsection{Colormaps} The {\tt GLUTcolormap} object maintains a colormap for color index GLUT windows. A {\tt GLUTcolormap} is not needed for RGBA GLUT windows because such windows have constant, read-only colormaps. GLUT attempts to share RGB X colormaps for RGBA GLUT windows with other X applications using ICCCM conventions (and when that fails, attempts sharing between windows within the GLUT program). Because RGB colormaps have constant entries, the GLUT window needs only the X colormap ID and needs no {\tt GLUTcolormap} to track the specific mapping of pixel values to colors. In the case of color index windows, the window's colormap is writable, and this complicates sharing. To be general, GLUT gives each GLUT window its own independently writable colormap, but because colormaps are generally limited by graphics hardware resources, GLUT provides a means of sharing color index colormaps. The {\tt glutCopyColormap} routine provides a way for two GLUT windows to share (by reference) the same X colormap. The scheme still allows independently writable colormaps because GLUT will ``copy on write'' a colormap being shared by reference between multiple windows. Each {\tt GLUTcolormap} has an associated array of {\tt GLUTcolorcell} structures maintaining red, green, and blue components for each pixel value in the colormap. //code typedef struct _GLUTcolorcell GLUTcolorcell; struct _GLUTcolorcell { /* GLUT_RED, GLUT_GREEN, GLUT_BLUE */ GLfloat component[3]; }; //tex \noindent The {\tt GLUTcolormap} has a pointer to the {\tt GLUTcolorcell} array. It also contains the X colormap ID and the specific X visual the colormap pertains to. Because color index colormaps can be shared by reference, a reference count is maintained for the number of windows using the {\tt GLUTcolormap}. All {\tt GLUTcolormap}s are maintained on a list to provide an initial color index colormap association for a window. When a color index window is created, {\tt \_\_glutAssociateColormap} in {\tt glut\_cindex.c} will create the initial association. //code typedef struct _GLUTcolormap GLUTcolormap; struct _GLUTcolormap { Visual *visual; /* visual of the colormap */ Colormap cmap; /* X colormap ID */ int refcnt; /* number of windows using colormap */ int size; /* number of cells in colormap */ int transparent; /* transparent pixel, or -1 if opaque */ GLUTcolorcell *cells; /* array of cells */ GLUTcolormap *next; /* next colormap in list */ }; //tex \subsubsection{Windows} The {\tt GLUTwindow} object maintains all the state associated with a GLUT window created by {\tt glutCreateWindow} or {\tt glutCreateSubWindow}. Each created window is listed in the {\tt \_\_glutWindowList} array. Windows on this list are indexed from zero, despite the GLUT API assigning window identifiers starting at one. Top-level windows (created by {\tt glutCreateWindow}) are distinguished from subwindows because top-level windows are created as children of the root window. Subwindows are created as children of top-level windows or other subwindows. //code typedef struct _GLUTwindow GLUTwindow; typedef struct _GLUToverlay GLUToverlay; struct _GLUTwindow { //tex \noindent Each {\tt GLUTwindow} contains its own zero-based index. //code int num; /* small integer window id (0-based) */ //tex \noindent Each {\tt GLUTwindow} maintains the underlying X objects it uses. Every GLUT window has its own distinct X window and associated, distinct OpenGL rendering context. The {\tt XVisualInfo*} describing the window's OpenGL frame buffer configuration is maintained. RGBA windows maintain their X colormap in the {\tt GLUTwindow} structure; color index windows use the previously described {\tt GLUTcolormap} structure. Windows with established overlays maintain overlay information in the {\tt GLUToverlay} structure described next. //dead /* Window system related state. */ //code Window win; /* X window for GLUT window */ GLXContext ctx; /* OpenGL context GLUT glut window */ XVisualInfo *vis; /* visual for window */ Colormap cmap; /* RGB colormap for window; None if CI */ GLUTcolormap *colormap; /* colormap; NULL if RGBA */ GLUToverlay *overlay; /* overlay; NULL if no overlay */ //tex Support for overlays means windows have a {\em layer in use}, either the overlay or normal plane. To avoid checking what layer is in use when making current to GLUT windows (that may or may not have overlays), the {\tt renderWin} and {\tt renderCtx} always hold the X window ID and GLX context handle for the layer in use. If {\tt renderWin} equals the {\tt win} field above, the normal plane is in use; otherwise, the overlay is in use. //code Window renderWin; /* X window for rendering (might be overlay) */ GLXContext renderCtx; /* OpenGL context for rendering (might be overlay) */ //tex \noindent GLUT tracks some per-window state like the window's width, height, map state, and visibility state. //dead /* GLUT settable or visible window state. */ //code int width; /* window width in pixels */ int height; /* window height in pixels */ int cursor; /* cursor name */ int visState; /* visibility state (-1 is unknown) */ int shownState; /* if window mapped */ int entryState; /* entry state (-1 is unknown) */ int damaged; /* is layer damaged by expose? */ //tex \noindent GLUT supports a pop-up menu bound to each of three mouse buttons (left, middle, and right). {\tt GLUT\_MAX\_MENUS} is the number of supported buttons. {\tt glutAttachMenu} associates a menu with a button in a specified window. The {\tt menu} array holds this association. Note that the association is {\em by name}. //code #define GLUT_MAX_MENUS 3 int menu[GLUT_MAX_MENUS]; /* attatched menu nums */ //tex \noindent {\tt parent} points to the parent {\tt GLUTwindow} and is {\tt NULL} if the window is a top-level window. {\tt children} points to a child of the window and is {\tt NULL} if the window has no children. The {\tt siblings} field forms a linked list to the remaining child windows. //dead /* Window relationship state. */ //code GLUTwindow *parent; /* parent window */ GLUTwindow *children; /* list of children */ GLUTwindow *siblings; /* list of siblings */ //tex \noindent While not visible through the API, there is a fair amount of state required for implementation reasons. //dead /* Misc. non-API visible (hidden) state. */ //code Bool fakeSingle; /* faking single buffer with double */ //tex \noindent GLUT emulates single buffered windows if no single buffered visual can be found matching the window's display mode {\em but} a matching double buffered visual can be found. This is because GLX does not mandate the existence of single buffered visuals. In this case, {\tt glutSwapBuffers} must be treated as non-operation and the window's OpenGL context must be set to draw into the front buffer. {\tt fakeSingle} determines if the window emulates being single buffered. //code Bool forceReshape; /* force reshape before display */ //tex \noindent X only sends {\tt ConfigureNotify} events when the window is resized, but not when a window is created. GLUT guarantees that a window's reshape callback will be triggered before the first display callback is triggered. {\tt forceReshape} tracks whether an initial reshape callback has been triggered to ensure GLUT's expected behavior. //code Bool isDirect; /* if direct context */ //tex \noindent If a window's context uses direct rendering, {\tt isDirect} is {\tt True}. When {\tt False}, a {\tt glFinish} is performed (via the work list facility) to keep OpenGL commands from buffering up when indirect rendering is in use. Otherwise, application interactivity is undermined by the latency caused by batching. //code long eventMask; /* mask of X events selected for */ //tex \noindent What X event should be selected for depends on what callbacks are registered. {\tt eventMask} maintains what events the window should select on. The window's event mask is not immediately updated, but instead {\tt GLUT\_EVENT\_MASK\_WORK} is put on the work list to batch the event mask update. //code int buttonUses; /* number of button uses, ref cnt */ //tex \noindent Selecting mouse button up and down events is required for multiple reasons: the mouse callback, attached pop-up menus, and mouse motion tracking. {\tt buttonUses} is a reference count of what uses are current. {\tt ButtonPress} and {\tt ButtonRelease} events are selected for when {\tt buttonUses} is greater than zero and not selected for when zero. //code int tabletPos[2]; /* tablet position (-1 is invalid) */ //tex \noindent Current X servers make it difficult to correctly track tablet position for two reasons. First, tablet position events are allowed report on the changed axis. Second, the X Input extension's {\tt XDeviceStateNotifyEvent} is unimplemented in X servers through X11R6. The GLUT tablet callbacks reports both the simultaneous X and Y tablet position. To report the combined position, GLUT tracks the last recorded simultaneous tablet position using {\tt tabletPos}. If necessary, GLUT will poll the tablet position if only a single axis is initially returned. //dead /* Work list related state. */ //tex GLUT's work list facility requires per-window state to determine what work is pending for the window. The {\tt workMask} is a bitmask containing the {\tt GLUT\_*\_WORK} mask bits (see Section \ref{iglut_mask_bits} to indicate what work is pending //code unsigned int workMask; /* mask of window work to be done */ //tex \noindent Windows with work to do are linked into the work list. {\tt prevWorkWin} is a reverse ordered list of window's on the work list. The list is started at {\tt \_\_glutWindowWorkList}. //code GLUTwindow *prevWorkWin; /* link list of windows to work on */ //tex \noindent The work list facility means that desired window state changes for showing, hiding, iconifying, repositioning, reshaping, and restacking the window must be recorded before the changes are actualized when the event list is processed: //code Bool desiredMapState; /* how to mapped window if on map work list */ int desiredConfMask; /* mask of desired window configuration */ int desiredX; /* desired X location */ int desiredY; /* desired Y location */ int desiredWidth; /* desired window width */ int desiredHeight; /* desired window height */ int desiredStack; /* desired window stack */ //tex \noindent Each per-window callback must have an associated {\tt GLUTwindow} field to record the currently registered routine for each callback: //dead /* Callbacks */ //code GLUTdisplayCB display; /* redraw callback */ GLUTreshapeCB reshape; /* resize callback (width,height) */ GLUTmouseCB mouse; /* mouse callback (button,state,x,y) */ GLUTmotionCB motion; /* motion callback (x,y) */ GLUTpassiveCB passive; /* passive motion callback (x,y) */ GLUTentryCB entry; /* window entry/exit callback (state) */ GLUTkeyboardCB keyboard; /* keyboard callback (ASCII,x,y) */ GLUTvisibilityCB visibility; /* visibility callback */ GLUTspecialCB special; /* special key callback */ GLUTbuttonBoxCB buttonBox; /* button box callback */ GLUTdialsCB dials; /* dials callback */ GLUTspaceMotionCB spaceMotion; /* Spaceball motion callback */ GLUTspaceRotateCB spaceRotate; /* Spaceball rotate callback */ GLUTspaceButtonCB spaceButton; /* Spaceball button callback */ GLUTtabletMotionCB tabletMotion; /* tablet motion callback */ GLUTtabletButtonCB tabletButton; /* tablet button callback */ //dead #ifdef SUPPORT_FORTRAN /* Special Fortran display callback unneeded since no parameters! */ GLUTreshapeFCB freshape; /* Fortran reshape callback */ GLUTmouseFCB fmouse; /* Fortran mouse callback */ GLUTmotionFCB fmotion; /* Fortran motion callback */ GLUTpassiveFCB fpassive; /* Fortran passive callback */ GLUTentryFCB fentry; /* Fortran entry callback */ GLUTkeyboardFCB fkeyboard; /* Fortran keyboard callback */ GLUTvisibilityFCB fvisibility; /* Fortran visibility callback */ GLUTspecialFCB fspecial; /* special key callback */ GLUTbuttonBoxFCB fbuttonBox; /* button box callback */ GLUTdialsFCB fdials; /* dials callback */ GLUTspaceMotionFCB fspaceMotion; /* Spaceball motion callback */ GLUTspaceRotateFCB fspaceRotate; /* Spaceball rotate callback */ GLUTspaceButtonFCB fspaceButton; /* Spaceball button callback */ GLUTtabletMotionFCB ftabletMotion; /* tablet motion callback */ GLUTtabletButtonFCB ftabletButton; /* tablet button callback */ #endif //code }; //tex \subsubsection{Overlays} When an overlay is established for a window, the window gets an associated {\tt GLUToverlay} structure. //code struct _GLUToverlay { Window win; GLXContext ctx; XVisualInfo *vis; /* visual for window */ Colormap cmap; /* RGB colormap for window; None if CI */ GLUTcolormap *colormap; /* colormap; NULL if RGBA */ //tex Like the normal plane of a window, an overlay also requires an X window ID, OpenGL rendering context, visual information, an X colormap, and associated {\tt GLUTcolormap} structure. The {\tt vis} visual information will be for an overlay visual with a transparent pixel. //code int shownState; /* if overlay window mapped */ Bool fakeSingle; /* faking single buffer with double */ Bool isDirect; /* if direct context */ int damaged; /* is layer damaged by expose? */ //tex These fields maintain the same state they maintain in the {\tt GLUTwindow} structure, but for the overlay. //code int transparentPixel; /* transparent pixel value */ GLUTdisplayCB display; /* redraw callback */ //dead /* Special Fortran display callback unneeded since no parameters! */ //code }; //tex A small amount of overlay specific state is maintained. Overlays have a {\tt transparentPixel} containing the transparent pixel of their overlay. Also, overlays can have a separate, distinct display callback for redisplaying the overlay. Overlays can be established and removed repeatedly with {\tt glutEstablishOverlay} and {\tt glutRemoveOverlay}. Removing the overlay destroys the associated X window and GLX context. However, yet to be processed input events could still arrive intended for the removed overlay's X window ID. These input events should not simply be discarded because they were generated at the inopportune time that the overlay was being removed. GLUT maintains a {\em stale window list}. When an overlay X window ID is destroyed, it is put on the stale window list. When any event input arrives, all the active normal and overlay X window IDs will be searched, but if the event's X window ID is not found, the stale window list is searched. A ``stale'' X input event destined for a removed overlay window can still be directed to the correct GLUT window by {\tt \_\_glutGetWindow}. When a {\tt DestroyNotify} event is delivered for the overlay window ID, no more events will be received for the window ID and the ID is safely removed from the stale window list. The stale window list is a linked list started at {\tt \_\_glutStaleWindowList}. //code typedef struct _GLUTstale GLUTstale; struct _GLUTstale { GLUTwindow *window; Window win; GLUTstale *next; }; extern GLUTstale *__glutStaleWindowList; //tex There are some X events that need to be delivered to both overlay and normal plane X windows. The {\tt GLUT\_OVERLAY\_EVENT\_FILTER\_MASK} lists the event masks for these events. The event mask used to select for on an overlay window events is the normal plane window's event mask bitwise AND-ed with the {\tt GLUT\_OVERLAY\_EVENT\_FILTER\_MASK}. //code #define GLUT_OVERLAY_EVENT_FILTER_MASK \ (ExposureMask | \ StructureNotifyMask | \ EnterWindowMask | \ LeaveWindowMask) //tex A second event mask is the {\tt GLUT\_DONT\_PROPAGATE\_FILTER\_MASK} that lists input events that should not propagate to ancestor windows. GLUT specifies that input event should be delivered only to the window receiving the event which is what every X window's {\em do not propagate} mask assures. By bitwise AND-ing this mask with the window's event mask, the window's {\em do not propagate} mask is calculated. //code #define GLUT_DONT_PROPAGATE_FILTER_MASK \ (ButtonReleaseMask | \ ButtonPressMask | \ KeyPressMask | \ KeyReleaseMask | \ PointerMotionMask | \ Button1MotionMask | \ Button2MotionMask | \ Button3MotionMask) //dead #define GLUT_HACK_STOP_PROPAGATE_MASK \ (KeyPressMask | \ KeyReleaseMask) //tex \subsubsection{Menus} GLUT's pop-up menus can be attached by name to buttons for each window. A menu is represented by the {\tt GLUTmenu} object. Each menu has a number of menu items, each represented by a {\tt GLUTmenuItem} structure. Each created menu is listed in the \_\_glutMenuList array index by its menu identifier. Menus on this list are indexed from zero, despite the GLUT API assigning menu identifiers starting at one. //code typedef struct _GLUTmenu GLUTmenu; typedef struct _GLUTmenuItem GLUTmenuItem; struct _GLUTmenu { int id; /* small integer menu id (0-based) */ //tex Each menu contains its own zero-based index //code Window win; /* X window for the menu */ //tex Even menu has an X window ID used to display the menu. This window is only mapped when the menu is popped-up. If overlays are supported, this window will use an overlay. //code GLUTselectCB select; /* callback function of menu */ //tex Each menu has a single callback established when {\tt glutCreateMenu} is called. //code GLUTmenuItem *list; /* list of menu entries */ int num; /* number of entries */ Bool managed; /* are the InputOnly windows size validated? */ int pixwidth; /* width of menu in pixels */ int pixheight; /* height of menu in pixels */ int submenus; /* number of submenu entries */ //tex Each menu has a linked list of {\tt GLUTmenuItem} structures. The {\tt num} field tells how many entries the menu currently has. The {\tt managed} field is set {\tt False} whenever the menu window's size need to be updated. Examples include when a new entry is added, an existing entry is removed, or the width of an entry changes. {\tt pixwidth} and {\tt pixheight} keep tracks of the menu's managed size. The number of submenus needs to be tracked because the ``trigger arrow'' adds extra width to the menu when it needs to be displayed. //code GLUTmenuItem *highlighted; /* pointer to highlighted menu entry, NULL not highlighted */ GLUTmenu *cascade; /* currently cascading this menu */ GLUTmenuItem *anchor; /* currently anchored to this entry */ int x; /* current x origin relative to the root window */ int y; /* current y origin relative to the root window */ //dead #ifdef SUPPORT_FORTRAN GLUTselectFCB fselect; /* callback function of menu */ #endif //code }; //tex These last fields are used when the menu is displayed. They track if an entry is highlighted, and if so what it is, what parent menu is cascading this menu; the menu currently anchored to (that is, cascading from), and the position of the menu. Every menu item has an {\tt InputOnly} X window. The menu item's appearance is actually rendered into the menu's X window. Having an {\tt InputOnly} window for the menu item allows menu item selection to be performed more efficiently. Every menu item has an associated {\tt GLUTmenu} structure it belongs //code struct _GLUTmenuItem { Window win; /* InputOnly X window for entry */ GLUTmenu *menu; /* menu entry belongs to */ Bool isTrigger; /* is a submenu trigger? */ int value; /* value to return for selecting this entry; doubles as submenu id (0-base) if submenu trigger */ //tex The {\tt isTrigger} boolean tells whether the menu is a submenu trigger established by {\tt glutAddSubMenu} or {\tt glutChangeToSubMenu} or a menu entry established by {\tt glutAddMenuEntry} or {\tt glutChangeToMenuEntry}. The {\tt value} field is overloaded to be the value passed to the menu callback if the entry is selected or the menu number of the submenu the trigger cascades. //code char *label; /* strdup'ed label string */ int len; /* length of label string */ int pixwidth; /* width of X window in pixels */ //tex The {\tt label} field contains the string displayed by the menu item with {\tt len} being the string's length in characters and {\tt pixwidth} being the strings width in pixels. The {\tt pixwidth} speeds recalculation of the menu's width when the menu needs to be re-managed. All the menu items for a menu are on a linked list. The list is ordered starting with bottom items with top items at the end. //code GLUTmenuItem *next; /* next menu entry on list for menu */ }; //tex \subsubsection{Timers} Each timer callback registered with {\tt glutTimerFunc} has an associated {\tt GLUTtimer} structure. All outstanding timer callbacks are listed on the {\tt \_\_glutTimerList} linked list. The list is sorted by time when the callback is to be called. Timer callbacks to be called sooner are nearer the front of the list. //code typedef struct _GLUTtimer GLUTtimer; struct _GLUTtimer { GLUTtimer *next; /* list of timers */ struct timeval timeout; /* time to be called */ //tex When the timer callback is due to be called, the callback's {\tt func} callback function is called, passing {\tt value} to the callback. //code GLUTtimerCB func; /* timer callback (value) */ int value; /* callback return value */ //dead #ifdef SUPPORT_FORTRAN GLUTtimerFCB ffunc; /* Fortran timer callback */ #endif //code }; //tex \subsubsection{Event Parser} GLUT supports the X Input extension to obtain input from tablet, dial \& button box, and Spaceball devices. Since most GLUT programs do not use these devices, the GLUT code associated with these devices should only linked with if programs request callbacks for these devices. GLUT provides an {\em event parser} mechanism that lets X events not understood by GLUT's basic event loop be passed on to a set of routines for processing other types of X events. The X Input extension events can be handled this way. The GLUT routines to register tablet, dial \& button box, and Spaceball callbacks also add an event parser for X Input extension events. Because the X Input extension event handler is dynamically made a part of GLUT's main loop through the event parser mechanism, only programs that use the tablet, dial \& button box, and Spaceball callbacks require GLUT and X Input extension code. //code typedef struct _GLUTeventParser GLUTeventParser; struct _GLUTeventParser { int (*func) (XEvent *); GLUTeventParser *next; }; //tex The event parser list itself is a linked list of function pointers taking an {\tt XEvent*} as a parameter. Event parsers are registered with {\tt \_\_glutRegisterEventParser}. //dead /* Declarations to implement glutFullScreen support with mwm/4Dwm. */ /* The following X property format is defined in Motif 1.1's Xm/MwmUtils.h, but GLUT should not depend on that header file. Note: Motif 1.2 expanded this structure with uninteresting fields (to GLUT) so just stick with the smaller Motif 1.1 structure. */ //tex To implement {\tt glutFullScreen}, the window manager needs to be informed that it should not decorate or add borders to the GLUT window covering the screen. For the Motif window manager, this is done by placing a special property on the top-level window to be made full size. The {\tt MotifWmHints} structure below encodes the format of the property. //code typedef struct { #define MWM_HINTS_DECORATIONS 2 long flags; long functions; long decorations; long input_mode; } MotifWmHints; //tex The remainder of {\tt glutint.h} is declarations for variables and functions used internal to GLUT's implementation. These variables and functions will be discussed as they are introduced within GLUT's source code. //dead /* private variables from glut_event.c */ extern GLUTwindow *__glutWindowWorkList; extern int __glutWindowDamaged; #ifdef SUPPORT_FORTRAN extern GLUTtimer *__glutTimerList; extern GLUTtimer *__glutNewTimer; #endif /* private variables from glut_init.c */ extern Atom __glutWMDeleteWindow; extern Display *__glutDisplay; extern unsigned int __glutDisplayMode; extern GLboolean __glutDebug; extern GLboolean __glutForceDirect; extern GLboolean __glutIconic; extern GLboolean __glutTryDirect; extern Window __glutRoot; extern XSizeHints __glutSizeHints; extern char **__glutArgv; extern char *__glutProgramName; extern int __glutArgc; extern int __glutConnectionFD; extern int __glutInitHeight; extern int __glutInitWidth; extern int __glutInitX; extern int __glutInitY; extern int __glutScreen; extern int __glutScreenHeight; extern int __glutScreenWidth; extern Atom __glutMotifHints; extern unsigned int __glutModifierMask; /* private variables from glut_menu.c */ extern GLUTmenu *__glutCurrentMenu; extern GLUTmenuItem *__glutItemSelected; extern GLUTmenu *__glutMappedMenu; extern GLUTwindow *__glutMenuWindow; extern void (*__glutMenuStatusFunc) (int, int, int); /* private variables from glut_win.c */ extern GLUTwindow **__glutWindowList; extern GLUTwindow *__glutCurrentWindow; extern int __glutWindowListSize; extern void (*__glutFreeOverlayFunc) (GLUToverlay *); /* private routines from glut_cindex.c */ extern GLUTcolormap *__glutAssociateColormap(XVisualInfo * vis); extern void __glutFreeColormap(GLUTcolormap *); /* private routines from glut_event.c */ extern void (*__glutUpdateInputDeviceMaskFunc) (GLUTwindow *); extern void __glutPutOnWorkList(GLUTwindow * window, int work_mask); extern void __glutRegisterEventParser(GLUTeventParser * parser); extern void __glutPostRedisplay(GLUTwindow * window, int layerMask); /* private routines from glut_init.c */ extern void __glutOpenXConnection(char *display); extern void __glutInitTime(struct timeval *beginning); /* private routines for glut_menu.c */ extern GLUTmenu *__glutGetMenu(Window win); extern GLUTmenu *__glutGetMenuByNum(int menunum); extern GLUTmenuItem *__glutGetMenuItem(GLUTmenu * menu, Window win, int *which); extern void __glutFinishMenu(Window win, int x, int y); extern void __glutMenuItemEnterOrLeave(GLUTmenuItem * item, int num, int type); extern void __glutPaintMenu(GLUTmenu * menu); extern void __glutSetMenu(GLUTmenu * menu); extern void __glutStartMenu(GLUTmenu * menu, GLUTwindow * window, int x, int y, int x_win, int y_win); /* private routines from glut_util.c */ extern void __glutWarning(char *format,...); extern void __glutFatalError(char *format,...); extern void __glutFatalUsage(char *format,...); /* private routines from glut_win.c */ extern GLUTwindow *__glutGetWindow(Window win); extern GLUTwindow *__glutToplevelOf(GLUTwindow * window); extern void __glutChangeWindowEventMask(long mask, Bool add); extern void __glutEstablishColormapsProperty( GLUTwindow * window); extern XVisualInfo *__glutDetermineVisual( unsigned int mode, Bool * fakeSingle, XVisualInfo * (getVisualInfo) (unsigned int)); extern XVisualInfo *__glutGetVisualInfo(unsigned int mode); extern void __glutSetWindow(GLUTwindow * window); extern void __glutReshapeFunc(GLUTreshapeCB reshapeFunc, int callingConvention); extern void __glutDefaultReshape(int, int); extern void __glutSetupColormap( XVisualInfo * vi, GLUTcolormap ** colormap, Colormap * cmap); /* private routines from glut_ext.c */ extern int __glutIsSupportedByGLX(char *); /* private routines from glut_input.c */ extern void __glutUpdateInputDeviceMask(GLUTwindow * window); #endif /* __glutint_h__ */