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