dc5f5d7009958acd3124efb4c6aa591eba1ef8e4
[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 #include <GL/freeglut.h>
29 #include "freeglut_internal.h"
30
31 #if TARGET_HOST_WINCE
32 #include <aygshell.h>
33 #pragma comment( lib, "Aygshell.lib" )
34
35 static wchar_t* fghWstrFromStr(const char* str)
36 {
37     int i,len=strlen(str);
38     wchar_t* wstr = (wchar_t*)malloc(2*len+2);
39     for(i=0; i<len; i++)
40         wstr[i] = str[i];
41     wstr[len] = 0;
42     return wstr;
43 }
44
45
46 #endif /* TARGET_HOST_WINCE */
47
48 /*
49  * TODO BEFORE THE STABLE RELEASE:
50  *
51  *  fgChooseVisual()        -- OK, but what about glutInitDisplayString()?
52  *  fgSetupPixelFormat      -- ignores the display mode settings
53  *  fgOpenWindow()          -- check the Win32 version, -iconic handling!
54  *  fgCloseWindow()         -- check the Win32 version
55  *  glutCreateWindow()      -- Check when default position and size is {-1,-1}
56  *  glutCreateSubWindow()   -- Check when default position and size is {-1,-1}
57  *  glutDestroyWindow()     -- check the Win32 version
58  *  glutSetWindow()         -- check the Win32 version
59  *  glutGetWindow()         -- OK
60  *  glutSetWindowTitle()    -- check the Win32 version
61  *  glutSetIconTitle()      -- check the Win32 version
62  *  glutShowWindow()        -- check the Win32 version
63  *  glutHideWindow()        -- check the Win32 version
64  *  glutIconifyWindow()     -- check the Win32 version
65  *  glutReshapeWindow()     -- check the Win32 version
66  *  glutPositionWindow()    -- check the Win32 version
67  *  glutPushWindow()        -- check the Win32 version
68  *  glutPopWindow()         -- check the Win32 version
69  */
70
71 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
72
73 /*
74  * Chooses a visual basing on the current display mode settings
75  */
76 #if TARGET_HOST_UNIX_X11
77
78 XVisualInfo* fgChooseVisual( void )
79 {
80 #define BUFFER_SIZES 6
81     int bufferSize[BUFFER_SIZES] = { 16, 12, 8, 4, 2, 1 };
82     GLboolean wantIndexedMode = GL_FALSE;
83     int attributes[ 32 ];
84     int where = 0;
85
86     /* First we have to process the display mode settings... */
87 /*
88  * XXX Why is there a semi-colon in this #define?  The code
89  * XXX that uses the macro seems to always add more semicolons...
90  */
91 #define ATTRIB(a) attributes[where++]=a;
92 #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}
93
94     if( fgState.DisplayMode & GLUT_INDEX )
95     {
96         ATTRIB_VAL( GLX_BUFFER_SIZE, 8 );
97         wantIndexedMode = GL_TRUE;
98     }
99     else
100     {
101         ATTRIB( GLX_RGBA );
102         ATTRIB_VAL( GLX_RED_SIZE,   1 );
103         ATTRIB_VAL( GLX_GREEN_SIZE, 1 );
104         ATTRIB_VAL( GLX_BLUE_SIZE,  1 );
105         if( fgState.DisplayMode & GLUT_ALPHA )
106             ATTRIB_VAL( GLX_ALPHA_SIZE, 1 );
107     }
108
109     if( fgState.DisplayMode & GLUT_DOUBLE )
110         ATTRIB( GLX_DOUBLEBUFFER );
111
112     if( fgState.DisplayMode & GLUT_STEREO )
113         ATTRIB( GLX_STEREO );
114
115     if( fgState.DisplayMode & GLUT_DEPTH )
116         ATTRIB_VAL( GLX_DEPTH_SIZE, 1 );
117
118     if( fgState.DisplayMode & GLUT_STENCIL )
119         ATTRIB_VAL( GLX_STENCIL_SIZE, 1 );
120
121     if( fgState.DisplayMode & GLUT_ACCUM )
122     {
123         ATTRIB_VAL( GLX_ACCUM_RED_SIZE,   1 );
124         ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 );
125         ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE,  1 );
126         if( fgState.DisplayMode & GLUT_ALPHA )
127             ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 );
128     }
129
130     /* Push a null at the end of the list */
131     ATTRIB( None );
132
133     if( ! wantIndexedMode )
134         return glXChooseVisual( fgDisplay.Display, fgDisplay.Screen,
135                                 attributes );
136     else
137     {
138         XVisualInfo* visualInfo;
139         int i;
140
141         /*
142          * In indexed mode, we need to check how many bits of depth can we
143          * achieve.  We do this by trying each possibility from the list
144          * given in the {bufferSize} array.  If we match, we return to caller.
145          */
146         for( i=0; i<BUFFER_SIZES; i++ )
147         {
148             attributes[ 1 ] = bufferSize[ i ];
149             visualInfo = glXChooseVisual( fgDisplay.Display, fgDisplay.Screen,
150                                           attributes );
151             if( visualInfo != NULL )
152                 return visualInfo;
153         }
154         return NULL;
155     }
156 }
157 #endif
158
159 /*
160  * Setup the pixel format for a Win32 window
161  */
162 #if TARGET_HOST_WIN32
163 GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
164                               unsigned char layer_type )
165 {
166 #if TARGET_HOST_WINCE
167     return GL_TRUE;
168 #else
169     PIXELFORMATDESCRIPTOR* ppfd, pfd;
170     int flags, pixelformat;
171
172     freeglut_return_val_if_fail( window != NULL, 0 );
173     flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
174     if( fgState.DisplayMode & GLUT_DOUBLE )
175         flags |= PFD_DOUBLEBUFFER;
176
177 #if defined(_MSC_VER)
178 #pragma message( "fgSetupPixelFormat(): there is still some work to do here!" )
179 #endif
180
181     /* Specify which pixel format do we opt for... */
182     pfd.nSize           = sizeof(PIXELFORMATDESCRIPTOR);
183     pfd.nVersion        = 1;
184     pfd.dwFlags         = flags;
185     pfd.iPixelType      = PFD_TYPE_RGBA;
186     pfd.cColorBits      = 24;
187     pfd.cRedBits        = 0;
188     pfd.cRedShift       = 0;
189     pfd.cGreenBits      = 0;
190     pfd.cGreenShift     = 0;
191     pfd.cBlueBits       = 0;
192     pfd.cBlueShift      = 0;
193     pfd.cAlphaBits      = 0;
194     pfd.cAlphaShift     = 0;
195     pfd.cAccumBits      = 0;
196     pfd.cAccumRedBits   = 0;
197     pfd.cAccumGreenBits = 0;
198     pfd.cAccumBlueBits  = 0;
199     pfd.cAccumAlphaBits = 0;
200 #if 0
201     pfd.cDepthBits      = 32;
202     pfd.cStencilBits    = 0;
203 #else
204     pfd.cDepthBits      = 24;
205     pfd.cStencilBits    = 8;
206 #endif
207     pfd.cAuxBuffers     = 0;
208     pfd.iLayerType      = layer_type;
209     pfd.bReserved       = 0;
210     pfd.dwLayerMask     = 0;
211     pfd.dwVisibleMask   = 0;
212     pfd.dwDamageMask    = 0;
213
214     pfd.cColorBits = (BYTE) GetDeviceCaps( window->Window.Device, BITSPIXEL );
215     ppfd = &pfd;
216
217     pixelformat = ChoosePixelFormat( window->Window.Device, ppfd );
218     if( pixelformat == 0 )
219         return GL_FALSE;
220
221     if( checkOnly )
222         return GL_TRUE;
223     return SetPixelFormat( window->Window.Device, pixelformat, ppfd );
224 #endif /* TARGET_HOST_WINCE */
225 }
226 #endif
227
228 /*
229  * Sets the OpenGL context and the fgStructure "Current Window" pointer to
230  * the window structure passed in.
231  */
232 void fgSetWindow ( SFG_Window *window )
233 {
234 #if TARGET_HOST_UNIX_X11
235     if ( window )
236         glXMakeCurrent(
237             fgDisplay.Display,
238             window->Window.Handle,
239             window->Window.Context
240         );
241 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
242     if( fgStructure.Window )
243         ReleaseDC( fgStructure.Window->Window.Handle,
244                    fgStructure.Window->Window.Device );
245
246     if ( window )
247     {
248         window->Window.Device = GetDC( window->Window.Handle );
249         wglMakeCurrent(
250             window->Window.Device,
251             window->Window.Context
252         );
253     }
254 #endif
255     fgStructure.Window = window;
256 }
257
258
259 /*
260  * Opens a window. Requires a SFG_Window object created and attached
261  * to the freeglut structure. OpenGL context is created here.
262  */
263 void fgOpenWindow( SFG_Window* window, const char* title,
264                    int x, int y, int w, int h,
265                    GLboolean gameMode, GLboolean isSubWindow )
266 {
267 #if TARGET_HOST_UNIX_X11
268     XSetWindowAttributes winAttr;
269     XTextProperty textProperty;
270     XSizeHints sizeHints;
271     XWMHints wmHints;
272     unsigned long mask;
273     unsigned int current_DisplayMode = fgState.DisplayMode ;
274
275     /* Save the display mode if we are creating a menu window */
276     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
277         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;
278
279     window->Window.VisualInfo = fgChooseVisual( );
280
281     if( window->IsMenu && ( ! fgStructure.MenuContext ) )
282         fgState.DisplayMode = current_DisplayMode ;
283
284     if( ! window->Window.VisualInfo )
285     {
286         /*
287          * The "fgChooseVisual" returned a null meaning that the visual
288          * context is not available.
289          * Try a couple of variations to see if they will work.
290          */
291         if( !( fgState.DisplayMode & GLUT_DOUBLE ) )
292         {
293             fgState.DisplayMode |= GLUT_DOUBLE ;
294             window->Window.VisualInfo = fgChooseVisual( );
295             fgState.DisplayMode &= ~GLUT_DOUBLE;
296         }
297
298         /*
299          * GLUT also checks for multi-sampling, but I don't see that
300          * anywhere else in FREEGLUT so I won't bother with it for the moment.
301          */
302     }
303
304     FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.VisualInfo != NULL,
305                                   "Unable to get window visual info", "fgOpenWindow" );
306
307     /*
308      * XXX HINT: the masks should be updated when adding/removing callbacks.
309      * XXX       This might speed up message processing. Is that true?
310      * XXX
311      * XXX A: Not appreciably, but it WILL make it easier to debug.
312      * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT
313      * XXX    turns off events that it doesn't need and is a whole lot
314      * XXX    more pleasant to trace.  (Think mouse-motion!  Tons of
315      * XXX    ``bonus'' GUI events stream in.)
316      */
317     winAttr.event_mask        =
318         StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
319         ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyRelease |
320         VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
321         PointerMotionMask | ButtonMotionMask;
322     winAttr.background_pixmap = None;
323     winAttr.background_pixel  = 0;
324     winAttr.border_pixel      = 0;
325
326     winAttr.colormap = XCreateColormap(
327         fgDisplay.Display, fgDisplay.RootWindow,
328         window->Window.VisualInfo->visual, AllocNone
329     );
330
331     mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
332
333     if( window->IsMenu )
334     {
335         winAttr.override_redirect = True;
336         mask |= CWOverrideRedirect;
337     }
338
339     window->Window.Handle = XCreateWindow(
340         fgDisplay.Display,
341         window->Parent == NULL ? fgDisplay.RootWindow :
342         window->Parent->Window.Handle,
343         x, y, w, h, 0,
344         window->Window.VisualInfo->depth, InputOutput,
345         window->Window.VisualInfo->visual, mask,
346         &winAttr
347     );
348
349     /*
350      * The GLX context creation, possibly trying the direct context rendering
351      *  or else use the current context if the user has so specified
352      */
353     if( window->IsMenu )
354     {
355         /*
356          * If there isn't already an OpenGL rendering context for menu
357          * windows, make one
358          */
359         if( !fgStructure.MenuContext )
360         {
361             fgStructure.MenuContext =
362                 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
363             fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo;
364             fgStructure.MenuContext->Context = glXCreateContext(
365                 fgDisplay.Display, fgStructure.MenuContext->VisualInfo,
366                 NULL, ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT )
367             );
368         }
369
370         /* window->Window.Context = fgStructure.MenuContext->Context; */
371         window->Window.Context = glXCreateContext(
372             fgDisplay.Display, window->Window.VisualInfo,
373             NULL, ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT )
374         );
375     }
376     else if( fgState.UseCurrentContext )
377     {
378         window->Window.Context = glXGetCurrentContext( );
379
380         if( ! window->Window.Context )
381             window->Window.Context = glXCreateContext(
382                 fgDisplay.Display, window->Window.VisualInfo,
383                 NULL, ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT )
384             );
385     }
386     else
387         window->Window.Context = glXCreateContext(
388             fgDisplay.Display, window->Window.VisualInfo,
389             NULL, ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT )
390         );
391
392 #if !defined( __FreeBSD__ ) && !defined( __NetBSD__ )
393     if(  !glXIsDirect( fgDisplay.Display, window->Window.Context ) )
394     {
395       if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
396         fgError( "Unable to force direct context rendering for window '%s'",
397                  title );
398       else if( fgState.DirectContext == GLUT_TRY_DIRECT_CONTEXT )
399         fgWarning( "Unable to create direct context rendering for window '%s'\nThis may hurt performance.",
400                  title );
401     }
402 #endif
403
404     glXMakeCurrent(
405         fgDisplay.Display,
406         window->Window.Handle,
407         window->Window.Context
408     );
409
410     /*
411      * XXX Assume the new window is visible by default
412      * XXX Is this a  safe assumption?
413      */
414     window->State.Visible = GL_TRUE;
415
416     sizeHints.flags = 0;
417     if ( fgState.Position.Use )
418         sizeHints.flags |= USPosition;
419     if ( fgState.Size.Use )
420         sizeHints.flags |= USSize;
421
422     /*
423      * Fill in the size hints values now (the x, y, width and height
424      * settings are obsolete, are there any more WMs that support them?)
425      * Unless the X servers actually stop supporting these, we should
426      * continue to fill them in.  It is *not* our place to tell the user
427      * that they should replace a window manager that they like, and which
428      * works, just because *we* think that it's not "modern" enough.
429      */
430     sizeHints.x      = x;
431     sizeHints.y      = y;
432     sizeHints.width  = w;
433     sizeHints.height = h;
434
435     wmHints.flags = StateHint;
436     wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState;
437     /* Prepare the window and iconified window names... */
438     XStringListToTextProperty( (char **) &title, 1, &textProperty );
439
440     XSetWMProperties(
441         fgDisplay.Display,
442         window->Window.Handle,
443         &textProperty,
444         &textProperty,
445         0,
446         0,
447         &sizeHints,
448         &wmHints,
449         NULL
450     );
451
452     XSetWMProtocols( fgDisplay.Display, window->Window.Handle,
453                      &fgDisplay.DeleteWindow, 1 );
454
455     XMapWindow( fgDisplay.Display, window->Window.Handle );
456
457 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
458
459     WNDCLASS wc;
460     DWORD flags;
461     DWORD exFlags = 0;
462     ATOM atom;
463
464     /* Grab the window class we have registered on glutInit(): */
465     atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );
466     FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found",
467                                    "fgOpenWindow" );
468
469     if( gameMode )
470     {
471         FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL,
472                                        "Game mode being invoked on a subwindow",
473                                        "fgOpenWindow" );
474
475         /*
476          * Set the window creation flags appropriately to make the window
477          * entirely visible:
478          */
479         flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
480     }
481     else
482     {
483 #if !TARGET_HOST_WINCE
484         if ( ( ! isSubWindow ) && ( ! window->IsMenu ) )
485         {
486             /*
487              * Update the window dimensions, taking account of window
488              * decorations.  "freeglut" is to create the window with the
489              * outside of its border at (x,y) and with dimensions (w,h).
490              */
491             w += (GetSystemMetrics( SM_CXSIZEFRAME ) )*2;
492             h += (GetSystemMetrics( SM_CYSIZEFRAME ) )*2 +
493                 GetSystemMetrics( SM_CYCAPTION );
494         }
495 #endif /* TARGET_HOST_WINCE */
496
497         if( ! fgState.Position.Use )
498         {
499             x = CW_USEDEFAULT;
500             y = CW_USEDEFAULT;
501         }
502         if( ! fgState.Size.Use )
503         {
504             w = CW_USEDEFAULT;
505             h = CW_USEDEFAULT;
506         }
507
508         /*
509          * There's a small difference between creating the top, child and
510          * game mode windows
511          */
512         flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
513
514         if ( window->IsMenu )
515         {
516             flags |= WS_POPUP;
517             exFlags |= WS_EX_TOOLWINDOW;
518         }
519 #if !TARGET_HOST_WINCE
520         else if( window->Parent == NULL )
521             flags |= WS_OVERLAPPEDWINDOW;
522 #endif
523         else
524             flags |= WS_CHILD;
525     }
526
527 #if TARGET_HOST_WINCE
528     {
529         wchar_t* wstr = fghWstrFromStr(title);
530
531         window->Window.Handle = CreateWindow(
532             _T("FREEGLUT"),
533             wstr,
534             WS_VISIBLE | WS_POPUP,
535             0,0, 240,320,
536             NULL,
537             NULL,
538             fgDisplay.Instance,
539             (LPVOID) window
540         );
541
542         free(wstr);
543
544         SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON);
545         SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON);
546         SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR);
547         MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE);
548         ShowWindow(window->Window.Handle, SW_SHOW);
549         UpdateWindow(window->Window.Handle);
550     }
551 #else
552     window->Window.Handle = CreateWindowEx(
553         exFlags,
554         "FREEGLUT",
555         title,
556         flags,
557         x, y, w, h,
558         (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle,
559         (HMENU) NULL,
560         fgDisplay.Instance,
561         (LPVOID) window
562     );
563 #endif /* TARGET_HOST_WINCE */
564
565     if( !( window->Window.Handle ) )
566         fgError( "Failed to create a window (%s)!", title );
567
568 #if TARGET_HOST_WINCE
569     ShowWindow( window->Window.Handle, SW_SHOW );
570 #else
571     ShowWindow( window->Window.Handle,
572                 fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW );
573 #endif /* TARGET_HOST_WINCE */
574
575     UpdateWindow( window->Window.Handle );
576     ShowCursor( TRUE );  /* XXX Old comments say "hide cusror"! */
577
578 #endif
579
580     fgSetWindow( window );
581
582     window->Window.DoubleBuffered =
583         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0;
584
585     if ( ! window->Window.DoubleBuffered )
586     {
587         glDrawBuffer ( GL_FRONT );
588         glReadBuffer ( GL_FRONT );
589     }
590 }
591
592 /*
593  * Closes a window, destroying the frame and OpenGL context
594  */
595 void fgCloseWindow( SFG_Window* window )
596 {
597 #if TARGET_HOST_UNIX_X11
598
599     glXDestroyContext( fgDisplay.Display, window->Window.Context );
600     XDestroyWindow( fgDisplay.Display, window->Window.Handle );
601     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
602
603 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
604
605     /* Make sure we don't close a window with current context active */
606     if( fgStructure.Window == window )
607         wglMakeCurrent( NULL, NULL );
608
609     /*
610      * Step through the list of windows.  If the rendering context
611      * is not being used by another window, then we delete it.
612      */
613     {
614         int used = FALSE ;
615         SFG_Window *iter ;
616
617         for( iter = (SFG_Window *)fgStructure.Windows.First;
618              iter;
619              iter = (SFG_Window *)iter->Node.Next )
620         {
621             if( ( iter->Window.Context == window->Window.Context ) &&
622                 ( iter != window ) )
623                 used = TRUE;
624         }
625
626         if( ! used )
627             wglDeleteContext( window->Window.Context );
628     }
629
630     DestroyWindow( window->Window.Handle );
631 #endif
632 }
633
634
635 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
636
637 /*
638  * Creates a new top-level freeglut window
639  */
640 int FGAPIENTRY glutCreateWindow( const char* title )
641 {
642     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" );
643
644     return fgCreateWindow( NULL, title, fgState.Position.X, fgState.Position.Y,
645                            fgState.Size.X, fgState.Size.Y, GL_FALSE,
646                            GL_FALSE )->ID;
647 }
648
649 /*
650  * This function creates a sub window.
651  */
652 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
653 {
654     int ret = 0;
655     SFG_Window* window = NULL;
656     SFG_Window* parent = NULL;
657
658     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" );
659     parent = fgWindowByID( parentID );
660     freeglut_return_val_if_fail( parent != NULL, 0 );
661     window = fgCreateWindow( parent, "", x, y, w, h, GL_FALSE, GL_FALSE );
662     ret = window->ID;
663
664     return ret;
665 }
666
667 /*
668  * Destroys a window and all of its subwindows
669  */
670 void FGAPIENTRY glutDestroyWindow( int windowID )
671 {
672     SFG_Window* window;
673     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" );
674     window = fgWindowByID( windowID );
675     freeglut_return_if_fail( window != NULL );
676     {
677         fgExecutionState ExecState = fgState.ExecState;
678         fgAddToWindowDestroyList( window );
679         fgState.ExecState = ExecState;
680     }
681 }
682
683 /*
684  * This function selects the current window
685  */
686 void FGAPIENTRY glutSetWindow( int ID )
687 {
688     SFG_Window* window = NULL;
689
690     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" );
691     if( fgStructure.Window != NULL )
692         if( fgStructure.Window->ID == ID )
693             return;
694
695     window = fgWindowByID( ID );
696     if( window == NULL )
697     {
698         fgWarning( "glutSetWindow(): window ID %d not found!", ID );
699         return;
700     }
701
702     fgSetWindow( window );
703 }
704
705 /*
706  * This function returns the ID number of the current window, 0 if none exists
707  */
708 int FGAPIENTRY glutGetWindow( void )
709 {
710     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindow" );
711     if( fgStructure.Window == NULL )
712         return 0;
713     return fgStructure.Window->ID;
714 }
715
716 /*
717  * This function makes the current window visible
718  */
719 void FGAPIENTRY glutShowWindow( void )
720 {
721     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" );
722     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" );
723
724 #if TARGET_HOST_UNIX_X11
725
726     XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
727     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
728
729 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
730
731     ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
732
733 #endif
734
735     fgStructure.Window->State.Redisplay = GL_TRUE;
736 }
737
738 /*
739  * This function hides the current window
740  */
741 void FGAPIENTRY glutHideWindow( void )
742 {
743     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" );
744     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" );
745
746 #if TARGET_HOST_UNIX_X11
747
748     if( fgStructure.Window->Parent == NULL )
749         XWithdrawWindow( fgDisplay.Display,
750                          fgStructure.Window->Window.Handle,
751                          fgDisplay.Screen );
752     else
753         XUnmapWindow( fgDisplay.Display,
754                       fgStructure.Window->Window.Handle );
755     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
756
757 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
758
759     ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
760
761 #endif
762
763     fgStructure.Window->State.Redisplay = GL_FALSE;
764 }
765
766 /*
767  * Iconify the current window (top-level windows only)
768  */
769 void FGAPIENTRY glutIconifyWindow( void )
770 {
771     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" );
772     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" );
773
774     fgStructure.Window->State.Visible   = GL_FALSE;
775 #if TARGET_HOST_UNIX_X11
776
777     XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
778                     fgDisplay.Screen );
779     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
780
781 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
782
783     ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
784
785 #endif
786
787     fgStructure.Window->State.Redisplay = GL_FALSE;
788 }
789
790 /*
791  * Set the current window's title
792  */
793 void FGAPIENTRY glutSetWindowTitle( const char* title )
794 {
795     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" );
796     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" );
797     if( ! fgStructure.Window->Parent )
798     {
799 #if TARGET_HOST_UNIX_X11
800
801         XTextProperty text;
802
803         text.value = (unsigned char *) title;
804         text.encoding = XA_STRING;
805         text.format = 8;
806         text.nitems = strlen( title );
807
808         XSetWMName(
809             fgDisplay.Display,
810             fgStructure.Window->Window.Handle,
811             &text
812         );
813
814         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
815
816 #elif TARGET_HOST_WIN32
817
818         SetWindowText( fgStructure.Window->Window.Handle, title );
819
820 #elif TARGET_HOST_WINCE
821         {
822             wchar_t* wstr = fghWstrFromStr(title);
823
824             SetWindowText( fgStructure.Window->Window.Handle, wstr );
825
826             free(wstr);
827         }
828 #endif
829     }
830 }
831
832 /*
833  * Set the current window's iconified title
834  */
835 void FGAPIENTRY glutSetIconTitle( const char* title )
836 {
837     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" );
838     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" );
839
840     if( ! fgStructure.Window->Parent )
841     {
842 #if TARGET_HOST_UNIX_X11
843
844         XTextProperty text;
845
846         text.value = (unsigned char *) title;
847         text.encoding = XA_STRING;
848         text.format = 8;
849         text.nitems = strlen( title );
850
851         XSetWMIconName(
852             fgDisplay.Display,
853             fgStructure.Window->Window.Handle,
854             &text
855         );
856
857         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
858
859 #elif TARGET_HOST_WIN32
860
861         SetWindowText( fgStructure.Window->Window.Handle, title );
862
863 #elif TARGET_HOST_WINCE
864         {
865             wchar_t* wstr = fghWstrFromStr(title);
866
867             SetWindowText( fgStructure.Window->Window.Handle, wstr );
868
869             free(wstr);
870         }
871 #endif
872     }
873 }
874
875 /*
876  * Change the current window's size
877  */
878 void FGAPIENTRY glutReshapeWindow( int width, int height )
879 {
880     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );
881     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );
882
883     fgStructure.Window->State.NeedToResize = GL_TRUE;
884     fgStructure.Window->State.Width  = width ;
885     fgStructure.Window->State.Height = height;
886 }
887
888 /*
889  * Change the current window's position
890  */
891 void FGAPIENTRY glutPositionWindow( int x, int y )
892 {
893     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );
894     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
895
896 #if TARGET_HOST_UNIX_X11
897
898     XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
899                  x, y );
900     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
901
902 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
903
904     {
905         RECT winRect;
906
907         /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
908         GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
909         MoveWindow(
910             fgStructure.Window->Window.Handle,
911             x,
912             y,
913             winRect.right - winRect.left,
914             winRect.bottom - winRect.top,
915             TRUE
916         );
917     }
918
919 #endif
920 }
921
922 /*
923  * Lowers the current window (by Z order change)
924  */
925 void FGAPIENTRY glutPushWindow( void )
926 {
927     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );
928     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );
929
930 #if TARGET_HOST_UNIX_X11
931
932     XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
933
934 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
935
936     SetWindowPos(
937         fgStructure.Window->Window.Handle,
938         HWND_BOTTOM,
939         0, 0, 0, 0,
940         SWP_NOSIZE | SWP_NOMOVE
941     );
942
943 #endif
944 }
945
946 /*
947  * Raises the current window (by Z order change)
948  */
949 void FGAPIENTRY glutPopWindow( void )
950 {
951     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );
952     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );
953
954 #if TARGET_HOST_UNIX_X11
955
956     XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
957
958 #elif TARGET_HOST_WIN32 || TARGET_HOST_WINCE
959
960     SetWindowPos(
961         fgStructure.Window->Window.Handle,
962         HWND_TOP,
963         0, 0, 0, 0,
964         SWP_NOSIZE | SWP_NOMOVE
965     );
966
967 #endif
968 }
969
970 /*
971  * Resize the current window so that it fits the whole screen
972  */
973 void FGAPIENTRY glutFullScreen( void )
974 {
975     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
976     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
977
978     {
979 #if TARGET_HOST_UNIX_X11
980         int x, y;
981         Window w;
982
983         XMoveResizeWindow(
984             fgDisplay.Display,
985             fgStructure.Window->Window.Handle,
986             0, 0,
987             fgDisplay.ScreenWidth,
988             fgDisplay.ScreenHeight
989         );
990
991         XFlush( fgDisplay.Display ); /* This is needed */
992
993         XTranslateCoordinates(
994             fgDisplay.Display,
995             fgStructure.Window->Window.Handle,
996             fgDisplay.RootWindow,
997             0, 0, &x, &y, &w
998         );
999
1000         if (x || y)
1001         {
1002             XMoveWindow(
1003                 fgDisplay.Display,
1004                 fgStructure.Window->Window.Handle,
1005                 -x, -y
1006             );
1007             XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
1008         }
1009 #elif TARGET_HOST_WIN32
1010         RECT rect;
1011
1012         /* For fullscreen mode, force the top-left corner to 0,0
1013          * and adjust the window rectangle so that the client area
1014          * covers the whole screen.
1015          */
1016
1017         rect.left   = 0;
1018         rect.top    = 0;
1019         rect.right  = fgDisplay.ScreenWidth;
1020         rect.bottom = fgDisplay.ScreenHeight;
1021
1022         AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
1023                                   WS_CLIPCHILDREN, FALSE );
1024
1025         /*
1026          * SWP_NOACTIVATE     Do not activate the window
1027          * SWP_NOOWNERZORDER  Do not change position in z-order
1028          * SWP_NOSENDCHANGING Supress WM_WINDOWPOSCHANGING message
1029          * SWP_NOZORDER       Retains the current Z order (ignore 2nd param)
1030          */
1031
1032         SetWindowPos( fgStructure.Window->Window.Handle,
1033                       HWND_TOP,
1034                       rect.left,
1035                       rect.top,
1036                       rect.right  - rect.left,
1037                       rect.bottom - rect.top,
1038                       SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
1039                       SWP_NOZORDER
1040                     );
1041 #endif
1042     }
1043 }
1044
1045 /*
1046  * A.Donev: Set and retrieve the window's user data
1047  */
1048 void* FGAPIENTRY glutGetWindowData( void )
1049 {
1050     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );
1051     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );
1052     return fgStructure.Window->UserData;
1053 }
1054
1055 void FGAPIENTRY glutSetWindowData(void* data)
1056 {
1057     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );
1058     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );
1059     fgStructure.Window->UserData = data;
1060 }
1061
1062 /*** END OF FILE ***/