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