8d4f80554c13053f122901049866e43b834e4f5d
[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     window->Window.VisualInfo = fgChooseVisual();
367     if ( ! window->Window.VisualInfo )
368     {
369       /*
370        * The "fgChooseVisual" returned a null meaning that the visual context is not available.
371        * Try a couple of variations to see if they will work.
372        */
373       if ( ! ( fgState.DisplayMode & GLUT_DOUBLE ) )
374       {
375         /*
376          * Single buffering--try it doubled
377          */
378         fgState.DisplayMode |= GLUT_DOUBLE ;
379         window->Window.VisualInfo = fgChooseVisual();
380       }
381
382       /*
383        * GLUT also checks for multi-sampling, but I don't see that anywhere else in FREEGLUT
384        * so I won't bother with it for the moment.
385        */
386     }
387
388     assert( window->Window.VisualInfo != NULL );
389
390     /*
391      * Have the windows attributes set
392      *
393      * HINT: the masks should be updated when adding/removing callbacks.
394      *       This might speed up message processing. Is that true?
395      */
396     winAttr.event_mask        = StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
397                                 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyRelease |
398                                 VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
399                                 PointerMotionMask | ButtonMotionMask;
400     winAttr.background_pixmap = None;
401     winAttr.background_pixel  = 0;
402     winAttr.border_pixel      = 0;
403
404     /*
405      * The color map is required, too
406      */
407     winAttr.colormap = XCreateColormap(
408         fgDisplay.Display, fgDisplay.RootWindow,
409         window->Window.VisualInfo->visual, AllocNone
410     );
411
412     /*
413      * This tells the XCreateWindow() what attributes are we supplying it with
414      */
415     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
416
417     /*
418      * Have the window created now
419      */
420     window->Window.Handle = XCreateWindow(
421         fgDisplay.Display,
422         window->Parent == NULL ? fgDisplay.RootWindow : window->Parent->Window.Handle,
423         x, y, w, h, 0,
424         window->Window.VisualInfo->depth, InputOutput,
425         window->Window.VisualInfo->visual, mask,
426         &winAttr
427     );
428
429     /*
430      * The GLX context creation, possibly trying the direct context rendering
431      *  or else use the current context if the user has so specified
432      */
433     if ( fgState.UseCurrentContext == TRUE )
434     {
435       window->Window.Context = glXGetCurrentContext();
436
437       if ( ! window->Window.Context )
438         window->Window.Context = glXCreateContext(
439             fgDisplay.Display, window->Window.VisualInfo,
440             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
441         );
442     }
443     else
444       window->Window.Context = glXCreateContext(
445           fgDisplay.Display, window->Window.VisualInfo,
446           NULL, fgState.ForceDirectContext | fgState.TryDirectContext
447       );
448
449     /*
450      * Make sure the context is direct when the user wants it forced
451      */
452     if( fgState.ForceDirectContext && !glXIsDirect( fgDisplay.Display, window->Window.Context ) )
453         fgError( "unable to force direct context rendering for window '%s'", title );
454
455     /*
456      * Set the new context as the current one. That's all about the window creation.
457      */
458     glXMakeCurrent(
459         fgDisplay.Display,
460         window->Window.Handle,
461         window->Window.Context
462     );
463
464     /*
465      * Assume the new window is visible by default
466      */
467     window->State.Visible = TRUE;
468
469     /*
470      * For the position and size hints -- make sure we are passing valid values
471      */
472     sizeHints.flags = 0;
473
474     if (fgState.Position.Use == TRUE) sizeHints.flags |= USPosition;
475     if (fgState.Size.Use     == TRUE) sizeHints.flags |= USSize;
476
477     /*
478      * Fill in the size hints values now (the x, y, width and height
479      * settings are obsolote, are there any more WMs that support them?)
480      */
481     sizeHints.x      = x; sizeHints.y      = y;
482     sizeHints.width  = w; sizeHints.height = h;
483
484     /*
485      * We can have forced all new windows start in iconified state:
486      */
487     wmHints.flags = StateHint;
488     wmHints.initial_state = (fgState.ForceIconic == FALSE) ? NormalState : IconicState;
489
490     /*
491      * Prepare the window and iconified window names...
492      */
493     XStringListToTextProperty( (char **) &title, 1, &textProperty );
494
495     /*
496      * Set the window's properties now
497      */
498     XSetWMProperties(
499         fgDisplay.Display,
500         window->Window.Handle,
501         &textProperty,
502         &textProperty,
503         0,
504         0,
505         &sizeHints,
506         &wmHints,
507         NULL
508     );
509
510     /*
511      * Make sure we are informed about the window deletion commands
512      */
513     XSetWMProtocols( fgDisplay.Display, window->Window.Handle, &fgDisplay.DeleteWindow, 1 );
514
515     /*
516      * Finally, have the window mapped to our display
517      */
518     XMapWindow( fgDisplay.Display, window->Window.Handle );
519
520     /*
521      * In game mode, move the viewport a bit to hide the decorations.
522      * This code depends on the XFree86 video mode extensions.
523      */
524     if( gameMode == TRUE )
525     {
526         /*
527          * This somehow fixes the glutGet() GLUT_WINDOW_X and GLUT_WINDOW_Y problem...
528          */
529         XMoveWindow( fgDisplay.Display, window->Window.Handle, x, y );
530
531 #       ifdef X_XF86VidModeSetViewPort
532
533         /*
534          * Set the newly created window as the current one...
535          */
536         fgSetWindow( window );
537
538         /*
539          * Move the viewport a bit down and right from top-left corner to hide the decorations
540          */
541         XF86VidModeSetViewPort(
542             fgDisplay.Display,
543             fgDisplay.Screen,
544             glutGet( GLUT_WINDOW_X ),
545             glutGet( GLUT_WINDOW_Y )
546         );
547
548 #       endif
549     }
550
551 #elif TAR
552 GET_HOST_WIN32
553
554         WNDCLASS wc;
555         int flags;
556         ATOM atom;
557
558     freeglut_assert_ready;
559
560         /*
561          * Grab the window class we have registered on glutInit():
562          */
563         atom = GetClassInfo( fgDisplay.Instance, "FREEGLUT", &wc );
564         assert( atom != 0 );
565
566     if( gameMode == FALSE )
567     {
568       if ( !isSubWindow )
569       {
570         /*
571          * Update the window dimensions, taking account of window decorations.
572          * "freeglut" is to create the window with the outside of its border at (x,y)
573          * and with dimensions (w,h).
574          */
575                 w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2;
576                 h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 + GetSystemMetrics( SM_CYCAPTION );
577       }
578
579
580       /*
581              * Check if the user wants us to use the default position/size
582              */
583             if( fgState.Position.Use == FALSE ) { x = CW_USEDEFAULT; y = CW_USEDEFAULT; }
584           
585   if( fgState.Size    .Use == FALSE ) { w = CW_USEDEFAULT; h = CW_USEDEFAULT; }
586
587         
588     /*
589              * There's a small difference between creating the top, child and game mode windows
590              */
591             flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
592
593             if( window->Parent == NULL )
594                     flags |= WS_OVERLAPPEDWINDOW;
595             else
596                     flags |= WS_CHILD;
597     }
598
599     else
600     {
601         /*
602          * In game mode, the story is a little bit different...
603          */
604         assert( window->Parent == NULL );
605
606         /*
607          * Set the window creation flags appropriately to make the window entirely visible:
608          */
609         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
610     }
611
612
613     /*
614      * Create the window now, passing the freeglut window structure as the parameter
615      */
616         window->Window.Handle = CreateWindow( 
617                 "FREEGLUT",
618         title,
619                 flags,
620         x, y, w, h,
621                 (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
622                 (HMENU) NULL,
623                 fgDisplay.Instance,
624                 (LPVOID) window
625         );
626
627         /*
628      * Make sure window was created
629      */
630         assert( window->Window.Handle != NULL );
631
632     /*
633      * Show and update the main window. Hide the mouse cursor.
634      */
635     ShowWindow( window->Window.Handle, fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
636     UpdateWindow( window->Window.Handle );
637     ShowCursor( TRUE );
638
639 #endif
640
641     /*
642      * Save the window's single- or double-buffering state
643      */
644     window->Window.DoubleBuffered = ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0 ;
645
646     /*
647      * If it's not double-buffered, make sure the rendering is done to the front buffer.
648      */
649     if ( ! window->Window.DoubleBuffered )
650     {
651       glDrawBuffer ( GL_FRONT ) ;
652       glReadBuffer ( GL_FRONT ) ;
653     }
654
655
656     /*
657      * Set the newly created window as the current one
658      */
659     fgSetWindow( window );
660 }
661
662
663 /*
664  * Closes a window, destroying the frame and OpenGL context
665  */
666 void fgCloseWindow( SFG_Window* window )
667 {
668     freeglut_assert_ready;
669
670 #if TARGET_HOST_UNIX_X11
671     /*
672      * As easy as kill bunnies with axes. Destroy the context first:
673      */
674     glXDestroyContext( fgDisplay.Display, window->Window.Context );
675
676     /*
677      * Then have the window killed:
678      */
679     XDestroyWindow( fgDisplay.Display, window->Window.Handle );
680
681     /*
682      * Finally, flush the rests down the stream
683      */
684     XFlush( fgDisplay.Display );
685
686 #elif TARGET_HOST_WIN32
687         /*
688          * Send the WM_CLOSE message to the window now
689          */
690         SendMessage( 
691                 window->Window.Handle,
692                 WM_CLOSE,
693                 0,
694                 0
695         );
696
697 #endif
698 }
699
700
701
702 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
703
704 /*
705  * Creates a new top-level freeglut window
706  */
707 int FGAPIENTRY glutCreateWindow( const char* title )
708 {
709     /*
710      * Create a new window and return its unique ID number
711      */
712     return( fgCreateWindow( NULL, title, fgState.Position.X, fgState.Position.Y,
713                             fgState.Size.X, fgState.Size.Y, FALSE )->ID );
714 }
715
716
717 /*
718  * This function creates a sub window.
719  */
720 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
721 {
722     SFG_Window* window = NULL;
723     SFG_Window* parent = NULL;
724
725     freeglut_assert_ready;
726
727     /*
728      * Find a parent to the newly created window...
729      */
730     parent = fgWindowByID( parentID );
731
732     /*
733      * Fail if the parent has not been found
734      */
735     freeglut_return_val_if_fail( parent != NULL, 0 );
736
737     /*
738      * Create the new window
739      */
740     window = fgCreateWindow( parent, "", x, y, w, h, FALSE );
741
742     /*
743      * Return the new window's ID
744      */
745     return( window->ID );
746 }
747
748
749 /*
750  * Destroys a window and all of its subwindows
751  */
752 void FGAPIENTRY glutDestroyWindow( int windowID )
753 {
754   fgExecutionState ExecState = fgState.ExecState ;
755
756   /*
757    * Grab the freeglut window pointer from the structure
758    */
759   SFG_Window* window = fgWindowByID( windowID );
760   freeglut_return_if_fail( window != NULL );
761
762   /*
763    * There is a function that performs all needed steps
764    * defined in freeglut_structure.c. Let's use it:
765    */
766   fgAddToWindowDestroyList( window, TRUE );
767
768   /*
769    * Since the "fgAddToWindowDestroyList" function could easily have set the "ExecState"
770    * to stop, let's set it back to what it was.
771    */
772   fgState.ExecState = ExecState ;
773 }
774
775
776 /*
777  * This function selects the current window
778  */
779 void FGAPIENTRY glutSetWindow( int ID )
780 {
781     SFG_Window* window = NULL;
782
783     /*
784      * Make sure we don't get called too early
785      */
786     freeglut_assert_ready;
787
788     /*
789      * Be wise. Be wise. Be wise. Be quick.
790      */
791     if( fgStructure.Window != NULL )
792         if( fgStructure.Window->ID == ID )
793             return;
794
795     /*
796      * Now we are sure there is sense in looking for the window
797      */
798     window = fgWindowByID( ID );
799
800     /*
801      * In the case of an utter failure...
802      */
803     if( window == NULL )
804     {
805         /*
806          * ...issue a warning message and keep rolling on
807          */
808         fgWarning( "glutSetWindow(): window ID %i not found!", ID );
809         return;
810     }
811
812
813     fgSetWindow ( window ) ;
814 }
815
816
817 /*
818  * This function returns the ID number of the current window, 0 if none exists
819  */
820 int FGAPIENTRY glutGetWindow( void )
821 {
822     freeglut_assert_ready;
823
824     /*
825      * Do we have a current window selected?
826      */
827     if( fgStructure.Window == NULL )
828     {
829         /*
830          * Nope. Return zero to mark the state.
831          */
832         return( 0 );
833     }
834
835
836     /*
837      * Otherwise, return the ID of the current window
838      */
839     return( fgStructure.Window->ID );
840 }
841
842
843 /*
844  * This function makes the current window visible
845  */
846 void FGAPIENTRY glutShowWindow( void )
847 {
848     freeglut_assert_ready; freeglut_assert_window;
849
850 #if TARGET_HOST_UNIX_X11
851     /*
852      * Showing the window is done via mapping under X
853      */
854     XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
855     XFlush( fgDisplay.Display );
856
857 #elif TARGET_HOST_WIN32
858         /*
859          * Restore the window's originial position and size
860          */
861         ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
862
863 #endif
864 }
865
866
867 /*
868  * This function hides the current window
869  */
870 void FGAPIENTRY glutHideWindow( void )
871 {
872     freeglut_assert_ready; freeglut_assert_window;
873
874 #if TARGET_HOST_UNIX_X11
875     /*
876      * The way we hide a window depends on if we're dealing
877      * with a top-level or children one...
878      */
879     if( fgStructure.Window->Parent == NULL )
880     {
881         /*
882          * This is a top-level window
883          */
884         XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen );
885     }
886
887     else
888     {
889         /*
890          * Nope, it's a child window
891          */
892         XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
893     }
894
895
896     /*
897      * Flush the X state now
898      */
899     XFlush( fgDisplay.Display );
900
901 #elif TARGET_HOST_WIN32
902         /*
903          * Hide the window
904          */
905         ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
906
907 #endif
908 }
909
910
911 /*
912  * Iconify the current window (top-level windows only)
913  */
914 void FGAPIENTRY glutIconifyWindow( void )
915 {
916     freeglut_assert_ready; freeglut_assert_window;
917
918 #if TARGET_HOST_UNIX_X11
919     /*
920      * Iconify the window and flush the X state
921      */
922     XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, fgDisplay.Screen );
923     XFlush( fgDisplay.Display );
924
925 #elif TARGET_HOST_WIN32
926         /*
927          * Minimize the current window (this should be the same as X window iconifying)
928          */
929         ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
930
931 #endif
932 }
933
934
935 /*
936  * Set the current window's title
937  */
938 void FGAPIENTRY glutSetWindowTitle( const char* title )
939 {
940         freeglut_assert_ready; freeglut_assert_window;
941
942     /*
943      * Works only for top-level windows
944      */
945     if( fgStructure.Window->Parent != NULL )
946         return;
947
948 #if TARGET_HOST_UNIX_X11
949         {
950                 XTextProperty text;
951
952                 /*
953                  * Prepare the text properties
954                  */
955                 text.value = (unsigned char *) title;
956                 text.encoding = XA_STRING;
957                 text.format = 8;
958                 text.nitems = strlen( title );
959
960                 /*
961                  * Set the title now
962                  */
963                 XSetWMName(
964                         fgDisplay.Display,
965                         fgStructure.Window->Window.Handle,
966                         &text
967                 );
968
969                 /*
970                  * Have the X display state flushed
971                  */
972                 XFlush( fgDisplay.Display );
973         }
974
975
976 #elif TARGET_HOST_WIN32
977         /*
978          * This seems to be a bit easier under Win32
979          */
980         SetWindowText( fgStructure.Window->Window.Handle, title );
981
982 #endif
983 }
984
985
986 /*
987  * Set the current window's iconified title
988  */
989 void FGAPIENTRY glutSetIconTitle( const char* title )
990 {
991     freeglut_assert_ready; freeglut_assert_window;
992
993     /*
994      * Works only for top-level windows
995      */
996     if( fgStructure.Window->Parent != NULL )
997         return;
998
999 #if TARGET_HOST_UNIX_X11
1000         {
1001                 XTextProperty text;
1002
1003                 /*
1004                  * Prepare the text properties
1005                  */
1006                 text.value = (unsigned char *) title;
1007                 text.encoding = XA_STRING;
1008                 text.format = 8;
1009                 text.nitems = strlen( title );
1010
1011                 /*
1012                  * Set the title now
1013                  */
1014                 XSetWMIconName(
1015                         fgDisplay.Display,
1016                         fgStructure.Window->Window.Handle,
1017                         &text
1018                 );
1019
1020                 /*
1021                  * Have the X display state flushed
1022                  */
1023                 XFlush( fgDisplay.Display );
1024         }
1025
1026
1027 #elif TARGET_HOST_WIN32
1028         /*
1029          * This seems to be a bit easier under Win32
1030          */
1031         SetWindowText( fgStructure.Window->Window.Handle, title );
1032
1033 #endif
1034 }
1035
1036
1037 /*
1038  * Change the current window's size
1039  */
1040 void FGAPIENTRY glutReshapeWindow( int width, int height )
1041 {
1042     freeglut_assert_ready; freeglut_assert_window;
1043
1044 #if TARGET_HOST_UNIX_X11
1045     /*
1046      * Resize the window and flush the X state
1047      */
1048     XResizeWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, width, height );
1049     XFlush( fgDisplay.Display );
1050
1051 #elif TARGET_HOST_WIN32
1052         {
1053                 RECT winRect;
1054     int x, y ;
1055
1056                 /*
1057                  * First off, grab the current window's position
1058                  */
1059                 GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
1060     x = winRect.left ;
1061     y = winRect.top ;
1062
1063     if ( fgStructure.Window->Parent == NULL )  /* If this is not a subwindow ... */
1064     {
1065       /*
1066        * Adjust the size of the window to allow for the size of the frame
1067        */
1068                 width += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
1069                 height += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 + GetSystemMetrics( SM_CYCAPTION );
1070     }
1071
1072     else  /* This is a subwindow, get the parent window's position and subtract it off */
1073     {
1074       GetWindowRect ( fgStructure.Window->Parent->Window.Handle, &winRect ) ;
1075       x -= winRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) ;
1076       y -= winRect.top + GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ) ;
1077     }
1078
1079
1080                 /*
1081                  * Resize the window, forcing a redraw to happen
1082                  */
1083                 MoveWindow(
1084                         fgStructure.Window->Window.Handle,
1085                         x,
1086                         y,
1087                         width,
1088                         height,
1089                         TRUE
1090                 );
1091         }
1092
1093 #endif
1094 }
1095
1096
1097 /*
1098  * Change the current window's position
1099  */
1100 void FGAPIENTRY glutPositionWindow( int x, int y )
1101 {
1102     freeglut_assert_ready; freeglut_assert_window;
1103
1104 #if TARGET_HOST_UNIX_X11
1105     /*
1106      * Reposition the window and flush the X state
1107      */
1108     XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, x, y );
1109     XFlush( fgDisplay.Display );
1110
1111 #elif TARGET_HOST_WIN32
1112         {
1113                 RECT winRect;
1114
1115                 /*
1116                  * First off, grab the current window's position
1117                  */
1118                 GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
1119
1120     /*
1121                  * Reposition the window, forcing a redraw to happen
1122                  */
1123                 MoveWindow(
1124                         fgStructure.Window->Window.Handle,
1125                         x,
1126                         y,
1127                         winRect.right - winRect.left,
1128                         winRect.bottom - winRect.top,
1129                         TRUE
1130                 );
1131         }
1132
1133
1134 #endif
1135 }
1136
1137
1138 /*
1139  * Lowers the current window (by Z order change)
1140  */
1141 void FGAPIENTRY glutPushWindow( void )
1142 {
1143     freeglut_assert_ready; freeglut_assert_window;
1144
1145 #if TARGET_HOST_UNIX_X11
1146     /*
1147      * Lower the current window
1148      */
1149     XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
1150
1151 #elif TARGET_HOST_WIN32
1152         /*
1153          * Set the new window's Z position, not affecting the rest of the settings:
1154          */
1155         SetWindowPos(
1156                 fgStructure.Window->Window.Handle,
1157                 HWND_BOTTOM,
1158                 0, 0, 0, 0,
1159                 SWP_NOSIZE | SWP_NOMOVE
1160         );
1161
1162 #endif
1163 }
1164
1165
1166 /*
1167  * Raises the current window (by Z order change)
1168  */
1169 void FGAPIENTRY glutPopWindow( void )
1170 {
1171     freeglut_assert_ready; freeglut_assert_window;
1172
1173 #if TARGET_HOST_UNIX_X11
1174     /*
1175      * Raise the current window
1176      */
1177     XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
1178
1179 #elif TARGET_HOST_WIN32
1180         /*
1181          * Set the new window's Z position, not affecting the rest of the settings:
1182          */
1183         SetWindowPos(
1184                 fgStructure.Window->Window.Handle,
1185                 HWND_TOP,
1186                 0, 0, 0, 0,
1187                 SWP_NOSIZE | SWP_NOMOVE
1188         );
1189
1190 #endif
1191 }
1192
1193
1194 /*
1195  * Resize the current window so that it fits the whole screen
1196  */
1197 void FGAPIENTRY glutFullScreen( void )
1198 {
1199     freeglut_assert_ready; freeglut_assert_window;
1200
1201     /*
1202      * Just have the window repositioned and resized
1203      */
1204     glutPositionWindow( 0, 0 );
1205
1206     glutReshapeWindow(
1207         fgDisplay.ScreenWidth,
1208         fgDisplay.ScreenHeight
1209     );
1210 }
1211
1212
1213 /*
1214  * A.Donev: Set and retrieve the window's user data
1215  */
1216 void* FGAPIENTRY glutGetWindowData( void )
1217 {
1218    return(fgStructure.Window->UserData);
1219 }
1220
1221
1222 void FGAPIENTRY glutSetWindowData(void* data)
1223 {
1224   fgStructure.Window->UserData=data;
1225 }
1226
1227
1228 /*** END OF FILE ***/