Polished off the say-nothing-new comments and lines-over-80-columns in
[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     return fgCreateWindow( NULL, title, fgState.Position.X, fgState.Position.Y,
579                            fgState.Size.X, fgState.Size.Y, FALSE )->ID;
580 }
581
582 /*
583  * This function creates a sub window.
584  */
585 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
586 {
587     SFG_Window* window = NULL;
588     SFG_Window* parent = NULL;
589
590     freeglut_assert_ready;
591     parent = fgWindowByID( parentID );
592     freeglut_return_val_if_fail( parent != NULL, 0 );
593     window = fgCreateWindow( parent, "", x, y, w, h, FALSE );
594     return window->ID;
595 }
596
597 /*
598  * Destroys a window and all of its subwindows
599  */
600 void FGAPIENTRY glutDestroyWindow( int windowID )
601 {
602     SFG_Window* window = fgWindowByID( windowID );
603     freeglut_return_if_fail( window != NULL );
604     {
605         fgExecutionState ExecState = fgState.ExecState;
606         fgAddToWindowDestroyList( window, TRUE );
607         fgState.ExecState = ExecState;
608     }
609 }
610
611 /*
612  * This function selects the current window
613  */
614 void FGAPIENTRY glutSetWindow( int ID )
615 {
616     SFG_Window* window = NULL;
617
618     freeglut_assert_ready;
619     if( fgStructure.Window != NULL )
620         if( fgStructure.Window->ID == ID )
621             return;
622
623     window = fgWindowByID( ID );
624     if( window == NULL )
625     {
626         fgWarning( "glutSetWindow(): window ID %i not found!", ID );
627         return;
628     }
629
630     fgSetWindow( window ) ;
631 }
632
633 /*
634  * This function returns the ID number of the current window, 0 if none exists
635  */
636 int FGAPIENTRY glutGetWindow( void )
637 {
638     freeglut_assert_ready;
639     if( fgStructure.Window == NULL )
640         return 0;
641     return fgStructure.Window->ID;
642 }
643
644 /*
645  * This function makes the current window visible
646  */
647 void FGAPIENTRY glutShowWindow( void )
648 {
649     freeglut_assert_ready;
650     freeglut_assert_window;
651
652 #if TARGET_HOST_UNIX_X11
653
654     XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
655     XFlush( fgDisplay.Display );
656
657 #elif TARGET_HOST_WIN32
658
659     ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
660
661 #endif
662
663     fgStructure.Window->State.Redisplay = TRUE;
664 }
665
666 /*
667  * This function hides the current window
668  */
669 void FGAPIENTRY glutHideWindow( void )
670 {
671     freeglut_assert_ready;
672     freeglut_assert_window;
673
674 #if TARGET_HOST_UNIX_X11
675
676     if( fgStructure.Window->Parent == NULL )
677         XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
678                          fgDisplay.Screen );
679     else
680         XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
681     XFlush( fgDisplay.Display );
682
683 #elif TARGET_HOST_WIN32
684
685     ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
686
687 #endif
688
689     fgStructure.Window->State.Redisplay = FALSE;
690 }
691
692 /*
693  * Iconify the current window (top-level windows only)
694  */
695 void FGAPIENTRY glutIconifyWindow( void )
696 {
697     freeglut_assert_ready;
698     freeglut_assert_window;
699
700 #if TARGET_HOST_UNIX_X11
701
702     XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
703                     fgDisplay.Screen );
704     XFlush( fgDisplay.Display );
705
706 #elif TARGET_HOST_WIN32
707
708     ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
709
710 #endif
711
712     fgStructure.Window->State.Redisplay = FALSE;
713 }
714
715 /*
716  * Set the current window's title
717  */
718 void FGAPIENTRY glutSetWindowTitle( const char* title )
719 {
720     freeglut_assert_ready;
721     freeglut_assert_window;
722     if( fgStructure.Window->Parent != NULL )
723         return;
724
725 #if TARGET_HOST_UNIX_X11
726
727     {
728         XTextProperty text;
729         
730         text.value = (unsigned char *) title;
731         text.encoding = XA_STRING;
732         text.format = 8;
733         text.nitems = strlen( title );
734         
735         XSetWMName(
736             fgDisplay.Display,
737             fgStructure.Window->Window.Handle,
738             &text
739         );
740         
741         XFlush( fgDisplay.Display );
742     }
743
744 #elif TARGET_HOST_WIN32
745
746     SetWindowText( fgStructure.Window->Window.Handle, title );
747
748 #endif
749
750 }
751
752 /*
753  * Set the current window's iconified title
754  */
755 void FGAPIENTRY glutSetIconTitle( const char* title )
756 {
757     freeglut_assert_ready;
758     freeglut_assert_window;
759
760     if( fgStructure.Window->Parent != NULL )
761         return;
762
763 #if TARGET_HOST_UNIX_X11
764
765     {
766         XTextProperty text;
767         
768         text.value = (unsigned char *) title;
769         text.encoding = XA_STRING;
770         text.format = 8;
771         text.nitems = strlen( title );
772
773         XSetWMIconName(
774             fgDisplay.Display,
775             fgStructure.Window->Window.Handle,
776             &text
777         );
778
779         XFlush( fgDisplay.Display );
780     }
781
782 #elif TARGET_HOST_WIN32
783
784         SetWindowText( fgStructure.Window->Window.Handle, title );
785
786 #endif
787
788 }
789
790 /*
791  * Change the current window's size
792  */
793 void FGAPIENTRY glutReshapeWindow( int width, int height )
794 {
795     freeglut_assert_ready;
796     freeglut_assert_window;
797
798 #if TARGET_HOST_UNIX_X11
799
800     XResizeWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
801                    width, height );
802     XFlush( fgDisplay.Display );
803
804 #elif TARGET_HOST_WIN32
805
806     {
807         RECT winRect;
808         int x, y;
809
810         GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
811         x = winRect.left;
812         y = winRect.top;
813
814         if ( fgStructure.Window->Parent == NULL )
815         {
816             /*
817              * Adjust the size of the window to allow for the size of the
818              * frame, if we are not a menu
819              */
820             if ( ! fgStructure.Window->IsMenu )
821             {
822                 width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
823                 height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 +
824                     GetSystemMetrics( SM_CYCAPTION );
825             }
826         }
827         else
828         {
829             GetWindowRect( fgStructure.Window->Parent->Window.Handle,
830                            &winRect );
831             x -= winRect.left + GetSystemMetrics( SM_CXSIZEFRAME );
832             y -= winRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) +
833                 GetSystemMetrics( SM_CYCAPTION );
834         }
835
836         MoveWindow(
837             fgStructure.Window->Window.Handle,
838             x,
839             y,
840             width,
841             height,
842             TRUE
843         );
844     }
845
846 #endif
847
848 }
849
850 /*
851  * Change the current window's position
852  */
853 void FGAPIENTRY glutPositionWindow( int x, int y )
854 {
855     freeglut_assert_ready;
856     freeglut_assert_window;
857
858 #if TARGET_HOST_UNIX_X11
859
860     XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, x, y );
861     XFlush( fgDisplay.Display );
862
863 #elif TARGET_HOST_WIN32
864
865     {
866         RECT winRect;
867         
868         GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
869         MoveWindow(
870             fgStructure.Window->Window.Handle,
871             x,
872             y,
873             winRect.right - winRect.left,
874             winRect.bottom - winRect.top,
875             TRUE
876         );
877     }
878
879 #endif
880
881 }
882
883 /*
884  * Lowers the current window (by Z order change)
885  */
886 void FGAPIENTRY glutPushWindow( void )
887 {
888     freeglut_assert_ready;
889     freeglut_assert_window;
890
891 #if TARGET_HOST_UNIX_X11
892
893     XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
894
895 #elif TARGET_HOST_WIN32
896
897     SetWindowPos(
898         fgStructure.Window->Window.Handle,
899         HWND_BOTTOM,
900         0, 0, 0, 0,
901         SWP_NOSIZE | SWP_NOMOVE
902     );
903
904 #endif
905
906 }
907
908 /*
909  * Raises the current window (by Z order change)
910  */
911 void FGAPIENTRY glutPopWindow( void )
912 {
913     freeglut_assert_ready;
914     freeglut_assert_window;
915
916 #if TARGET_HOST_UNIX_X11
917
918     XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
919
920 #elif TARGET_HOST_WIN32
921
922     SetWindowPos(
923         fgStructure.Window->Window.Handle,
924         HWND_TOP,
925         0, 0, 0, 0,
926         SWP_NOSIZE | SWP_NOMOVE
927     );
928
929 #endif
930
931 }
932
933 /*
934  * Resize the current window so that it fits the whole screen
935  */
936 void FGAPIENTRY glutFullScreen( void )
937 {
938     freeglut_assert_ready;
939     freeglut_assert_window;
940
941 #if TARGET_HOST_UNIX_X11
942     {
943         int x, y;
944         Window w;
945
946         XMoveResizeWindow(
947             fgDisplay.Display,
948             fgStructure.Window->Window.Handle,
949             0, 0,
950             fgDisplay.ScreenWidth,
951             fgDisplay.ScreenHeight
952         );
953         XFlush( fgDisplay.Display );
954
955         XTranslateCoordinates(
956             fgDisplay.Display,
957             fgStructure.Window->Window.Handle,
958             fgDisplay.RootWindow,
959             0, 0, &x, &y, &w
960         );
961
962         if (x || y)
963         {
964             XMoveWindow(
965                 fgDisplay.Display,
966                 fgStructure.Window->Window.Handle,
967                 -x, -y
968             );
969             XFlush( fgDisplay.Display );
970         }
971     }
972 #elif TARGET_HOST_WIN32
973     MoveWindow(
974         fgStructure.Window->Window.Handle,
975         0, 0,
976         fgDisplay.ScreenWidth,
977         fgDisplay.ScreenHeight,
978         TRUE
979     );
980 #endif
981 }
982
983 /*
984  * A.Donev: Set and retrieve the window's user data
985  */
986 void* FGAPIENTRY glutGetWindowData( void )
987 {
988     return fgStructure.Window->UserData;
989 }
990
991 void FGAPIENTRY glutSetWindowData(void* data)
992 {
993     fgStructure.Window->UserData=data;
994 }
995
996 /*** END OF FILE ***/