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