source: trunk/src/opengl/glut/glut_win.c

Last change on this file was 3086, checked in by sandervl, 25 years ago

update

File size: 28.3 KB
Line 
1/* $Id: glut_win.c,v 1.8 2000-03-11 17:07:45 sandervl Exp $ */
2/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
3
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. */
7
8#include <stdlib.h>
9#include <stdio.h>
10#include <string.h>
11#include <assert.h>
12#if !defined(_WIN32) && !defined(__WIN32OS2__)
13#include <X11/Xlib.h>
14#include <X11/Xatom.h>
15#endif
16
17#include "glutint.h"
18
19GLUTwindow *__glutCurrentWindow = NULL;
20GLUTwindow **__glutWindowList = NULL;
21int __glutWindowListSize = 0;
22#if !defined(_WIN32) && !defined(__WIN32OS2__)
23GLUTstale *__glutStaleWindowList = NULL;
24#endif
25GLUTwindow *__glutMenuWindow = NULL;
26
27void (*__glutFreeOverlayFunc) (GLUToverlay *);
28XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
29 Criterion * requiredCriteria, int nRequired, int requiredMask, void** fbc) = NULL;
30
31static Criterion requiredWindowCriteria[] =
32{
33 {LEVEL, EQ, 0},
34 {TRANSPARENT, EQ, 0}
35};
36static int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
37static int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
38
39static void
40cleanWindowWorkList(GLUTwindow * window)
41{
42 GLUTwindow **pEntry = &__glutWindowWorkList;
43 GLUTwindow *entry = __glutWindowWorkList;
44
45 /* Tranverse singly-linked window work list look for the
46 window. */
47 while (entry) {
48 if (entry == window) {
49 /* Found it; delete it. */
50 *pEntry = entry->prevWorkWin;
51 return;
52 } else {
53 pEntry = &entry->prevWorkWin;
54 entry = *pEntry;
55 }
56 }
57}
58
59#if !defined(_WIN32) && !defined(__WIN32OS2__)
60
61static void
62cleanStaleWindowList(GLUTwindow * window)
63{
64 GLUTstale **pEntry = &__glutStaleWindowList;
65 GLUTstale *entry = __glutStaleWindowList;
66
67 /* Tranverse singly-linked stale window list look for the
68 window ID. */
69 while (entry) {
70 if (entry->window == window) {
71 /* Found it; delete it. */
72 *pEntry = entry->next;
73 free(entry);
74 return;
75 } else {
76 pEntry = &entry->next;
77 entry = *pEntry;
78 }
79 }
80}
81
82#endif
83
84static GLUTwindow *__glutWindowCache = NULL;
85
86GLUTwindow *
87__glutGetWindow(Window win)
88{
89 int i;
90
91 /* Does win belong to the last window ID looked up? */
92 if (__glutWindowCache && (win == __glutWindowCache->win ||
93 (__glutWindowCache->overlay && win ==
94 __glutWindowCache->overlay->win))) {
95 return
96 __glutWindowCache;
97 }
98 /* Otherwise scan the window list looking for the window ID. */
99 for (i = 0; i < __glutWindowListSize; i++) {
100 if (__glutWindowList[i]) {
101 if (win == __glutWindowList[i]->win) {
102 __glutWindowCache = __glutWindowList[i];
103 return __glutWindowCache;
104 }
105 if (__glutWindowList[i]->overlay) {
106 if (win == __glutWindowList[i]->overlay->win) {
107 __glutWindowCache = __glutWindowList[i];
108 return __glutWindowCache;
109 }
110 }
111 }
112 }
113#if !defined(_WIN32) && !defined(__WIN32OS2__)
114 {
115 GLUTstale *entry;
116
117 /* Scan through destroyed overlay window IDs for which no
118 DestroyNotify has yet been received. */
119 for (entry = __glutStaleWindowList; entry; entry = entry->next) {
120 if (entry->win == win)
121 return entry->window;
122 }
123 }
124#endif
125 return NULL;
126}
127
128/* CENTRY */
129int GLAPIENTRY
130glutGetWindow(void)
131{
132 if (__glutCurrentWindow) {
133 return __glutCurrentWindow->num + 1;
134 } else {
135 return 0;
136 }
137}
138/* ENDCENTRY */
139
140void
141__glutSetWindow(GLUTwindow * window)
142{
143 /* It is tempting to try to short-circuit the call to
144 glXMakeCurrent if we "know" we are going to make current
145 to a window we are already current to. In fact, this
146 assumption breaks when GLUT is expected to integrated with
147 other OpenGL windowing APIs that also make current to
148 OpenGL contexts. Since glXMakeCurrent short-circuits the
149 "already bound" case, GLUT avoids the temptation to do so
150 too. */
151 __glutCurrentWindow = window;
152
153 MAKE_CURRENT_LAYER(__glutCurrentWindow);
154
155#if !defined(_WIN32) && !defined(__WIN32OS2__)
156 /* We should be careful to force a finish between each
157 iteration through the GLUT main loop if indirect OpenGL
158 contexts are in use; indirect contexts tend to have much
159 longer latency because lots of OpenGL extension requests
160 can queue up in the X protocol stream. We accomplish this
161 by posting GLUT_FINISH_WORK to be done. */
162 if (!__glutCurrentWindow->isDirect)
163 __glutPutOnWorkList(__glutCurrentWindow, GLUT_FINISH_WORK);
164#endif
165
166 /* If debugging is enabled, we'll want to check this window
167 for any OpenGL errors every iteration through the GLUT
168 main loop. To accomplish this, we post the
169 GLUT_DEBUG_WORK to be done on this window. */
170 if (__glutDebug) {
171 __glutPutOnWorkList(__glutCurrentWindow, GLUT_DEBUG_WORK);
172 }
173}
174
175/* CENTRY */
176void GLAPIENTRY
177glutSetWindow(int win)
178{
179 GLUTwindow *window;
180
181 if (win < 1 || win > __glutWindowListSize) {
182 __glutWarning("glutSetWindow attempted on bogus window.");
183 return;
184 }
185 window = __glutWindowList[win - 1];
186 if (!window) {
187 __glutWarning("glutSetWindow attempted on bogus window.");
188 return;
189 }
190 __glutSetWindow(window);
191}
192/* ENDCENTRY */
193
194static int
195getUnusedWindowSlot(void)
196{
197 int i;
198
199 /* Look for allocated, unused slot. */
200 for (i = 0; i < __glutWindowListSize; i++) {
201 if (!__glutWindowList[i]) {
202 return i;
203 }
204 }
205 /* Allocate a new slot. */
206 __glutWindowListSize++;
207 if (__glutWindowList) {
208 __glutWindowList = (GLUTwindow **)
209 realloc(__glutWindowList,
210 __glutWindowListSize * sizeof(GLUTwindow *));
211 } else {
212 /* XXX Some realloc's do not correctly perform a malloc
213 when asked to perform a realloc on a NULL pointer,
214 though the ANSI C library spec requires this. */
215 __glutWindowList = (GLUTwindow **)
216 malloc(sizeof(GLUTwindow *));
217 }
218 if (!__glutWindowList)
219 __glutFatalError("out of memory.");
220 __glutWindowList[__glutWindowListSize - 1] = NULL;
221 return __glutWindowListSize - 1;
222}
223
224static XVisualInfo *
225getVisualInfoCI(unsigned int mode)
226{
227 static int bufSizeList[] =
228 {16, 12, 8, 4, 2, 1, 0};
229 XVisualInfo *vi;
230 int list[32];
231 int i, n = 0;
232
233 /* Should not be looking at display mode mask if
234 __glutDisplayString is non-NULL. */
235 assert(!__glutDisplayString);
236
237 list[n++] = GLX_BUFFER_SIZE;
238 list[n++] = 1;
239 if (GLUT_WIND_IS_DOUBLE(mode)) {
240 list[n++] = GLX_DOUBLEBUFFER;
241 }
242 if (GLUT_WIND_IS_STEREO(mode)) {
243 list[n++] = GLX_STEREO;
244 }
245 if (GLUT_WIND_HAS_DEPTH(mode)) {
246 list[n++] = GLX_DEPTH_SIZE;
247 list[n++] = 1;
248 }
249 if (GLUT_WIND_HAS_STENCIL(mode)) {
250 list[n++] = GLX_STENCIL_SIZE;
251 list[n++] = 1;
252 }
253 list[n] = (int) None; /* terminate list */
254
255 /* glXChooseVisual specify GLX_BUFFER_SIZE prefers the
256 "smallest index buffer of at least the specified size".
257 This would be reasonable if GLUT allowed the user to
258 specify the required buffe size, but GLUT's display mode
259 is too simplistic (easy to use?). GLUT should try to find
260 the "largest". So start with a large buffer size and
261 shrink until we find a matching one that exists. */
262
263 for (i = 0; bufSizeList[i]; i++) {
264 /* XXX Assumes list[1] is where GLX_BUFFER_SIZE parameter
265 is. */
266 list[1] = bufSizeList[i];
267 vi = glXChooseVisual(__glutDisplay,
268 __glutScreen, list);
269 if (vi)
270 return vi;
271 }
272 return NULL;
273}
274
275static XVisualInfo *
276getVisualInfoRGB(unsigned int mode)
277{
278 int list[32];
279 int n = 0;
280
281 /* Should not be looking at display mode mask if
282 __glutDisplayString is non-NULL. */
283 assert(!__glutDisplayString);
284
285 /* XXX Would a caching mechanism to minize the calls to
286 glXChooseVisual? You'd have to reference count
287 XVisualInfo* pointers. Would also have to properly
288 interact with glutInitDisplayString. */
289
290 list[n++] = GLX_RGBA;
291 list[n++] = GLX_RED_SIZE;
292 list[n++] = 1;
293 list[n++] = GLX_GREEN_SIZE;
294 list[n++] = 1;
295 list[n++] = GLX_BLUE_SIZE;
296 list[n++] = 1;
297 if (GLUT_WIND_HAS_ALPHA(mode)) {
298 list[n++] = GLX_ALPHA_SIZE;
299 list[n++] = 1;
300 }
301 if (GLUT_WIND_IS_DOUBLE(mode)) {
302 list[n++] = GLX_DOUBLEBUFFER;
303 }
304 if (GLUT_WIND_IS_STEREO(mode)) {
305 list[n++] = GLX_STEREO;
306 }
307 if (GLUT_WIND_HAS_DEPTH(mode)) {
308 list[n++] = GLX_DEPTH_SIZE;
309 list[n++] = 1;
310 }
311 if (GLUT_WIND_HAS_STENCIL(mode)) {
312 list[n++] = GLX_STENCIL_SIZE;
313 list[n++] = 1;
314 }
315 if (GLUT_WIND_HAS_ACCUM(mode)) {
316 list[n++] = GLX_ACCUM_RED_SIZE;
317 list[n++] = 1;
318 list[n++] = GLX_ACCUM_GREEN_SIZE;
319 list[n++] = 1;
320 list[n++] = GLX_ACCUM_BLUE_SIZE;
321 list[n++] = 1;
322 if (GLUT_WIND_HAS_ALPHA(mode)) {
323 list[n++] = GLX_ACCUM_ALPHA_SIZE;
324 list[n++] = 1;
325 }
326 }
327#if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
328 if (GLUT_WIND_IS_MULTISAMPLE(mode)) {
329 if (!__glutIsSupportedByGLX("GLX_SGIS_multisample"))
330 return NULL;
331 list[n++] = GLX_SAMPLES_SGIS;
332 /* XXX Is 4 a reasonable minimum acceptable number of
333 samples? */
334 list[n++] = 4;
335 }
336#endif
337 list[n] = (int) None; /* terminate list*/
338
339 return glXChooseVisual(__glutDisplay,
340 __glutScreen, list);
341}
342
343XVisualInfo *
344__glutGetVisualInfo(unsigned int mode)
345{
346 /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
347 if (GLUT_WIND_IS_LUMINANCE(mode))
348 return NULL;
349
350 if (GLUT_WIND_IS_RGB(mode))
351 {
352 return getVisualInfoRGB(mode);
353 }
354 else
355 {
356 return getVisualInfoCI(mode);
357 }
358}
359
360XVisualInfo *
361__glutDetermineVisual(
362 unsigned int displayMode,
363 Bool * treatAsSingle,
364 XVisualInfo * (getVisualInfo) (unsigned int))
365{
366 XVisualInfo *vis;
367
368 /* Should not be looking at display mode mask if
369 __glutDisplayString is non-NULL. */
370 assert(!__glutDisplayString);
371
372 *treatAsSingle = GLUT_WIND_IS_SINGLE(displayMode);
373 vis = getVisualInfo(displayMode);
374 if (!vis) {
375 /* Fallback cases when can't get exactly what was asked
376 for... */
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;
386 }
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);
396 }
397 }
398 return vis;
399}
400
401void GLUTCALLBACK
402__glutDefaultDisplay(void)
403{
404 /* XXX Remove the warning after GLUT 3.0. */
405 __glutWarning("The following is a new check for GLUT 3.0; update your code.");
406 __glutFatalError(
407 "redisplay needed for window %d, but no display callback.",
408 __glutCurrentWindow->num + 1);
409}
410
411void GLUTCALLBACK
412__glutDefaultReshape(int width, int height)
413{
414 GLUToverlay *overlay;
415
416 /* Adjust the viewport of the window (and overlay if one
417 exists). */
418 MAKE_CURRENT_WINDOW(__glutCurrentWindow);
419 glViewport(0, 0, (GLsizei) width, (GLsizei) height);
420 overlay = __glutCurrentWindow->overlay;
421 if (overlay) {
422 MAKE_CURRENT_OVERLAY(overlay);
423 glViewport(0, 0, (GLsizei) width, (GLsizei) height);
424 }
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);
429}
430
431XVisualInfo *
432__glutDetermineWindowVisual(Bool * treatAsSingle, Bool * visAlloced, void **fbc)
433{
434 if (__glutDisplayString) {
435
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
444 the application. */
445
446 assert(__glutDetermineVisualFromString);
447 *visAlloced = False;
448 *fbc = NULL;
449 return __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
450 requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, fbc);
451 } else {
452 *visAlloced = True;
453 *fbc = NULL;
454
455 return __glutDetermineVisual(__glutDisplayMode,
456 treatAsSingle, __glutGetVisualInfo);
457 }
458}
459
460/* ARGSUSED5 */ /* Only Win32 uses gameMode parameter. */
461GLUTwindow *
462__glutCreateWindow(GLUTwindow * parent,
463 int x, int y, int width, int height, int gameMode)
464{
465 GLUTwindow *window;
466 XSetWindowAttributes wa;
467 unsigned long attribMask;
468 int winnum;
469 int i;
470#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
471 GLXFBConfigSGIX fbc;
472#else
473 void *fbc;
474#endif
475
476#if defined(_WIN32) || defined(__WIN32OS2__)
477 WNDCLASS wc;
478 int style;
479
480 if (!GetClassInfo(GetModuleHandle(NULL), "GLUT", &wc)) {
481 __glutOpenWin32Connection(NULL);
482 }
483#else
484 if (!__glutDisplay) {
485 __glutOpenXConnection(NULL);
486 }
487#endif
488 if (__glutGameModeWindow) {
489 __glutFatalError("cannot create windows in game mode.");
490 }
491 winnum = getUnusedWindowSlot();
492 window = (GLUTwindow *) malloc(sizeof(GLUTwindow));
493 if (!window) {
494 __glutFatalError("out of memory.");
495 }
496 window->num = winnum;
497
498#if !defined(_WIN32) && !defined(__WIN32OS2__)
499 window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
500 &window->visAlloced, (void**) &fbc);
501 if (!window->vis) {
502 __glutFatalError(
503 "visual with necessary capabilities not found.");
504 }
505 __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
506#endif
507 window->eventMask = StructureNotifyMask | ExposureMask;
508
509 attribMask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
510 wa.background_pixmap = None;
511 wa.border_pixel = 0;
512 wa.colormap = window->cmap;
513 wa.event_mask = window->eventMask;
514 if (parent) {
515 if (parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
516 wa.event_mask |= GLUT_HACK_STOP_PROPAGATE_MASK;
517 attribMask |= CWDontPropagate;
518 wa.do_not_propagate_mask = parent->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
519 } else {
520 wa.do_not_propagate_mask = 0;
521 }
522
523 /* Stash width and height before Win32's __glutAdjustCoords
524 possibly overwrites the values. */
525 window->width = width;
526 window->height = height;
527 window->forceReshape = True;
528 window->ignoreKeyRepeat = False;
529
530#if defined(_WIN32) || defined(__WIN32OS2__)
531 __glutAdjustCoords(parent ? parent->win : NULL,
532 &x, &y, &width, &height);
533 if (parent) {
534 style = WS_CHILD;
535 } else {
536 if (gameMode) {
537 /* Game mode window should be a WS_POPUP window to
538 ensure that the taskbar is hidden by it. A standard
539 WS_OVERLAPPEDWINDOW does not hide the task bar. */
540 style = WS_POPUP | WS_MAXIMIZE;
541 } else {
542 /* A standard toplevel window with borders and such. */
543 style = WS_OVERLAPPEDWINDOW;
544 }
545 }
546 window->win = CreateWindow("GLUT", "GLUT",
547 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
548 x, y, width, height, parent ? parent->win : __glutRoot,
549 NULL, GetModuleHandle(NULL), 0);
550
551 window->hdc = GetDC(window->win);
552 /* Must set the XHDC for fake glXChooseVisual & fake
553 glXCreateContext & fake XAllocColorCells. */
554 XHDC = window->hdc;
555 window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
556 &window->visAlloced, &fbc);
557 if (!window->vis) {
558 __glutFatalError(
559 "pixel format with necessary capabilities not found.");
560 }
561
562 if (!SetPixelFormat(window->hdc,
563 ChoosePixelFormat(window->hdc, window->vis),
564 window->vis)) {
565 __glutFatalError("SetPixelFormat failed during window create.");
566 }
567 __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
568 /* Make sure subwindows get a windowStatus callback. */
569 if (parent) {
570 PostMessage(parent->win, WM_ACTIVATE, 0, 0);
571 }
572 window->renderDc = window->hdc;
573#else
574 window->win = XCreateWindow(__glutDisplay,
575 parent == NULL ? __glutRoot : parent->win,
576 x, y, width, height, 0,
577 window->vis->depth, InputOutput, window->vis->visual,
578 attribMask, &wa);
579#endif
580 window->renderWin = window->win;
581#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
582 if (fbc) {
583 window->ctx = glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
584 GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
585 } else
586#endif
587 {
588 window->ctx = glXCreateContext(__glutDisplay, window->vis,
589 None, __glutTryDirect);
590 }
591 if (!window->ctx) {
592 __glutFatalError(
593 "failed to create OpenGL rendering context.");
594 }
595 window->renderCtx = window->ctx;
596#if !defined(_WIN32) && !defined(__WIN32OS2__)
597 window->isDirect = glXIsDirect(__glutDisplay, window->ctx);
598
599 if (__glutForceDirect) {
600 if (!window->isDirect)
601 __glutFatalError("direct rendering not possible.");
602 }
603#endif
604
605 window->parent = parent;
606 if (parent) {
607 window->siblings = parent->children;
608 parent->children = window;
609 } else {
610 window->siblings = NULL;
611 }
612 window->overlay = NULL;
613 window->children = NULL;
614 window->display = __glutDefaultDisplay;
615 window->reshape = __glutDefaultReshape;
616 window->mouse = NULL;
617 window->motion = NULL;
618 window->passive = NULL;
619 window->entry = NULL;
620 window->keyboard = NULL;
621 window->keyboardUp = NULL;
622 window->windowStatus = NULL;
623 window->visibility = NULL;
624 window->special = NULL;
625 window->specialUp = NULL;
626 window->buttonBox = NULL;
627 window->dials = NULL;
628 window->spaceMotion = NULL;
629 window->spaceRotate = NULL;
630 window->spaceButton = NULL;
631 window->tabletMotion = NULL;
632 window->tabletButton = NULL;
633#if defined(_WIN32) || defined(__WIN32OS2__)
634 window->joystick = NULL;
635 window->joyPollInterval = 0;
636#endif
637 window->tabletPos[0] = -1;
638 window->tabletPos[1] = -1;
639 window->shownState = 0;
640 window->visState = -1; /* not VisibilityUnobscured,
641 VisibilityPartiallyObscured, or
642 VisibilityFullyObscured */
643 window->entryState = -1; /* not EnterNotify or LeaveNotify */
644
645 window->desiredConfMask = 0;
646 window->buttonUses = 0;
647 window->cursor = GLUT_CURSOR_INHERIT;
648
649 /* Setup window to be mapped when glutMainLoop starts. */
650 window->workMask = GLUT_MAP_WORK;
651#if defined(_WIN32) || defined(__WIN32OS2__)
652 if (gameMode) {
653 /* When mapping a game mode window, just show
654 the window. We have already created the game
655 mode window with a maximize flag at creation
656 time. Doing a ShowWindow(window->win, SW_SHOWNORMAL)
657 would be wrong for a game mode window since it
658 would unmaximize the window. */
659 window->desiredMapState = GameModeState;
660 } else {
661 window->desiredMapState = NormalState;
662 }
663#else
664 window->desiredMapState = NormalState;
665#endif
666 window->prevWorkWin = __glutWindowWorkList;
667 __glutWindowWorkList = window;
668
669 /* Initially, no menus attached. */
670 for (i = 0; i < GLUT_MAX_MENUS; i++) {
671 window->menu[i] = 0;
672 }
673
674 /* Add this new window to the window list. */
675 __glutWindowList[winnum] = window;
676
677 /* Make the new window the current window. */
678 __glutSetWindow(window);
679
680 __glutDetermineMesaSwapHackSupport();
681
682 if (window->treatAsSingle) {
683 /* We do this because either the window really is single
684 buffered (in which case this is redundant, but harmless,
685 because this is the initial single-buffered context
686 state); or we are treating a double buffered window as a
687 single-buffered window because the system does not appear
688 to export any suitable single- buffered visuals (in which
689 the following are necessary). */
690 glDrawBuffer(GL_FRONT);
691 glReadBuffer(GL_FRONT);
692 }
693 return window;
694}
695
696/* CENTRY */
697int GLAPIENTRY
698glutCreateWindow(const char *title)
699{
700 static int firstWindow = 1;
701 GLUTwindow *window;
702#if !defined(_WIN32) && !defined(__WIN32OS2__)
703 XWMHints *wmHints;
704#endif
705 Window win;
706 XTextProperty textprop;
707
708 if (__glutGameModeWindow) {
709 __glutFatalError("cannot create windows in game mode.");
710 }
711 window = __glutCreateWindow(NULL,
712 __glutSizeHints.x, __glutSizeHints.y,
713 __glutInitWidth, __glutInitHeight,
714 /* not game mode */ 0);
715 win = window->win;
716 /* Setup ICCCM properties. */
717 textprop.value = (unsigned char *) title;
718 textprop.encoding = XA_STRING;
719 textprop.format = 8;
720 textprop.nitems = strlen(title);
721#if defined(_WIN32) || defined(__WIN32OS2__)
722 SetWindowText(win, title);
723 if (__glutIconic) {
724 window->desiredMapState = IconicState;
725 }
726#else
727 wmHints = XAllocWMHints();
728 wmHints->initial_state =
729 __glutIconic ? IconicState : NormalState;
730 wmHints->flags = StateHint;
731 XSetWMProperties(__glutDisplay, win, &textprop, &textprop,
732 /* Only put WM_COMMAND property on first window. */
733 firstWindow ? __glutArgv : NULL,
734 firstWindow ? __glutArgc : 0,
735 &__glutSizeHints, wmHints, NULL);
736 XFree(wmHints);
737 XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
738#endif
739 firstWindow = 0;
740 return window->num + 1;
741}
742
743int GLAPIENTRY
744glutCreateSubWindow(int win, int x, int y, int width, int height)
745{
746 GLUTwindow *window;
747
748 window = __glutCreateWindow(__glutWindowList[win - 1],
749 x, y, width, height, /* not game mode */ 0);
750#if !defined(_WIN32) && !defined(__WIN32OS2__)
751 {
752 GLUTwindow *toplevel;
753
754 toplevel = __glutToplevelOf(window);
755 if (toplevel->cmap != window->cmap) {
756 __glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
757 }
758 }
759#endif
760 return window->num + 1;
761}
762/* ENDCENTRY */
763
764void
765__glutDestroyWindow(GLUTwindow * window,
766 GLUTwindow * initialWindow)
767{
768 GLUTwindow **prev, *cur, *parent, *siblings;
769
770 /* Recursively destroy any children. */
771 cur = window->children;
772 while (cur) {
773 siblings = cur->siblings;
774 __glutDestroyWindow(cur, initialWindow);
775 cur = siblings;
776 }
777 /* Remove from parent's children list (only necessary for
778 non-initial windows and subwindows!). */
779 parent = window->parent;
780 if (parent && parent == initialWindow->parent) {
781 prev = &parent->children;
782 cur = parent->children;
783 while (cur) {
784 if (cur == window) {
785 *prev = cur->siblings;
786 break;
787 }
788 prev = &(cur->siblings);
789 cur = cur->siblings;
790 }
791 }
792 /* Unbind if bound to this window. */
793 if (window == __glutCurrentWindow) {
794 UNMAKE_CURRENT();
795 __glutCurrentWindow = NULL;
796 }
797 /* Begin tearing down window itself. */
798 if (window->overlay) {
799 __glutFreeOverlayFunc(window->overlay);
800 }
801 XDestroyWindow(__glutDisplay, window->win);
802 glXDestroyContext(__glutDisplay, window->ctx);
803 if (window->colormap) {
804 /* Only color index windows have colormap data structure. */
805 __glutFreeColormap(window->colormap);
806 }
807 /* NULLing the __glutWindowList helps detect is a window
808 instance has been destroyed, given a window number. */
809 __glutWindowList[window->num] = NULL;
810
811 /* Cleanup data structures that might contain window. */
812 cleanWindowWorkList(window);
813#if !defined(_WIN32) && !defined(__WIN32OS2__)
814 cleanStaleWindowList(window);
815#endif
816 /* Remove window from the "get window cache" if it is there. */
817 if (__glutWindowCache == window)
818 __glutWindowCache = NULL;
819
820 if (window->visAlloced) {
821 /* Only free XVisualInfo* gotten from glXChooseVisual. */
822 XFree(window->vis);
823 }
824
825 if (window == __glutGameModeWindow) {
826 /* Destroying the game mode window should implicitly
827 have GLUT leave game mode. */
828 __glutCloseDownGameMode();
829 }
830
831 free(window);
832}
833
834/* CENTRY */
835void GLAPIENTRY
836glutDestroyWindow(int win)
837{
838 GLUTwindow *window = __glutWindowList[win - 1];
839
840 if (__glutMappedMenu && __glutMenuWindow == window) {
841 __glutFatalUsage("destroying menu window not allowed while menus in use");
842 }
843#if !defined(_WIN32) && !defined(__WIN32OS2__)
844 /* If not a toplevel window... */
845 if (window->parent) {
846 /* Destroying subwindows may change colormap requirements;
847 recalculate toplevel window's WM_COLORMAP_WINDOWS
848 property. */
849 __glutPutOnWorkList(__glutToplevelOf(window->parent),
850 GLUT_COLORMAP_WORK);
851 }
852#endif
853 __glutDestroyWindow(window, window);
854}
855/* ENDCENTRY */
856
857void
858__glutChangeWindowEventMask(long eventMask, Bool add)
859{
860 if (add) {
861 /* Add eventMask to window's event mask. */
862 if ((__glutCurrentWindow->eventMask & eventMask) !=
863 eventMask) {
864 __glutCurrentWindow->eventMask |= eventMask;
865 __glutPutOnWorkList(__glutCurrentWindow,
866 GLUT_EVENT_MASK_WORK);
867 }
868 } else {
869 /* Remove eventMask from window's event mask. */
870 if (__glutCurrentWindow->eventMask & eventMask) {
871 __glutCurrentWindow->eventMask &= ~eventMask;
872 __glutPutOnWorkList(__glutCurrentWindow,
873 GLUT_EVENT_MASK_WORK);
874 }
875 }
876}
877
878void GLAPIENTRY
879glutDisplayFunc(GLUTdisplayCB displayFunc)
880{
881 /* XXX Remove the warning after GLUT 3.0. */
882 if (!displayFunc)
883 __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
884 __glutCurrentWindow->display = displayFunc;
885}
886
887void GLAPIENTRY
888glutMouseFunc(GLUTmouseCB mouseFunc)
889{
890 if (__glutCurrentWindow->mouse) {
891 if (!mouseFunc) {
892 /* Previous mouseFunc being disabled. */
893 __glutCurrentWindow->buttonUses--;
894 __glutChangeWindowEventMask(
895 ButtonPressMask | ButtonReleaseMask,
896 __glutCurrentWindow->buttonUses > 0);
897 }
898 } else {
899 if (mouseFunc) {
900 /* Previously no mouseFunc, new one being installed. */
901 __glutCurrentWindow->buttonUses++;
902 __glutChangeWindowEventMask(
903 ButtonPressMask | ButtonReleaseMask, True);
904 }
905 }
906 __glutCurrentWindow->mouse = mouseFunc;
907}
908
909void GLAPIENTRY
910glutMotionFunc(GLUTmotionCB motionFunc)
911{
912 /* Hack. Some window managers (4Dwm by default) will mask
913 motion events if the client is not selecting for button
914 press and release events. So we select for press and
915 release events too (being careful to use reference
916 counting). */
917 if (__glutCurrentWindow->motion) {
918 if (!motionFunc) {
919 /* previous mouseFunc being disabled */
920 __glutCurrentWindow->buttonUses--;
921 __glutChangeWindowEventMask(
922 ButtonPressMask | ButtonReleaseMask,
923 __glutCurrentWindow->buttonUses > 0);
924 }
925 } else {
926 if (motionFunc) {
927 /* Previously no mouseFunc, new one being installed. */
928 __glutCurrentWindow->buttonUses++;
929 __glutChangeWindowEventMask(
930 ButtonPressMask | ButtonReleaseMask, True);
931 }
932 }
933 /* Real work of selecting for passive mouse motion. */
934 __glutChangeWindowEventMask(
935 Button1MotionMask | Button2MotionMask | Button3MotionMask,
936 motionFunc != NULL);
937 __glutCurrentWindow->motion = motionFunc;
938}
939
940void GLAPIENTRY
941glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc)
942{
943 __glutChangeWindowEventMask(PointerMotionMask,
944 passiveMotionFunc != NULL);
945
946 /* Passive motion also requires watching enters and leaves so
947 that a fake passive motion event can be generated on an
948 enter. */
949 __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
950 __glutCurrentWindow->entry != NULL || passiveMotionFunc != NULL);
951
952 __glutCurrentWindow->passive = passiveMotionFunc;
953}
954
955void GLAPIENTRY
956glutEntryFunc(GLUTentryCB entryFunc)
957{
958 __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
959 entryFunc != NULL || __glutCurrentWindow->passive);
960 __glutCurrentWindow->entry = entryFunc;
961 if (!entryFunc) {
962 __glutCurrentWindow->entryState = -1;
963 }
964}
965
966void GLAPIENTRY
967glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc)
968{
969 __glutChangeWindowEventMask(VisibilityChangeMask,
970 windowStatusFunc != NULL);
971 __glutCurrentWindow->windowStatus = windowStatusFunc;
972 if (!windowStatusFunc) {
973 /* Make state invalid. */
974 __glutCurrentWindow->visState = -1;
975 }
976}
977
978static void GLUTCALLBACK
979visibilityHelper(int status)
980{
981 if (status == GLUT_HIDDEN || status == GLUT_FULLY_COVERED)
982 ((GLUTvisibilityCB)(__glutCurrentWindow->visibility))(GLUT_NOT_VISIBLE);
983 else
984 ((GLUTvisibilityCB)(__glutCurrentWindow->visibility))(GLUT_VISIBLE);
985}
986
987void GLAPIENTRY
988glutVisibilityFunc(GLUTvisibilityCB visibilityFunc)
989{
990 __glutCurrentWindow->visibility = visibilityFunc;
991 if (visibilityFunc)
992 glutWindowStatusFunc(visibilityHelper);
993 else
994 glutWindowStatusFunc(NULL);
995}
996
997void GLAPIENTRY
998glutReshapeFunc(GLUTreshapeCB reshapeFunc)
999{
1000 if (reshapeFunc) {
1001 __glutCurrentWindow->reshape = reshapeFunc;
1002 } else {
1003 __glutCurrentWindow->reshape = __glutDefaultReshape;
1004 }
1005}
Note: See TracBrowser for help on using the repository browser.