f4d50e1105564c432eb3921967e88192de9fe7b0
[freeglut] / src / x11 / freeglut_window_x11.c
1 /*\r
2  * freeglut_window_x11.c\r
3  *\r
4  * Window management methods for X11\r
5  *\r
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.\r
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>\r
8  * Copied for Platform code by Evan Felix <karcaw at gmail.com>\r
9  * Creation date: Thur Feb 2 2012\r
10  *\r
11  * Permission is hereby granted, free of charge, to any person obtaining a\r
12  * copy of this software and associated documentation files (the "Software"),\r
13  * to deal in the Software without restriction, including without limitation\r
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
15  * and/or sell copies of the Software, and to permit persons to whom the\r
16  * Software is furnished to do so, subject to the following conditions:\r
17  *\r
18  * The above copyright notice and this permission notice shall be included\r
19  * in all copies or substantial portions of the Software.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
24  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
25  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
27  */\r
28 \r
29 #define FREEGLUT_BUILDING_LIB\r
30 #include <GL/freeglut.h>\r
31 #include <limits.h>  /* LONG_MAX */\r
32 #include <unistd.h>  /* usleep */\r
33 #include "../Common/freeglut_internal.h"\r
34 \r
35 /* pushing attribute/value pairs into an array */\r
36 #define ATTRIB(a) attributes[where++]=(a)\r
37 #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}\r
38 \r
39 \r
40 #ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB\r
41 #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2\r
42 #endif\r
43 \r
44 #ifndef GLX_CONTEXT_MAJOR_VERSION_ARB\r
45 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091\r
46 #endif\r
47 \r
48 #ifndef GLX_CONTEXT_MINOR_VERSION_ARB\r
49 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092\r
50 #endif\r
51 \r
52 #ifndef GLX_CONTEXT_FLAGS_ARB\r
53 #define GLX_CONTEXT_FLAGS_ARB 0x2094\r
54 #endif\r
55 \r
56 #ifndef GLX_CONTEXT_PROFILE_MASK_ARB\r
57 #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126\r
58 #endif\r
59 \r
60 #ifndef GLX_CONTEXT_DEBUG_BIT_ARB\r
61 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001\r
62 #endif\r
63 \r
64 #ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB\r
65 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002\r
66 #endif\r
67 \r
68 #ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB\r
69 #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001\r
70 #endif\r
71 \r
72 #ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB\r
73 #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002\r
74 #endif\r
75 \r
76 #ifndef GLX_RGBA_FLOAT_TYPE\r
77 #define GLX_RGBA_FLOAT_TYPE 0x20B9\r
78 #endif\r
79 \r
80 #ifndef GLX_RGBA_FLOAT_BIT\r
81 #define GLX_RGBA_FLOAT_BIT 0x00000004\r
82 #endif\r
83 \r
84 \r
85 /*\r
86  * Chooses a visual basing on the current display mode settings\r
87  */\r
88 \r
89 GLXFBConfig* fgPlatformChooseFBConfig( int *numcfgs )\r
90 {\r
91   GLboolean wantIndexedMode = GL_FALSE;\r
92   int attributes[ 100 ];\r
93   int where = 0, numAuxBuffers;\r
94 \r
95   /* First we have to process the display mode settings... */\r
96   if( fgState.DisplayMode & GLUT_INDEX ) {\r
97     ATTRIB_VAL( GLX_BUFFER_SIZE, 8 );\r
98     /*  Buffer size is selected later.  */\r
99 \r
100     ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT );\r
101     wantIndexedMode = GL_TRUE;\r
102   } else {\r
103     ATTRIB_VAL( GLX_RED_SIZE,   1 );\r
104     ATTRIB_VAL( GLX_GREEN_SIZE, 1 );\r
105     ATTRIB_VAL( GLX_BLUE_SIZE,  1 );\r
106     if( fgState.DisplayMode & GLUT_ALPHA ) {\r
107       ATTRIB_VAL( GLX_ALPHA_SIZE, 1 );\r
108     }\r
109   }\r
110 \r
111   if( fgState.DisplayMode & GLUT_DOUBLE ) {\r
112     ATTRIB_VAL( GLX_DOUBLEBUFFER, True );\r
113   }\r
114 \r
115   if( fgState.DisplayMode & GLUT_STEREO ) {\r
116     ATTRIB_VAL( GLX_STEREO, True );\r
117   }\r
118 \r
119   if( fgState.DisplayMode & GLUT_DEPTH ) {\r
120     ATTRIB_VAL( GLX_DEPTH_SIZE, 1 );\r
121   }\r
122 \r
123   if( fgState.DisplayMode & GLUT_STENCIL ) {\r
124     ATTRIB_VAL( GLX_STENCIL_SIZE, 1 );\r
125   }\r
126 \r
127   if( fgState.DisplayMode & GLUT_ACCUM ) {\r
128     ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 );\r
129     ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 );\r
130     ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 );\r
131     if( fgState.DisplayMode & GLUT_ALPHA ) {\r
132       ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 );\r
133     }\r
134   }\r
135 \r
136   numAuxBuffers = fghNumberOfAuxBuffersRequested();\r
137   if ( numAuxBuffers > 0 ) {\r
138     ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers );\r
139   }\r
140 \r
141   if( fgState.DisplayMode & GLUT_SRGB ) {\r
142     ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True );\r
143   }\r
144 \r
145   if (fgState.DisplayMode & GLUT_MULTISAMPLE) {\r
146     ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1);\r
147     ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber);\r
148   }\r
149 \r
150   /* Push a terminator at the end of the list */\r
151   ATTRIB( None );\r
152 \r
153     {\r
154         GLXFBConfig * fbconfigArray;  /*  Array of FBConfigs  */\r
155         GLXFBConfig * fbconfig;       /*  The FBConfig we want  */\r
156         int fbconfigArraySize;        /*  Number of FBConfigs in the array  */\r
157 \r
158 \r
159         /*  Get all FBConfigs that match "attributes".  */\r
160         fbconfigArray = glXChooseFBConfig( fgDisplay.pDisplay.Display,\r
161                                            fgDisplay.pDisplay.Screen,\r
162                                            attributes,\r
163                                            &fbconfigArraySize );\r
164 \r
165         if (fbconfigArray != NULL)\r
166         {\r
167             int result;  /* Returned by glXGetFBConfigAttrib, not checked. */\r
168 \r
169 \r
170             if( wantIndexedMode )\r
171             {\r
172                 /*\r
173                  * In index mode, we want the largest buffer size, i.e. visual\r
174                  * depth.  Here, FBConfigs are sorted by increasing buffer size\r
175                  * first, so FBConfigs with the largest size come last.\r
176                  */\r
177 \r
178                 int bufferSizeMin, bufferSizeMax;\r
179 \r
180                 /*  Get bufferSizeMin.  */\r
181                 result =\r
182                   glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,\r
183                                         fbconfigArray[0],\r
184                                         GLX_BUFFER_SIZE,\r
185                                         &bufferSizeMin );\r
186                 /*  Get bufferSizeMax.  */\r
187                 result =\r
188                   glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,\r
189                                         fbconfigArray[fbconfigArraySize - 1],\r
190                                         GLX_BUFFER_SIZE,\r
191                                         &bufferSizeMax );\r
192 \r
193                 if (bufferSizeMax > bufferSizeMin)\r
194                 {\r
195                     /* \r
196                      * Free and reallocate fbconfigArray, keeping only FBConfigs\r
197                      * with the largest buffer size.\r
198                      */\r
199                     XFree(fbconfigArray);\r
200 \r
201                     /*  Add buffer size token at the end of the list.  */\r
202                     where--;\r
203                     ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax );\r
204                     ATTRIB( None );\r
205 \r
206                     fbconfigArray = glXChooseFBConfig( fgDisplay.pDisplay.Display,\r
207                                                        fgDisplay.pDisplay.Screen,\r
208                                                        attributes,\r
209                                                        &fbconfigArraySize );\r
210                 }\r
211             }\r
212 \r
213             /*\r
214              * We now have an array of FBConfigs, the first one being the "best"\r
215              * one.  So we should return only this FBConfig:\r
216              *\r
217              * int fbconfigXID;\r
218              *\r
219              *  - pick the XID of the FBConfig we want\r
220              * result = glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,\r
221              *                                fbconfigArray[0],\r
222              *                                GLX_FBCONFIG_ID,\r
223              *                                &fbconfigXID );\r
224              *\r
225              * - free the array\r
226              * XFree(fbconfigArray);\r
227              *\r
228              * - reset "attributes" with the XID\r
229              * where = 0;\r
230              * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID );\r
231              * ATTRIB( None );\r
232              *\r
233              * - get our FBConfig only\r
234              * fbconfig = glXChooseFBConfig( fgDisplay.pDisplay.Display,\r
235              *                               fgDisplay.pDisplay.Screen,\r
236              *                               attributes,\r
237              *                               &fbconfigArraySize );\r
238              *\r
239              * However, for some configurations (for instance multisampling with\r
240              * Mesa 6.5.2 and ATI drivers), this does not work:\r
241              * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid\r
242              * XID.  Further investigation is needed.\r
243              *\r
244              * So, for now, we return the whole array of FBConfigs.  This should\r
245              * not produce any side effects elsewhere.\r
246              */\r
247             fbconfig = fbconfigArray;\r
248         }\r
249         else\r
250         {\r
251            fbconfig = NULL;\r
252         }\r
253 \r
254         if (numcfgs)\r
255                 *numcfgs = fbconfigArraySize;\r
256 \r
257         return fbconfig;\r
258     }\r
259 }\r
260 \r
261 \r
262 static void fghFillContextAttributes( int *attributes ) {\r
263   int where = 0, contextFlags, contextProfile;\r
264 \r
265   if ( !fghIsLegacyContextVersionRequested() ) {\r
266     ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );\r
267     ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );\r
268   }\r
269 \r
270   contextFlags =\r
271     fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) |\r
272     fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );\r
273   if ( contextFlags != 0 ) {\r
274     ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags );\r
275   }\r
276 \r
277   contextProfile =\r
278     fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) |\r
279     fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );\r
280   if ( contextProfile != 0 ) {\r
281     ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile );\r
282   }\r
283 \r
284   ATTRIB( 0 );\r
285 }\r
286 \r
287 typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config,\r
288                                                GLXContext share_list, Bool direct,\r
289                                                const int *attrib_list);\r
290 \r
291 static GLXContext fghCreateNewContext( SFG_Window* window )\r
292 {\r
293   /* for color model calculation */\r
294   int menu = ( window->IsMenu && !fgStructure.MenuContext );\r
295   int index_mode = ( fgState.DisplayMode & GLUT_INDEX );\r
296 \r
297   /* "classic" context creation */\r
298   Display *dpy = fgDisplay.pDisplay.Display;\r
299   GLXFBConfig config = *(window->Window.pContext.FBConfig);\r
300   int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE;\r
301   GLXContext share_list = NULL;\r
302   Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT );\r
303   GLXContext context;\r
304 \r
305   /* new context creation */\r
306   int attributes[9];\r
307   CreateContextAttribsProc createContextAttribs = (CreateContextAttribsProc) fgPlatformGetProcAddress( "glXCreateContextAttribsARB" );\r
308  \r
309   /* glXCreateContextAttribsARB not found, yet the user has requested the new context creation */\r
310   if ( !createContextAttribs && !fghIsLegacyContextRequested() ) {\r
311     fgWarning( "OpenGL >2.1 context requested but glXCreateContextAttribsARB is not available! Falling back to legacy context creation" );\r
312         fgState.MajorVersion = 2;\r
313         fgState.MinorVersion = 1;\r
314   }\r
315 \r
316   /* If nothing fancy has been required, simply use the old context creation GLX API entry */\r
317   if ( fghIsLegacyContextRequested() || !createContextAttribs )\r
318   {\r
319     context = glXCreateNewContext( dpy, config, render_type, share_list, direct );\r
320     if ( context == NULL ) {\r
321       fghContextCreationError();\r
322     }\r
323     return context;\r
324   }\r
325 \r
326   /* color index mode is not available anymore with OpenGL 3.0 */\r
327   if ( render_type == GLX_COLOR_INDEX_TYPE ) {\r
328     fgWarning( "color index mode is deprecated, using RGBA mode" );\r
329   }\r
330 \r
331   fghFillContextAttributes( attributes );\r
332 \r
333   context = createContextAttribs( dpy, config, share_list, direct, attributes );\r
334   if ( context == NULL ) {\r
335     fghContextCreationError();\r
336   }\r
337   return context;\r
338 }\r
339 \r
340 \r
341 #define _NET_WM_STATE_TOGGLE    2\r
342 static int fghResizeFullscrToggle(void)\r
343 {\r
344     XWindowAttributes attributes;\r
345 \r
346     if(glutGet(GLUT_FULL_SCREEN)) {\r
347         /* restore original window size */\r
348         SFG_Window *win = fgStructure.CurrentWindow;\r
349         fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;\r
350         fgStructure.CurrentWindow->State.Width  = win->State.pWState.OldWidth;\r
351         fgStructure.CurrentWindow->State.Height = win->State.pWState.OldHeight;\r
352 \r
353     } else {\r
354         /* resize the window to cover the entire screen */\r
355         XGetWindowAttributes(fgDisplay.pDisplay.Display,\r
356                 fgStructure.CurrentWindow->Window.Handle,\r
357                 &attributes);\r
358         \r
359         /*\r
360          * The "x" and "y" members of "attributes" are the window's coordinates\r
361          * relative to its parent, i.e. to the decoration window.\r
362          */\r
363         XMoveResizeWindow(fgDisplay.pDisplay.Display,\r
364                 fgStructure.CurrentWindow->Window.Handle,\r
365                 -attributes.x,\r
366                 -attributes.y,\r
367                 fgDisplay.ScreenWidth,\r
368                 fgDisplay.ScreenHeight);\r
369     }\r
370     return 0;\r
371 }\r
372 \r
373 static int fghEwmhFullscrToggle(void)\r
374 {\r
375     XEvent xev;\r
376     long evmask = SubstructureRedirectMask | SubstructureNotifyMask;\r
377 \r
378     if(!fgDisplay.pDisplay.State || !fgDisplay.pDisplay.StateFullScreen) {\r
379         return -1;\r
380     }\r
381 \r
382     xev.type = ClientMessage;\r
383     xev.xclient.window = fgStructure.CurrentWindow->Window.Handle;\r
384     xev.xclient.message_type = fgDisplay.pDisplay.State;\r
385     xev.xclient.format = 32;\r
386     xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE;\r
387     xev.xclient.data.l[1] = fgDisplay.pDisplay.StateFullScreen;\r
388     xev.xclient.data.l[2] = 0;  /* no second property to toggle */\r
389     xev.xclient.data.l[3] = 1;  /* source indication: application */\r
390     xev.xclient.data.l[4] = 0;  /* unused */\r
391 \r
392     if(!XSendEvent(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow, 0, evmask, &xev)) {\r
393         return -1;\r
394     }\r
395     return 0;\r
396 }\r
397 \r
398 static int fghToggleFullscreen(void)\r
399 {\r
400     /* first try the EWMH (_NET_WM_STATE) method ... */\r
401     if(fghEwmhFullscrToggle() != -1) {\r
402         return 0;\r
403     }\r
404 \r
405     /* fall back to resizing the window */\r
406     if(fghResizeFullscrToggle() != -1) {\r
407         return 0;\r
408     }\r
409     return -1;\r
410 }\r
411 \r
412 void fgPlatformSetWindow ( SFG_Window *window )\r
413 {\r
414     if ( window )\r
415     {\r
416         glXMakeContextCurrent(\r
417             fgDisplay.pDisplay.Display,\r
418             window->Window.Handle,\r
419             window->Window.Handle,\r
420             window->Window.Context\r
421         );\r
422     }\r
423 }\r
424 \r
425 static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg)\r
426 {\r
427     Window window = (Window)arg;\r
428     return (event->type == MapNotify) && (event->xmap.window == window);\r
429 }\r
430 \r
431 /*\r
432  * Opens a window. Requires a SFG_Window object created and attached\r
433  * to the freeglut structure. OpenGL context is created here.\r
434  */\r
435 void fgPlatformOpenWindow( SFG_Window* window, const char* title,\r
436                            GLboolean positionUse, int x, int y,\r
437                            GLboolean sizeUse, int w, int h,\r
438                            GLboolean gameMode, GLboolean isSubWindow )\r
439 {\r
440     XVisualInfo * visualInfo = NULL;\r
441     XSetWindowAttributes winAttr;\r
442     XTextProperty textProperty;\r
443     XSizeHints sizeHints;\r
444     XWMHints wmHints;\r
445     XEvent eventReturnBuffer; /* return buffer required for a call */\r
446     unsigned long mask;\r
447     int num_FBConfigs, i;\r
448     unsigned int current_DisplayMode = fgState.DisplayMode ;\r
449 \r
450     /* Save the display mode if we are creating a menu window */\r
451     if( window->IsMenu && ( ! fgStructure.MenuContext ) )\r
452         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;\r
453 \r
454     window->Window.pContext.FBConfig = fgPlatformChooseFBConfig( &num_FBConfigs );\r
455 \r
456     if( window->IsMenu && ( ! fgStructure.MenuContext ) )\r
457         fgState.DisplayMode = current_DisplayMode ;\r
458 \r
459     if( ! window->Window.pContext.FBConfig )\r
460     {\r
461         /*\r
462          * The "fgPlatformChooseFBConfig" returned a null meaning that the visual\r
463          * context is not available.\r
464          * Try a couple of variations to see if they will work.\r
465          */\r
466         if( !( fgState.DisplayMode & GLUT_DOUBLE ) )\r
467         {\r
468             fgState.DisplayMode |= GLUT_DOUBLE ;\r
469             window->Window.pContext.FBConfig = fgPlatformChooseFBConfig( &num_FBConfigs );\r
470             fgState.DisplayMode &= ~GLUT_DOUBLE;\r
471         }\r
472 \r
473         if( fgState.DisplayMode & GLUT_MULTISAMPLE )\r
474         {\r
475             fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;\r
476             window->Window.pContext.FBConfig = fgPlatformChooseFBConfig( &num_FBConfigs );\r
477             fgState.DisplayMode |= GLUT_MULTISAMPLE;\r
478         }\r
479     }\r
480 \r
481     FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.pContext.FBConfig != NULL,\r
482                                   "FBConfig with necessary capabilities not found", "fgOpenWindow" );\r
483 \r
484     /*  Get the X visual.  */\r
485     for (i = 0; i < num_FBConfigs; i++) {\r
486             visualInfo = glXGetVisualFromFBConfig( fgDisplay.pDisplay.Display,\r
487                                                    window->Window.pContext.FBConfig[i] );\r
488             if (visualInfo)\r
489                 break;\r
490     }\r
491 \r
492     FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL,\r
493                                   "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" );\r
494 \r
495     /*\r
496      * XXX HINT: the masks should be updated when adding/removing callbacks.\r
497      * XXX       This might speed up message processing. Is that true?\r
498      * XXX\r
499      * XXX A: Not appreciably, but it WILL make it easier to debug.\r
500      * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT\r
501      * XXX    turns off events that it doesn't need and is a whole lot\r
502      * XXX    more pleasant to trace.  (Think mouse-motion!  Tons of\r
503      * XXX    ``bonus'' GUI events stream in.)\r
504      */\r
505     winAttr.event_mask        =\r
506         StructureNotifyMask | SubstructureNotifyMask | ExposureMask |\r
507         ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |\r
508         VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |\r
509         PointerMotionMask | ButtonMotionMask;\r
510     winAttr.background_pixmap = None;\r
511     winAttr.background_pixel  = 0;\r
512     winAttr.border_pixel      = 0;\r
513 \r
514     winAttr.colormap = XCreateColormap(\r
515         fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow,\r
516         visualInfo->visual, AllocNone\r
517     );\r
518 \r
519     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;\r
520 \r
521     if( window->IsMenu || ( gameMode == GL_TRUE ) )\r
522     {\r
523         winAttr.override_redirect = True;\r
524         mask |= CWOverrideRedirect;\r
525     }\r
526 \r
527     if( ! positionUse )\r
528         x = y = -1; /* default window position */\r
529     if( ! sizeUse )\r
530         w = h = 300; /* default window size */\r
531 \r
532     window->Window.Handle = XCreateWindow(\r
533         fgDisplay.pDisplay.Display,\r
534         window->Parent == NULL ? fgDisplay.pDisplay.RootWindow :\r
535         window->Parent->Window.Handle,\r
536         x, y, w, h, 0,\r
537         visualInfo->depth, InputOutput,\r
538         visualInfo->visual, mask,\r
539         &winAttr\r
540     );\r
541 \r
542     /*\r
543      * The GLX context creation, possibly trying the direct context rendering\r
544      *  or else use the current context if the user has so specified\r
545      */\r
546 \r
547     if( window->IsMenu )\r
548     {\r
549         /*\r
550          * If there isn't already an OpenGL rendering context for menu\r
551          * windows, make one\r
552          */\r
553         if( !fgStructure.MenuContext )\r
554         {\r
555             fgStructure.MenuContext =\r
556                 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );\r
557             fgStructure.MenuContext->MContext = fghCreateNewContext( window );\r
558         }\r
559 \r
560         /* window->Window.Context = fgStructure.MenuContext->MContext; */\r
561         window->Window.Context = fghCreateNewContext( window );\r
562     }\r
563     else if( fgState.UseCurrentContext )\r
564     {\r
565         window->Window.Context = glXGetCurrentContext( );\r
566 \r
567         if( ! window->Window.Context )\r
568             window->Window.Context = fghCreateNewContext( window );\r
569     }\r
570     else\r
571         window->Window.Context = fghCreateNewContext( window );\r
572 \r
573 #if !defined( __FreeBSD__ ) && !defined( __NetBSD__ )\r
574     if(  !glXIsDirect( fgDisplay.pDisplay.Display, window->Window.Context ) )\r
575     {\r
576       if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )\r
577         fgError( "Unable to force direct context rendering for window '%s'",\r
578                  title );\r
579     }\r
580 #endif\r
581 \r
582     /*\r
583      * XXX Assume the new window is visible by default\r
584      * XXX Is this a  safe assumption?\r
585      */\r
586     window->State.Visible = GL_TRUE;\r
587 \r
588     sizeHints.flags = 0;\r
589     if ( positionUse )\r
590         sizeHints.flags |= USPosition;\r
591     if ( sizeUse )\r
592         sizeHints.flags |= USSize;\r
593 \r
594     /*\r
595      * Fill in the size hints values now (the x, y, width and height\r
596      * settings are obsolete, are there any more WMs that support them?)\r
597      * Unless the X servers actually stop supporting these, we should\r
598      * continue to fill them in.  It is *not* our place to tell the user\r
599      * that they should replace a window manager that they like, and which\r
600      * works, just because *we* think that it's not "modern" enough.\r
601      */\r
602     sizeHints.x      = x;\r
603     sizeHints.y      = y;\r
604     sizeHints.width  = w;\r
605     sizeHints.height = h;\r
606 \r
607     wmHints.flags = StateHint;\r
608     wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState;\r
609     /* Prepare the window and iconified window names... */\r
610     XStringListToTextProperty( (char **) &title, 1, &textProperty );\r
611 \r
612     XSetWMProperties(\r
613         fgDisplay.pDisplay.Display,\r
614         window->Window.Handle,\r
615         &textProperty,\r
616         &textProperty,\r
617         0,\r
618         0,\r
619         &sizeHints,\r
620         &wmHints,\r
621         NULL\r
622     );\r
623     XFree( textProperty.value );\r
624 \r
625     XSetWMProtocols( fgDisplay.pDisplay.Display, window->Window.Handle,\r
626                      &fgDisplay.pDisplay.DeleteWindow, 1 );\r
627 \r
628     glXMakeContextCurrent(\r
629         fgDisplay.pDisplay.Display,\r
630         window->Window.Handle,\r
631         window->Window.Handle,\r
632         window->Window.Context\r
633     );\r
634 \r
635     /* register extension events _before_ window is mapped */\r
636     #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H\r
637        fgRegisterDevices( fgDisplay.pDisplay.Display, &(window->Window.Handle) );\r
638     #endif\r
639 \r
640     XMapWindow( fgDisplay.pDisplay.Display, window->Window.Handle );\r
641 \r
642     XFree(visualInfo);\r
643 \r
644     if( !isSubWindow)\r
645         XPeekIfEvent( fgDisplay.pDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, (XPointer)(window->Window.Handle) );\r
646 }\r
647 \r
648 \r
649 /*\r
650  * Closes a window, destroying the frame and OpenGL context\r
651  */\r
652 void fgPlatformCloseWindow( SFG_Window* window )\r
653 {\r
654     if( window->Window.Context )\r
655         glXDestroyContext( fgDisplay.pDisplay.Display, window->Window.Context );\r
656     XFree( window->Window.pContext.FBConfig );\r
657 \r
658     if( window->Window.Handle ) {\r
659         XDestroyWindow( fgDisplay.pDisplay.Display, window->Window.Handle );\r
660     }\r
661     /* XFlush( fgDisplay.pDisplay.Display ); */ /* XXX Shouldn't need this */\r
662 }\r
663 \r
664 \r
665 /*\r
666  * This function makes the current window visible\r
667  */\r
668 void fgPlatformGlutShowWindow( void )\r
669 {\r
670     XMapWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );\r
671     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
672 }\r
673 \r
674 /*\r
675  * This function hides the current window\r
676  */\r
677 void fgPlatformGlutHideWindow( void )\r
678 {\r
679     if( fgStructure.CurrentWindow->Parent == NULL )\r
680         XWithdrawWindow( fgDisplay.pDisplay.Display,\r
681                          fgStructure.CurrentWindow->Window.Handle,\r
682                          fgDisplay.pDisplay.Screen );\r
683     else\r
684         XUnmapWindow( fgDisplay.pDisplay.Display,\r
685                       fgStructure.CurrentWindow->Window.Handle );\r
686     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
687 }\r
688 \r
689 /*\r
690  * Iconify the current window (top-level windows only)\r
691  */\r
692 void fgPlatformGlutIconifyWindow( void )\r
693 {\r
694     XIconifyWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,\r
695                     fgDisplay.pDisplay.Screen );\r
696     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
697 }\r
698 \r
699 /*\r
700  * Set the current window's title\r
701  */\r
702 void fgPlatformGlutSetWindowTitle( const char* title )\r
703 {\r
704     XTextProperty text;\r
705 \r
706     text.value = (unsigned char *) title;\r
707     text.encoding = XA_STRING;\r
708     text.format = 8;\r
709     text.nitems = strlen( title );\r
710 \r
711     XSetWMName(\r
712         fgDisplay.pDisplay.Display,\r
713         fgStructure.CurrentWindow->Window.Handle,\r
714         &text\r
715     );\r
716 \r
717     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
718 }\r
719 \r
720 /*\r
721  * Set the current window's iconified title\r
722  */\r
723 void fgPlatformGlutSetIconTitle( const char* title )\r
724 {\r
725     XTextProperty text;\r
726 \r
727     text.value = (unsigned char *) title;\r
728     text.encoding = XA_STRING;\r
729     text.format = 8;\r
730     text.nitems = strlen( title );\r
731 \r
732     XSetWMIconName(\r
733         fgDisplay.pDisplay.Display,\r
734         fgStructure.CurrentWindow->Window.Handle,\r
735         &text\r
736     );\r
737 \r
738     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
739 }\r
740 \r
741 /*\r
742  * Change the current window's position\r
743  */\r
744 void fgPlatformGlutPositionWindow( int x, int y )\r
745 {\r
746     XMoveWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,\r
747                  x, y );\r
748     XFlush( fgDisplay.pDisplay.Display ); /* XXX Shouldn't need this */\r
749 }\r
750 \r
751 /*\r
752  * Lowers the current window (by Z order change)\r
753  */\r
754 void fgPlatformGlutPushWindow( void )\r
755 {\r
756     XLowerWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );\r
757 }\r
758 \r
759 /*\r
760  * Raises the current window (by Z order change)\r
761  */\r
762 void fgPlatformGlutPopWindow( void )\r
763 {\r
764     XRaiseWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle );\r
765 }\r
766 \r
767 /*\r
768  * Resize the current window so that it fits the whole screen\r
769  */\r
770 void fgPlatformGlutFullScreen( SFG_Window *win )\r
771 {\r
772     if(!glutGet(GLUT_FULL_SCREEN)) {\r
773         if(fghToggleFullscreen() != -1) {\r
774             win->State.IsFullscreen = GL_TRUE;\r
775         }\r
776     }\r
777 }\r
778 \r
779 /*\r
780  * If we are fullscreen, resize the current window back to its original size\r
781  */\r
782 void fgPlatformGlutLeaveFullScreen( SFG_Window *win )\r
783 {\r
784     if(glutGet(GLUT_FULL_SCREEN)) {\r
785         if(fghToggleFullscreen() != -1) {\r
786             win->State.IsFullscreen = GL_FALSE;\r
787         }\r
788     }\r
789 }\r
790 \r
791 /*\r
792  * Toggle the window's full screen state.\r
793  */\r
794 void fgPlatformGlutFullScreenToggle( SFG_Window *win )\r
795 {\r
796     if(fghToggleFullscreen() != -1) {\r
797         win->State.IsFullscreen = !win->State.IsFullscreen;\r
798     }\r
799 }\r
800 \r