6fc6ade4a6eccb021b4df599bcc5e256f7dc49cd
[freeglut] / 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     /*
528      * Show and update the main window. Hide(???) the mouse cursor.
529      */
530     ShowWindow( window->Window.Handle,
531                 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
532     UpdateWindow( window->Window.Handle );
533     ShowCursor( TRUE );
534
535 #endif
536
537     window->Window.DoubleBuffered =
538         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0 ;
539
540     /*
541      * If it's not double-buffered, make sure the rendering is done to the
542      * front buffer.
543      */
544     if ( ! window->Window.DoubleBuffered )
545     {
546         glDrawBuffer ( GL_FRONT ) ;
547         glReadBuffer ( GL_FRONT ) ;
548     }
549
550     /*
551      * Set the newly created window as the current one
552      */
553     fgSetWindow( window );
554 }
555
556 /*
557  * Closes a window, destroying the frame and OpenGL context
558  */
559 void fgCloseWindow( SFG_Window* window )
560 {
561     freeglut_assert_ready;
562
563 #if TARGET_HOST_UNIX_X11
564     /*
565      * As easy as kill bunnies with axes. Destroy the context first:
566      */
567     glXDestroyContext( fgDisplay.Display, window->Window.Context );
568
569     /*
570      * Then have the window killed:
571      */
572     XDestroyWindow( fgDisplay.Display, window->Window.Handle );
573
574     /*
575      * Finally, flush the rests down the stream
576      */
577     XFlush( fgDisplay.Display );
578
579 #elif TARGET_HOST_WIN32
580         /*
581          * Send the WM_CLOSE message to the window now
582          */
583         SendMessage( 
584                 window->Window.Handle,
585                 WM_CLOSE,
586                 0,
587                 0
588         );
589
590 #endif
591 }
592
593
594 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
595
596 /*
597  * Creates a new top-level freeglut window
598  */
599 int FGAPIENTRY glutCreateWindow( const char* title )
600 {
601     /*
602      * Create a new window and return its unique ID number
603      */
604     return( fgCreateWindow( NULL, title, fgState.Position.X, fgState.Position.Y,
605                             fgState.Size.X, fgState.Size.Y, FALSE )->ID );
606 }
607
608 /*
609  * This function creates a sub window.
610  */
611 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
612 {
613     SFG_Window* window = NULL;
614     SFG_Window* parent = NULL;
615
616     freeglut_assert_ready;
617
618     /*
619      * Find a parent to the newly created window...
620      */
621     parent = fgWindowByID( parentID );
622
623     /*
624      * Fail if the parent has not been found
625      */
626     freeglut_return_val_if_fail( parent != NULL, 0 );
627
628     /*
629      * Create the new window
630      */
631     window = fgCreateWindow( parent, "", x, y, w, h, FALSE );
632
633     /*
634      * Return the new window's ID
635      */
636     return( window->ID );
637 }
638
639 /*
640  * Destroys a window and all of its subwindows
641  */
642 void FGAPIENTRY glutDestroyWindow( int windowID )
643 {
644   fgExecutionState ExecState = fgState.ExecState ;
645
646   /*
647    * Grab the freeglut window pointer from the structure
648    */
649   SFG_Window* window = fgWindowByID( windowID );
650   freeglut_return_if_fail( window != NULL );
651
652   /*
653    * There is a function that performs all needed steps
654    * defined in freeglut_structure.c. Let's use it:
655    */
656   fgAddToWindowDestroyList( window, TRUE );
657
658   /*
659    * Since the "fgAddToWindowDestroyList" function could easily have set the "ExecState"
660    * to stop, let's set it back to what it was.
661    */
662   fgState.ExecState = ExecState ;
663 }
664
665 /*
666  * This function selects the current window
667  */
668 void FGAPIENTRY glutSetWindow( int ID )
669 {
670     SFG_Window* window = NULL;
671
672     /*
673      * Make sure we don't get called too early
674      */
675     freeglut_assert_ready;
676
677     /*
678      * Be wise. Be wise. Be wise. Be quick.
679      */
680     if( fgStructure.Window != NULL )
681         if( fgStructure.Window->ID == ID )
682             return;
683
684     /*
685      * Now we are sure there is sense in looking for the window
686      */
687     window = fgWindowByID( ID );
688
689     /*
690      * In the case of an utter failure...
691      */
692     if( window == NULL )
693     {
694         /*
695          * ...issue a warning message and keep rolling on
696          */
697         fgWarning( "glutSetWindow(): window ID %i not found!", ID );
698         return;
699     }
700
701     fgSetWindow ( window ) ;
702 }
703
704 /*
705  * This function returns the ID number of the current window, 0 if none exists
706  */
707 int FGAPIENTRY glutGetWindow( void )
708 {
709     freeglut_assert_ready;
710
711     /*
712      * Do we have a current window selected?
713      */
714     if( fgStructure.Window == NULL )
715     {
716         /*
717          * Nope. Return zero to mark the state.
718          */
719         return( 0 );
720     }
721
722     /*
723      * Otherwise, return the ID of the current window
724      */
725     return( fgStructure.Window->ID );
726 }
727
728 /*
729  * This function makes the current window visible
730  */
731 void FGAPIENTRY glutShowWindow( void )
732 {
733     freeglut_assert_ready; freeglut_assert_window;
734
735 #if TARGET_HOST_UNIX_X11
736     /*
737      * Showing the window is done via mapping under X
738      */
739     XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
740     XFlush( fgDisplay.Display );
741
742 #elif TARGET_HOST_WIN32
743         /*
744          * Restore the window's originial position and size
745          */
746         ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
747
748 #endif
749
750   /*
751    * Since the window is visible, we need to redisplay it ...
752    */
753   fgStructure.Window->State.Redisplay = TRUE;
754
755 }
756
757 /*
758  * This function hides the current window
759  */
760 void FGAPIENTRY glutHideWindow( void )
761 {
762     freeglut_assert_ready; freeglut_assert_window;
763
764 #if TARGET_HOST_UNIX_X11
765     /*
766      * The way we hide a window depends on if we're dealing
767      * with a top-level or children one...
768      */
769     if( fgStructure.Window->Parent == NULL )
770     {
771         /*
772          * This is a top-level window
773          */
774         XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen );
775     }
776     else
777     {
778         /*
779          * Nope, it's a child window
780          */
781         XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
782     }
783
784     /*
785      * Flush the X state now
786      */
787     XFlush( fgDisplay.Display );
788
789 #elif TARGET_HOST_WIN32
790         /*
791          * Hide the window
792          */
793         ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
794
795 #endif
796
797   /*
798    * Since the window is hidden, we don't need to redisplay it ...
799    */
800   fgStructure.Window->State.Redisplay = FALSE;
801 }
802
803 /*
804  * Iconify the current window (top-level windows only)
805  */
806 void FGAPIENTRY glutIconifyWindow( void )
807 {
808     freeglut_assert_ready; freeglut_assert_window;
809
810 #if TARGET_HOST_UNIX_X11
811     /*
812      * Iconify the window and flush the X state
813      */
814     XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen );
815     XFlush( fgDisplay.Display );
816
817 #elif TARGET_HOST_WIN32
818         /*
819          * Minimize the current window (this should be the same as X window iconifying)
820          */
821         ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
822
823 #endif
824
825   /*
826    * Since the window is just an icon, we don't need to redisplay it ...
827    */
828   fgStructure.Window->State.Redisplay = FALSE;
829
830 }
831
832 /*
833  * Set the current window's title
834  */
835 void FGAPIENTRY glutSetWindowTitle( const char* title )
836 {
837         freeglut_assert_ready; freeglut_assert_window;
838
839     /*
840      * Works only for top-level windows
841      */
842     if( fgStructure.Window->Parent != NULL )
843         return;
844
845 #if TARGET_HOST_UNIX_X11
846         {
847                 XTextProperty text;
848
849                 /*
850                  * Prepare the text properties
851                  */
852                 text.value = (unsigned char *) title;
853                 text.encoding = XA_STRING;
854                 text.format = 8;
855                 text.nitems = strlen( title );
856
857                 /*
858                  * Set the title now
859                  */
860                 XSetWMName(
861                         fgDisplay.Display,
862                         fgStructure.Window->Window.Handle,
863                         &text
864                 );
865
866                 /*
867                  * Have the X display state flushed
868                  */
869                 XFlush( fgDisplay.Display );
870         }
871
872 #elif TARGET_HOST_WIN32
873         /*
874          * This seems to be a bit easier under Win32
875          */
876         SetWindowText( fgStructure.Window->Window.Handle, title );
877
878 #endif
879 }
880
881 /*
882  * Set the current window's iconified title
883  */
884 void FGAPIENTRY glutSetIconTitle( const char* title )
885 {
886     freeglut_assert_ready; freeglut_assert_window;
887
888     /*
889      * Works only for top-level windows
890      */
891     if( fgStructure.Window->Parent != NULL )
892         return;
893
894 #if TARGET_HOST_UNIX_X11
895         {
896                 XTextProperty text;
897
898                 /*
899                  * Prepare the text properties
900                  */
901                 text.value = (unsigned char *) title;
902                 text.encoding = XA_STRING;
903                 text.format = 8;
904                 text.nitems = strlen( title );
905
906                 /*
907                  * Set the title now
908                  */
909                 XSetWMIconName(
910                         fgDisplay.Display,
911                         fgStructure.Window->Window.Handle,
912                         &text
913                 );
914
915                 /*
916                  * Have the X display state flushed
917                  */
918                 XFlush( fgDisplay.Display );
919         }
920
921 #elif TARGET_HOST_WIN32
922         /*
923          * This seems to be a bit easier under Win32
924          */
925         SetWindowText( fgStructure.Window->Window.Handle, title );
926
927 #endif
928 }
929
930 /*
931  * Change the current window's size
932  */
933 void FGAPIENTRY glutReshapeWindow( int width, int height )
934 {
935     freeglut_assert_ready; freeglut_assert_window;
936
937 #if TARGET_HOST_UNIX_X11
938     /*
939      * Resize the window and flush the X state
940      */
941     XResizeWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, width, height );
942     XFlush( fgDisplay.Display );
943
944 #elif TARGET_HOST_WIN32
945         {
946                 RECT winRect;
947     int x, y ;
948
949                 /*
950                  * First off, grab the current window's position
951                  */
952                 GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
953     x = winRect.left ;
954     y = winRect.top ;
955
956     if ( fgStructure.Window->Parent == NULL )  /* If this is not a subwindow ... */
957     {
958       /*
959        * Adjust the size of the window to allow for the size of the frame, if we are not a menu
960        */
961       if ( ! fgStructure.Window->IsMenu )
962       {
963                 width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
964                 height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + GetSystemMetrics( SM_CYCAPTION );
965       }
966     }
967     else  /* This is a subwindow, get the parent window's position and subtract it off */
968     {
969       GetWindowRect ( fgStructure.Window->Parent->Window.Handle, &winRect ) ;
970       x -= winRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) ;
971       y -= winRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ) ;
972     }
973
974                 /*
975                  * Resize the window, forcing a redraw to happen
976                  */
977                 MoveWindow(
978                         fgStructure.Window->Window.Handle,
979                         x,
980                         y,
981                         width,
982                         height,
983                         TRUE
984                 );
985         }
986 #endif
987 }
988
989 /*
990  * Change the current window's position
991  */
992 void FGAPIENTRY glutPositionWindow( int x, int y )
993 {
994     freeglut_assert_ready; freeglut_assert_window;
995
996 #if TARGET_HOST_UNIX_X11
997     /*
998      * Reposition the window and flush the X state
999      */
1000     XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, x, y );
1001     XFlush( fgDisplay.Display );
1002
1003 #elif TARGET_HOST_WIN32
1004         {
1005                 RECT winRect;
1006
1007                 /*
1008                  * First off, grab the current window's position
1009                  */
1010                 GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
1011
1012     /*
1013                  * Reposition the window, forcing a redraw to happen
1014                  */
1015                 MoveWindow(
1016                         fgStructure.Window->Window.Handle,
1017                         x,
1018                         y,
1019                         winRect.right - winRect.left,
1020                         winRect.bottom - winRect.top,
1021                         TRUE
1022                 );
1023         }
1024
1025 #endif
1026 }
1027
1028 /*
1029  * Lowers the current window (by Z order change)
1030  */
1031 void FGAPIENTRY glutPushWindow( void )
1032 {
1033     freeglut_assert_ready; freeglut_assert_window;
1034
1035 #if TARGET_HOST_UNIX_X11
1036     /*
1037      * Lower the current window
1038      */
1039     XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
1040
1041 #elif TARGET_HOST_WIN32
1042         /*
1043          * Set the new window's Z position, not affecting the rest of the settings:
1044          */
1045         SetWindowPos(
1046                 fgStructure.Window->Window.Handle,
1047                 HWND_BOTTOM,
1048                 0, 0, 0, 0,
1049                 SWP_NOSIZE | SWP_NOMOVE
1050         );
1051
1052 #endif
1053 }
1054
1055 /*
1056  * Raises the current window (by Z order change)
1057  */
1058 void FGAPIENTRY glutPopWindow( void )
1059 {
1060     freeglut_assert_ready; freeglut_assert_window;
1061
1062 #if TARGET_HOST_UNIX_X11
1063     /*
1064      * Raise the current window
1065      */
1066     XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
1067
1068 #elif TARGET_HOST_WIN32
1069         /*
1070          * Set the new window's Z position, not affecting the rest of the settings:
1071          */
1072         SetWindowPos(
1073                 fgStructure.Window->Window.Handle,
1074                 HWND_TOP,
1075                 0, 0, 0, 0,
1076                 SWP_NOSIZE | SWP_NOMOVE
1077         );
1078
1079 #endif
1080 }
1081
1082 /*
1083  * Resize the current window so that it fits the whole screen
1084  */
1085 void FGAPIENTRY glutFullScreen( void )
1086 {
1087     freeglut_assert_ready; freeglut_assert_window;
1088
1089 #if TARGET_HOST_UNIX_X11
1090     {
1091         int x, y;
1092         Window w;
1093
1094         XMoveResizeWindow(
1095             fgDisplay.Display,
1096             fgStructure.Window->Window.Handle,
1097             0, 0,
1098             fgDisplay.ScreenWidth,
1099             fgDisplay.ScreenHeight
1100         );
1101         XFlush( fgDisplay.Display );
1102
1103         XTranslateCoordinates(
1104             fgDisplay.Display,
1105             fgStructure.Window->Window.Handle,
1106             fgDisplay.RootWindow,
1107             0, 0, &x, &y, &w
1108         );
1109
1110         if (x || y)
1111         {
1112             XMoveWindow(
1113                 fgDisplay.Display,
1114                 fgStructure.Window->Window.Handle,
1115                 -x, -y
1116             );
1117             XFlush( fgDisplay.Display );
1118         }
1119     }
1120 #elif TARGET_HOST_WIN32
1121     MoveWindow(
1122         fgStructure.Window->Window.Handle,
1123         0, 0,
1124         fgDisplay.ScreenWidth,
1125         fgDisplay.ScreenHeight,
1126         TRUE
1127     );
1128 #endif
1129 }
1130
1131 /*
1132  * A.Donev: Set and retrieve the window's user data
1133  */
1134 void* FGAPIENTRY glutGetWindowData( void )
1135 {
1136    return(fgStructure.Window->UserData);
1137 }
1138
1139 void FGAPIENTRY glutSetWindowData(void* data)
1140 {
1141   fgStructure.Window->UserData=data;
1142 }
1143
1144 /*** END OF FILE ***/