Major menu changes (they appear in their own window, have own rendering context)...
[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()      -- see what happens when default position and size is {-1,-1}
45  *  glutCreateSubWindow()   -- see what happens 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 XVisualInfo* fgChooseVisual( void )
67 {
68     int bufferSize[] = { 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 #   define ATTRIB(a) attributes[where++]=a;
77
78     /*
79      * Decide if we want a true or indexed color visual:
80      */
81     if( !(fgState.DisplayMode & GLUT_INDEX) )
82     {
83         /*
84          * We are sure that there will be R, B and B components requested:
85          */
86         ATTRIB( GLX_RGBA       );
87         ATTRIB( GLX_RED_SIZE   ); ATTRIB( 1 );
88         ATTRIB( GLX_GREEN_SIZE ); ATTRIB( 1 );
89         ATTRIB( GLX_BLUE_SIZE  ); ATTRIB( 1 );
90
91         /*
92          * Check if the A component is required, too:
93          */
94         if( fgState.DisplayMode & GLUT_ALPHA )
95         {
96             ATTRIB( GLX_ALPHA_SIZE ); ATTRIB( 1 );
97         }
98     }
99     else
100     {
101         /*
102          * We've got an indexed color request
103          */
104         ATTRIB( GLX_BUFFER_SIZE ); ATTRIB( 8 );
105
106         /*
107          * Set the 'I want indexed mode' switch
108          */
109         wantIndexedMode = TRUE;
110     }
111
112     /*
113      * We can have double or single buffered contexts created
114      */
115     if( fgState.DisplayMode & GLUT_DOUBLE )
116     {
117         ATTRIB( GLX_DOUBLEBUFFER );
118     }
119
120     /*
121      * Stereoscopy seems a nice thing to have
122      */
123     if( fgState.DisplayMode & GLUT_STEREO )
124     {
125         ATTRIB( GLX_STEREO );
126     }
127
128     /*
129      * Depth buffer is almost always required
130      */
131     if( fgState.DisplayMode & GLUT_DEPTH )
132     {
133         ATTRIB( GLX_DEPTH_SIZE ); ATTRIB( 1 );
134     }
135
136     /*
137      * Stenciling support
138      */
139     if( fgState.DisplayMode & GLUT_STENCIL )
140     {
141         ATTRIB( GLX_STENCIL_SIZE ); ATTRIB( 1 );
142     }
143
144     /*
145      * And finally the accumulation buffers
146      */
147     if( fgState.DisplayMode & GLUT_ACCUM )
148     {
149         ATTRIB( GLX_ACCUM_RED_SIZE );   ATTRIB( 1 );
150         ATTRIB( GLX_ACCUM_GREEN_SIZE ); ATTRIB( 1 );
151         ATTRIB( GLX_ACCUM_BLUE_SIZE );  ATTRIB( 1 );
152
153         /*
154          * Check if the A component is required, too:
155          */
156         if( fgState.DisplayMode & GLUT_ALPHA )
157         {
158             ATTRIB( GLX_ACCUM_ALPHA_SIZE ); ATTRIB( 1 );
159         }
160     }
161
162     /*
163      * Push a null at the end of the list
164      */
165     ATTRIB( None );
166
167     /*
168      * OKi now, we've got two cases -- RGB(A) and index mode visuals
169      */
170     if( wantIndexedMode == FALSE )
171     {
172         /*
173          * The easier one. And more common, too.
174          */
175         return( glXChooseVisual( fgDisplay.Display, fgDisplay.Screen, attributes ) );
176     }
177     else
178     {
179         XVisualInfo* visualInfo;
180         int i;
181
182         /*
183          * In indexed mode, we need to check how many bits of depth can we achieve
184          */
185         for( i=0; i<6; i++ )
186         {
187
188             /*
189              * The GLX_BUFFER_SIZE value comes always first, so:
190              */
191             attributes[ 1 ] = bufferSize[ i ];
192
193             /*
194              * Check if such visual is possible
195              */
196             visualInfo = glXChooseVisual( fgDisplay.Display, fgDisplay.Screen, attributes );
197
198             /*
199              * The buffer size are sorted in descendant order, so choose the first:
200              */
201             if( visualInfo != NULL )
202                 return( visualInfo );
203         }
204
205         /*
206          * If we are still here, it means that the visual info was not found
207          */
208         return( NULL );
209     }
210 }
211 #endif
212
213 /*
214  * Setup the pixel format for a Win32 window
215  */
216 #if TARGET_HOST_WIN32
217 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, unsigned char layer_type )
218 {
219         PIXELFORMATDESCRIPTOR* ppfd, pfd;
220         int flags, pixelformat;
221
222         /*
223          * Check if the window seems valid
224          */
225         freeglut_return_val_if_fail( window != NULL, 0 );
226
227         /*
228          * The pixel format should allow us to draw to the window using OpenGL
229          */
230         flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
231         
232         /*
233          * It might be the case for us to use double buffering
234          */
235   if( fgState.DisplayMode & GLUT_DOUBLE )
236     flags |= PFD_DOUBLEBUFFER;
237
238   /*
239    * Specify which pixel format do we opt for...
240    */
241 #       pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )
242
243   pfd.nSize                             = sizeof(PIXELFORMATDESCRIPTOR);
244   pfd.nVersion                  = 1;
245   pfd.dwFlags                           = flags;
246   pfd.iPixelType                        = PFD_TYPE_RGBA;
247   pfd.cColorBits                        = 24;
248   pfd.cRedBits                  = 0;
249   pfd.cRedShift                 = 0;
250   pfd.cGreenBits                        = 0;
251   pfd.cGreenShift                       = 0;
252   pfd.cBlueBits                 = 0;
253   pfd.cBlueShift                        = 0;
254   pfd.cAlphaBits                        = 0;
255   pfd.cAlphaShift                       = 0;
256   pfd.cAccumBits                        = 0;
257   pfd.cAccumRedBits             = 0;
258   pfd.cAccumGreenBits           = 0;
259   pfd.cAccumBlueBits            = 0;
260   pfd.cAccumAlphaBits           = 0;
261 #if 0
262   pfd.cDepthBits                        = 32;
263   pfd.cStencilBits              = 0;
264 #else
265   pfd.cDepthBits                        = 24;
266   pfd.cStencilBits              = 8;
267 #endif
268   pfd.cAuxBuffers                       = 0;
269   pfd.iLayerType                        = layer_type;
270   pfd.bReserved                 = 0;
271   pfd.dwLayerMask                       = 0;
272   pfd.dwVisibleMask             = 0;
273   pfd.dwDamageMask              = 0;
274
275   /*
276    * Fill in the color bits...
277    */
278   pfd.cColorBits = (BYTE) GetDeviceCaps( window->Window.Device, BITSPIXEL );
279   ppfd = &pfd;
280
281         /*
282          * Choose the pixel format that matches our demand
283          */
284   pixelformat = ChoosePixelFormat( window->Window.Device, ppfd );
285         if( pixelformat == 0 )
286                 return( FALSE );
287
288         /*
289          * We might have been called to check if the pixel format exists only
290          */
291         if( checkOnly )
292                 return( TRUE );
293
294         /*
295          * Finally, set the window's pixel format
296          */
297         return ( SetPixelFormat( window->Window.Device, pixelformat, ppfd ) ) ;
298 }
299 #endif
300
301 /*
302  * Sets the OpenGL context and the fgStructure "Current Window" pointer to the window
303  * structure passed in.
304  */
305 void fgSetWindow ( SFG_Window *window )
306 {
307 #if TARGET_HOST_UNIX_X11
308     /*
309          * Make the selected window's GLX context the current one
310      */
311     glXMakeCurrent(
312         fgDisplay.Display,
313         window->Window.Handle,
314         window->Window.Context
315     );
316
317 #elif TARGET_HOST_WIN32
318         /*
319          * Release the previous' context's device context
320          */
321         if( fgStructure.Window != NULL )
322                 ReleaseDC( fgStructure.Window->Window.Handle, fgStructure.Window->Window.Device );
323
324   if ( window )
325   {
326         /*
327            * We will care about releasing the device context later
328            */
329         window->Window.Device = GetDC( window->Window.Handle );
330
331         /*
332            * Set the new current context:
333            */
334         wglMakeCurrent( 
335                 window->Window.Device, 
336                   window->Window.Context 
337         );
338   }
339 #endif
340
341     /*
342      * Remember that we have changed the current window state
343      */
344     fgStructure.Window = window;
345 }
346
347
348 /*
349  * Opens a window. Requires a SFG_Window object created and attached
350  * to the freeglut structure. OpenGL context is created here.
351  */
352 void fgOpenWindow( SFG_Window* window, const char* title, int x, int y, int w, int h, GLboolean gameMode, int isSubWindow )
353 {
354 #if TARGET_HOST_UNIX_X11
355     XSetWindowAttributes winAttr;
356     XTextProperty textProperty;
357     XSizeHints sizeHints;
358     XWMHints wmHints;
359     unsigned long mask;
360
361     freeglut_assert_ready;
362
363     /*
364      * Here we are upon the stage. Have the visual selected.
365      */
366     if ( fgState.BuildingAMenu )
367     {
368       /*
369        * If there isn't already an OpenGL rendering context for menu windows, make one
370        */
371       if ( !fgStructure.MenuContext )
372       {
373         unsigned int current_DisplayMode = fgState.DisplayMode ;
374         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ;
375         window->Window.VisualInfo = fgChooseVisual();
376         fgState.DisplayMode = current_DisplayMode ;
377       }
378       else
379         window->Window.VisualInfo = fgChooseVisual();
380     }
381     else
382       window->Window.VisualInfo = fgChooseVisual();
383
384     if ( ! window->Window.VisualInfo )
385     {
386       /*
387        * The "fgChooseVisual" returned a null meaning that the visual context is not available.
388        * Try a couple of variations to see if they will work.
389        */
390       if ( ! ( fgState.DisplayMode & GLUT_DOUBLE ) )
391       {
392         /*
393          * Single buffering--try it doubled
394          */
395         fgState.DisplayMode |= GLUT_DOUBLE ;
396         window->Window.VisualInfo = fgChooseVisual();
397       }
398
399       /*
400        * GLUT also checks for multi-sampling, but I don't see that anywhere else in FREEGLUT
401        * so I won't bother with it for the moment.
402        */
403     }
404
405     assert( window->Window.VisualInfo != NULL );
406
407     /*
408      * Have the windows attributes set
409      *
410      * HINT: the masks should be updated when adding/removing callbacks.
411      *       This might speed up message processing. Is that true?
412      */
413     winAttr.event_mask        = StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
414                                 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyRelease |
415                                 VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
416                                 PointerMotionMask | ButtonMotionMask;
417     winAttr.background_pixmap = None;
418     winAttr.background_pixel  = 0;
419     winAttr.border_pixel      = 0;
420
421     /*
422      * The color map is required, too
423      */
424     winAttr.colormap = XCreateColormap(
425         fgDisplay.Display, fgDisplay.RootWindow,
426         window->Window.VisualInfo->visual, AllocNone
427     );
428
429     /*
430      * This tells the XCreateWindow() what attributes are we supplying it with
431      */
432     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
433
434     /*
435      * Have the window created now
436      */
437     window->Window.Handle = XCreateWindow(
438         fgDisplay.Display,
439         window->Parent == NULL ? fgDisplay.RootWindow : window->Parent->Window.Handle,
440         x, y, w, h, 0,
441         window->Window.VisualInfo->depth, InputOutput,
442         window->Window.VisualInfo->visual, mask,
443         &winAttr
444     );
445
446     /*
447      * The GLX context creation, possibly trying the direct context rendering
448      *  or else use the current context if the user has so specified
449      */
450     if ( fgState.BuildingAMenu )
451     {
452       /*
453        * If there isn't already an OpenGL rendering context for menu windows, make one
454        */
455       if ( !fgStructure.MenuContext )
456       {
457         fgStructure.MenuContext = (SFG_MenuContext *)malloc ( sizeof(SFG_MenuContext) ) ;
458         fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo ;
459         fgStructure.MenuContext->Context = glXCreateContext(
460             fgDisplay.Display, fgStructure.MenuContext->VisualInfo,
461             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
462         );
463       }
464
465 /*      window->Window.Context = fgStructure.MenuContext->Context ; */
466       window->Window.Context = glXCreateContext(
467             fgDisplay.Display, window->Window.VisualInfo,
468             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
469         );
470     }
471     else if ( fgState.UseCurrentContext == TRUE )
472     {
473       window->Window.Context = glXGetCurrentContext();
474
475       if ( ! window->Window.Context )
476         window->Window.Context = glXCreateContext(
477             fgDisplay.Display, window->Window.VisualInfo,
478             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
479         );
480     }
481     else
482       window->Window.Context = glXCreateContext(
483           fgDisplay.Display, window->Window.VisualInfo,
484           NULL, fgState.ForceDirectContext | fgState.TryDirectContext
485       );
486
487     /*
488      * Make sure the context is direct when the user wants it forced
489      */
490     if( fgState.ForceDirectContext && !glXIsDirect( fgDisplay.Display, window->Window.Context ) )
491         fgError( "unable to force direct context rendering for window '%s'", title );
492
493     /*
494      * Set the new context as the current one. That's all about the window creation.
495      */
496     glXMakeCurrent(
497         fgDisplay.Display,
498         window->Window.Handle,
499         window->Window.Context
500     );
501
502     /*
503      * Assume the new window is visible by default
504      */
505     window->State.Visible = TRUE;
506
507     /*
508      * For the position and size hints -- make sure we are passing valid values
509      */
510     sizeHints.flags = 0;
511
512     if (fgState.Position.Use == TRUE) sizeHints.flags |= USPosition;
513     if (fgState.Size.Use     == TRUE) sizeHints.flags |= USSize;
514
515     /*
516      * Fill in the size hints values now (the x, y, width and height
517      * settings are obsolote, are there any more WMs that support them?)
518      */
519     sizeHints.x      = x; sizeHints.y      = y;
520     sizeHints.width  = w; sizeHints.height = h;
521
522     /*
523      * We can have forced all new windows start in iconified state:
524      */
525     wmHints.flags = StateHint;
526     wmHints.initial_state = (fgState.ForceIconic == FALSE) ? NormalState : IconicState;
527
528     /*
529      * Prepare the window and iconified window names...
530      */
531     XStringListToTextProperty( (char **) &title, 1, &textProperty );
532
533     /*
534      * Set the window's properties now
535      */
536     XSetWMProperties(
537         fgDisplay.Display,
538         window->Window.Handle,
539         &textProperty,
540         &textProperty,
541         0,
542         0,
543         &sizeHints,
544         &wmHints,
545         NULL
546     );
547
548     /*
549      * Make sure we are informed about the window deletion commands
550      */
551     XSetWMProtocols( fgDisplay.Display, window->Window.Handle, &fgDisplay.DeleteWindow, 1 );
552
553     /*
554      * Finally, have the window mapped to our display
555      */
556     XMapWindow( fgDisplay.Display, window->Window.Handle );
557
558     /*
559      * In game mode, move the viewport a bit to hide the decorations.
560      * This code depends on the XFree86 video mode extensions.
561      */
562     if( gameMode == TRUE )
563     {
564         /*
565          * This somehow fixes the glutGet() GLUT_WINDOW_X and GLUT_WINDOW_Y problem...
566          */
567         XMoveWindow( fgDisplay.Display, window->Window.Handle, x, y );
568
569 #       ifdef X_XF86VidModeSetViewPort
570
571         /*
572          * Set the newly created window as the current one...
573          */
574         fgSetWindow( window );
575
576         /*
577          * Move the viewport a bit down and right from top-left corner to hide the decorations
578          */
579         XF86VidModeSetViewPort(
580             fgDisplay.Display,
581             fgDisplay.Screen,
582             glutGet( GLUT_WINDOW_X ),
583             glutGet( GLUT_WINDOW_Y )
584         );
585
586 #       endif
587     }
588
589 #elif TARGET_HOST_WIN32
590
591         WNDCLASS wc;
592         int flags;
593         ATOM atom;
594
595     freeglut_assert_ready;
596
597         /*
598          * Grab the window class we have registered on glutInit():
599          */
600         atom = GetClassInfo( fgDisplay.Instance, "FREEGLUT", &wc );
601         assert( atom != 0 );
602
603     if( gameMode == FALSE )
604     {
605       if ( ( !isSubWindow ) && ( ! window->IsMenu ) )
606       {
607         /*
608          * Update the window dimensions, taking account of window decorations.
609          * "freeglut" is to create the window with the outside of its border at (x,y)
610          * and with dimensions (w,h).
611          */
612                 w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2;
613                 h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 + GetSystemMetrics( SM_CYCAPTION );
614       }
615
616       /*
617              * Check if the user wants us to use the default position/size
618              */
619             if( fgState.Position.Use == FALSE ) { x = CW_USEDEFAULT; y = CW_USEDEFAULT; }
620             if( fgState.Size    .Use == FALSE ) { w = CW_USEDEFAULT; h = CW_USEDEFAULT; }
621
622             /*
623              * There's a small difference between creating the top, child and game mode windows
624              */
625             flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
626
627       /*
628        * If we're a menu, set our flags to include WS_POPUP to remove decorations
629        */
630       if ( window->IsMenu )
631         flags |= WS_POPUP ;
632             else if( window->Parent == NULL )
633                     flags |= WS_OVERLAPPEDWINDOW;
634             else
635                     flags |= WS_CHILD;
636     }
637     else
638     {
639         /*
640          * In game mode, the story is a little bit different...
641          */
642         assert( window->Parent == NULL );
643
644         /*
645          * Set the window creation flags appropriately to make the window entirely visible:
646          */
647         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
648     }
649
650     /*
651      * Create the window now, passing the freeglut window structure as the parameter
652      */
653         window->Window.Handle = CreateWindow( 
654                 "FREEGLUT",
655         title,
656                 flags,
657         x, y, w, h,
658                 (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
659                 (HMENU) NULL,
660                 fgDisplay.Instance,
661                 (LPVOID) window
662         );
663
664         /*
665      * Make sure window was created
666      */
667         assert( window->Window.Handle != NULL );
668
669     /*
670      * Show and update the main window. Hide the mouse cursor.
671      */
672     ShowWindow( window->Window.Handle, fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
673     UpdateWindow( window->Window.Handle );
674     ShowCursor( TRUE );
675
676 #endif
677
678     /*
679      * Save the window's single- or double-buffering state
680      */
681     window->Window.DoubleBuffered = ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0 ;
682
683     /*
684      * If it's not double-buffered, make sure the rendering is done to the front buffer.
685      */
686     if ( ! window->Window.DoubleBuffered )
687     {
688       glDrawBuffer ( GL_FRONT ) ;
689       glReadBuffer ( GL_FRONT ) ;
690     }
691
692     /*
693      * Set the newly created window as the current one
694      */
695     fgSetWindow( window );
696 }
697
698 /*
699  * Closes a window, destroying the frame and OpenGL context
700  */
701 void fgCloseWindow( SFG_Window* window )
702 {
703     freeglut_assert_ready;
704
705 #if TARGET_HOST_UNIX_X11
706     /*
707      * As easy as kill bunnies with axes. Destroy the context first:
708      */
709     glXDestroyContext( fgDisplay.Display, window->Window.Context );
710
711     /*
712      * Then have the window killed:
713      */
714     XDestroyWindow( fgDisplay.Display, window->Window.Handle );
715
716     /*
717      * Finally, flush the rests down the stream
718      */
719     XFlush( fgDisplay.Display );
720
721 #elif TARGET_HOST_WIN32
722         /*
723          * Send the WM_CLOSE message to the window now
724          */
725         SendMessage( 
726                 window->Window.Handle,
727                 WM_CLOSE,
728                 0,
729                 0
730         );
731
732 #endif
733 }
734
735
736 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
737
738 /*
739  * Creates a new top-level freeglut window
740  */
741 int FGAPIENTRY glutCreateWindow( const char* title )
742 {
743     /*
744      * Create a new window and return its unique ID number
745      */
746     return( fgCreateWindow( NULL, title, fgState.Position.X, fgState.Position.Y,
747                             fgState.Size.X, fgState.Size.Y, FALSE )->ID );
748 }
749
750 /*
751  * This function creates a sub window.
752  */
753 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
754 {
755     SFG_Window* window = NULL;
756     SFG_Window* parent = NULL;
757
758     freeglut_assert_ready;
759
760     /*
761      * Find a parent to the newly created window...
762      */
763     parent = fgWindowByID( parentID );
764
765     /*
766      * Fail if the parent has not been found
767      */
768     freeglut_return_val_if_fail( parent != NULL, 0 );
769
770     /*
771      * Create the new window
772      */
773     window = fgCreateWindow( parent, "", x, y, w, h, FALSE );
774
775     /*
776      * Return the new window's ID
777      */
778     return( window->ID );
779 }
780
781 /*
782  * Destroys a window and all of its subwindows
783  */
784 void FGAPIENTRY glutDestroyWindow( int windowID )
785 {
786   fgExecutionState ExecState = fgState.ExecState ;
787
788   /*
789    * Grab the freeglut window pointer from the structure
790    */
791   SFG_Window* window = fgWindowByID( windowID );
792   freeglut_return_if_fail( window != NULL );
793
794   /*
795    * There is a function that performs all needed steps
796    * defined in freeglut_structure.c. Let's use it:
797    */
798   fgAddToWindowDestroyList( window, TRUE );
799
800   /*
801    * Since the "fgAddToWindowDestroyList" function could easily have set the "ExecState"
802    * to stop, let's set it back to what it was.
803    */
804   fgState.ExecState = ExecState ;
805 }
806
807 /*
808  * This function selects the current window
809  */
810 void FGAPIENTRY glutSetWindow( int ID )
811 {
812     SFG_Window* window = NULL;
813
814     /*
815      * Make sure we don't get called too early
816      */
817     freeglut_assert_ready;
818
819     /*
820      * Be wise. Be wise. Be wise. Be quick.
821      */
822     if( fgStructure.Window != NULL )
823         if( fgStructure.Window->ID == ID )
824             return;
825
826     /*
827      * Now we are sure there is sense in looking for the window
828      */
829     window = fgWindowByID( ID );
830
831     /*
832      * In the case of an utter failure...
833      */
834     if( window == NULL )
835     {
836         /*
837          * ...issue a warning message and keep rolling on
838          */
839         fgWarning( "glutSetWindow(): window ID %i not found!", ID );
840         return;
841     }
842
843     fgSetWindow ( window ) ;
844 }
845
846 /*
847  * This function returns the ID number of the current window, 0 if none exists
848  */
849 int FGAPIENTRY glutGetWindow( void )
850 {
851     freeglut_assert_ready;
852
853     /*
854      * Do we have a current window selected?
855      */
856     if( fgStructure.Window == NULL )
857     {
858         /*
859          * Nope. Return zero to mark the state.
860          */
861         return( 0 );
862     }
863
864     /*
865      * Otherwise, return the ID of the current window
866      */
867     return( fgStructure.Window->ID );
868 }
869
870 /*
871  * This function makes the current window visible
872  */
873 void FGAPIENTRY glutShowWindow( void )
874 {
875     freeglut_assert_ready; freeglut_assert_window;
876
877 #if TARGET_HOST_UNIX_X11
878     /*
879      * Showing the window is done via mapping under X
880      */
881     XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
882     XFlush( fgDisplay.Display );
883
884 #elif TARGET_HOST_WIN32
885         /*
886          * Restore the window's originial position and size
887          */
888         ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
889
890 #endif
891
892   /*
893    * Since the window is visible, we need to redisplay it ...
894    */
895   fgStructure.Window->State.Redisplay = TRUE;
896
897 }
898
899 /*
900  * This function hides the current window
901  */
902 void FGAPIENTRY glutHideWindow( void )
903 {
904     freeglut_assert_ready; freeglut_assert_window;
905
906 #if TARGET_HOST_UNIX_X11
907     /*
908      * The way we hide a window depends on if we're dealing
909      * with a top-level or children one...
910      */
911     if( fgStructure.Window->Parent == NULL )
912     {
913         /*
914          * This is a top-level window
915          */
916         XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen );
917     }
918     else
919     {
920         /*
921          * Nope, it's a child window
922          */
923         XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
924     }
925
926     /*
927      * Flush the X state now
928      */
929     XFlush( fgDisplay.Display );
930
931 #elif TARGET_HOST_WIN32
932         /*
933          * Hide the window
934          */
935         ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
936
937 #endif
938
939   /*
940    * Since the window is hidden, we don't need to redisplay it ...
941    */
942   fgStructure.Window->State.Redisplay = FALSE;
943 }
944
945 /*
946  * Iconify the current window (top-level windows only)
947  */
948 void FGAPIENTRY glutIconifyWindow( void )
949 {
950     freeglut_assert_ready; freeglut_assert_window;
951
952 #if TARGET_HOST_UNIX_X11
953     /*
954      * Iconify the window and flush the X state
955      */
956     XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen );
957     XFlush( fgDisplay.Display );
958
959 #elif TARGET_HOST_WIN32
960         /*
961          * Minimize the current window (this should be the same as X window iconifying)
962          */
963         ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
964
965 #endif
966
967   /*
968    * Since the window is just an icon, we don't need to redisplay it ...
969    */
970   fgStructure.Window->State.Redisplay = FALSE;
971
972 }
973
974 /*
975  * Set the current window's title
976  */
977 void FGAPIENTRY glutSetWindowTitle( const char* title )
978 {
979         freeglut_assert_ready; freeglut_assert_window;
980
981     /*
982      * Works only for top-level windows
983      */
984     if( fgStructure.Window->Parent != NULL )
985         return;
986
987 #if TARGET_HOST_UNIX_X11
988         {
989                 XTextProperty text;
990
991                 /*
992                  * Prepare the text properties
993                  */
994                 text.value = (unsigned char *) title;
995                 text.encoding = XA_STRING;
996                 text.format = 8;
997                 text.nitems = strlen( title );
998
999                 /*
1000                  * Set the title now
1001                  */
1002                 XSetWMName(
1003                         fgDisplay.Display,
1004                         fgStructure.Window->Window.Handle,
1005                         &text
1006                 );
1007
1008                 /*
1009                  * Have the X display state flushed
1010                  */
1011                 XFlush( fgDisplay.Display );
1012         }
1013
1014 #elif TARGET_HOST_WIN32
1015         /*
1016          * This seems to be a bit easier under Win32
1017          */
1018         SetWindowText( fgStructure.Window->Window.Handle, title );
1019
1020 #endif
1021 }
1022
1023 /*
1024  * Set the current window's iconified title
1025  */
1026 void FGAPIENTRY glutSetIconTitle( const char* title )
1027 {
1028     freeglut_assert_ready; freeglut_assert_window;
1029
1030     /*
1031      * Works only for top-level windows
1032      */
1033     if( fgStructure.Window->Parent != NULL )
1034         return;
1035
1036 #if TARGET_HOST_UNIX_X11
1037         {
1038                 XTextProperty text;
1039
1040                 /*
1041                  * Prepare the text properties
1042                  */
1043                 text.value = (unsigned char *) title;
1044                 text.encoding = XA_STRING;
1045                 text.format = 8;
1046                 text.nitems = strlen( title );
1047
1048                 /*
1049                  * Set the title now
1050                  */
1051                 XSetWMIconName(
1052                         fgDisplay.Display,
1053                         fgStructure.Window->Window.Handle,
1054                         &text
1055                 );
1056
1057                 /*
1058                  * Have the X display state flushed
1059                  */
1060                 XFlush( fgDisplay.Display );
1061         }
1062
1063 #elif TARGET_HOST_WIN32
1064         /*
1065          * This seems to be a bit easier under Win32
1066          */
1067         SetWindowText( fgStructure.Window->Window.Handle, title );
1068
1069 #endif
1070 }
1071
1072 /*
1073  * Change the current window's size
1074  */
1075 void FGAPIENTRY glutReshapeWindow( int width, int height )
1076 {
1077     freeglut_assert_ready; freeglut_assert_window;
1078
1079 #if TARGET_HOST_UNIX_X11
1080     /*
1081      * Resize the window and flush the X state
1082      */
1083     XResizeWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, width, height );
1084     XFlush( fgDisplay.Display );
1085
1086 #elif TARGET_HOST_WIN32
1087         {
1088                 RECT winRect;
1089     int x, y ;
1090
1091                 /*
1092                  * First off, grab the current window's position
1093                  */
1094                 GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
1095     x = winRect.left ;
1096     y = winRect.top ;
1097
1098     if ( fgStructure.Window->Parent == NULL )  /* If this is not a subwindow ... */
1099     {
1100       /*
1101        * Adjust the size of the window to allow for the size of the frame, if we are not a menu
1102        */
1103       if ( ! fgStructure.Window->IsMenu )
1104       {
1105                 width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
1106                 height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + GetSystemMetrics( SM_CYCAPTION );
1107       }
1108     }
1109     else  /* This is a subwindow, get the parent window's position and subtract it off */
1110     {
1111       GetWindowRect ( fgStructure.Window->Parent->Window.Handle, &winRect ) ;
1112       x -= winRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) ;
1113       y -= winRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ) ;
1114     }
1115
1116                 /*
1117                  * Resize the window, forcing a redraw to happen
1118                  */
1119                 MoveWindow(
1120                         fgStructure.Window->Window.Handle,
1121                         x,
1122                         y,
1123                         width,
1124                         height,
1125                         TRUE
1126                 );
1127         }
1128 #endif
1129 }
1130
1131 /*
1132  * Change the current window's position
1133  */
1134 void FGAPIENTRY glutPositionWindow( int x, int y )
1135 {
1136     freeglut_assert_ready; freeglut_assert_window;
1137
1138 #if TARGET_HOST_UNIX_X11
1139     /*
1140      * Reposition the window and flush the X state
1141      */
1142     XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, x, y );
1143     XFlush( fgDisplay.Display );
1144
1145 #elif TARGET_HOST_WIN32
1146         {
1147                 RECT winRect;
1148
1149                 /*
1150                  * First off, grab the current window's position
1151                  */
1152                 GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
1153
1154     /*
1155                  * Reposition the window, forcing a redraw to happen
1156                  */
1157                 MoveWindow(
1158                         fgStructure.Window->Window.Handle,
1159                         x,
1160                         y,
1161                         winRect.right - winRect.left,
1162                         winRect.bottom - winRect.top,
1163                         TRUE
1164                 );
1165         }
1166
1167 #endif
1168 }
1169
1170 /*
1171  * Lowers the current window (by Z order change)
1172  */
1173 void FGAPIENTRY glutPushWindow( void )
1174 {
1175     freeglut_assert_ready; freeglut_assert_window;
1176
1177 #if TARGET_HOST_UNIX_X11
1178     /*
1179      * Lower the current window
1180      */
1181     XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
1182
1183 #elif TARGET_HOST_WIN32
1184         /*
1185          * Set the new window's Z position, not affecting the rest of the settings:
1186          */
1187         SetWindowPos(
1188                 fgStructure.Window->Window.Handle,
1189                 HWND_BOTTOM,
1190                 0, 0, 0, 0,
1191                 SWP_NOSIZE | SWP_NOMOVE
1192         );
1193
1194 #endif
1195 }
1196
1197 /*
1198  * Raises the current window (by Z order change)
1199  */
1200 void FGAPIENTRY glutPopWindow( void )
1201 {
1202     freeglut_assert_ready; freeglut_assert_window;
1203
1204 #if TARGET_HOST_UNIX_X11
1205     /*
1206      * Raise the current window
1207      */
1208     XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
1209
1210 #elif TARGET_HOST_WIN32
1211         /*
1212          * Set the new window's Z position, not affecting the rest of the settings:
1213          */
1214         SetWindowPos(
1215                 fgStructure.Window->Window.Handle,
1216                 HWND_TOP,
1217                 0, 0, 0, 0,
1218                 SWP_NOSIZE | SWP_NOMOVE
1219         );
1220
1221 #endif
1222 }
1223
1224 /*
1225  * Resize the current window so that it fits the whole screen
1226  */
1227 void FGAPIENTRY glutFullScreen( void )
1228 {
1229     freeglut_assert_ready; freeglut_assert_window;
1230
1231     /*
1232      * Just have the window repositioned and resized
1233      */
1234     glutPositionWindow( 0, 0 );
1235
1236     glutReshapeWindow(
1237         fgDisplay.ScreenWidth,
1238         fgDisplay.ScreenHeight
1239     );
1240 }
1241
1242 /*
1243  * A.Donev: Set and retrieve the window's user data
1244  */
1245 void* FGAPIENTRY glutGetWindowData( void )
1246 {
1247    return(fgStructure.Window->UserData);
1248 }
1249
1250 void FGAPIENTRY glutSetWindowData(void* data)
1251 {
1252   fgStructure.Window->UserData=data;
1253 }
1254
1255 /*** END OF FILE ***/
1256
1257
1258
1259
1260
1261
1262
1263
1264