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