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