2 /* Copyright (c) Mark J. Kilgard, 1994, 1997. */
4 /* This program is freely distributable without licensing fees
5 and is provided without guarantee or warrantee expressed or
6 implied. This program is -not- in the public domain. */
9 #include <GL/vms_x_fix.h>
18 #include <X11/Xatom.h>
23 GLUTwindow
*__glutCurrentWindow
= NULL
;
24 GLUTwindow
**__glutWindowList
= NULL
;
25 int __glutWindowListSize
= 0;
27 GLUTstale
*__glutStaleWindowList
= NULL
;
29 GLUTwindow
*__glutMenuWindow
= NULL
;
31 void (*__glutFreeOverlayFunc
) (GLUToverlay
*);
32 XVisualInfo
*(*__glutDetermineVisualFromString
) (char *string
, Bool
* treatAsSingle
,
33 Criterion
* requiredCriteria
, int nRequired
, int requiredMask
, void** fbc
) = NULL
;
35 static Criterion requiredWindowCriteria
[] =
40 static int numRequiredWindowCriteria
= sizeof(requiredWindowCriteria
) / sizeof(Criterion
);
41 static int requiredWindowCriteriaMask
= (1 << LEVEL
) | (1 << TRANSPARENT
);
44 cleanWindowWorkList(GLUTwindow
* window
)
46 GLUTwindow
**pEntry
= &__glutWindowWorkList
;
47 GLUTwindow
*entry
= __glutWindowWorkList
;
49 /* Tranverse singly-linked window work list look for the
52 if (entry
== window
) {
53 /* Found it; delete it. */
54 *pEntry
= entry
->prevWorkWin
;
57 pEntry
= &entry
->prevWorkWin
;
66 cleanStaleWindowList(GLUTwindow
* window
)
68 GLUTstale
**pEntry
= &__glutStaleWindowList
;
69 GLUTstale
*entry
= __glutStaleWindowList
;
71 /* Tranverse singly-linked stale window list look for the
74 if (entry
->window
== window
) {
75 /* Found it; delete it. */
76 *pEntry
= entry
->next
;
80 pEntry
= &entry
->next
;
88 static GLUTwindow
*__glutWindowCache
= NULL
;
91 __glutGetWindow(Window win
)
95 /* Does win belong to the last window ID looked up? */
96 if (__glutWindowCache
&& (win
== __glutWindowCache
->win
||
97 (__glutWindowCache
->overlay
&& win
==
98 __glutWindowCache
->overlay
->win
))) {
102 /* Otherwise scan the window list looking for the window ID. */
103 for (i
= 0; i
< __glutWindowListSize
; i
++) {
104 if (__glutWindowList
[i
]) {
105 if (win
== __glutWindowList
[i
]->win
) {
106 __glutWindowCache
= __glutWindowList
[i
];
107 return __glutWindowCache
;
109 if (__glutWindowList
[i
]->overlay
) {
110 if (win
== __glutWindowList
[i
]->overlay
->win
) {
111 __glutWindowCache
= __glutWindowList
[i
];
112 return __glutWindowCache
;
121 /* Scan through destroyed overlay window IDs for which no
122 DestroyNotify has yet been received. */
123 for (entry
= __glutStaleWindowList
; entry
; entry
= entry
->next
) {
124 if (entry
->win
== win
)
125 return entry
->window
;
136 if (__glutCurrentWindow
) {
137 return __glutCurrentWindow
->num
+ 1;
145 __glutSetWindow(GLUTwindow
* window
)
147 /* It is tempting to try to short-circuit the call to
148 glXMakeCurrent if we "know" we are going to make current
149 to a window we are already current to. In fact, this
150 assumption breaks when GLUT is expected to integrated with
151 other OpenGL windowing APIs that also make current to
152 OpenGL contexts. Since glXMakeCurrent short-circuits the
153 "already bound" case, GLUT avoids the temptation to do so
155 __glutCurrentWindow
= window
;
157 MAKE_CURRENT_LAYER(__glutCurrentWindow
);
160 /* We should be careful to force a finish between each
161 iteration through the GLUT main loop if indirect OpenGL
162 contexts are in use; indirect contexts tend to have much
163 longer latency because lots of OpenGL extension requests
164 can queue up in the X protocol stream. We accomplish this
165 by posting GLUT_FINISH_WORK to be done. */
166 if (!__glutCurrentWindow
->isDirect
)
167 __glutPutOnWorkList(__glutCurrentWindow
, GLUT_FINISH_WORK
);
170 /* If debugging is enabled, we'll want to check this window
171 for any OpenGL errors every iteration through the GLUT
172 main loop. To accomplish this, we post the
173 GLUT_DEBUG_WORK to be done on this window. */
175 __glutPutOnWorkList(__glutCurrentWindow
, GLUT_DEBUG_WORK
);
181 glutSetWindow(int win
)
185 if (win
< 1 || win
> __glutWindowListSize
) {
186 __glutWarning("glutSetWindow attempted on bogus window.");
189 window
= __glutWindowList
[win
- 1];
191 __glutWarning("glutSetWindow attempted on bogus window.");
194 __glutSetWindow(window
);
199 getUnusedWindowSlot(void)
203 /* Look for allocated, unused slot. */
204 for (i
= 0; i
< __glutWindowListSize
; i
++) {
205 if (!__glutWindowList
[i
]) {
209 /* Allocate a new slot. */
210 __glutWindowListSize
++;
211 if (__glutWindowList
) {
212 __glutWindowList
= (GLUTwindow
**)
213 realloc(__glutWindowList
,
214 __glutWindowListSize
* sizeof(GLUTwindow
*));
216 /* XXX Some realloc's do not correctly perform a malloc
217 when asked to perform a realloc on a NULL pointer,
218 though the ANSI C library spec requires this. */
219 __glutWindowList
= (GLUTwindow
**)
220 malloc(sizeof(GLUTwindow
*));
222 if (!__glutWindowList
)
223 __glutFatalError("out of memory.");
224 __glutWindowList
[__glutWindowListSize
- 1] = NULL
;
225 return __glutWindowListSize
- 1;
229 getVisualInfoCI(unsigned int mode
)
231 static int bufSizeList
[] =
232 {16, 12, 8, 4, 2, 1, 0};
237 /* Should not be looking at display mode mask if
238 __glutDisplayString is non-NULL. */
239 assert(!__glutDisplayString
);
241 list
[n
++] = GLX_BUFFER_SIZE
;
243 if (GLUT_WIND_IS_DOUBLE(mode
)) {
244 list
[n
++] = GLX_DOUBLEBUFFER
;
246 if (GLUT_WIND_IS_STEREO(mode
)) {
247 list
[n
++] = GLX_STEREO
;
249 if (GLUT_WIND_HAS_DEPTH(mode
)) {
250 list
[n
++] = GLX_DEPTH_SIZE
;
253 if (GLUT_WIND_HAS_STENCIL(mode
)) {
254 list
[n
++] = GLX_STENCIL_SIZE
;
257 list
[n
] = (int) None
; /* terminate list */
259 /* glXChooseVisual specify GLX_BUFFER_SIZE prefers the
260 "smallest index buffer of at least the specified size".
261 This would be reasonable if GLUT allowed the user to
262 specify the required buffe size, but GLUT's display mode
263 is too simplistic (easy to use?). GLUT should try to find
264 the "largest". So start with a large buffer size and
265 shrink until we find a matching one that exists. */
267 for (i
= 0; bufSizeList
[i
]; i
++) {
268 /* XXX Assumes list[1] is where GLX_BUFFER_SIZE parameter
270 list
[1] = bufSizeList
[i
];
271 vi
= glXChooseVisual(__glutDisplay
,
280 getVisualInfoRGB(unsigned int mode
)
285 /* Should not be looking at display mode mask if
286 __glutDisplayString is non-NULL. */
287 assert(!__glutDisplayString
);
289 /* XXX Would a caching mechanism to minize the calls to
290 glXChooseVisual? You'd have to reference count
291 XVisualInfo* pointers. Would also have to properly
292 interact with glutInitDisplayString. */
294 list
[n
++] = GLX_RGBA
;
295 list
[n
++] = GLX_RED_SIZE
;
297 list
[n
++] = GLX_GREEN_SIZE
;
299 list
[n
++] = GLX_BLUE_SIZE
;
301 if (GLUT_WIND_HAS_ALPHA(mode
)) {
302 list
[n
++] = GLX_ALPHA_SIZE
;
305 if (GLUT_WIND_IS_DOUBLE(mode
)) {
306 list
[n
++] = GLX_DOUBLEBUFFER
;
308 if (GLUT_WIND_IS_STEREO(mode
)) {
309 list
[n
++] = GLX_STEREO
;
311 if (GLUT_WIND_HAS_DEPTH(mode
)) {
312 list
[n
++] = GLX_DEPTH_SIZE
;
315 if (GLUT_WIND_HAS_STENCIL(mode
)) {
316 list
[n
++] = GLX_STENCIL_SIZE
;
319 if (GLUT_WIND_HAS_ACCUM(mode
)) {
320 list
[n
++] = GLX_ACCUM_RED_SIZE
;
322 list
[n
++] = GLX_ACCUM_GREEN_SIZE
;
324 list
[n
++] = GLX_ACCUM_BLUE_SIZE
;
326 if (GLUT_WIND_HAS_ALPHA(mode
)) {
327 list
[n
++] = GLX_ACCUM_ALPHA_SIZE
;
331 #if defined(GLX_VERSION_1_1) && (defined(GLX_SGIS_multisample) || defined(GLX_ARB_multisample))
332 if (GLUT_WIND_IS_MULTISAMPLE(mode
)) {
333 if (!__glutIsSupportedByGLX("GLX_SGIS_multisample") &&
334 !__glutIsSupportedByGLX("GLX_ARB_multisample"))
336 #if defined(GLX_ARB_multisample)
337 list
[n
++] = GLX_SAMPLES_ARB
;
338 #elif defined(GLX_SGIS_multisample)
339 list
[n
++] = GLX_SAMPLES_SGIS
;
341 /* XXX Is 4 a reasonable minimum acceptable number of
346 list
[n
] = (int) None
; /* terminate list */
348 return glXChooseVisual(__glutDisplay
,
353 __glutGetVisualInfo(unsigned int mode
)
355 /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
356 if (GLUT_WIND_IS_LUMINANCE(mode
))
359 if (GLUT_WIND_IS_RGB(mode
))
360 return getVisualInfoRGB(mode
);
362 return getVisualInfoCI(mode
);
366 __glutDetermineVisual(
367 unsigned int displayMode
,
368 Bool
* treatAsSingle
,
369 XVisualInfo
* (getVisualInfo
) (unsigned int))
373 /* Should not be looking at display mode mask if
374 __glutDisplayString is non-NULL. */
375 assert(!__glutDisplayString
);
377 *treatAsSingle
= GLUT_WIND_IS_SINGLE(displayMode
);
378 vis
= getVisualInfo(displayMode
);
380 /* Fallback cases when can't get exactly what was asked
382 if (GLUT_WIND_IS_SINGLE(displayMode
)) {
383 /* If we can't find a single buffered visual, try looking
384 for a double buffered visual. We can treat a double
385 buffered visual as a single buffer visual by changing
386 the draw buffer to GL_FRONT and treating any swap
387 buffers as no-ops. */
388 displayMode
|= GLUT_DOUBLE
;
389 vis
= getVisualInfo(displayMode
);
390 *treatAsSingle
= True
;
392 if (!vis
&& GLUT_WIND_IS_MULTISAMPLE(displayMode
)) {
393 /* If we can't seem to get multisampling (ie, not Reality
394 Engine class graphics!), go without multisampling. It
395 is up to the application to query how many multisamples
396 were allocated (0 equals no multisampling) if the
397 application is going to use multisampling for more than
398 just antialiasing. */
399 displayMode
&= ~GLUT_MULTISAMPLE
;
400 vis
= getVisualInfo(displayMode
);
406 static void GLUTCALLBACK
407 __glutDefaultDisplay(void)
409 /* XXX Remove the warning after GLUT 3.0. */
410 __glutWarning("The following is a new check for GLUT 3.0; update your code.");
412 "redisplay needed for window %d, but no display callback.",
413 __glutCurrentWindow
->num
+ 1);
417 __glutDefaultReshape(int width
, int height
)
419 GLUToverlay
*overlay
;
421 /* Adjust the viewport of the window (and overlay if one
423 MAKE_CURRENT_WINDOW(__glutCurrentWindow
);
424 glViewport(0, 0, (GLsizei
) width
, (GLsizei
) height
);
425 overlay
= __glutCurrentWindow
->overlay
;
427 MAKE_CURRENT_OVERLAY(overlay
);
428 glViewport(0, 0, (GLsizei
) width
, (GLsizei
) height
);
430 /* Make sure we are current to the current layer (application
431 should be able to count on the current layer not changing
432 unless the application explicitly calls glutUseLayer). */
433 MAKE_CURRENT_LAYER(__glutCurrentWindow
);
437 __glutDetermineWindowVisual(Bool
* treatAsSingle
, Bool
* visAlloced
, void **fbc
)
439 if (__glutDisplayString
) {
441 /* __glutDisplayString should be NULL except if
442 glutInitDisplayString has been called to register a
443 different display string. Calling glutInitDisplayString
444 means using a string instead of an integer mask determine
445 the visual to use. Using the function pointer variable
446 __glutDetermineVisualFromString below avoids linking in
447 the code for implementing glutInitDisplayString (ie,
448 glut_dstr.o) unless glutInitDisplayString gets called by
451 assert(__glutDetermineVisualFromString
);
454 return __glutDetermineVisualFromString(__glutDisplayString
, treatAsSingle
,
455 requiredWindowCriteria
, numRequiredWindowCriteria
, requiredWindowCriteriaMask
, fbc
);
459 return __glutDetermineVisual(__glutDisplayMode
,
460 treatAsSingle
, __glutGetVisualInfo
);
464 /* ARGSUSED5 */ /* Only Win32 uses gameMode parameter. */
466 __glutCreateWindow(GLUTwindow
* parent
,
467 int x
, int y
, int width
, int height
, int gameMode
)
470 XSetWindowAttributes wa
;
471 unsigned long attribMask
;
474 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
484 if (!GetClassInfo(GetModuleHandle(NULL
), "GLUT", &wc
)) {
485 __glutOpenWin32Connection(NULL
);
488 if (!__glutDisplay
) {
489 __glutOpenXConnection(NULL
);
492 if (__glutGameModeWindow
) {
493 __glutFatalError("cannot create windows in game mode.");
495 winnum
= getUnusedWindowSlot();
496 window
= (GLUTwindow
*) malloc(sizeof(GLUTwindow
));
498 __glutFatalError("out of memory.");
500 window
->num
= winnum
;
503 window
->vis
= __glutDetermineWindowVisual(&window
->treatAsSingle
,
504 &window
->visAlloced
, (void**) &fbc
);
507 "visual with necessary capabilities not found.");
509 __glutSetupColormap(window
->vis
, &window
->colormap
, &window
->cmap
);
511 window
->eventMask
= StructureNotifyMask
| ExposureMask
;
513 attribMask
= CWBackPixmap
| CWBorderPixel
| CWColormap
| CWEventMask
;
514 wa
.background_pixmap
= None
;
516 wa
.colormap
= window
->cmap
;
517 wa
.event_mask
= window
->eventMask
;
519 if (parent
->eventMask
& GLUT_HACK_STOP_PROPAGATE_MASK
)
520 wa
.event_mask
|= GLUT_HACK_STOP_PROPAGATE_MASK
;
521 attribMask
|= CWDontPropagate
;
522 wa
.do_not_propagate_mask
= parent
->eventMask
& GLUT_DONT_PROPAGATE_FILTER_MASK
;
524 wa
.do_not_propagate_mask
= 0;
527 /* Stash width and height before Win32's __glutAdjustCoords
528 possibly overwrites the values. */
529 window
->width
= width
;
530 window
->height
= height
;
531 window
->forceReshape
= True
;
532 window
->ignoreKeyRepeat
= False
;
535 __glutAdjustCoords(parent
? parent
->win
: NULL
,
536 &x
, &y
, &width
, &height
);
541 /* Game mode window should be a WS_POPUP window to
542 ensure that the taskbar is hidden by it. A standard
543 WS_OVERLAPPEDWINDOW does not hide the task bar. */
544 style
= WS_POPUP
| WS_MAXIMIZE
;
546 /* A standard toplevel window with borders and such. */
547 style
= WS_OVERLAPPEDWINDOW
;
550 window
->win
= CreateWindow("GLUT", "GLUT",
551 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| style
,
552 x
, y
, width
, height
, parent
? parent
->win
: __glutRoot
,
553 NULL
, GetModuleHandle(NULL
), 0);
554 window
->hdc
= GetDC(window
->win
);
555 /* Must set the XHDC for fake glXChooseVisual & fake
556 glXCreateContext & fake XAllocColorCells. */
558 window
->vis
= __glutDetermineWindowVisual(&window
->treatAsSingle
,
559 &window
->visAlloced
, &fbc
);
562 "pixel format with necessary capabilities not found.");
564 if (!SetPixelFormat(window
->hdc
,
565 ChoosePixelFormat(window
->hdc
, window
->vis
),
567 __glutFatalError("SetPixelFormat failed during window create.");
569 __glutSetupColormap(window
->vis
, &window
->colormap
, &window
->cmap
);
570 /* Make sure subwindows get a windowStatus callback. */
572 PostMessage(parent
->win
, WM_ACTIVATE
, 0, 0);
574 window
->renderDc
= window
->hdc
;
576 window
->win
= XCreateWindow(__glutDisplay
,
577 parent
== NULL
? __glutRoot
: parent
->win
,
578 x
, y
, width
, height
, 0,
579 window
->vis
->depth
, InputOutput
, window
->vis
->visual
,
582 window
->renderWin
= window
->win
;
583 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
585 window
->ctx
= __glut_glXCreateContextWithConfigSGIX(__glutDisplay
, fbc
,
586 GLX_RGBA_TYPE_SGIX
, None
, __glutTryDirect
);
590 window
->ctx
= glXCreateContext(__glutDisplay
, window
->vis
,
591 None
, __glutTryDirect
);
595 "failed to create OpenGL rendering context.");
597 window
->renderCtx
= window
->ctx
;
599 window
->isDirect
= glXIsDirect(__glutDisplay
, window
->ctx
);
600 if (__glutForceDirect
) {
601 if (!window
->isDirect
)
602 __glutFatalError("direct rendering not possible.");
606 window
->parent
= parent
;
608 window
->siblings
= parent
->children
;
609 parent
->children
= window
;
611 window
->siblings
= NULL
;
613 window
->overlay
= NULL
;
614 window
->children
= NULL
;
615 window
->display
= __glutDefaultDisplay
;
616 window
->reshape
= __glutDefaultReshape
;
617 window
->mouse
= NULL
;
618 window
->motion
= NULL
;
619 window
->passive
= NULL
;
620 window
->entry
= NULL
;
621 window
->keyboard
= NULL
;
622 window
->keyboardUp
= NULL
;
623 window
->windowStatus
= NULL
;
624 window
->visibility
= NULL
;
625 window
->special
= NULL
;
626 window
->specialUp
= NULL
;
627 window
->buttonBox
= NULL
;
628 window
->dials
= NULL
;
629 window
->spaceMotion
= NULL
;
630 window
->spaceRotate
= NULL
;
631 window
->spaceButton
= NULL
;
632 window
->tabletMotion
= NULL
;
633 window
->tabletButton
= NULL
;
635 window
->joystick
= NULL
;
636 window
->joyPollInterval
= 0;
638 window
->tabletPos
[0] = -1;
639 window
->tabletPos
[1] = -1;
640 window
->shownState
= 0;
641 window
->visState
= -1; /* not VisibilityUnobscured,
642 VisibilityPartiallyObscured, or
643 VisibilityFullyObscured */
644 window
->entryState
= -1; /* not EnterNotify or LeaveNotify */
646 window
->desiredConfMask
= 0;
647 window
->buttonUses
= 0;
648 window
->cursor
= GLUT_CURSOR_INHERIT
;
650 /* Setup window to be mapped when glutMainLoop starts. */
651 window
->workMask
= GLUT_MAP_WORK
;
654 /* When mapping a game mode window, just show
655 the window. We have already created the game
656 mode window with a maximize flag at creation
657 time. Doing a ShowWindow(window->win, SW_SHOWNORMAL)
658 would be wrong for a game mode window since it
659 would unmaximize the window. */
660 window
->desiredMapState
= GameModeState
;
662 window
->desiredMapState
= NormalState
;
665 window
->desiredMapState
= NormalState
;
667 window
->prevWorkWin
= __glutWindowWorkList
;
668 __glutWindowWorkList
= window
;
670 /* Initially, no menus attached. */
671 for (i
= 0; i
< GLUT_MAX_MENUS
; i
++) {
675 /* Add this new window to the window list. */
676 __glutWindowList
[winnum
] = window
;
678 /* Make the new window the current window. */
679 __glutSetWindow(window
);
681 __glutDetermineMesaSwapHackSupport();
683 if (window
->treatAsSingle
) {
684 /* We do this because either the window really is single
685 buffered (in which case this is redundant, but harmless,
686 because this is the initial single-buffered context
687 state); or we are treating a double buffered window as a
688 single-buffered window because the system does not appear
689 to export any suitable single- buffered visuals (in which
690 the following are necessary). */
691 glDrawBuffer(GL_FRONT
);
692 glReadBuffer(GL_FRONT
);
699 glutCreateWindow(const char *title
)
701 static int firstWindow
= 1;
707 XTextProperty textprop
;
709 if (__glutGameModeWindow
) {
710 __glutFatalError("cannot create windows in game mode.");
712 window
= __glutCreateWindow(NULL
,
713 __glutSizeHints
.x
, __glutSizeHints
.y
,
714 __glutInitWidth
, __glutInitHeight
,
715 /* not game mode */ 0);
717 /* Setup ICCCM properties. */
718 textprop
.value
= (unsigned char *) title
;
719 textprop
.encoding
= XA_STRING
;
721 textprop
.nitems
= strlen(title
);
723 SetWindowText(win
, title
);
725 window
->desiredMapState
= IconicState
;
728 wmHints
= XAllocWMHints();
729 wmHints
->initial_state
=
730 __glutIconic
? IconicState
: NormalState
;
731 wmHints
->flags
= StateHint
;
732 XSetWMProperties(__glutDisplay
, win
, &textprop
, &textprop
,
733 /* Only put WM_COMMAND property on first window. */
734 firstWindow
? __glutArgv
: NULL
,
735 firstWindow
? __glutArgc
: 0,
736 &__glutSizeHints
, wmHints
, NULL
);
738 XSetWMProtocols(__glutDisplay
, win
, &__glutWMDeleteWindow
, 1);
741 return window
->num
+ 1;
746 __glutCreateWindowWithExit(const char *title
, void (__cdecl
*exitfunc
)(int))
748 __glutExitFunc
= exitfunc
;
749 return glutCreateWindow(title
);
754 glutCreateSubWindow(int win
, int x
, int y
, int width
, int height
)
758 window
= __glutCreateWindow(__glutWindowList
[win
- 1],
759 x
, y
, width
, height
, /* not game mode */ 0);
762 GLUTwindow
*toplevel
;
764 toplevel
= __glutToplevelOf(window
);
765 if (toplevel
->cmap
!= window
->cmap
) {
766 __glutPutOnWorkList(toplevel
, GLUT_COLORMAP_WORK
);
770 return window
->num
+ 1;
775 __glutDestroyWindow(GLUTwindow
* window
,
776 GLUTwindow
* initialWindow
)
778 GLUTwindow
**prev
, *cur
, *parent
, *siblings
;
780 /* Recursively destroy any children. */
781 cur
= window
->children
;
783 siblings
= cur
->siblings
;
784 __glutDestroyWindow(cur
, initialWindow
);
787 /* Remove from parent's children list (only necessary for
788 non-initial windows and subwindows!). */
789 parent
= window
->parent
;
790 if (parent
&& parent
== initialWindow
->parent
) {
791 prev
= &parent
->children
;
792 cur
= parent
->children
;
795 *prev
= cur
->siblings
;
798 prev
= &(cur
->siblings
);
802 /* Unbind if bound to this window. */
803 if (window
== __glutCurrentWindow
) {
805 __glutCurrentWindow
= NULL
;
807 /* Begin tearing down window itself. */
808 if (window
->overlay
) {
809 __glutFreeOverlayFunc(window
->overlay
);
811 XDestroyWindow(__glutDisplay
, window
->win
);
812 glXDestroyContext(__glutDisplay
, window
->ctx
);
813 if (window
->colormap
) {
814 /* Only color index windows have colormap data structure. */
815 __glutFreeColormap(window
->colormap
);
817 /* NULLing the __glutWindowList helps detect is a window
818 instance has been destroyed, given a window number. */
819 __glutWindowList
[window
->num
] = NULL
;
821 /* Cleanup data structures that might contain window. */
822 cleanWindowWorkList(window
);
824 cleanStaleWindowList(window
);
826 /* Remove window from the "get window cache" if it is there. */
827 if (__glutWindowCache
== window
)
828 __glutWindowCache
= NULL
;
830 if (window
->visAlloced
) {
831 /* Only free XVisualInfo* gotten from glXChooseVisual. */
835 if (window
== __glutGameModeWindow
) {
836 /* Destroying the game mode window should implicitly
837 have GLUT leave game mode. */
838 __glutCloseDownGameMode();
846 glutDestroyWindow(int win
)
848 GLUTwindow
*window
= __glutWindowList
[win
- 1];
850 if (__glutMappedMenu
&& __glutMenuWindow
== window
) {
851 __glutFatalUsage("destroying menu window not allowed while menus in use");
854 /* If not a toplevel window... */
855 if (window
->parent
) {
856 /* Destroying subwindows may change colormap requirements;
857 recalculate toplevel window's WM_COLORMAP_WINDOWS
859 __glutPutOnWorkList(__glutToplevelOf(window
->parent
),
863 __glutDestroyWindow(window
, window
);
864 XFlush(__glutDisplay
);
869 __glutChangeWindowEventMask(long eventMask
, Bool add
)
872 /* Add eventMask to window's event mask. */
873 if ((__glutCurrentWindow
->eventMask
& eventMask
) !=
875 __glutCurrentWindow
->eventMask
|= eventMask
;
876 __glutPutOnWorkList(__glutCurrentWindow
,
877 GLUT_EVENT_MASK_WORK
);
880 /* Remove eventMask from window's event mask. */
881 if (__glutCurrentWindow
->eventMask
& eventMask
) {
882 __glutCurrentWindow
->eventMask
&= ~eventMask
;
883 __glutPutOnWorkList(__glutCurrentWindow
,
884 GLUT_EVENT_MASK_WORK
);
890 glutDisplayFunc(GLUTdisplayCB displayFunc
)
892 /* XXX Remove the warning after GLUT 3.0. */
894 __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
895 __glutCurrentWindow
->display
= displayFunc
;
899 glutMouseFunc(GLUTmouseCB mouseFunc
)
901 if (__glutCurrentWindow
->mouse
) {
903 /* Previous mouseFunc being disabled. */
904 __glutCurrentWindow
->buttonUses
--;
905 __glutChangeWindowEventMask(
906 ButtonPressMask
| ButtonReleaseMask
,
907 __glutCurrentWindow
->buttonUses
> 0);
911 /* Previously no mouseFunc, new one being installed. */
912 __glutCurrentWindow
->buttonUses
++;
913 __glutChangeWindowEventMask(
914 ButtonPressMask
| ButtonReleaseMask
, True
);
917 __glutCurrentWindow
->mouse
= mouseFunc
;
921 glutMotionFunc(GLUTmotionCB motionFunc
)
923 /* Hack. Some window managers (4Dwm by default) will mask
924 motion events if the client is not selecting for button
925 press and release events. So we select for press and
926 release events too (being careful to use reference
928 if (__glutCurrentWindow
->motion
) {
930 /* previous mouseFunc being disabled */
931 __glutCurrentWindow
->buttonUses
--;
932 __glutChangeWindowEventMask(
933 ButtonPressMask
| ButtonReleaseMask
,
934 __glutCurrentWindow
->buttonUses
> 0);
938 /* Previously no mouseFunc, new one being installed. */
939 __glutCurrentWindow
->buttonUses
++;
940 __glutChangeWindowEventMask(
941 ButtonPressMask
| ButtonReleaseMask
, True
);
944 /* Real work of selecting for passive mouse motion. */
945 __glutChangeWindowEventMask(
946 Button1MotionMask
| Button2MotionMask
| Button3MotionMask
,
948 __glutCurrentWindow
->motion
= motionFunc
;
952 glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc
)
954 __glutChangeWindowEventMask(PointerMotionMask
,
955 passiveMotionFunc
!= NULL
);
957 /* Passive motion also requires watching enters and leaves so
958 that a fake passive motion event can be generated on an
960 __glutChangeWindowEventMask(EnterWindowMask
| LeaveWindowMask
,
961 __glutCurrentWindow
->entry
!= NULL
|| passiveMotionFunc
!= NULL
);
963 __glutCurrentWindow
->passive
= passiveMotionFunc
;
967 glutEntryFunc(GLUTentryCB entryFunc
)
969 __glutChangeWindowEventMask(EnterWindowMask
| LeaveWindowMask
,
970 entryFunc
!= NULL
|| __glutCurrentWindow
->passive
);
971 __glutCurrentWindow
->entry
= entryFunc
;
973 __glutCurrentWindow
->entryState
= -1;
978 glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc
)
980 __glutChangeWindowEventMask(VisibilityChangeMask
,
981 windowStatusFunc
!= NULL
);
982 __glutCurrentWindow
->windowStatus
= windowStatusFunc
;
983 if (!windowStatusFunc
) {
984 /* Make state invalid. */
985 __glutCurrentWindow
->visState
= -1;
989 static void GLUTCALLBACK
990 visibilityHelper(int status
)
992 if (status
== GLUT_HIDDEN
|| status
== GLUT_FULLY_COVERED
)
993 __glutCurrentWindow
->visibility(GLUT_NOT_VISIBLE
);
995 __glutCurrentWindow
->visibility(GLUT_VISIBLE
);
999 glutVisibilityFunc(GLUTvisibilityCB visibilityFunc
)
1001 __glutCurrentWindow
->visibility
= visibilityFunc
;
1003 glutWindowStatusFunc(visibilityHelper
);
1005 glutWindowStatusFunc(NULL
);
1009 glutReshapeFunc(GLUTreshapeCB reshapeFunc
)
1012 __glutCurrentWindow
->reshape
= reshapeFunc
;
1014 __glutCurrentWindow
->reshape
= __glutDefaultReshape
;