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