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