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