Noted one of a few cases where we do something immediately that could more
[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 #include "../include/GL/freeglut.h"
33 #include "freeglut_internal.h"
34
35 /*
36  * TODO BEFORE THE STABLE RELEASE:
37  *
38  *  fgChooseVisual()        -- OK, but what about glutInitDisplayString()?
39  *  fgSetupPixelFormat      -- ignores the display mode settings
40  *  fgOpenWindow()          -- check the Win32 version, -iconic handling!
41  *  fgCloseWindow()         -- check the Win32 version
42  *  glutCreateWindow()      -- Check when default position and size is {-1,-1}
43  *  glutCreateSubWindow()   -- Check when default position and size is {-1,-1}
44  *  glutDestroyWindow()     -- check the Win32 version
45  *  glutSetWindow()         -- check the Win32 version
46  *  glutGetWindow()         -- OK
47  *  glutSetWindowTitle()    -- check the Win32 version
48  *  glutSetIconTitle()      -- check the Win32 version
49  *  glutShowWindow()        -- check the Win32 version
50  *  glutHideWindow()        -- check the Win32 version
51  *  glutIconifyWindow()     -- check the Win32 version
52  *  glutReshapeWindow()     -- check the Win32 version
53  *  glutPositionWindow()    -- check the Win32 version
54  *  glutPushWindow()        -- check the Win32 version
55  *  glutPopWindow()         -- check the Win32 version
56  */
57
58 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
59
60 /*
61  * Chooses a visual basing on the current display mode settings
62  */
63 #if TARGET_HOST_UNIX_X11
64
65 XVisualInfo* fgChooseVisual( void )
66 {
67 #define BUFFER_SIZES 6
68     int bufferSize[BUFFER_SIZES] = { 16, 12, 8, 4, 2, 1 };
69     GLboolean wantIndexedMode = FALSE;
70     int attributes[ 32 ];
71     int where = 0;
72
73     /*
74      * First we have to process the display mode settings...
75      */
76 /*
77  * Why is there a semi-colon in this #define?  The code
78  * that uses the macro seems to always add more semicolons...
79  */
80 #define ATTRIB(a) attributes[where++]=a;
81 #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}
82
83     if( fgState.DisplayMode & GLUT_INDEX )
84     {
85         ATTRIB_VAL( GLX_BUFFER_SIZE, 8 );
86         wantIndexedMode = TRUE;
87     }
88     else
89     {
90         ATTRIB( GLX_RGBA );
91         ATTRIB_VAL( GLX_RED_SIZE,   1 );
92         ATTRIB_VAL( GLX_GREEN_SIZE, 1 );
93         ATTRIB_VAL( GLX_BLUE_SIZE,  1 );
94         if( fgState.DisplayMode & GLUT_ALPHA )
95             ATTRIB_VAL( GLX_ALPHA_SIZE, 1 );
96     }
97
98     if( fgState.DisplayMode & GLUT_DOUBLE )
99         ATTRIB( GLX_DOUBLEBUFFER );
100
101     if( fgState.DisplayMode & GLUT_STEREO )
102         ATTRIB( GLX_STEREO );
103
104     if( fgState.DisplayMode & GLUT_DEPTH )
105         ATTRIB_VAL( GLX_DEPTH_SIZE, 1 );
106
107     if( fgState.DisplayMode & GLUT_STENCIL )
108         ATTRIB_VAL( GLX_STENCIL_SIZE, 1 );
109
110     if( fgState.DisplayMode & GLUT_ACCUM )
111     {
112         ATTRIB_VAL( GLX_ACCUM_RED_SIZE,   1 );
113         ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 );
114         ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE,  1 );
115         if( fgState.DisplayMode & GLUT_ALPHA )
116             ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 );
117     }
118
119     /*
120      * Push a null at the end of the list
121      */
122     ATTRIB( None );
123
124     if( wantIndexedMode == FALSE )
125         return glXChooseVisual( fgDisplay.Display, fgDisplay.Screen,
126                                 attributes );
127     else
128     {
129         XVisualInfo* visualInfo;
130         int i;
131
132         /*
133          * In indexed mode, we need to check how many bits of depth can we
134          * achieve.  We do this by trying each possibility from the list
135          * given in the {bufferSize} array.  If we match, we return to caller.
136          */
137         for( i=0; i<BUFFER_SIZES; i++ )
138         {
139             attributes[ 1 ] = bufferSize[ i ];
140             visualInfo = glXChooseVisual( fgDisplay.Display, fgDisplay.Screen,
141                                           attributes );
142             if( visualInfo != NULL )
143                 return visualInfo;
144         }
145         return NULL;
146     }
147 }
148 #endif
149
150 /*
151  * Setup the pixel format for a Win32 window
152  */
153 #if TARGET_HOST_WIN32
154 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
155                               unsigned char layer_type )
156 {
157     PIXELFORMATDESCRIPTOR* ppfd, pfd;
158     int flags, pixelformat;
159
160     freeglut_return_val_if_fail( window != NULL, 0 );
161     flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
162     if( fgState.DisplayMode & GLUT_DOUBLE )
163         flags |= PFD_DOUBLEBUFFER;
164
165 #pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )
166
167     /*
168      * Specify which pixel format do we opt for...
169      */
170     pfd.nSize           = sizeof(PIXELFORMATDESCRIPTOR);
171     pfd.nVersion        = 1;
172     pfd.dwFlags         = flags;
173     pfd.iPixelType      = PFD_TYPE_RGBA;
174     pfd.cColorBits      = 24;
175     pfd.cRedBits        = 0;
176     pfd.cRedShift       = 0;
177     pfd.cGreenBits      = 0;
178     pfd.cGreenShift     = 0;
179     pfd.cBlueBits       = 0;
180     pfd.cBlueShift      = 0;
181     pfd.cAlphaBits      = 0;
182     pfd.cAlphaShift     = 0;
183     pfd.cAccumBits      = 0;
184     pfd.cAccumRedBits   = 0;
185     pfd.cAccumGreenBits = 0;
186     pfd.cAccumBlueBits  = 0;
187     pfd.cAccumAlphaBits = 0;
188 #if 0
189     pfd.cDepthBits      = 32;
190     pfd.cStencilBits    = 0;
191 #else
192     pfd.cDepthBits      = 24;
193     pfd.cStencilBits    = 8;
194 #endif
195     pfd.cAuxBuffers     = 0;
196     pfd.iLayerType      = layer_type;
197     pfd.bReserved       = 0;
198     pfd.dwLayerMask     = 0;
199     pfd.dwVisibleMask   = 0;
200     pfd.dwDamageMask    = 0;
201
202     pfd.cColorBits = (BYTE) GetDeviceCaps( window->Window.Device, BITSPIXEL );
203     ppfd = &pfd;
204     
205     pixelformat = ChoosePixelFormat( window->Window.Device, ppfd );
206     if( pixelformat == 0 )
207         return FALSE;
208
209     if( checkOnly )
210         return TRUE;
211     return SetPixelFormat( window->Window.Device, pixelformat, ppfd );
212 }
213 #endif
214
215 /*
216  * Sets the OpenGL context and the fgStructure "Current Window" pointer to
217  * the window structure passed in.
218  */
219 void fgSetWindow ( SFG_Window *window )
220 {
221 #if TARGET_HOST_UNIX_X11
222     if ( window )
223         glXMakeCurrent(
224             fgDisplay.Display,
225             window->Window.Handle,
226             window->Window.Context
227         );
228 #elif TARGET_HOST_WIN32
229     if( fgStructure.Window )
230         ReleaseDC( fgStructure.Window->Window.Handle,
231                    fgStructure.Window->Window.Device );
232
233     if ( window )
234     {
235         window->Window.Device = GetDC( window->Window.Handle );
236         wglMakeCurrent( 
237             window->Window.Device, 
238             window->Window.Context
239         );
240     }
241 #endif
242     fgStructure.Window = window;
243 }
244
245
246 /*
247  * Opens a window. Requires a SFG_Window object created and attached
248  * to the freeglut structure. OpenGL context is created here.
249  */
250 void fgOpenWindow( SFG_Window* window, const char* title,
251                    int x, int y, int w, int h,
252                    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      * XXX fgChooseVisual() is a common part of all three.
265      * XXX With a little thought, we should be able to greatly
266      * XXX simplify this.
267      */
268     if ( !fgState.BuildingAMenu )
269       window->Window.VisualInfo = fgChooseVisual();
270     else if ( fgStructure.MenuContext )
271         window->Window.VisualInfo = fgChooseVisual();
272     else
273     {
274         unsigned int current_DisplayMode = fgState.DisplayMode ;
275         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ;
276         window->Window.VisualInfo = fgChooseVisual();
277         fgState.DisplayMode = current_DisplayMode ;
278     }
279
280     if ( ! window->Window.VisualInfo )
281     {
282         /*
283          * The "fgChooseVisual" returned a null meaning that the visual
284          * context is not available.
285          * Try a couple of variations to see if they will work.
286          */
287         if ( ! ( fgState.DisplayMode & GLUT_DOUBLE ) )
288         {
289             fgState.DisplayMode |= GLUT_DOUBLE ;
290             window->Window.VisualInfo = fgChooseVisual();
291             fgState.DisplayMode &= ~GLUT_DOUBLE ;
292         }
293         
294         /*
295          * GLUT also checks for multi-sampling, but I don't see that
296          * anywhere else in FREEGLUT so I won't bother with it for the moment.
297          */
298     }
299
300     assert( window->Window.VisualInfo != NULL );
301
302     /*
303      * XXX HINT: the masks should be updated when adding/removing callbacks.
304      * XXX       This might speed up message processing. Is that true?
305      * XXX
306      * XXX A: Not appreciably, but it WILL make it easier to debug.
307      * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT
308      * XXX    turns off events that it doesn't need and is a whole lot
309      * XXX    more pleasant to trace.  (Hint: Think mouse-motion!)
310      * XXX
311      * XXX    It may make a difference in networked environments or on
312      * XXX    some very slow systems, but I think that that is secondary
313      * XXX    to making debugging easier.
314      */
315     winAttr.event_mask        = StructureNotifyMask | SubstructureNotifyMask |
316         ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask |
317         KeyRelease | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
318         PointerMotionMask | ButtonMotionMask;
319     winAttr.background_pixmap = None;
320     winAttr.background_pixel  = 0;
321     winAttr.border_pixel      = 0;
322
323     winAttr.colormap = XCreateColormap(
324         fgDisplay.Display, fgDisplay.RootWindow,
325         window->Window.VisualInfo->visual, AllocNone
326     );
327
328     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
329
330     if ( fgState.BuildingAMenu )
331     {
332         winAttr.override_redirect = True;
333         mask |= CWOverrideRedirect;
334     }
335
336     window->Window.Handle = XCreateWindow(
337         fgDisplay.Display,
338         window->Parent == NULL ? fgDisplay.RootWindow :
339                                  window->Parent->Window.Handle,
340         x, y, w, h, 0,
341         window->Window.VisualInfo->depth, InputOutput,
342         window->Window.VisualInfo->visual, mask,
343         &winAttr
344     );
345
346     /*
347      * The GLX context creation, possibly trying the direct context rendering
348      *  or else use the current context if the user has so specified
349      */
350     if ( fgState.BuildingAMenu )
351     {
352         /*
353          * If there isn't already an OpenGL rendering context for menu
354          * windows, make one
355          */
356         if ( !fgStructure.MenuContext )
357         {
358             fgStructure.MenuContext =
359                 (SFG_MenuContext *)malloc ( sizeof(SFG_MenuContext) );
360             fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo;
361             fgStructure.MenuContext->Context = glXCreateContext(
362                 fgDisplay.Display, fgStructure.MenuContext->VisualInfo,
363                 NULL, fgState.ForceDirectContext | fgState.TryDirectContext
364             );
365         }
366
367 /*      window->Window.Context = fgStructure.MenuContext->Context ; */
368         window->Window.Context = glXCreateContext(
369             fgDisplay.Display, window->Window.VisualInfo,
370             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
371         );
372     }
373     else if ( fgState.UseCurrentContext == TRUE )
374     {
375       window->Window.Context = glXGetCurrentContext();
376
377       if ( ! window->Window.Context )
378         window->Window.Context = glXCreateContext(
379             fgDisplay.Display, window->Window.VisualInfo,
380             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
381         );
382     }
383     else
384         window->Window.Context = glXCreateContext(
385             fgDisplay.Display, window->Window.VisualInfo,
386             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
387         );
388
389     if( fgState.ForceDirectContext &&
390         !glXIsDirect( fgDisplay.Display, window->Window.Context ) )
391         fgError( "unable to force direct context rendering for window '%s'",
392                  title );
393
394     glXMakeCurrent(
395         fgDisplay.Display,
396         window->Window.Handle,
397         window->Window.Context
398     );
399
400     /*
401      * XXX Assume the new window is visible by default
402      * XXX Is this a  safe assumption?
403      */
404     window->State.Visible = TRUE;
405
406     sizeHints.flags = 0;
407     if (fgState.Position.Use == TRUE)
408         sizeHints.flags |= USPosition;
409     if (fgState.Size.Use     == TRUE)
410         sizeHints.flags |= USSize;
411
412     /*
413      * Fill in the size hints values now (the x, y, width and height
414      * settings are obsolote, are there any more WMs that support them?)
415      * Unless the X servers actually stop supporting these, we should
416      * continue to fill them in.  It is *not* our place to tell the user
417      * that they should replace a window manager that they like, and which
418      * works, just because *we* think that it's not "modern" enough.
419      */
420     sizeHints.x      = x;
421     sizeHints.y      = y;
422     sizeHints.width  = w;
423     sizeHints.height = h;
424
425     wmHints.flags = StateHint;
426     wmHints.initial_state =
427         (fgState.ForceIconic == FALSE) ? NormalState : IconicState;
428
429     /*
430      * Prepare the window and iconified window names...
431      */
432     XStringListToTextProperty( (char **) &title, 1, &textProperty );
433
434     XSetWMProperties(
435         fgDisplay.Display,
436         window->Window.Handle,
437         &textProperty,
438         &textProperty,
439         0,
440         0,
441         &sizeHints,
442         &wmHints,
443         NULL
444     );
445     XSetWMProtocols( fgDisplay.Display, window->Window.Handle,
446                      &fgDisplay.DeleteWindow, 1 );
447     XMapWindow( fgDisplay.Display, window->Window.Handle );
448
449 #elif TARGET_HOST_WIN32
450
451     WNDCLASS wc;
452     int flags;
453     ATOM atom;
454
455     freeglut_assert_ready;
456     
457     /*
458      * Grab the window class we have registered on glutInit():
459      */
460     atom = GetClassInfo( fgDisplay.Instance, "FREEGLUT", &wc );
461     assert( atom != 0 );
462     
463     if( gameMode != FALSE )
464     {
465         assert( window->Parent == NULL );
466
467         /*
468          * Set the window creation flags appropriately to make the window
469          * entirely visible:
470          */
471         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
472     }
473     else
474     {
475         if ( ( !isSubWindow ) && ( ! window->IsMenu ) )
476         {
477             /*
478              * Update the window dimensions, taking account of window
479              * decorations.  "freeglut" is to create the window with the
480              * outside of its border at (x,y) and with dimensions (w,h).
481              */
482             w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2;
483             h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 +
484                 GetSystemMetrics( SM_CYCAPTION );
485         }
486
487         if( fgState.Position.Use == FALSE )
488         {
489             x = CW_USEDEFAULT;
490             y = CW_USEDEFAULT;
491         }
492         if( fgState.Size.Use == FALSE )
493         {
494             w = CW_USEDEFAULT;
495             h = CW_USEDEFAULT;
496         }
497
498         /*
499          * There's a small difference between creating the top, child and
500          * game mode windows
501          */
502         flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
503
504         if ( window->IsMenu )
505             flags |= WS_POPUP ;
506         else if( window->Parent == NULL )
507             flags |= WS_OVERLAPPEDWINDOW;
508         else
509             flags |= WS_CHILD;
510     }
511
512     window->Window.Handle = CreateWindow( 
513         "FREEGLUT",
514         title,
515         flags,
516         x, y, w, h,
517         (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
518         (HMENU) NULL,
519         fgDisplay.Instance,
520         (LPVOID) window
521     );
522     if( !( window->Window.Handle ) )
523         fgError( "Failed to create a window (%s)!", title );
524
525     ShowWindow( window->Window.Handle,
526                 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
527     UpdateWindow( window->Window.Handle );
528     ShowCursor( TRUE );  /* XXX Old comments say "hide cusror"! */
529
530 #endif
531
532     window->Window.DoubleBuffered =
533         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0 ;
534
535     if ( ! window->Window.DoubleBuffered )
536     {
537         glDrawBuffer ( GL_FRONT ) ;
538         glReadBuffer ( GL_FRONT ) ;
539     }
540     fgSetWindow( window );
541 }
542
543 /*
544  * Closes a window, destroying the frame and OpenGL context
545  */
546 void fgCloseWindow( SFG_Window* window )
547 {
548     freeglut_assert_ready;
549
550 #if TARGET_HOST_UNIX_X11
551
552     glXDestroyContext( fgDisplay.Display, window->Window.Context );
553     XDestroyWindow( fgDisplay.Display, window->Window.Handle );
554     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
555
556 #elif TARGET_HOST_WIN32
557
558     SendMessage( 
559         window->Window.Handle,
560         WM_CLOSE,
561         0,
562         0
563     );
564
565 #endif
566 }
567
568
569 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
570
571 /*
572  * Creates a new top-level freeglut window
573  */
574 int FGAPIENTRY glutCreateWindow( const char* title )
575 {
576     return fgCreateWindow( NULL, title, fgState.Position.X, fgState.Position.Y,
577                            fgState.Size.X, fgState.Size.Y, FALSE )->ID;
578 }
579
580 /*
581  * This function creates a sub window.
582  */
583 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
584 {
585     SFG_Window* window = NULL;
586     SFG_Window* parent = NULL;
587
588     freeglut_assert_ready;
589     parent = fgWindowByID( parentID );
590     freeglut_return_val_if_fail( parent != NULL, 0 );
591     window = fgCreateWindow( parent, "", x, y, w, h, FALSE );
592     return window->ID;
593 }
594
595 /*
596  * Destroys a window and all of its subwindows
597  */
598 void FGAPIENTRY glutDestroyWindow( int windowID )
599 {
600     SFG_Window* window = fgWindowByID( windowID );
601     freeglut_return_if_fail( window != NULL );
602     {
603         fgExecutionState ExecState = fgState.ExecState;
604         fgAddToWindowDestroyList( window, TRUE );
605         fgState.ExecState = ExecState;
606     }
607 }
608
609 /*
610  * This function selects the current window
611  */
612 void FGAPIENTRY glutSetWindow( int ID )
613 {
614     SFG_Window* window = NULL;
615
616     freeglut_assert_ready;
617     if( fgStructure.Window != NULL )
618         if( fgStructure.Window->ID == ID )
619             return;
620
621     window = fgWindowByID( ID );
622     if( window == NULL )
623     {
624         fgWarning( "glutSetWindow(): window ID %i not found!", ID );
625         return;
626     }
627
628     fgSetWindow( window ) ;
629 }
630
631 /*
632  * This function returns the ID number of the current window, 0 if none exists
633  */
634 int FGAPIENTRY glutGetWindow( void )
635 {
636     freeglut_assert_ready;
637     if( fgStructure.Window == NULL )
638         return 0;
639     return fgStructure.Window->ID;
640 }
641
642 /*
643  * This function makes the current window visible
644  */
645 void FGAPIENTRY glutShowWindow( void )
646 {
647     freeglut_assert_ready;
648     freeglut_assert_window;
649
650 #if TARGET_HOST_UNIX_X11
651
652     XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
653     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
654
655 #elif TARGET_HOST_WIN32
656
657     ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
658
659 #endif
660
661     fgStructure.Window->State.Redisplay = TRUE;
662 }
663
664 /*
665  * This function hides the current window
666  */
667 void FGAPIENTRY glutHideWindow( void )
668 {
669     freeglut_assert_ready;
670     freeglut_assert_window;
671
672 #if TARGET_HOST_UNIX_X11
673
674     if( fgStructure.Window->Parent == NULL )
675         XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
676                          fgDisplay.Screen );
677     else
678         XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
679     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
680
681 #elif TARGET_HOST_WIN32
682
683     ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
684
685 #endif
686
687     fgStructure.Window->State.Redisplay = FALSE;
688 }
689
690 /*
691  * Iconify the current window (top-level windows only)
692  */
693 void FGAPIENTRY glutIconifyWindow( void )
694 {
695     freeglut_assert_ready;
696     freeglut_assert_window;
697
698 #if TARGET_HOST_UNIX_X11
699
700     XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
701                     fgDisplay.Screen );
702     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
703
704 #elif TARGET_HOST_WIN32
705
706     ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
707
708 #endif
709
710     fgStructure.Window->State.Redisplay = FALSE;
711 }
712
713 /*
714  * Set the current window's title
715  */
716 void FGAPIENTRY glutSetWindowTitle( const char* title )
717 {
718     freeglut_assert_ready;
719     freeglut_assert_window;
720     if( fgStructure.Window->Parent != NULL )
721         return;
722
723 #if TARGET_HOST_UNIX_X11
724
725     {
726         XTextProperty text;
727         
728         text.value = (unsigned char *) title;
729         text.encoding = XA_STRING;
730         text.format = 8;
731         text.nitems = strlen( title );
732         
733         XSetWMName(
734             fgDisplay.Display,
735             fgStructure.Window->Window.Handle,
736             &text
737         );
738         
739         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
740     }
741
742 #elif TARGET_HOST_WIN32
743
744     SetWindowText( fgStructure.Window->Window.Handle, title );
745
746 #endif
747
748 }
749
750 /*
751  * Set the current window's iconified title
752  */
753 void FGAPIENTRY glutSetIconTitle( const char* title )
754 {
755     freeglut_assert_ready;
756     freeglut_assert_window;
757
758     if( fgStructure.Window->Parent != NULL )
759         return;
760
761 #if TARGET_HOST_UNIX_X11
762
763     {
764         XTextProperty text;
765         
766         text.value = (unsigned char *) title;
767         text.encoding = XA_STRING;
768         text.format = 8;
769         text.nitems = strlen( title );
770
771         XSetWMIconName(
772             fgDisplay.Display,
773             fgStructure.Window->Window.Handle,
774             &text
775         );
776
777         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
778     }
779
780 #elif TARGET_HOST_WIN32
781
782     SetWindowText( fgStructure.Window->Window.Handle, title );
783
784 #endif
785
786 }
787
788 /*
789  * Change the current window's size
790  */
791 void FGAPIENTRY glutReshapeWindow( int width, int height )
792 {
793     freeglut_assert_ready;
794     freeglut_assert_window;
795
796 #if TARGET_HOST_UNIX_X11
797
798     XResizeWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
799                    width, height );
800     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
801     /*
802      * XXX REALLY shouldn't be done.  GLUT docs state that this
803      * XXX isn't even processed immediately, but rather waits
804      * XXX for return to the mainloop.  "This allows multiple
805      * XXX glutReshapeWindow, glutPositionWindow, and glutFullScreen
806      * XXX requests to the same window to be coalesced."  (This is
807      * XXX having some deleterious effect on a sample program of mine.)
808      * XXX Not only does GLUT not flush at this point, GLUT doesn't even
809      * XXX *do* the reshape at this point!  We should probably rip this
810      * XXX out and do what GLUT promises.  It would be more efficient, and
811      * XXX might be more compatible.
812      */
813
814 #elif TARGET_HOST_WIN32
815
816     {
817         RECT winRect;
818         int x, y;
819
820         GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
821         x = winRect.left;
822         y = winRect.top;
823
824         if ( fgStructure.Window->Parent == NULL )
825         {
826             /*
827              * Adjust the size of the window to allow for the size of the
828              * frame, if we are not a menu
829              */
830             if ( ! fgStructure.Window->IsMenu )
831             {
832                 width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
833                 height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 +
834                     GetSystemMetrics( SM_CYCAPTION );
835             }
836         }
837         else
838         {
839             GetWindowRect( fgStructure.Window->Parent->Window.Handle,
840                            &winRect );
841             x -= winRect.left + GetSystemMetrics( SM_CXSIZEFRAME );
842             y -= winRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) +
843                 GetSystemMetrics( SM_CYCAPTION );
844         }
845
846         MoveWindow(
847             fgStructure.Window->Window.Handle,
848             x,
849             y,
850             width,
851             height,
852             TRUE
853         );
854     }
855
856 #endif
857
858 }
859
860 /*
861  * Change the current window's position
862  */
863 void FGAPIENTRY glutPositionWindow( int x, int y )
864 {
865     freeglut_assert_ready;
866     freeglut_assert_window;
867
868 #if TARGET_HOST_UNIX_X11
869
870     XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, x, y );
871     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
872
873 #elif TARGET_HOST_WIN32
874
875     {
876         RECT winRect;
877         
878         GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
879         MoveWindow(
880             fgStructure.Window->Window.Handle,
881             x,
882             y,
883             winRect.right - winRect.left,
884             winRect.bottom - winRect.top,
885             TRUE
886         );
887     }
888
889 #endif
890
891 }
892
893 /*
894  * Lowers the current window (by Z order change)
895  */
896 void FGAPIENTRY glutPushWindow( void )
897 {
898     freeglut_assert_ready;
899     freeglut_assert_window;
900
901 #if TARGET_HOST_UNIX_X11
902
903     XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
904
905 #elif TARGET_HOST_WIN32
906
907     SetWindowPos(
908         fgStructure.Window->Window.Handle,
909         HWND_BOTTOM,
910         0, 0, 0, 0,
911         SWP_NOSIZE | SWP_NOMOVE
912     );
913
914 #endif
915
916 }
917
918 /*
919  * Raises the current window (by Z order change)
920  */
921 void FGAPIENTRY glutPopWindow( void )
922 {
923     freeglut_assert_ready;
924     freeglut_assert_window;
925
926 #if TARGET_HOST_UNIX_X11
927
928     XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
929
930 #elif TARGET_HOST_WIN32
931
932     SetWindowPos(
933         fgStructure.Window->Window.Handle,
934         HWND_TOP,
935         0, 0, 0, 0,
936         SWP_NOSIZE | SWP_NOMOVE
937     );
938
939 #endif
940
941 }
942
943 /*
944  * Resize the current window so that it fits the whole screen
945  */
946 void FGAPIENTRY glutFullScreen( void )
947 {
948     freeglut_assert_ready;
949     freeglut_assert_window;
950
951 #if TARGET_HOST_UNIX_X11
952     {
953         int x, y;
954         Window w;
955
956         XMoveResizeWindow(
957             fgDisplay.Display,
958             fgStructure.Window->Window.Handle,
959             0, 0,
960             fgDisplay.ScreenWidth,
961             fgDisplay.ScreenHeight
962         );
963         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
964
965         XTranslateCoordinates(
966             fgDisplay.Display,
967             fgStructure.Window->Window.Handle,
968             fgDisplay.RootWindow,
969             0, 0, &x, &y, &w
970         );
971
972         if (x || y)
973         {
974             XMoveWindow(
975                 fgDisplay.Display,
976                 fgStructure.Window->Window.Handle,
977                 -x, -y
978             );
979             XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
980         }
981     }
982 #elif TARGET_HOST_WIN32
983     MoveWindow(
984         fgStructure.Window->Window.Handle,
985         0, 0,
986         fgDisplay.ScreenWidth,
987         fgDisplay.ScreenHeight,
988         TRUE
989     );
990 #endif
991 }
992
993 /*
994  * A.Donev: Set and retrieve the window's user data
995  */
996 void* FGAPIENTRY glutGetWindowData( void )
997 {
998     return fgStructure.Window->UserData;
999 }
1000
1001 void FGAPIENTRY glutSetWindowData(void* data)
1002 {
1003     fgStructure.Window->UserData=data;
1004 }
1005
1006 /*** END OF FILE ***/