root/foundation-libs/mesalibs-maxx/glut_win-new.c

Revision 7, 28.1 KB (checked in by emasson, 3 years ago)

initial import for the community edition

Line 
1
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)
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)
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)
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)
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 APIENTRY
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)
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 APIENTRY
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    return getVisualInfoRGB(mode);
352  else
353    return getVisualInfoCI(mode);
354}
355
356XVisualInfo *
357__glutDetermineVisual(
358  unsigned int displayMode,
359  Bool * treatAsSingle,
360  XVisualInfo * (getVisualInfo) (unsigned int))
361{
362  XVisualInfo *vis;
363
364  /* Should not be looking at display mode mask if
365     __glutDisplayString is non-NULL. */
366  assert(!__glutDisplayString);
367
368  *treatAsSingle = GLUT_WIND_IS_SINGLE(displayMode);
369  vis = getVisualInfo(displayMode);
370  if (!vis) {
371    /* Fallback cases when can't get exactly what was asked
372       for... */
373    if (GLUT_WIND_IS_SINGLE(displayMode)) {
374      /* If we can't find a single buffered visual, try looking
375         for a double buffered visual.  We can treat a double
376         buffered visual as a single buffer visual by changing
377         the draw buffer to GL_FRONT and treating any swap
378         buffers as no-ops. */
379      displayMode |= GLUT_DOUBLE;
380      vis = getVisualInfo(displayMode);
381      *treatAsSingle = True;
382    }
383    if (!vis && GLUT_WIND_IS_MULTISAMPLE(displayMode)) {
384      /* If we can't seem to get multisampling (ie, not Reality
385         Engine class graphics!), go without multisampling.  It
386         is up to the application to query how many multisamples
387         were allocated (0 equals no multisampling) if the
388         application is going to use multisampling for more than
389         just antialiasing. */
390      displayMode &= ~GLUT_MULTISAMPLE;
391      vis = getVisualInfo(displayMode);
392    }
393  }
394  return vis;
395}
396
397void GLUTCALLBACK
398__glutDefaultDisplay(void)
399{
400  /* XXX Remove the warning after GLUT 3.0. */
401  __glutWarning("The following is a new check for GLUT 3.0; update your code.");
402  __glutFatalError(
403    "redisplay needed for window %d, but no display callback.",
404    __glutCurrentWindow->num + 1);
405}
406
407void GLUTCALLBACK
408__glutDefaultReshape(int width, int height)
409{
410  GLUToverlay *overlay;
411
412  /* Adjust the viewport of the window (and overlay if one
413     exists). */
414  MAKE_CURRENT_WINDOW(__glutCurrentWindow);
415  glViewport(0, 0, (GLsizei) width, (GLsizei) height);
416  overlay = __glutCurrentWindow->overlay;
417  if (overlay) {
418    MAKE_CURRENT_OVERLAY(overlay);
419    glViewport(0, 0, (GLsizei) width, (GLsizei) height);
420  }
421  /* Make sure we are current to the current layer (application
422     should be able to count on the current layer not changing
423     unless the application explicitly calls glutUseLayer). */
424  MAKE_CURRENT_LAYER(__glutCurrentWindow);
425}
426
427XVisualInfo *
428__glutDetermineWindowVisual(Bool * treatAsSingle, Bool * visAlloced, void **fbc)
429{
430  if (__glutDisplayString) {
431
432    /* __glutDisplayString should be NULL except if
433       glutInitDisplayString has been called to register a
434       different display string.  Calling glutInitDisplayString
435       means using a string instead of an integer mask determine
436       the visual to use. Using the function pointer variable
437       __glutDetermineVisualFromString below avoids linking in
438       the code for implementing glutInitDisplayString (ie,
439       glut_dstr.o) unless glutInitDisplayString gets called by
440       the application. */
441
442    assert(__glutDetermineVisualFromString);
443    *visAlloced = False;
444    *fbc = NULL;
445    return __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
446      requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, fbc);
447  } else {
448    *visAlloced = True;
449    *fbc = NULL;
450    return __glutDetermineVisual(__glutDisplayMode,
451      treatAsSingle, __glutGetVisualInfo);
452  }
453}
454
455/* ARGSUSED5 */  /* Only Win32 uses gameMode parameter. */
456GLUTwindow *
457__glutCreateWindow(GLUTwindow * parent,
458  int x, int y, int width, int height, int gameMode)
459{
460  GLUTwindow *window;
461  XSetWindowAttributes wa;
462  unsigned long attribMask;
463  int winnum;
464  int i;
465  XClassHint *hints;
466#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
467  GLXFBConfigSGIX fbc;
468#else
469  void *fbc;
470#endif
471
472#if defined(_WIN32)
473  WNDCLASS wc;
474  int style;
475
476  if (!GetClassInfo(GetModuleHandle(NULL), "GLUT", &wc)) {
477    __glutOpenWin32Connection(NULL);
478  }
479#else
480  if (!__glutDisplay) {
481    __glutOpenXConnection(NULL);
482  }
483#endif
484  if (__glutGameModeWindow) {
485    __glutFatalError("cannot create windows in game mode.");
486  }
487  winnum = getUnusedWindowSlot();
488  window = (GLUTwindow *) malloc(sizeof(GLUTwindow));
489  if (!window) {
490    __glutFatalError("out of memory.");
491  }
492  window->num = winnum;
493
494#if !defined(_WIN32)
495  window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
496    &window->visAlloced, (void**) &fbc);
497  if (!window->vis) {
498    __glutFatalError(
499      "visual with necessary capabilities not found.");
500  }
501  __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
502#endif
503  window->eventMask = StructureNotifyMask | ExposureMask;
504
505  attribMask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
506  wa.background_pixmap = None;
507  wa.border_pixel = 0;
508  wa.colormap = window->cmap;
509  wa.event_mask = window->eventMask;
510  if (parent) {
511    if (parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
512      wa.event_mask |= GLUT_HACK_STOP_PROPAGATE_MASK;
513    attribMask |= CWDontPropagate;
514    wa.do_not_propagate_mask = parent->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
515  } else {
516    wa.do_not_propagate_mask = 0;
517  }
518
519  /* Stash width and height before Win32's __glutAdjustCoords
520     possibly overwrites the values. */
521  window->width = width;
522  window->height = height;
523  window->forceReshape = True;
524  window->ignoreKeyRepeat = False;
525
526#if defined(_WIN32)
527  __glutAdjustCoords(parent ? parent->win : NULL,
528    &x, &y, &width, &height);
529  if (parent) {
530    style = WS_CHILD;
531  } else {
532    if (gameMode) {
533      /* Game mode window should be a WS_POPUP window to
534         ensure that the taskbar is hidden by it.  A standard
535         WS_OVERLAPPEDWINDOW does not hide the task bar. */
536      style = WS_POPUP | WS_MAXIMIZE;
537    } else {
538      /* A standard toplevel window with borders and such. */
539      style = WS_OVERLAPPEDWINDOW;
540    }
541  }
542  window->win = CreateWindow("GLUT", "GLUT",
543    WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
544    x, y, width, height, parent ? parent->win : __glutRoot,
545    NULL, GetModuleHandle(NULL), 0);
546  window->hdc = GetDC(window->win);
547  /* Must set the XHDC for fake glXChooseVisual & fake
548     glXCreateContext & fake XAllocColorCells. */
549  XHDC = window->hdc;
550  window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
551    &window->visAlloced, &fbc);
552  if (!window->vis) {
553    __glutFatalError(
554      "pixel format with necessary capabilities not found.");
555  }
556  if (!SetPixelFormat(window->hdc,
557      ChoosePixelFormat(window->hdc, window->vis),
558      window->vis)) {
559    __glutFatalError("SetPixelFormat failed during window create.");
560  }
561  __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
562  /* Make sure subwindows get a windowStatus callback. */
563  if (parent) {
564    PostMessage(parent->win, WM_ACTIVATE, 0, 0);
565  }
566  window->renderDc = window->hdc;
567#else
568  window->win = XCreateWindow(__glutDisplay,
569    parent == NULL ? __glutRoot : parent->win,
570    x, y, width, height, 0,
571    window->vis->depth, InputOutput, window->vis->visual,
572    attribMask, &wa);
573   
574    hints = XAllocClassHint();
575    hints->res_class = __glutProgramName;
576    hints->res_name = __glutProgramName;
577    XSetClassHint(__glutDisplay,  window->win, hints);
578
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)
597  window->isDirect = glXIsDirect(__glutDisplay, window->ctx);
598  if (__glutForceDirect) {
599    if (!window->isDirect)
600      __glutFatalError("direct rendering not possible.");
601  }
602#endif
603
604  window->parent = parent;
605  if (parent) {
606    window->siblings = parent->children;
607    parent->children = window;
608  } else {
609    window->siblings = NULL;
610  }
611  window->overlay = NULL;
612  window->children = NULL;
613  window->display = __glutDefaultDisplay;
614  window->reshape = __glutDefaultReshape;
615  window->mouse = NULL;
616  window->motion = NULL;
617  window->passive = NULL;
618  window->entry = NULL;
619  window->keyboard = NULL;
620  window->keyboardUp = NULL;
621  window->windowStatus = NULL;
622  window->visibility = NULL;
623  window->special = NULL;
624  window->specialUp = NULL;
625  window->buttonBox = NULL;
626  window->dials = NULL;
627  window->spaceMotion = NULL;
628  window->spaceRotate = NULL;
629  window->spaceButton = NULL;
630  window->tabletMotion = NULL;
631  window->tabletButton = NULL;
632#ifdef _WIN32
633  window->joystick = NULL;
634  window->joyPollInterval = 0;
635#endif
636  window->tabletPos[0] = -1;
637  window->tabletPos[1] = -1;
638  window->shownState = 0;
639  window->visState = -1;  /* not VisibilityUnobscured,
640                             VisibilityPartiallyObscured, or
641                             VisibilityFullyObscured */
642  window->entryState = -1;  /* not EnterNotify or LeaveNotify */
643
644  window->desiredConfMask = 0;
645  window->buttonUses = 0;
646  window->cursor = GLUT_CURSOR_INHERIT;
647
648  /* Setup window to be mapped when glutMainLoop starts. */
649  window->workMask = GLUT_MAP_WORK;
650#ifdef _WIN32
651  if (gameMode) {
652    /* When mapping a game mode window, just show
653       the window.  We have already created the game
654       mode window with a maximize flag at creation
655       time.  Doing a ShowWindow(window->win, SW_SHOWNORMAL)
656       would be wrong for a game mode window since it
657       would unmaximize the window. */
658    window->desiredMapState = GameModeState;
659  } else {
660    window->desiredMapState = NormalState;
661  }
662#else
663  window->desiredMapState = NormalState;
664#endif
665  window->prevWorkWin = __glutWindowWorkList;
666  __glutWindowWorkList = window;
667
668  /* Initially, no menus attached. */
669  for (i = 0; i < GLUT_MAX_MENUS; i++) {
670    window->menu[i] = 0;
671  }
672
673  /* Add this new window to the window list. */
674  __glutWindowList[winnum] = window;
675
676  /* Make the new window the current window. */
677  __glutSetWindow(window);
678
679  __glutDetermineMesaSwapHackSupport();
680
681  if (window->treatAsSingle) {
682    /* We do this because either the window really is single
683       buffered (in which case this is redundant, but harmless,
684       because this is the initial single-buffered context
685       state); or we are treating a double buffered window as a
686       single-buffered window because the system does not appear
687       to export any suitable single- buffered visuals (in which
688       the following are necessary). */
689    glDrawBuffer(GL_FRONT);
690    glReadBuffer(GL_FRONT);
691  }
692  return window;
693}
694
695/* CENTRY */
696int APIENTRY
697glutCreateWindow(const char *title)
698{
699  static int firstWindow = 1;
700  GLUTwindow *window;
701#if !defined(_WIN32)
702  XWMHints *wmHints;
703#endif
704  Window win;
705  XTextProperty textprop;
706
707  if (__glutGameModeWindow) {
708    __glutFatalError("cannot create windows in game mode.");
709  }
710  window = __glutCreateWindow(NULL,
711    __glutSizeHints.x, __glutSizeHints.y,
712    __glutInitWidth, __glutInitHeight,
713    /* not game mode */ 0);
714  win = window->win;
715  /* Setup ICCCM properties. */
716  textprop.value = (unsigned char *) title;
717  textprop.encoding = XA_STRING;
718  textprop.format = 8;
719  textprop.nitems = strlen(title);
720#if defined(_WIN32)
721  SetWindowText(win, title);
722  if (__glutIconic) {
723    window->desiredMapState = IconicState;
724  }
725#else
726  wmHints = XAllocWMHints();
727  wmHints->initial_state =
728    __glutIconic ? IconicState : NormalState;
729  wmHints->flags = StateHint;
730  XSetWMProperties(__glutDisplay, win, &textprop, &textprop,
731  /* Only put WM_COMMAND property on first window. */
732    firstWindow ? __glutArgv : NULL,
733    firstWindow ? __glutArgc : 0,
734    &__glutSizeHints, wmHints, NULL);
735  XFree(wmHints);
736  XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
737#endif
738  firstWindow = 0;
739  return window->num + 1;
740}
741
742#ifdef _WIN32
743int APIENTRY
744__glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int))
745{
746  __glutExitFunc = exitfunc;
747  return glutCreateWindow(title);
748}
749#endif
750
751int APIENTRY
752glutCreateSubWindow(int win, int x, int y, int width, int height)
753{
754  GLUTwindow *window;
755
756  window = __glutCreateWindow(__glutWindowList[win - 1],
757    x, y, width, height, /* not game mode */ 0);
758#if !defined(_WIN32)
759  {
760    GLUTwindow *toplevel;
761
762    toplevel = __glutToplevelOf(window);
763    if (toplevel->cmap != window->cmap) {
764      __glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
765    }
766  }
767#endif
768  return window->num + 1;
769}
770/* ENDCENTRY */
771
772void
773__glutDestroyWindow(GLUTwindow * window,
774  GLUTwindow * initialWindow)
775{
776  GLUTwindow **prev, *cur, *parent, *siblings;
777
778  /* Recursively destroy any children. */
779  cur = window->children;
780  while (cur) {
781    siblings = cur->siblings;
782    __glutDestroyWindow(cur, initialWindow);
783    cur = siblings;
784  }
785  /* Remove from parent's children list (only necessary for
786     non-initial windows and subwindows!). */
787  parent = window->parent;
788  if (parent && parent == initialWindow->parent) {
789    prev = &parent->children;
790    cur = parent->children;
791    while (cur) {
792      if (cur == window) {
793        *prev = cur->siblings;
794        break;
795      }
796      prev = &(cur->siblings);
797      cur = cur->siblings;
798    }
799  }
800  /* Unbind if bound to this window. */
801  if (window == __glutCurrentWindow) {
802    UNMAKE_CURRENT();
803    __glutCurrentWindow = NULL;
804  }
805  /* Begin tearing down window itself. */
806  if (window->overlay) {
807    __glutFreeOverlayFunc(window->overlay);
808  }
809  XDestroyWindow(__glutDisplay, window->win);
810  glXDestroyContext(__glutDisplay, window->ctx);
811  if (window->colormap) {
812    /* Only color index windows have colormap data structure. */
813    __glutFreeColormap(window->colormap);
814  }
815  /* NULLing the __glutWindowList helps detect is a window
816     instance has been destroyed, given a window number. */
817  __glutWindowList[window->num] = NULL;
818
819  /* Cleanup data structures that might contain window. */
820  cleanWindowWorkList(window);
821#if !defined(_WIN32)
822  cleanStaleWindowList(window);
823#endif
824  /* Remove window from the "get window cache" if it is there. */
825  if (__glutWindowCache == window)
826    __glutWindowCache = NULL;
827
828  if (window->visAlloced) {
829    /* Only free XVisualInfo* gotten from glXChooseVisual. */
830    XFree(window->vis);
831  }
832
833  if (window == __glutGameModeWindow) {
834    /* Destroying the game mode window should implicitly
835       have GLUT leave game mode. */
836    __glutCloseDownGameMode();
837  }
838
839  free(window);
840}
841
842/* CENTRY */
843void APIENTRY
844glutDestroyWindow(int win)
845{
846  GLUTwindow *window = __glutWindowList[win - 1];
847
848  if (__glutMappedMenu && __glutMenuWindow == window) {
849    __glutFatalUsage("destroying menu window not allowed while menus in use");
850  }
851#if !defined(_WIN32)
852  /* If not a toplevel window... */
853  if (window->parent) {
854    /* Destroying subwindows may change colormap requirements;
855       recalculate toplevel window's WM_COLORMAP_WINDOWS
856       property. */
857    __glutPutOnWorkList(__glutToplevelOf(window->parent),
858      GLUT_COLORMAP_WORK);
859  }
860#endif
861  __glutDestroyWindow(window, window);
862  XFlush(__glutDisplay);
863}
864/* ENDCENTRY */
865
866void
867__glutChangeWindowEventMask(long eventMask, Bool add)
868{
869  if (add) {
870    /* Add eventMask to window's event mask. */
871    if ((__glutCurrentWindow->eventMask & eventMask) !=
872      eventMask) {
873      __glutCurrentWindow->eventMask |= eventMask;
874      __glutPutOnWorkList(__glutCurrentWindow,
875        GLUT_EVENT_MASK_WORK);
876    }
877  } else {
878    /* Remove eventMask from window's event mask. */
879    if (__glutCurrentWindow->eventMask & eventMask) {
880      __glutCurrentWindow->eventMask &= ~eventMask;
881      __glutPutOnWorkList(__glutCurrentWindow,
882        GLUT_EVENT_MASK_WORK);
883    }
884  }
885}
886
887void APIENTRY
888glutDisplayFunc(GLUTdisplayCB displayFunc)
889{
890  /* XXX Remove the warning after GLUT 3.0. */
891  if (!displayFunc)
892    __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
893  __glutCurrentWindow->display = displayFunc;
894}
895
896void APIENTRY
897glutMouseFunc(GLUTmouseCB mouseFunc)
898{
899  if (__glutCurrentWindow->mouse) {
900    if (!mouseFunc) {
901      /* Previous mouseFunc being disabled. */
902      __glutCurrentWindow->buttonUses--;
903      __glutChangeWindowEventMask(
904        ButtonPressMask | ButtonReleaseMask,
905        __glutCurrentWindow->buttonUses > 0);
906    }
907  } else {
908    if (mouseFunc) {
909      /* Previously no mouseFunc, new one being installed. */
910      __glutCurrentWindow->buttonUses++;
911      __glutChangeWindowEventMask(
912        ButtonPressMask | ButtonReleaseMask, True);
913    }
914  }
915  __glutCurrentWindow->mouse = mouseFunc;
916}
917
918void APIENTRY
919glutMotionFunc(GLUTmotionCB motionFunc)
920{
921  /* Hack.  Some window managers (4Dwm by default) will mask
922     motion events if the client is not selecting for button
923     press and release events. So we select for press and
924     release events too (being careful to use reference
925     counting).  */
926  if (__glutCurrentWindow->motion) {
927    if (!motionFunc) {
928      /* previous mouseFunc being disabled */
929      __glutCurrentWindow->buttonUses--;
930      __glutChangeWindowEventMask(
931        ButtonPressMask | ButtonReleaseMask,
932        __glutCurrentWindow->buttonUses > 0);
933    }
934  } else {
935    if (motionFunc) {
936      /* Previously no mouseFunc, new one being installed. */
937      __glutCurrentWindow->buttonUses++;
938      __glutChangeWindowEventMask(
939        ButtonPressMask | ButtonReleaseMask, True);
940    }
941  }
942  /* Real work of selecting for passive mouse motion.  */
943  __glutChangeWindowEventMask(
944    Button1MotionMask | Button2MotionMask | Button3MotionMask,
945    motionFunc != NULL);
946  __glutCurrentWindow->motion = motionFunc;
947}
948
949void APIENTRY
950glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc)
951{
952  __glutChangeWindowEventMask(PointerMotionMask,
953    passiveMotionFunc != NULL);
954
955  /* Passive motion also requires watching enters and leaves so
956     that a fake passive motion event can be generated on an
957     enter. */
958  __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
959    __glutCurrentWindow->entry != NULL || passiveMotionFunc != NULL);
960
961  __glutCurrentWindow->passive = passiveMotionFunc;
962}
963
964void APIENTRY
965glutEntryFunc(GLUTentryCB entryFunc)
966{
967  __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
968    entryFunc != NULL || __glutCurrentWindow->passive);
969  __glutCurrentWindow->entry = entryFunc;
970  if (!entryFunc) {
971    __glutCurrentWindow->entryState = -1;
972  }
973}
974
975void APIENTRY
976glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc)
977{
978  __glutChangeWindowEventMask(VisibilityChangeMask,
979    windowStatusFunc != NULL);
980  __glutCurrentWindow->windowStatus = windowStatusFunc;
981  if (!windowStatusFunc) {
982    /* Make state invalid. */
983    __glutCurrentWindow->visState = -1;
984  }
985}
986
987static void GLUTCALLBACK
988visibilityHelper(int status)
989{
990  if (status == GLUT_HIDDEN || status == GLUT_FULLY_COVERED)
991    __glutCurrentWindow->visibility(GLUT_NOT_VISIBLE);
992  else
993    __glutCurrentWindow->visibility(GLUT_VISIBLE);
994}
995
996void APIENTRY
997glutVisibilityFunc(GLUTvisibilityCB visibilityFunc)
998{
999  __glutCurrentWindow->visibility = visibilityFunc;
1000  if (visibilityFunc)
1001    glutWindowStatusFunc(visibilityHelper);
1002  else
1003    glutWindowStatusFunc(NULL);
1004}
1005
1006void APIENTRY
1007glutReshapeFunc(GLUTreshapeCB reshapeFunc)
1008{
1009  if (reshapeFunc) {
1010    __glutCurrentWindow->reshape = reshapeFunc;
1011  } else {
1012    __glutCurrentWindow->reshape = __glutDefaultReshape;
1013  }
1014}
Note: See TracBrowser for help on using the browser.