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)
332 if (GLUT_WIND_IS_MULTISAMPLE(mode
)) {
333 if (!__glutIsSupportedByGLX("GLX_SGIS_multisample"))
335 list
[n
++] = GLX_SAMPLES_SGIS
;
336 /* XXX Is 4 a reasonable minimum acceptable number of
341 list
[n
] = (int) None
; /* terminate list */
343 return glXChooseVisual(__glutDisplay
,
348 __glutGetVisualInfo(unsigned int mode
)
350 /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
351 if (GLUT_WIND_IS_LUMINANCE(mode
))
354 if (GLUT_WIND_IS_RGB(mode
))
355 return getVisualInfoRGB(mode
);
357 return getVisualInfoCI(mode
);
361 __glutDetermineVisual(
362 unsigned int displayMode
,
363 Bool
* treatAsSingle
,
364 XVisualInfo
* (getVisualInfo
) (unsigned int))
368 /* Should not be looking at display mode mask if
369 __glutDisplayString is non-NULL. */
370 assert(!__glutDisplayString
);
372 *treatAsSingle
= GLUT_WIND_IS_SINGLE(displayMode
);
373 vis
= getVisualInfo(displayMode
);
375 /* Fallback cases when can't get exactly what was asked
377 if (GLUT_WIND_IS_SINGLE(displayMode
)) {
378 /* If we can't find a single buffered visual, try looking
379 for a double buffered visual. We can treat a double
380 buffered visual as a single buffer visual by changing
381 the draw buffer to GL_FRONT and treating any swap
382 buffers as no-ops. */
383 displayMode
|= GLUT_DOUBLE
;
384 vis
= getVisualInfo(displayMode
);
385 *treatAsSingle
= True
;
387 if (!vis
&& GLUT_WIND_IS_MULTISAMPLE(displayMode
)) {
388 /* If we can't seem to get multisampling (ie, not Reality
389 Engine class graphics!), go without multisampling. It
390 is up to the application to query how many multisamples
391 were allocated (0 equals no multisampling) if the
392 application is going to use multisampling for more than
393 just antialiasing. */
394 displayMode
&= ~GLUT_MULTISAMPLE
;
395 vis
= getVisualInfo(displayMode
);
401 static void GLUTCALLBACK
402 __glutDefaultDisplay(void)
404 /* XXX Remove the warning after GLUT 3.0. */
405 __glutWarning("The following is a new check for GLUT 3.0; update your code.");
407 "redisplay needed for window %d, but no display callback.",
408 __glutCurrentWindow
->num
+ 1);
412 __glutDefaultReshape(int width
, int height
)
414 GLUToverlay
*overlay
;
416 /* Adjust the viewport of the window (and overlay if one
418 MAKE_CURRENT_WINDOW(__glutCurrentWindow
);
419 glViewport(0, 0, (GLsizei
) width
, (GLsizei
) height
);
420 overlay
= __glutCurrentWindow
->overlay
;
422 MAKE_CURRENT_OVERLAY(overlay
);
423 glViewport(0, 0, (GLsizei
) width
, (GLsizei
) height
);
425 /* Make sure we are current to the current layer (application
426 should be able to count on the current layer not changing
427 unless the application explicitly calls glutUseLayer). */
428 MAKE_CURRENT_LAYER(__glutCurrentWindow
);
432 __glutDetermineWindowVisual(Bool
* treatAsSingle
, Bool
* visAlloced
, void **fbc
)
434 if (__glutDisplayString
) {
436 /* __glutDisplayString should be NULL except if
437 glutInitDisplayString has been called to register a
438 different display string. Calling glutInitDisplayString
439 means using a string instead of an integer mask determine
440 the visual to use. Using the function pointer variable
441 __glutDetermineVisualFromString below avoids linking in
442 the code for implementing glutInitDisplayString (ie,
443 glut_dstr.o) unless glutInitDisplayString gets called by
446 assert(__glutDetermineVisualFromString
);
449 return __glutDetermineVisualFromString(__glutDisplayString
, treatAsSingle
,
450 requiredWindowCriteria
, numRequiredWindowCriteria
, requiredWindowCriteriaMask
, fbc
);
454 return __glutDetermineVisual(__glutDisplayMode
,
455 treatAsSingle
, __glutGetVisualInfo
);
459 /* ARGSUSED5 */ /* Only Win32 uses gameMode parameter. */
461 __glutCreateWindow(GLUTwindow
* parent
,
462 int x
, int y
, int width
, int height
, int gameMode
)
465 XSetWindowAttributes wa
;
466 unsigned long attribMask
;
469 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
479 if (!GetClassInfo(GetModuleHandle(NULL
), "GLUT", &wc
)) {
480 __glutOpenWin32Connection(NULL
);
483 if (!__glutDisplay
) {
484 __glutOpenXConnection(NULL
);
487 if (__glutGameModeWindow
) {
488 __glutFatalError("cannot create windows in game mode.");
490 winnum
= getUnusedWindowSlot();
491 window
= (GLUTwindow
*) malloc(sizeof(GLUTwindow
));
493 __glutFatalError("out of memory.");
495 window
->num
= winnum
;
498 window
->vis
= __glutDetermineWindowVisual(&window
->treatAsSingle
,
499 &window
->visAlloced
, (void**) &fbc
);
502 "visual with necessary capabilities not found.");
504 __glutSetupColormap(window
->vis
, &window
->colormap
, &window
->cmap
);
506 window
->eventMask
= StructureNotifyMask
| ExposureMask
;
508 attribMask
= CWBackPixmap
| CWBorderPixel
| CWColormap
| CWEventMask
;
509 wa
.background_pixmap
= None
;
511 wa
.colormap
= window
->cmap
;
512 wa
.event_mask
= window
->eventMask
;
514 if (parent
->eventMask
& GLUT_HACK_STOP_PROPAGATE_MASK
)
515 wa
.event_mask
|= GLUT_HACK_STOP_PROPAGATE_MASK
;
516 attribMask
|= CWDontPropagate
;
517 wa
.do_not_propagate_mask
= parent
->eventMask
& GLUT_DONT_PROPAGATE_FILTER_MASK
;
519 wa
.do_not_propagate_mask
= 0;
522 /* Stash width and height before Win32's __glutAdjustCoords
523 possibly overwrites the values. */
524 window
->width
= width
;
525 window
->height
= height
;
526 window
->forceReshape
= True
;
527 window
->ignoreKeyRepeat
= False
;
530 __glutAdjustCoords(parent
? parent
->win
: NULL
,
531 &x
, &y
, &width
, &height
);
536 /* Game mode window should be a WS_POPUP window to
537 ensure that the taskbar is hidden by it. A standard
538 WS_OVERLAPPEDWINDOW does not hide the task bar. */
539 style
= WS_POPUP
| WS_MAXIMIZE
;
541 /* A standard toplevel window with borders and such. */
542 style
= WS_OVERLAPPEDWINDOW
;
545 window
->win
= CreateWindow("GLUT", "GLUT",
546 WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| style
,
547 x
, y
, width
, height
, parent
? parent
->win
: __glutRoot
,
548 NULL
, GetModuleHandle(NULL
), 0);
549 window
->hdc
= GetDC(window
->win
);
550 /* Must set the XHDC for fake glXChooseVisual & fake
551 glXCreateContext & fake XAllocColorCells. */
553 window
->vis
= __glutDetermineWindowVisual(&window
->treatAsSingle
,
554 &window
->visAlloced
, &fbc
);
557 "pixel format with necessary capabilities not found.");
559 if (!SetPixelFormat(window
->hdc
,
560 ChoosePixelFormat(window
->hdc
, window
->vis
),
562 __glutFatalError("SetPixelFormat failed during window create.");
564 __glutSetupColormap(window
->vis
, &window
->colormap
, &window
->cmap
);
565 /* Make sure subwindows get a windowStatus callback. */
567 PostMessage(parent
->win
, WM_ACTIVATE
, 0, 0);
569 window
->renderDc
= window
->hdc
;
571 window
->win
= XCreateWindow(__glutDisplay
,
572 parent
== NULL
? __glutRoot
: parent
->win
,
573 x
, y
, width
, height
, 0,
574 window
->vis
->depth
, InputOutput
, window
->vis
->visual
,
577 window
->renderWin
= window
->win
;
578 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
580 window
->ctx
= __glut_glXCreateContextWithConfigSGIX(__glutDisplay
, fbc
,
581 GLX_RGBA_TYPE_SGIX
, None
, __glutTryDirect
);
585 window
->ctx
= glXCreateContext(__glutDisplay
, window
->vis
,
586 None
, __glutTryDirect
);
590 "failed to create OpenGL rendering context.");
592 window
->renderCtx
= window
->ctx
;
594 window
->isDirect
= glXIsDirect(__glutDisplay
, window
->ctx
);
595 if (__glutForceDirect
) {
596 if (!window
->isDirect
)
597 __glutFatalError("direct rendering not possible.");
601 window
->parent
= parent
;
603 window
->siblings
= parent
->children
;
604 parent
->children
= window
;
606 window
->siblings
= NULL
;
608 window
->overlay
= NULL
;
609 window
->children
= NULL
;
610 window
->display
= __glutDefaultDisplay
;
611 window
->reshape
= __glutDefaultReshape
;
612 window
->mouse
= NULL
;
613 window
->motion
= NULL
;
614 window
->passive
= NULL
;
615 window
->entry
= NULL
;
616 window
->keyboard
= NULL
;
617 window
->keyboardUp
= NULL
;
618 window
->windowStatus
= NULL
;
619 window
->visibility
= NULL
;
620 window
->special
= NULL
;
621 window
->specialUp
= NULL
;
622 window
->buttonBox
= NULL
;
623 window
->dials
= NULL
;
624 window
->spaceMotion
= NULL
;
625 window
->spaceRotate
= NULL
;
626 window
->spaceButton
= NULL
;
627 window
->tabletMotion
= NULL
;
628 window
->tabletButton
= NULL
;
630 window
->joystick
= NULL
;
631 window
->joyPollInterval
= 0;
633 window
->tabletPos
[0] = -1;
634 window
->tabletPos
[1] = -1;
635 window
->shownState
= 0;
636 window
->visState
= -1; /* not VisibilityUnobscured,
637 VisibilityPartiallyObscured, or
638 VisibilityFullyObscured */
639 window
->entryState
= -1; /* not EnterNotify or LeaveNotify */
641 window
->desiredConfMask
= 0;
642 window
->buttonUses
= 0;
643 window
->cursor
= GLUT_CURSOR_INHERIT
;
645 /* Setup window to be mapped when glutMainLoop starts. */
646 window
->workMask
= GLUT_MAP_WORK
;
649 /* When mapping a game mode window, just show
650 the window. We have already created the game
651 mode window with a maximize flag at creation
652 time. Doing a ShowWindow(window->win, SW_SHOWNORMAL)
653 would be wrong for a game mode window since it
654 would unmaximize the window. */
655 window
->desiredMapState
= GameModeState
;
657 window
->desiredMapState
= NormalState
;
660 window
->desiredMapState
= NormalState
;
662 window
->prevWorkWin
= __glutWindowWorkList
;
663 __glutWindowWorkList
= window
;
665 /* Initially, no menus attached. */
666 for (i
= 0; i
< GLUT_MAX_MENUS
; i
++) {
670 /* Add this new window to the window list. */
671 __glutWindowList
[winnum
] = window
;
673 /* Make the new window the current window. */
674 __glutSetWindow(window
);
676 __glutDetermineMesaSwapHackSupport();
678 if (window
->treatAsSingle
) {
679 /* We do this because either the window really is single
680 buffered (in which case this is redundant, but harmless,
681 because this is the initial single-buffered context
682 state); or we are treating a double buffered window as a
683 single-buffered window because the system does not appear
684 to export any suitable single- buffered visuals (in which
685 the following are necessary). */
686 glDrawBuffer(GL_FRONT
);
687 glReadBuffer(GL_FRONT
);
694 glutCreateWindow(const char *title
)
696 static int firstWindow
= 1;
702 XTextProperty textprop
;
704 if (__glutGameModeWindow
) {
705 __glutFatalError("cannot create windows in game mode.");
707 window
= __glutCreateWindow(NULL
,
708 __glutSizeHints
.x
, __glutSizeHints
.y
,
709 __glutInitWidth
, __glutInitHeight
,
710 /* not game mode */ 0);
712 /* Setup ICCCM properties. */
713 textprop
.value
= (unsigned char *) title
;
714 textprop
.encoding
= XA_STRING
;
716 textprop
.nitems
= strlen(title
);
718 SetWindowText(win
, title
);
720 window
->desiredMapState
= IconicState
;
723 wmHints
= XAllocWMHints();
724 wmHints
->initial_state
=
725 __glutIconic
? IconicState
: NormalState
;
726 wmHints
->flags
= StateHint
;
727 XSetWMProperties(__glutDisplay
, win
, &textprop
, &textprop
,
728 /* Only put WM_COMMAND property on first window. */
729 firstWindow
? __glutArgv
: NULL
,
730 firstWindow
? __glutArgc
: 0,
731 &__glutSizeHints
, wmHints
, NULL
);
733 XSetWMProtocols(__glutDisplay
, win
, &__glutWMDeleteWindow
, 1);
736 return window
->num
+ 1;
741 __glutCreateWindowWithExit(const char *title
, void (__cdecl
*exitfunc
)(int))
743 __glutExitFunc
= exitfunc
;
744 return glutCreateWindow(title
);
749 glutCreateSubWindow(int win
, int x
, int y
, int width
, int height
)
753 window
= __glutCreateWindow(__glutWindowList
[win
- 1],
754 x
, y
, width
, height
, /* not game mode */ 0);
757 GLUTwindow
*toplevel
;
759 toplevel
= __glutToplevelOf(window
);
760 if (toplevel
->cmap
!= window
->cmap
) {
761 __glutPutOnWorkList(toplevel
, GLUT_COLORMAP_WORK
);
765 return window
->num
+ 1;
770 __glutDestroyWindow(GLUTwindow
* window
,
771 GLUTwindow
* initialWindow
)
773 GLUTwindow
**prev
, *cur
, *parent
, *siblings
;
775 /* Recursively destroy any children. */
776 cur
= window
->children
;
778 siblings
= cur
->siblings
;
779 __glutDestroyWindow(cur
, initialWindow
);
782 /* Remove from parent's children list (only necessary for
783 non-initial windows and subwindows!). */
784 parent
= window
->parent
;
785 if (parent
&& parent
== initialWindow
->parent
) {
786 prev
= &parent
->children
;
787 cur
= parent
->children
;
790 *prev
= cur
->siblings
;
793 prev
= &(cur
->siblings
);
797 /* Unbind if bound to this window. */
798 if (window
== __glutCurrentWindow
) {
800 __glutCurrentWindow
= NULL
;
802 /* Begin tearing down window itself. */
803 if (window
->overlay
) {
804 __glutFreeOverlayFunc(window
->overlay
);
806 XDestroyWindow(__glutDisplay
, window
->win
);
807 glXDestroyContext(__glutDisplay
, window
->ctx
);
808 if (window
->colormap
) {
809 /* Only color index windows have colormap data structure. */
810 __glutFreeColormap(window
->colormap
);
812 /* NULLing the __glutWindowList helps detect is a window
813 instance has been destroyed, given a window number. */
814 __glutWindowList
[window
->num
] = NULL
;
816 /* Cleanup data structures that might contain window. */
817 cleanWindowWorkList(window
);
819 cleanStaleWindowList(window
);
821 /* Remove window from the "get window cache" if it is there. */
822 if (__glutWindowCache
== window
)
823 __glutWindowCache
= NULL
;
825 if (window
->visAlloced
) {
826 /* Only free XVisualInfo* gotten from glXChooseVisual. */
830 if (window
== __glutGameModeWindow
) {
831 /* Destroying the game mode window should implicitly
832 have GLUT leave game mode. */
833 __glutCloseDownGameMode();
841 glutDestroyWindow(int win
)
843 GLUTwindow
*window
= __glutWindowList
[win
- 1];
845 if (__glutMappedMenu
&& __glutMenuWindow
== window
) {
846 __glutFatalUsage("destroying menu window not allowed while menus in use");
849 /* If not a toplevel window... */
850 if (window
->parent
) {
851 /* Destroying subwindows may change colormap requirements;
852 recalculate toplevel window's WM_COLORMAP_WINDOWS
854 __glutPutOnWorkList(__glutToplevelOf(window
->parent
),
858 __glutDestroyWindow(window
, window
);
859 XFlush(__glutDisplay
);
864 __glutChangeWindowEventMask(long eventMask
, Bool add
)
867 /* Add eventMask to window's event mask. */
868 if ((__glutCurrentWindow
->eventMask
& eventMask
) !=
870 __glutCurrentWindow
->eventMask
|= eventMask
;
871 __glutPutOnWorkList(__glutCurrentWindow
,
872 GLUT_EVENT_MASK_WORK
);
875 /* Remove eventMask from window's event mask. */
876 if (__glutCurrentWindow
->eventMask
& eventMask
) {
877 __glutCurrentWindow
->eventMask
&= ~eventMask
;
878 __glutPutOnWorkList(__glutCurrentWindow
,
879 GLUT_EVENT_MASK_WORK
);
885 glutDisplayFunc(GLUTdisplayCB displayFunc
)
887 /* XXX Remove the warning after GLUT 3.0. */
889 __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
890 __glutCurrentWindow
->display
= displayFunc
;
894 glutMouseFunc(GLUTmouseCB mouseFunc
)
896 if (__glutCurrentWindow
->mouse
) {
898 /* Previous mouseFunc being disabled. */
899 __glutCurrentWindow
->buttonUses
--;
900 __glutChangeWindowEventMask(
901 ButtonPressMask
| ButtonReleaseMask
,
902 __glutCurrentWindow
->buttonUses
> 0);
906 /* Previously no mouseFunc, new one being installed. */
907 __glutCurrentWindow
->buttonUses
++;
908 __glutChangeWindowEventMask(
909 ButtonPressMask
| ButtonReleaseMask
, True
);
912 __glutCurrentWindow
->mouse
= mouseFunc
;
916 glutMotionFunc(GLUTmotionCB motionFunc
)
918 /* Hack. Some window managers (4Dwm by default) will mask
919 motion events if the client is not selecting for button
920 press and release events. So we select for press and
921 release events too (being careful to use reference
923 if (__glutCurrentWindow
->motion
) {
925 /* previous mouseFunc being disabled */
926 __glutCurrentWindow
->buttonUses
--;
927 __glutChangeWindowEventMask(
928 ButtonPressMask
| ButtonReleaseMask
,
929 __glutCurrentWindow
->buttonUses
> 0);
933 /* Previously no mouseFunc, new one being installed. */
934 __glutCurrentWindow
->buttonUses
++;
935 __glutChangeWindowEventMask(
936 ButtonPressMask
| ButtonReleaseMask
, True
);
939 /* Real work of selecting for passive mouse motion. */
940 __glutChangeWindowEventMask(
941 Button1MotionMask
| Button2MotionMask
| Button3MotionMask
,
943 __glutCurrentWindow
->motion
= motionFunc
;
947 glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc
)
949 __glutChangeWindowEventMask(PointerMotionMask
,
950 passiveMotionFunc
!= NULL
);
952 /* Passive motion also requires watching enters and leaves so
953 that a fake passive motion event can be generated on an
955 __glutChangeWindowEventMask(EnterWindowMask
| LeaveWindowMask
,
956 __glutCurrentWindow
->entry
!= NULL
|| passiveMotionFunc
!= NULL
);
958 __glutCurrentWindow
->passive
= passiveMotionFunc
;
962 glutEntryFunc(GLUTentryCB entryFunc
)
964 __glutChangeWindowEventMask(EnterWindowMask
| LeaveWindowMask
,
965 entryFunc
!= NULL
|| __glutCurrentWindow
->passive
);
966 __glutCurrentWindow
->entry
= entryFunc
;
968 __glutCurrentWindow
->entryState
= -1;
973 glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc
)
975 __glutChangeWindowEventMask(VisibilityChangeMask
,
976 windowStatusFunc
!= NULL
);
977 __glutCurrentWindow
->windowStatus
= windowStatusFunc
;
978 if (!windowStatusFunc
) {
979 /* Make state invalid. */
980 __glutCurrentWindow
->visState
= -1;
984 static void GLUTCALLBACK
985 visibilityHelper(int status
)
987 if (status
== GLUT_HIDDEN
|| status
== GLUT_FULLY_COVERED
)
988 __glutCurrentWindow
->visibility(GLUT_NOT_VISIBLE
);
990 __glutCurrentWindow
->visibility(GLUT_VISIBLE
);
994 glutVisibilityFunc(GLUTvisibilityCB visibilityFunc
)
996 __glutCurrentWindow
->visibility
= visibilityFunc
;
998 glutWindowStatusFunc(visibilityHelper
);
1000 glutWindowStatusFunc(NULL
);
1004 glutReshapeFunc(GLUTreshapeCB reshapeFunc
)
1007 __glutCurrentWindow
->reshape
= reshapeFunc
;
1009 __glutCurrentWindow
->reshape
= __glutDefaultReshape
;