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