There is a problem with the way I did glutFullscreen() in my last commit.
[freeglut] / src / freeglut_window.c
1 /*
2  * freeglut_window.c
3  *
4  * Window management methods.
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8  * Creation date: Fri Dec 3 1999
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #define  G_LOG_DOMAIN  "freeglut-window"
33
34 #include "../include/GL/freeglut.h"
35 #include "freeglut_internal.h"
36
37 /*
38  * TODO BEFORE THE STABLE RELEASE:
39  *
40  *  fgChooseVisual()        -- OK, but what about glutInitDisplayString()?
41  *  fgSetupPixelFormat      -- ignores the display mode settings
42  *  fgOpenWindow()          -- check the Win32 version, -iconic handling!
43  *  fgCloseWindow()         -- check the Win32 version
44  *  glutCreateWindow()      -- see what happens when default position and size is {-1,-1}
45  *  glutCreateSubWindow()   -- see what happens when default position and size is {-1,-1}
46  *  glutDestroyWindow()     -- check the Win32 version
47  *  glutSetWindow()         -- check the Win32 version
48  *  glutGetWindow()         -- OK
49  *  glutSetWindowTitle()    -- check the Win32 version
50  *  glutSetIconTitle()      -- check the Win32 version
51  *  glutShowWindow()        -- check the Win32 version
52  *  glutHideWindow()        -- check the Win32 version
53  *  glutIconifyWindow()     -- check the Win32 version
54  *  glutReshapeWindow()     -- check the Win32 version
55  *  glutPositionWindow()    -- check the Win32 version
56  *  glutPushWindow()        -- check the Win32 version
57  *  glutPopWindow()         -- check the Win32 version
58  */
59
60 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
61
62 /*
63  * Chooses a visual basing on the current display mode settings
64  */
65 #if TARGET_HOST_UNIX_X11
66
67 XVisualInfo* fgChooseVisual( void )
68 {
69     int bufferSize[] = { 16, 12, 8, 4, 2, 1 };
70     GLboolean wantIndexedMode = FALSE;
71     int attributes[ 32 ];
72     int where = 0;
73
74     /*
75      * First we have to process the display mode settings...
76      */
77 #   define ATTRIB(a) attributes[where++]=a;
78
79     /*
80      * Decide if we want a true or indexed color visual:
81      */
82     if( !(fgState.DisplayMode & GLUT_INDEX) )
83     {
84         /*
85          * We are sure that there will be R, B and B components requested:
86          */
87         ATTRIB( GLX_RGBA       );
88         ATTRIB( GLX_RED_SIZE   ); ATTRIB( 1 );
89         ATTRIB( GLX_GREEN_SIZE ); ATTRIB( 1 );
90         ATTRIB( GLX_BLUE_SIZE  ); ATTRIB( 1 );
91
92         /*
93          * Check if the A component is required, too:
94          */
95         if( fgState.DisplayMode & GLUT_ALPHA )
96         {
97             ATTRIB( GLX_ALPHA_SIZE ); ATTRIB( 1 );
98         }
99     }
100     else
101     {
102         /*
103          * We've got an indexed color request
104          */
105         ATTRIB( GLX_BUFFER_SIZE ); ATTRIB( 8 );
106
107         /*
108          * Set the 'I want indexed mode' switch
109          */
110         wantIndexedMode = TRUE;
111     }
112
113     /*
114      * We can have double or single buffered contexts created
115      */
116     if( fgState.DisplayMode & GLUT_DOUBLE )
117     {
118         ATTRIB( GLX_DOUBLEBUFFER );
119     }
120
121     /*
122      * Stereoscopy seems a nice thing to have
123      */
124     if( fgState.DisplayMode & GLUT_STEREO )
125     {
126         ATTRIB( GLX_STEREO );
127     }
128
129     /*
130      * Depth buffer is almost always required
131      */
132     if( fgState.DisplayMode & GLUT_DEPTH )
133     {
134         ATTRIB( GLX_DEPTH_SIZE ); ATTRIB( 1 );
135     }
136
137     /*
138      * Stenciling support
139      */
140     if( fgState.DisplayMode & GLUT_STENCIL )
141     {
142         ATTRIB( GLX_STENCIL_SIZE ); ATTRIB( 1 );
143     }
144
145     /*
146      * And finally the accumulation buffers
147      */
148     if( fgState.DisplayMode & GLUT_ACCUM )
149     {
150         ATTRIB( GLX_ACCUM_RED_SIZE );   ATTRIB( 1 );
151         ATTRIB( GLX_ACCUM_GREEN_SIZE ); ATTRIB( 1 );
152         ATTRIB( GLX_ACCUM_BLUE_SIZE );  ATTRIB( 1 );
153
154         /*
155          * Check if the A component is required, too:
156          */
157         if( fgState.DisplayMode & GLUT_ALPHA )
158         {
159             ATTRIB( GLX_ACCUM_ALPHA_SIZE ); ATTRIB( 1 );
160         }
161     }
162
163     /*
164      * Push a null at the end of the list
165      */
166     ATTRIB( None );
167
168     /*
169      * OKi now, we've got two cases -- RGB(A) and index mode visuals
170      */
171     if( wantIndexedMode == FALSE )
172     {
173         /*
174          * The easier one. And more common, too.
175          */
176         return( glXChooseVisual( fgDisplay.Display, fgDisplay.Screen, attributes ) );
177     }
178     else
179     {
180         XVisualInfo* visualInfo;
181         int i;
182
183         /*
184          * In indexed mode, we need to check how many bits of depth can we achieve
185          */
186         for( i=0; i<6; i++ )
187         {
188
189             /*
190              * The GLX_BUFFER_SIZE value comes always first, so:
191              */
192             attributes[ 1 ] = bufferSize[ i ];
193
194             /*
195              * Check if such visual is possible
196              */
197             visualInfo = glXChooseVisual( fgDisplay.Display, fgDisplay.Screen, attributes );
198
199             /*
200              * The buffer size are sorted in descendant order, so choose the first:
201              */
202             if( visualInfo != NULL )
203                 return( visualInfo );
204         }
205
206         /*
207          * If we are still here, it means that the visual info was not found
208          */
209         return( NULL );
210     }
211 }
212 #endif
213
214 /*
215  * Setup the pixel format for a Win32 window
216  */
217 #if TARGET_HOST_WIN32
218 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, unsigned char layer_type )
219 {
220         PIXELFORMATDESCRIPTOR* ppfd, pfd;
221         int flags, pixelformat;
222
223         /*
224          * Check if the window seems valid
225          */
226         freeglut_return_val_if_fail( window != NULL, 0 );
227
228         /*
229          * The pixel format should allow us to draw to the window using OpenGL
230          */
231         flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
232         
233         /*
234          * It might be the case for us to use double buffering
235          */
236   if( fgState.DisplayMode & GLUT_DOUBLE )
237     flags |= PFD_DOUBLEBUFFER;
238
239   /*
240    * Specify which pixel format do we opt for...
241    */
242 #       pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )
243
244   pfd.nSize                             = sizeof(PIXELFORMATDESCRIPTOR);
245   pfd.nVersion                  = 1;
246   pfd.dwFlags                           = flags;
247   pfd.iPixelType                        = PFD_TYPE_RGBA;
248   pfd.cColorBits                        = 24;
249   pfd.cRedBits                  = 0;
250   pfd.cRedShift                 = 0;
251   pfd.cGreenBits                        = 0;
252   pfd.cGreenShift                       = 0;
253   pfd.cBlueBits                 = 0;
254   pfd.cBlueShift                        = 0;
255   pfd.cAlphaBits                        = 0;
256   pfd.cAlphaShift                       = 0;
257   pfd.cAccumBits                        = 0;
258   pfd.cAccumRedBits             = 0;
259   pfd.cAccumGreenBits           = 0;
260   pfd.cAccumBlueBits            = 0;
261   pfd.cAccumAlphaBits           = 0;
262 #if 0
263   pfd.cDepthBits                        = 32;
264   pfd.cStencilBits              = 0;
265 #else
266   pfd.cDepthBits                        = 24;
267   pfd.cStencilBits              = 8;
268 #endif
269   pfd.cAuxBuffers                       = 0;
270   pfd.iLayerType                        = layer_type;
271   pfd.bReserved                 = 0;
272   pfd.dwLayerMask                       = 0;
273   pfd.dwVisibleMask             = 0;
274   pfd.dwDamageMask              = 0;
275
276   /*
277    * Fill in the color bits...
278    */
279   pfd.cColorBits = (BYTE) GetDeviceCaps( window->Window.Device, BITSPIXEL );
280   ppfd = &pfd;
281
282         /*
283          * Choose the pixel format that matches our demand
284          */
285   pixelformat = ChoosePixelFormat( window->Window.Device, ppfd );
286         if( pixelformat == 0 )
287                 return( FALSE );
288
289         /*
290          * We might have been called to check if the pixel format exists only
291          */
292         if( checkOnly )
293                 return( TRUE );
294
295         /*
296          * Finally, set the window's pixel format
297          */
298         return ( SetPixelFormat( window->Window.Device, pixelformat, ppfd ) ) ;
299 }
300 #endif
301
302 /*
303  * Sets the OpenGL context and the fgStructure "Current Window" pointer to the window
304  * structure passed in.
305  */
306 void fgSetWindow ( SFG_Window *window )
307 {
308 #if TARGET_HOST_UNIX_X11
309   if ( window )
310   {
311     /*
312          * Make the selected window's GLX context the current one
313      */
314     glXMakeCurrent(
315         fgDisplay.Display,
316         window->Window.Handle,
317         window->Window.Context
318     );
319   }
320 #elif TARGET_HOST_WIN32
321         /*
322          * Release the previous' context's device context
323          */
324         if( fgStructure.Window != NULL )
325                 ReleaseDC( fgStructure.Window->Window.Handle, fgStructure.Window->Window.Device );
326
327   if ( window )
328   {
329         /*
330            * We will care about releasing the device context later
331            */
332         window->Window.Device = GetDC( window->Window.Handle );
333
334         /*
335            * Set the new current context:
336            */
337         wglMakeCurrent( 
338                 window->Window.Device, 
339                   window->Window.Context 
340         );
341   }
342 #endif
343
344     /*
345      * Remember that we have changed the current window state
346      */
347     fgStructure.Window = window;
348 }
349
350
351 /*
352  * Opens a window. Requires a SFG_Window object created and attached
353  * to the freeglut structure. OpenGL context is created here.
354  */
355 void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, int h, GLboolean gameMode, int isSubWindow )
356 {
357 #if TARGET_HOST_UNIX_X11
358     XSetWindowAttributes winAttr;
359     XTextProperty textProperty;
360     XSizeHints sizeHints;
361     XWMHints wmHints;
362     unsigned long mask;
363
364     freeglut_assert_ready;
365
366     /*
367      * Here we are upon the stage. Have the visual selected.
368      */
369     if ( fgState.BuildingAMenu )
370     {
371       /*
372        * If there isn't already an OpenGL rendering context for menu windows, make one
373        */
374       if ( !fgStructure.MenuContext )
375       {
376         unsigned int current_DisplayMode = fgState.DisplayMode ;
377         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ;
378         window->Window.VisualInfo = fgChooseVisual();
379         fgState.DisplayMode = current_DisplayMode ;
380       }
381       else
382         window->Window.VisualInfo = fgChooseVisual();
383     }
384     else
385       window->Window.VisualInfo = fgChooseVisual();
386
387     if ( ! window->Window.VisualInfo )
388     {
389       /*
390        * The "fgChooseVisual" returned a null meaning that the visual context is not available.
391        * Try a couple of variations to see if they will work.
392        */
393       if ( ! ( fgState.DisplayMode & GLUT_DOUBLE ) )
394       {
395         /*
396          * Single buffering--try it doubled
397          */
398         fgState.DisplayMode |= GLUT_DOUBLE ;
399         window->Window.VisualInfo = fgChooseVisual();
400         /* OK, we got a double-buffered window, but we only wanted
401          * single-buffered.  Clear the double-buffer flag now.
402          */
403         fgState.DisplayMode &= ~GLUT_DOUBLE ;
404       }
405
406       /*
407        * GLUT also checks for multi-sampling, but I don't see that anywhere else in FREEGLUT
408        * so I won't bother with it for the moment.
409        */
410     }
411
412     assert( window->Window.VisualInfo != NULL );
413
414     /*
415      * Have the windows attributes set
416      *
417      * HINT: the masks should be updated when adding/removing callbacks.
418      *       This might speed up message processing. Is that true?
419      */
420     winAttr.event_mask        = StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
421                                 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyRelease |
422                                 VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
423                                 PointerMotionMask | ButtonMotionMask;
424     winAttr.background_pixmap = None;
425     winAttr.background_pixel  = 0;
426     winAttr.border_pixel      = 0;
427
428     /*
429      * The color map is required, too
430      */
431     winAttr.colormap = XCreateColormap(
432         fgDisplay.Display, fgDisplay.RootWindow,
433         window->Window.VisualInfo->visual, AllocNone
434     );
435
436     /*
437      * This tells the XCreateWindow() what attributes are we supplying it with
438      */
439     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
440
441     /*
442      * If this is a menu window we want the window manager to ignore it.
443      */
444     if ( fgState.BuildingAMenu )
445     {
446         winAttr.override_redirect = True;
447         mask |= CWOverrideRedirect;
448     }
449
450     /*
451      * Have the window created now
452      */
453     window->Window.Handle = XCreateWindow(
454         fgDisplay.Display,
455         window->Parent == NULL ? fgDisplay.RootWindow : window->Parent->Window.Handle,
456         x, y, w, h, 0,
457         window->Window.VisualInfo->depth, InputOutput,
458         window->Window.VisualInfo->visual, mask,
459         &winAttr
460     );
461
462     /*
463      * The GLX context creation, possibly trying the direct context rendering
464      *  or else use the current context if the user has so specified
465      */
466     if ( fgState.BuildingAMenu )
467     {
468       /*
469        * If there isn't already an OpenGL rendering context for menu windows, make one
470        */
471       if ( !fgStructure.MenuContext )
472       {
473         fgStructure.MenuContext = (SFG_MenuContext *)malloc ( sizeof(SFG_MenuContext) ) ;
474         fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo ;
475         fgStructure.MenuContext->Context = glXCreateContext(
476             fgDisplay.Display, fgStructure.MenuContext->VisualInfo,
477             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
478         );
479       }
480
481 /*      window->Window.Context = fgStructure.MenuContext->Context ; */
482       window->Window.Context = glXCreateContext(
483             fgDisplay.Display, window->Window.VisualInfo,
484             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
485         );
486     }
487     else if ( fgState.UseCurrentContext == TRUE )
488     {
489       window->Window.Context = glXGetCurrentContext();
490
491       if ( ! window->Window.Context )
492         window->Window.Context = glXCreateContext(
493             fgDisplay.Display, window->Window.VisualInfo,
494             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
495         );
496     }
497     else
498       window->Window.Context = glXCreateContext(
499           fgDisplay.Display, window->Window.VisualInfo,
500           NULL, fgState.ForceDirectContext | fgState.TryDirectContext
501       );
502
503     /*
504      * Make sure the context is direct when the user wants it forced
505      */
506     if( fgState.ForceDirectContext && !glXIsDirect( fgDisplay.Display, window->Window.Context ) )
507         fgError( "unable to force direct context rendering for window '%s'", title );
508
509     /*
510      * Set the new context as the current one. That's all about the window creation.
511      */
512     glXMakeCurrent(
513         fgDisplay.Display,
514         window->Window.Handle,
515         window->Window.Context
516     );
517
518     /*
519      * Assume the new window is visible by default
520      */
521     window->State.Visible = TRUE;
522
523     /*
524      * For the position and size hints -- make sure we are passing valid values
525      */
526     sizeHints.flags = 0;
527
528     if (fgState.Position.Use == TRUE) sizeHints.flags |= USPosition;
529     if (fgState.Size.Use     == TRUE) sizeHints.flags |= USSize;
530
531     /*
532      * Fill in the size hints values now (the x, y, width and height
533      * settings are obsolote, are there any more WMs that support them?)
534      */
535     sizeHints.x      = x; sizeHints.y      = y;
536     sizeHints.width  = w; sizeHints.height = h;
537
538     /*
539      * We can have forced all new windows start in iconified state:
540      */
541     wmHints.flags = StateHint;
542     wmHints.initial_state = (fgState.ForceIconic == FALSE) ? NormalState : IconicState;
543
544     /*
545      * Prepare the window and iconified window names...
546      */
547     XStringListToTextProperty( (char **) &title, 1, &textProperty );
548
549     /*
550      * Set the window's properties now
551      */
552     XSetWMProperties(
553         fgDisplay.Display,
554         window->Window.Handle,
555         &textProperty,
556         &textProperty,
557         0,
558         0,
559         &sizeHints,
560         &wmHints,
561         NULL
562     );
563
564     /*
565      * Make sure we are informed about the window deletion commands
566      */
567     XSetWMProtocols( fgDisplay.Display, window->Window.Handle, &fgDisplay.DeleteWindow, 1 );
568
569     /*
570      * Finally, have the window mapped to our display
571      */
572     XMapWindow( fgDisplay.Display, window->Window.Handle );
573
574 #elif TARGET_HOST_WIN32
575
576         WNDCLASS wc;
577         int flags;
578         ATOM atom;
579
580     freeglut_assert_ready;
581
582         /*
583          * Grab the window class we have registered on glutInit():
584          */
585         atom = GetClassInfo( fgDisplay.Instance, "FREEGLUT", &wc );
586         assert( atom != 0 );
587
588     if( gameMode == FALSE )
589     {
590       if ( ( !isSubWindow ) && ( ! window->IsMenu ) )
591       {
592         /*
593          * Update the window dimensions, taking account of window decorations.
594          * "freeglut" is to create the window with the outside of its border at (x,y)
595          * and with dimensions (w,h).
596          */
597                 w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2;
598                 h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 + GetSystemMetrics( SM_CYCAPTION );
599       }
600
601       /*
602              * Check if the user wants us to use the default position/size
603              */
604             if( fgState.Position.Use == FALSE ) { x = CW_USEDEFAULT; y = CW_USEDEFAULT; }
605             if( fgState.Size    .Use == FALSE ) { w = CW_USEDEFAULT; h = CW_USEDEFAULT; }
606
607             /*
608              * There's a small difference between creating the top, child and game mode windows
609              */
610             flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
611
612       /*
613        * If we're a menu, set our flags to include WS_POPUP to remove decorations
614        */
615       if ( window->IsMenu )
616         flags |= WS_POPUP ;
617             else if( window->Parent == NULL )
618                     flags |= WS_OVERLAPPEDWINDOW;
619             else
620                     flags |= WS_CHILD;
621     }
622     else
623     {
624         /*
625          * In game mode, the story is a little bit different...
626          */
627         assert( window->Parent == NULL );
628
629         /*
630          * Set the window creation flags appropriately to make the window entirely visible:
631          */
632         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
633     }
634
635     /*
636      * Create the window now, passing the freeglut window structure as the parameter
637      */
638         window->Window.Handle = CreateWindow( 
639                 "FREEGLUT",
640         title,
641                 flags,
642         x, y, w, h,
643                 (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
644                 (HMENU) NULL,
645                 fgDisplay.Instance,
646                 (LPVOID) window
647         );
648
649         /*
650      * Make sure window was created
651      */
652         assert( window->Window.Handle != NULL );
653
654     /*
655      * Show and update the main window. Hide the mouse cursor.
656      */
657     ShowWindow( window->Window.Handle, fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
658     UpdateWindow( window->Window.Handle );
659     ShowCursor( TRUE );
660
661 #endif
662
663     /*
664      * Save the window's single- or double-buffering state
665      */
666     window->Window.DoubleBuffered = ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0 ;
667
668     /*
669      * If it's not double-buffered, make sure the rendering is done to the front buffer.
670      */
671     if ( ! window->Window.DoubleBuffered )
672     {
673       glDrawBuffer ( GL_FRONT ) ;
674       glReadBuffer ( GL_FRONT ) ;
675     }
676
677     /*
678      * Set the newly created window as the current one
679      */
680     fgSetWindow( window );
681 }
682
683 /*
684  * Closes a window, destroying the frame and OpenGL context
685  */
686 void fgCloseWindow( SFG_Window* window )
687 {
688     freeglut_assert_ready;
689
690 #if TARGET_HOST_UNIX_X11
691     /*
692      * As easy as kill bunnies with axes. Destroy the context first:
693      */
694     glXDestroyContext( fgDisplay.Display, window->Window.Context );
695
696     /*
697      * Then have the window killed:
698      */
699     XDestroyWindow( fgDisplay.Display, window->Window.Handle );
700
701     /*
702      * Finally, flush the rests down the stream
703      */
704     XFlush( fgDisplay.Display );
705
706 #elif TARGET_HOST_WIN32
707         /*
708          * Send the WM_CLOSE message to the window now
709          */
710         SendMessage( 
711                 window->Window.Handle,
712                 WM_CLOSE,
713                 0,
714                 0
715         );
716
717 #endif
718 }
719
720
721 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
722
723 /*
724  * Creates a new top-level freeglut window
725  */
726 int FGAPIENTRY glutCreateWindow( const char* title )
727 {
728     /*
729      * Create a new window and return its unique ID number
730      */
731     return( fgCreateWindow( NULL, title, fgState.Position.X, fgState.Position.Y,
732                             fgState.Size.X, fgState.Size.Y, FALSE )->ID );
733 }
734
735 /*
736  * This function creates a sub window.
737  */
738 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
739 {
740     SFG_Window* window = NULL;
741     SFG_Window* parent = NULL;
742
743     freeglut_assert_ready;
744
745     /*
746      * Find a parent to the newly created window...
747      */
748     parent = fgWindowByID( parentID );
749
750     /*
751      * Fail if the parent has not been found
752      */
753     freeglut_return_val_if_fail( parent != NULL, 0 );
754
755     /*
756      * Create the new window
757      */
758     window = fgCreateWindow( parent, "", x, y, w, h, FALSE );
759
760     /*
761      * Return the new window's ID
762      */
763     return( window->ID );
764 }
765
766 /*
767  * Destroys a window and all of its subwindows
768  */
769 void FGAPIENTRY glutDestroyWindow( int windowID )
770 {
771   fgExecutionState ExecState = fgState.ExecState ;
772
773   /*
774    * Grab the freeglut window pointer from the structure
775    */
776   SFG_Window* window = fgWindowByID( windowID );
777   freeglut_return_if_fail( window != NULL );
778
779   /*
780    * There is a function that performs all needed steps
781    * defined in freeglut_structure.c. Let's use it:
782    */
783   fgAddToWindowDestroyList( window, TRUE );
784
785   /*
786    * Since the "fgAddToWindowDestroyList" function could easily have set the "ExecState"
787    * to stop, let's set it back to what it was.
788    */
789   fgState.ExecState = ExecState ;
790 }
791
792 /*
793  * This function selects the current window
794  */
795 void FGAPIENTRY glutSetWindow( int ID )
796 {
797     SFG_Window* window = NULL;
798
799     /*
800      * Make sure we don't get called too early
801      */
802     freeglut_assert_ready;
803
804     /*
805      * Be wise. Be wise. Be wise. Be quick.
806      */
807     if( fgStructure.Window != NULL )
808         if( fgStructure.Window->ID == ID )
809             return;
810
811     /*
812      * Now we are sure there is sense in looking for the window
813      */
814     window = fgWindowByID( ID );
815
816     /*
817      * In the case of an utter failure...
818      */
819     if( window == NULL )
820     {
821         /*
822          * ...issue a warning message and keep rolling on
823          */
824         fgWarning( "glutSetWindow(): window ID %i not found!", ID );
825         return;
826     }
827
828     fgSetWindow ( window ) ;
829 }
830
831 /*
832  * This function returns the ID number of the current window, 0 if none exists
833  */
834 int FGAPIENTRY glutGetWindow( void )
835 {
836     freeglut_assert_ready;
837
838     /*
839      * Do we have a current window selected?
840      */
841     if( fgStructure.Window == NULL )
842     {
843         /*
844          * Nope. Return zero to mark the state.
845          */
846         return( 0 );
847     }
848
849     /*
850      * Otherwise, return the ID of the current window
851      */
852     return( fgStructure.Window->ID );
853 }
854
855 /*
856  * This function makes the current window visible
857  */
858 void FGAPIENTRY glutShowWindow( void )
859 {
860     freeglut_assert_ready; freeglut_assert_window;
861
862 #if TARGET_HOST_UNIX_X11
863     /*
864      * Showing the window is done via mapping under X
865      */
866     XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
867     XFlush( fgDisplay.Display );
868
869 #elif TARGET_HOST_WIN32
870         /*
871          * Restore the window's originial position and size
872          */
873         ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
874
875 #endif
876
877   /*
878    * Since the window is visible, we need to redisplay it ...
879    */
880   fgStructure.Window->State.Redisplay = TRUE;
881
882 }
883
884 /*
885  * This function hides the current window
886  */
887 void FGAPIENTRY glutHideWindow( void )
888 {
889     freeglut_assert_ready; freeglut_assert_window;
890
891 #if TARGET_HOST_UNIX_X11
892     /*
893      * The way we hide a window depends on if we're dealing
894      * with a top-level or children one...
895      */
896     if( fgStructure.Window->Parent == NULL )
897     {
898         /*
899          * This is a top-level window
900          */
901         XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen );
902     }
903     else
904     {
905         /*
906          * Nope, it's a child window
907          */
908         XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
909     }
910
911     /*
912      * Flush the X state now
913      */
914     XFlush( fgDisplay.Display );
915
916 #elif TARGET_HOST_WIN32
917         /*
918          * Hide the window
919          */
920         ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
921
922 #endif
923
924   /*
925    * Since the window is hidden, we don't need to redisplay it ...
926    */
927   fgStructure.Window->State.Redisplay = FALSE;
928 }
929
930 /*
931  * Iconify the current window (top-level windows only)
932  */
933 void FGAPIENTRY glutIconifyWindow( void )
934 {
935     freeglut_assert_ready; freeglut_assert_window;
936
937 #if TARGET_HOST_UNIX_X11
938     /*
939      * Iconify the window and flush the X state
940      */
941     XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen );
942     XFlush( fgDisplay.Display );
943
944 #elif TARGET_HOST_WIN32
945         /*
946          * Minimize the current window (this should be the same as X window iconifying)
947          */
948         ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
949
950 #endif
951
952   /*
953    * Since the window is just an icon, we don't need to redisplay it ...
954    */
955   fgStructure.Window->State.Redisplay = FALSE;
956
957 }
958
959 /*
960  * Set the current window's title
961  */
962 void FGAPIENTRY glutSetWindowTitle( const char* title )
963 {
964         freeglut_assert_ready; freeglut_assert_window;
965
966     /*
967      * Works only for top-level windows
968      */
969     if( fgStructure.Window->Parent != NULL )
970         return;
971
972 #if TARGET_HOST_UNIX_X11
973         {
974                 XTextProperty text;
975
976                 /*
977                  * Prepare the text properties
978                  */
979                 text.value = (unsigned char *) title;
980                 text.encoding = XA_STRING;
981                 text.format = 8;
982                 text.nitems = strlen( title );
983
984                 /*
985                  * Set the title now
986                  */
987                 XSetWMName(
988                         fgDisplay.Display,
989                         fgStructure.Window->Window.Handle,
990                         &text
991                 );
992
993                 /*
994                  * Have the X display state flushed
995                  */
996                 XFlush( fgDisplay.Display );
997         }
998
999 #elif TARGET_HOST_WIN32
1000         /*
1001          * This seems to be a bit easier under Win32
1002          */
1003         SetWindowText( fgStructure.Window->Window.Handle, title );
1004
1005 #endif
1006 }
1007
1008 /*
1009  * Set the current window's iconified title
1010  */
1011 void FGAPIENTRY glutSetIconTitle( const char* title )
1012 {
1013     freeglut_assert_ready; freeglut_assert_window;
1014
1015     /*
1016      * Works only for top-level windows
1017      */
1018     if( fgStructure.Window->Parent != NULL )
1019         return;
1020
1021 #if TARGET_HOST_UNIX_X11
1022         {
1023                 XTextProperty text;
1024
1025                 /*
1026                  * Prepare the text properties
1027                  */
1028                 text.value = (unsigned char *) title;
1029                 text.encoding = XA_STRING;
1030                 text.format = 8;
1031                 text.nitems = strlen( title );
1032
1033                 /*
1034                  * Set the title now
1035                  */
1036                 XSetWMIconName(
1037                         fgDisplay.Display,
1038                         fgStructure.Window->Window.Handle,
1039                         &text
1040                 );
1041
1042                 /*
1043                  * Have the X display state flushed
1044                  */
1045                 XFlush( fgDisplay.Display );
1046         }
1047
1048 #elif TARGET_HOST_WIN32
1049         /*
1050          * This seems to be a bit easier under Win32
1051          */
1052         SetWindowText( fgStructure.Window->Window.Handle, title );
1053
1054 #endif
1055 }
1056
1057 /*
1058  * Change the current window's size
1059  */
1060 void FGAPIENTRY glutReshapeWindow( int width, int height )
1061 {
1062     freeglut_assert_ready; freeglut_assert_window;
1063
1064 #if TARGET_HOST_UNIX_X11
1065     /*
1066      * Resize the window and flush the X state
1067      */
1068     XResizeWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, width, height );
1069     XFlush( fgDisplay.Display );
1070
1071 #elif TARGET_HOST_WIN32
1072         {
1073                 RECT winRect;
1074     int x, y ;
1075
1076                 /*
1077                  * First off, grab the current window's position
1078                  */
1079                 GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
1080     x = winRect.left ;
1081     y = winRect.top ;
1082
1083     if ( fgStructure.Window->Parent == NULL )  /* If this is not a subwindow ... */
1084     {
1085       /*
1086        * Adjust the size of the window to allow for the size of the frame, if we are not a menu
1087        */
1088       if ( ! fgStructure.Window->IsMenu )
1089       {
1090                 width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
1091                 height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + GetSystemMetrics( SM_CYCAPTION );
1092       }
1093     }
1094     else  /* This is a subwindow, get the parent window's position and subtract it off */
1095     {
1096       GetWindowRect ( fgStructure.Window->Parent->Window.Handle, &winRect ) ;
1097       x -= winRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) ;
1098       y -= winRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ) ;
1099     }
1100
1101                 /*
1102                  * Resize the window, forcing a redraw to happen
1103                  */
1104                 MoveWindow(
1105                         fgStructure.Window->Window.Handle,
1106                         x,
1107                         y,
1108                         width,
1109                         height,
1110                         TRUE
1111                 );
1112         }
1113 #endif
1114 }
1115
1116 /*
1117  * Change the current window's position
1118  */
1119 void FGAPIENTRY glutPositionWindow( int x, int y )
1120 {
1121     freeglut_assert_ready; freeglut_assert_window;
1122
1123 #if TARGET_HOST_UNIX_X11
1124     /*
1125      * Reposition the window and flush the X state
1126      */
1127     XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, x, y );
1128     XFlush( fgDisplay.Display );
1129
1130 #elif TARGET_HOST_WIN32
1131         {
1132                 RECT winRect;
1133
1134                 /*
1135                  * First off, grab the current window's position
1136                  */
1137                 GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
1138
1139     /*
1140                  * Reposition the window, forcing a redraw to happen
1141                  */
1142                 MoveWindow(
1143                         fgStructure.Window->Window.Handle,
1144                         x,
1145                         y,
1146                         winRect.right - winRect.left,
1147                         winRect.bottom - winRect.top,
1148                         TRUE
1149                 );
1150         }
1151
1152 #endif
1153 }
1154
1155 /*
1156  * Lowers the current window (by Z order change)
1157  */
1158 void FGAPIENTRY glutPushWindow( void )
1159 {
1160     freeglut_assert_ready; freeglut_assert_window;
1161
1162 #if TARGET_HOST_UNIX_X11
1163     /*
1164      * Lower the current window
1165      */
1166     XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
1167
1168 #elif TARGET_HOST_WIN32
1169         /*
1170          * Set the new window's Z position, not affecting the rest of the settings:
1171          */
1172         SetWindowPos(
1173                 fgStructure.Window->Window.Handle,
1174                 HWND_BOTTOM,
1175                 0, 0, 0, 0,
1176                 SWP_NOSIZE | SWP_NOMOVE
1177         );
1178
1179 #endif
1180 }
1181
1182 /*
1183  * Raises the current window (by Z order change)
1184  */
1185 void FGAPIENTRY glutPopWindow( void )
1186 {
1187     freeglut_assert_ready; freeglut_assert_window;
1188
1189 #if TARGET_HOST_UNIX_X11
1190     /*
1191      * Raise the current window
1192      */
1193     XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
1194
1195 #elif TARGET_HOST_WIN32
1196         /*
1197          * Set the new window's Z position, not affecting the rest of the settings:
1198          */
1199         SetWindowPos(
1200                 fgStructure.Window->Window.Handle,
1201                 HWND_TOP,
1202                 0, 0, 0, 0,
1203                 SWP_NOSIZE | SWP_NOMOVE
1204         );
1205
1206 #endif
1207 }
1208
1209 /*
1210  * Resize the current window so that it fits the whole screen
1211  */
1212 void FGAPIENTRY glutFullScreen( void )
1213 {
1214     freeglut_assert_ready; freeglut_assert_window;
1215
1216 #if TARGET_HOST_UNIX_X11
1217     {
1218         int x, y;
1219         Window w;
1220
1221         XMoveResizeWindow(
1222             fgDisplay.Display,
1223             fgStructure.Window->Window.Handle,
1224             0, 0,
1225             fgDisplay.ScreenWidth,
1226             fgDisplay.ScreenHeight
1227         );
1228         XFlush( fgDisplay.Display );
1229
1230         XTranslateCoordinates(
1231             fgDisplay.Display,
1232             fgStructure.Window->Window.Handle,
1233             fgDisplay.RootWindow,
1234             0, 0, &x, &y, &w
1235         );
1236
1237         if (x || y)
1238         {
1239             XMoveWindow(
1240                 fgDisplay.Display,
1241                 fgStructure.Window->Window.Handle,
1242                 -x, -y
1243             );
1244             XFlush( fgDisplay.Display );
1245         }
1246     }
1247 #elif TARGET_HOST_WIN32
1248     MoveWindow(
1249         fgStructure.Window->Window.Handle,
1250         0, 0,
1251         fgDisplay.ScreenWidth,
1252         fgDisplay.ScreenHeight,
1253         TRUE
1254     );
1255 #endif
1256 }
1257
1258 /*
1259  * A.Donev: Set and retrieve the window's user data
1260  */
1261 void* FGAPIENTRY glutGetWindowData( void )
1262 {
1263    return(fgStructure.Window->UserData);
1264 }
1265
1266 void FGAPIENTRY glutSetWindowData(void* data)
1267 {
1268   fgStructure.Window->UserData=data;
1269 }
1270
1271 /*** END OF FILE ***/