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 #define VisualIDMask 0
357 getVisualInfoID(int id
)
364 return XGetVisualInfo(__glutDisplay
, VisualIDMask
, &temp
, &count
);
369 __glutGetVisualInfo(unsigned int mode
)
372 /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
373 if (GLUT_WIND_IS_LUMINANCE(mode
))
376 visStr
= getenv("GLUT_FORCE_VISUAL");
378 int id
= atoi(visStr
);
379 return getVisualInfoID(id
);
382 if (GLUT_WIND_IS_RGB(mode
))
383 return getVisualInfoRGB(mode
);
385 return getVisualInfoCI(mode
);
389 __glutDetermineVisual(
390 unsigned int displayMode
,
391 Bool
* treatAsSingle
,
392 XVisualInfo
* (getVisualInfo
) (unsigned int))
396 /* Should not be looking at display mode mask if
397 __glutDisplayString is non-NULL. */
398 assert(!__glutDisplayString
);
400 *treatAsSingle
= GLUT_WIND_IS_SINGLE(displayMode
);
401 vis
= getVisualInfo(displayMode
);
403 /* Fallback cases when can't get exactly what was asked
405 if (GLUT_WIND_IS_SINGLE(displayMode
)) {
406 /* If we can't find a single buffered visual, try looking
407 for a double buffered visual. We can treat a double
408 buffered visual as a single buffer visual by changing
409 the draw buffer to GL_FRONT and treating any swap
410 buffers as no-ops. */
411 displayMode
|= GLUT_DOUBLE
;
412 vis
= getVisualInfo(displayMode
);
413 *treatAsSingle
= True
;
415 if (!vis
&& GLUT_WIND_IS_MULTISAMPLE(displayMode
)) {
416 /* If we can't seem to get multisampling (ie, not Reality
417 Engine class graphics!), go without multisampling. It
418 is up to the application to query how many multisamples
419 were allocated (0 equals no multisampling) if the
420 application is going to use multisampling for more than
421 just antialiasing. */
422 displayMode
&= ~GLUT_MULTISAMPLE
;
423 vis
= getVisualInfo(displayMode
);
429 static void GLUTCALLBACK
430 __glutDefaultDisplay(void)
432 /* XXX Remove the warning after GLUT 3.0. */
433 __glutWarning("The following is a new check for GLUT 3.0; update your code.");
435 "redisplay needed for window %d, but no display callback.",
436 __glutCurrentWindow
->num
+ 1);
440 __glutDefaultReshape(int width
, int height
)
442 GLUToverlay
*overlay
;
444 /* Adjust the viewport of the window (and overlay if one
446 MAKE_CURRENT_WINDOW(__glutCurrentWindow
);
447 glViewport(0, 0, (GLsizei
) width
, (GLsizei
) height
);
448 overlay
= __glutCurrentWindow
->overlay
;
450 MAKE_CURRENT_OVERLAY(overlay
);
451 glViewport(0, 0, (GLsizei
) width
, (GLsizei
) height
);
453 /* Make sure we are current to the current layer (application
454 should be able to count on the current layer not changing
455 unless the application explicitly calls glutUseLayer). */
456 MAKE_CURRENT_LAYER(__glutCurrentWindow
);
460 __glutDetermineWindowVisual(Bool
* treatAsSingle
, Bool
* visAlloced
, void **fbc
)
462 if (__glutDisplayString
) {
464 /* __glutDisplayString should be NULL except if
465 glutInitDisplayString has been called to register a
466 different display string. Calling glutInitDisplayString
467 means using a string instead of an integer mask determine
468 the visual to use. Using the function pointer variable
469 __glutDetermineVisualFromString below avoids linking in
470 the code for implementing glutInitDisplayString (ie,
471 glut_dstr.o) unless glutInitDisplayString gets called by
474 assert(__glutDetermineVisualFromString
);
477 return __glutDetermineVisualFromString(__glutDisplayString
, treatAsSingle
,
478 requiredWindowCriteria
, numRequiredWindowCriteria
, requiredWindowCriteriaMask
, fbc
);
482 return __glutDetermineVisual(__glutDisplayMode
,
483 treatAsSingle
, __glutGetVisualInfo
);
487 /* ARGSUSED5 */ /* Only Win32 uses gameMode parameter. */
489 __glutCreateWindow(GLUTwindow
* parent
,
490 int x
, int y
, int width
, int height
, int gameMode
)
493 XSetWindowAttributes wa
;
494 unsigned long attribMask
;
503 if (!GetClassInfo(GetModuleHandle(NULL
), "GLUT", &wc
)) {
504 __glutOpenWin32Connection(NULL
);
507 if (!__glutDisplay
) {
508 __glutOpenXConnection(NULL
);
511 if (__glutGameModeWindow
) {
512 __glutFatalError("cannot create windows in game mode.");
514 winnum
= getUnusedWindowSlot();
515 window
= (GLUTwindow
*) malloc(sizeof(GLUTwindow
));
517 __glutFatalError("out of memory.");
519 window
->num
= winnum
;
522 window
->vis
= __glutDetermineWindowVisual(&window
->treatAsSingle
,
523 &window
->visAlloced
, &fbc
);
526 "visual with necessary capabilities not found.");
528 __glutSetupColormap(window
->vis
, &window
->colormap
, &window
->cmap
);
530 window
->eventMask
= StructureNotifyMask
| ExposureMask
;
532 attribMask
= CWBackPixmap
| CWBorderPixel
| CWColormap
| CWEventMask
;
533 wa
.background_pixmap
= None
;
535 wa
.colormap
= window
->cmap
;
536 wa
.event_mask
= window
->eventMask
;
538 if (parent
->eventMask
& GLUT_HACK_STOP_PROPAGATE_MASK
)
539 wa
.event_mask
|= GLUT_HACK_STOP_PROPAGATE_MASK
;
540 attribMask
|= CWDontPropagate
;
541 wa
.do_not_propagate_mask
= parent
->eventMask
& GLUT_DONT_PROPAGATE_FILTER_MASK
;
543 wa
.do_not_propagate_mask
= 0;
546 /* Stash width and height before Win32's __glutAdjustCoords
547 possibly overwrites the values. */
548 window
->width
= width
;
549 window
->height
= height
;
550 window
->forceReshape
= True
;
551 window
->ignoreKeyRepeat
= False
;
554 __glutAdjustCoords(parent
? parent
->win
: NULL
,
555 &x
, &y
, &width
, &height
);
560 /* Game mode window should be a WS_POPUP window to
561 ensure that the taskbar is hidden by it. A standard
562 WS_OVERLAPPEDWINDOW does not hide the task bar. */
563 style
= WS_POPUP
| WS_MAXIMIZE
;
565 /* A standard toplevel window with borders and such. */
566 style
= WS_OVERLAPPEDWINDOW
;
569 window
->win
= CreateWindow("GLUT", "GLUT",
570 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| style
,
571 x
, y
, width
, height
, parent
? parent
->win
: __glutRoot
,
572 NULL
, GetModuleHandle(NULL
), 0);
573 window
->hdc
= GetDC(window
->win
);
574 /* Must set the XHDC for fake glXChooseVisual & fake
575 glXCreateContext & fake XAllocColorCells. */
577 window
->vis
= __glutDetermineWindowVisual(&window
->treatAsSingle
,
578 &window
->visAlloced
, &fbc
);
581 "pixel format with necessary capabilities not found.");
583 if (!SetPixelFormat(window
->hdc
,
584 ChoosePixelFormat(window
->hdc
, window
->vis
),
586 __glutFatalError("SetPixelFormat failed during window create.");
588 __glutSetupColormap(window
->vis
, &window
->colormap
, &window
->cmap
);
589 /* Make sure subwindows get a windowStatus callback. */
591 PostMessage(parent
->win
, WM_ACTIVATE
, 0, 0);
593 window
->renderDc
= window
->hdc
;
595 window
->win
= XCreateWindow(__glutDisplay
,
596 parent
== NULL
? __glutRoot
: parent
->win
,
597 x
, y
, width
, height
, 0,
598 window
->vis
->depth
, InputOutput
, window
->vis
->visual
,
601 window
->renderWin
= window
->win
;
602 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
604 window
->ctx
= __glut_glXCreateContextWithConfigSGIX(__glutDisplay
, fbc
,
605 GLX_RGBA_TYPE_SGIX
, None
, __glutTryDirect
);
609 window
->ctx
= glXCreateContext(__glutDisplay
, window
->vis
,
610 None
, __glutTryDirect
);
614 "failed to create OpenGL rendering context.");
616 window
->renderCtx
= window
->ctx
;
618 window
->isDirect
= glXIsDirect(__glutDisplay
, window
->ctx
);
619 if (__glutForceDirect
) {
620 if (!window
->isDirect
)
621 __glutFatalError("direct rendering not possible.");
625 window
->parent
= parent
;
627 window
->siblings
= parent
->children
;
628 parent
->children
= window
;
630 window
->siblings
= NULL
;
632 window
->overlay
= NULL
;
633 window
->children
= NULL
;
634 window
->display
= __glutDefaultDisplay
;
635 window
->reshape
= __glutDefaultReshape
;
636 window
->mouse
= NULL
;
637 window
->motion
= NULL
;
638 window
->passive
= NULL
;
639 window
->entry
= NULL
;
640 window
->keyboard
= NULL
;
641 window
->keyboardUp
= NULL
;
642 window
->windowStatus
= NULL
;
643 window
->visibility
= NULL
;
644 window
->special
= NULL
;
645 window
->specialUp
= NULL
;
646 window
->buttonBox
= NULL
;
647 window
->dials
= NULL
;
648 window
->spaceMotion
= NULL
;
649 window
->spaceRotate
= NULL
;
650 window
->spaceButton
= NULL
;
651 window
->tabletMotion
= NULL
;
652 window
->tabletButton
= NULL
;
654 window
->joystick
= NULL
;
655 window
->joyPollInterval
= 0;
657 window
->tabletPos
[0] = -1;
658 window
->tabletPos
[1] = -1;
659 window
->shownState
= 0;
660 window
->visState
= -1; /* not VisibilityUnobscured,
661 VisibilityPartiallyObscured, or
662 VisibilityFullyObscured */
663 window
->entryState
= -1; /* not EnterNotify or LeaveNotify */
665 window
->desiredConfMask
= 0;
666 window
->buttonUses
= 0;
667 window
->cursor
= GLUT_CURSOR_INHERIT
;
669 /* Setup window to be mapped when glutMainLoop starts. */
670 window
->workMask
= GLUT_MAP_WORK
;
673 /* When mapping a game mode window, just show
674 the window. We have already created the game
675 mode window with a maximize flag at creation
676 time. Doing a ShowWindow(window->win, SW_SHOWNORMAL)
677 would be wrong for a game mode window since it
678 would unmaximize the window. */
679 window
->desiredMapState
= GameModeState
;
681 window
->desiredMapState
= NormalState
;
684 window
->desiredMapState
= NormalState
;
686 window
->prevWorkWin
= __glutWindowWorkList
;
687 __glutWindowWorkList
= window
;
689 /* Initially, no menus attached. */
690 for (i
= 0; i
< GLUT_MAX_MENUS
; i
++) {
694 /* Add this new window to the window list. */
695 __glutWindowList
[winnum
] = window
;
697 /* Make the new window the current window. */
698 __glutSetWindow(window
);
700 __glutDetermineMesaSwapHackSupport();
702 if (window
->treatAsSingle
) {
703 /* We do this because either the window really is single
704 buffered (in which case this is redundant, but harmless,
705 because this is the initial single-buffered context
706 state); or we are treating a double buffered window as a
707 single-buffered window because the system does not appear
708 to export any suitable single- buffered visuals (in which
709 the following are necessary). */
710 glDrawBuffer(GL_FRONT
);
711 glReadBuffer(GL_FRONT
);
718 glutCreateWindow(const char *title
)
720 static int firstWindow
= 1;
726 XTextProperty textprop
;
728 if (__glutGameModeWindow
) {
729 __glutFatalError("cannot create windows in game mode.");
731 window
= __glutCreateWindow(NULL
,
732 __glutSizeHints
.x
, __glutSizeHints
.y
,
733 __glutInitWidth
, __glutInitHeight
,
734 /* not game mode */ 0);
736 /* Setup ICCCM properties. */
737 textprop
.value
= (unsigned char *) title
;
738 textprop
.encoding
= XA_STRING
;
740 textprop
.nitems
= strlen(title
);
742 SetWindowText(win
, title
);
744 window
->desiredMapState
= IconicState
;
747 wmHints
= XAllocWMHints();
748 wmHints
->initial_state
=
749 __glutIconic
? IconicState
: NormalState
;
750 wmHints
->flags
= StateHint
;
751 XSetWMProperties(__glutDisplay
, win
, &textprop
, &textprop
,
752 /* Only put WM_COMMAND property on first window. */
753 firstWindow
? __glutArgv
: NULL
,
754 firstWindow
? __glutArgc
: 0,
755 &__glutSizeHints
, wmHints
, NULL
);
757 XSetWMProtocols(__glutDisplay
, win
, &__glutWMDeleteWindow
, 1);
760 return window
->num
+ 1;
765 __glutCreateWindowWithExit(const char *title
, void (__cdecl
*exitfunc
)(int))
767 __glutExitFunc
= exitfunc
;
768 return glutCreateWindow(title
);
773 glutCreateSubWindow(int win
, int x
, int y
, int width
, int height
)
777 window
= __glutCreateWindow(__glutWindowList
[win
- 1],
778 x
, y
, width
, height
, /* not game mode */ 0);
781 GLUTwindow
*toplevel
;
783 toplevel
= __glutToplevelOf(window
);
784 if (toplevel
->cmap
!= window
->cmap
) {
785 __glutPutOnWorkList(toplevel
, GLUT_COLORMAP_WORK
);
789 return window
->num
+ 1;
794 __glutDestroyWindow(GLUTwindow
* window
,
795 GLUTwindow
* initialWindow
)
797 GLUTwindow
**prev
, *cur
, *parent
, *siblings
;
799 /* Recursively destroy any children. */
800 cur
= window
->children
;
802 siblings
= cur
->siblings
;
803 __glutDestroyWindow(cur
, initialWindow
);
806 /* Remove from parent's children list (only necessary for
807 non-initial windows and subwindows!). */
808 parent
= window
->parent
;
809 if (parent
&& parent
== initialWindow
->parent
) {
810 prev
= &parent
->children
;
811 cur
= parent
->children
;
814 *prev
= cur
->siblings
;
817 prev
= &(cur
->siblings
);
821 /* Unbind if bound to this window. */
822 if (window
== __glutCurrentWindow
) {
824 __glutCurrentWindow
= NULL
;
826 /* Begin tearing down window itself. */
827 if (window
->overlay
) {
828 __glutFreeOverlayFunc(window
->overlay
);
830 XDestroyWindow(__glutDisplay
, window
->win
);
831 glXDestroyContext(__glutDisplay
, window
->ctx
);
832 if (window
->colormap
) {
833 /* Only color index windows have colormap data structure. */
834 __glutFreeColormap(window
->colormap
);
836 /* NULLing the __glutWindowList helps detect is a window
837 instance has been destroyed, given a window number. */
838 __glutWindowList
[window
->num
] = NULL
;
840 /* Cleanup data structures that might contain window. */
841 cleanWindowWorkList(window
);
843 cleanStaleWindowList(window
);
845 /* Remove window from the "get window cache" if it is there. */
846 if (__glutWindowCache
== window
)
847 __glutWindowCache
= NULL
;
849 if (window
->visAlloced
) {
850 /* Only free XVisualInfo* gotten from glXChooseVisual. */
854 if (window
== __glutGameModeWindow
) {
855 /* Destroying the game mode window should implicitly
856 have GLUT leave game mode. */
857 __glutCloseDownGameMode();
865 glutDestroyWindow(int win
)
867 GLUTwindow
*window
= __glutWindowList
[win
- 1];
869 if (__glutMappedMenu
&& __glutMenuWindow
== window
) {
870 __glutFatalUsage("destroying menu window not allowed while menus in use");
873 /* If not a toplevel window... */
874 if (window
->parent
) {
875 /* Destroying subwindows may change colormap requirements;
876 recalculate toplevel window's WM_COLORMAP_WINDOWS
878 __glutPutOnWorkList(__glutToplevelOf(window
->parent
),
882 __glutDestroyWindow(window
, window
);
883 XFlush(__glutDisplay
);
888 __glutChangeWindowEventMask(long eventMask
, Bool add
)
891 /* Add eventMask to window's event mask. */
892 if ((__glutCurrentWindow
->eventMask
& eventMask
) !=
894 __glutCurrentWindow
->eventMask
|= eventMask
;
895 __glutPutOnWorkList(__glutCurrentWindow
,
896 GLUT_EVENT_MASK_WORK
);
899 /* Remove eventMask from window's event mask. */
900 if (__glutCurrentWindow
->eventMask
& eventMask
) {
901 __glutCurrentWindow
->eventMask
&= ~eventMask
;
902 __glutPutOnWorkList(__glutCurrentWindow
,
903 GLUT_EVENT_MASK_WORK
);
909 glutDisplayFunc(GLUTdisplayCB displayFunc
)
911 /* XXX Remove the warning after GLUT 3.0. */
913 __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
914 __glutCurrentWindow
->display
= displayFunc
;
918 glutMouseFunc(GLUTmouseCB mouseFunc
)
920 if (__glutCurrentWindow
->mouse
) {
922 /* Previous mouseFunc being disabled. */
923 __glutCurrentWindow
->buttonUses
--;
924 __glutChangeWindowEventMask(
925 ButtonPressMask
| ButtonReleaseMask
,
926 __glutCurrentWindow
->buttonUses
> 0);
930 /* Previously no mouseFunc, new one being installed. */
931 __glutCurrentWindow
->buttonUses
++;
932 __glutChangeWindowEventMask(
933 ButtonPressMask
| ButtonReleaseMask
, True
);
936 __glutCurrentWindow
->mouse
= mouseFunc
;
940 glutMotionFunc(GLUTmotionCB motionFunc
)
942 /* Hack. Some window managers (4Dwm by default) will mask
943 motion events if the client is not selecting for button
944 press and release events. So we select for press and
945 release events too (being careful to use reference
947 if (__glutCurrentWindow
->motion
) {
949 /* previous mouseFunc being disabled */
950 __glutCurrentWindow
->buttonUses
--;
951 __glutChangeWindowEventMask(
952 ButtonPressMask
| ButtonReleaseMask
,
953 __glutCurrentWindow
->buttonUses
> 0);
957 /* Previously no mouseFunc, new one being installed. */
958 __glutCurrentWindow
->buttonUses
++;
959 __glutChangeWindowEventMask(
960 ButtonPressMask
| ButtonReleaseMask
, True
);
963 /* Real work of selecting for passive mouse motion. */
964 __glutChangeWindowEventMask(
965 Button1MotionMask
| Button2MotionMask
| Button3MotionMask
,
967 __glutCurrentWindow
->motion
= motionFunc
;
971 glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc
)
973 __glutChangeWindowEventMask(PointerMotionMask
,
974 passiveMotionFunc
!= NULL
);
976 /* Passive motion also requires watching enters and leaves so
977 that a fake passive motion event can be generated on an
979 __glutChangeWindowEventMask(EnterWindowMask
| LeaveWindowMask
,
980 __glutCurrentWindow
->entry
!= NULL
|| passiveMotionFunc
!= NULL
);
982 __glutCurrentWindow
->passive
= passiveMotionFunc
;
986 glutEntryFunc(GLUTentryCB entryFunc
)
988 __glutChangeWindowEventMask(EnterWindowMask
| LeaveWindowMask
,
989 entryFunc
!= NULL
|| __glutCurrentWindow
->passive
);
990 __glutCurrentWindow
->entry
= entryFunc
;
992 __glutCurrentWindow
->entryState
= -1;
997 glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc
)
999 __glutChangeWindowEventMask(VisibilityChangeMask
,
1000 windowStatusFunc
!= NULL
);
1001 __glutCurrentWindow
->windowStatus
= windowStatusFunc
;
1002 if (!windowStatusFunc
) {
1003 /* Make state invalid. */
1004 __glutCurrentWindow
->visState
= -1;
1008 static void GLUTCALLBACK
1009 visibilityHelper(int status
)
1011 if (status
== GLUT_HIDDEN
|| status
== GLUT_FULLY_COVERED
)
1012 __glutCurrentWindow
->visibility(GLUT_NOT_VISIBLE
);
1014 __glutCurrentWindow
->visibility(GLUT_VISIBLE
);
1018 glutVisibilityFunc(GLUTvisibilityCB visibilityFunc
)
1020 __glutCurrentWindow
->visibility
= visibilityFunc
;
1022 glutWindowStatusFunc(visibilityHelper
);
1024 glutWindowStatusFunc(NULL
);
1028 glutReshapeFunc(GLUTreshapeCB reshapeFunc
)
1031 __glutCurrentWindow
->reshape
= reshapeFunc
;
1033 __glutCurrentWindow
->reshape
= __glutDefaultReshape
;