Putting in Jocelyn Frechot's X11 visual context changes. THIS WILL BREAK THE BUILD...
[freeglut] / src / freeglut_state.c
1 /*
2  * freeglut_state.c
3  *
4  * Freeglut state query 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: Thu Dec 16 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 /*
32  * TODO BEFORE THE STABLE RELEASE:
33  *
34  *  glutGet()               -- X11 tests passed, but check if all enums
35  *                             handled (what about Win32?)
36  *  glutDeviceGet()         -- X11 tests passed, but check if all enums
37  *                             handled (what about Win32?)
38  *  glutGetModifiers()      -- OK, but could also remove the limitation
39  *  glutLayerGet()          -- what about GLUT_NORMAL_DAMAGED?
40  *
41  * The fail-on-call policy will help adding the most needed things imho.
42  */
43
44 /* -- LOCAL DEFINITIONS ---------------------------------------------------- */
45
46 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
47
48 #if TARGET_HOST_POSIX_X11
49 /*
50  * Queries the GL context about some attributes
51  */
52 static int fghGetConfig( int attribute )
53 {
54   int returnValue = 0;
55   int result;  /*  Not checked  */
56
57   if( fgStructure.CurrentWindow )
58       result = glXGetFBConfigAttrib( fgDisplay.Display,
59                                      *(fgStructure.CurrentWindow->Window.FBConfig),
60                                      attribute,
61                                      &returnValue );
62
63   return returnValue;
64 }
65 #endif
66
67 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
68
69 /*
70  * General settings assignment method
71  */
72 void FGAPIENTRY glutSetOption( GLenum eWhat, int value )
73 {
74     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetOption" );
75
76     /*
77      * XXX In chronological code add order.  (WHY in that order?)
78      */
79     switch( eWhat )
80     {
81     case GLUT_INIT_WINDOW_X:
82         fgState.Position.X = (GLint)value;
83         break;
84
85     case GLUT_INIT_WINDOW_Y:
86         fgState.Position.Y = (GLint)value;
87         break;
88
89     case GLUT_INIT_WINDOW_WIDTH:
90         fgState.Size.X = (GLint)value;
91         break;
92
93     case GLUT_INIT_WINDOW_HEIGHT:
94         fgState.Size.Y = (GLint)value;
95         break;
96
97     case GLUT_INIT_DISPLAY_MODE:
98         fgState.DisplayMode = (unsigned int)value;
99         break;
100
101     case GLUT_ACTION_ON_WINDOW_CLOSE:
102         fgState.ActionOnWindowClose = value;
103         break;
104
105     case GLUT_RENDERING_CONTEXT:
106         fgState.UseCurrentContext =
107             ( value == GLUT_USE_CURRENT_CONTEXT ) ? GL_TRUE : GL_FALSE;
108         break;
109
110     case GLUT_DIRECT_RENDERING:
111         fgState.DirectContext = value;
112         break;
113
114     case GLUT_WINDOW_CURSOR:
115         if( fgStructure.CurrentWindow != NULL )
116             fgStructure.CurrentWindow->State.Cursor = value;
117         break;
118
119     default:
120         fgWarning( "glutSetOption(): missing enum handle %d", eWhat );
121         break;
122     }
123 }
124
125 #if TARGET_HOST_MS_WINDOWS
126 /* The following include file is available from SGI but is not standard:
127  *   #include <GL/wglext.h>
128  * So we copy the necessary parts out of it to support the multisampling query
129  */
130 #define WGL_SAMPLES_ARB                0x2042
131 #endif
132
133
134 /*
135  * General settings query method
136  */
137 int FGAPIENTRY glutGet( GLenum eWhat )
138 {
139 #if TARGET_HOST_MS_WINDOWS
140     int returnValue ;
141     GLboolean boolValue ;
142 #endif
143
144     int nsamples = 0;
145
146     switch (eWhat)
147     {
148     case GLUT_INIT_STATE:
149         return fgState.Initialised;
150
151     case GLUT_ELAPSED_TIME:
152         return fgElapsedTime();
153     }
154
155     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGet" );
156
157     /* XXX In chronological code add order.  (WHY in that order?) */
158     switch( eWhat )
159     {
160     /* Following values are stored in fgState and fgDisplay global structures */
161     case GLUT_SCREEN_WIDTH:         return fgDisplay.ScreenWidth   ;
162     case GLUT_SCREEN_HEIGHT:        return fgDisplay.ScreenHeight  ;
163     case GLUT_SCREEN_WIDTH_MM:      return fgDisplay.ScreenWidthMM ;
164     case GLUT_SCREEN_HEIGHT_MM:     return fgDisplay.ScreenHeightMM;
165     case GLUT_INIT_WINDOW_X:        return fgState.Position.Use ?
166                                            fgState.Position.X : -1 ;
167     case GLUT_INIT_WINDOW_Y:        return fgState.Position.Use ?
168                                            fgState.Position.Y : -1 ;
169     case GLUT_INIT_WINDOW_WIDTH:    return fgState.Size.Use ?
170                                            fgState.Size.X : -1     ;
171     case GLUT_INIT_WINDOW_HEIGHT:   return fgState.Size.Use ?
172                                            fgState.Size.Y : -1     ;
173     case GLUT_INIT_DISPLAY_MODE:    return fgState.DisplayMode     ;
174
175 #if TARGET_HOST_POSIX_X11
176     /*
177      * The window/context specific queries are handled mostly by
178      * fghGetConfig().
179      */
180     case GLUT_WINDOW_NUM_SAMPLES:
181 #ifdef GLX_VERSION_1_3
182         glGetIntegerv(GL_SAMPLES, &nsamples);
183 #endif
184         return nsamples;
185
186     /*
187      * The rest of GLX queries under X are general enough to use a macro to
188      * check them
189      */
190 #   define GLX_QUERY(a,b) case a: return fghGetConfig( b );
191
192     GLX_QUERY( GLUT_WINDOW_RGBA,                GLX_RGBA                );
193     GLX_QUERY( GLUT_WINDOW_DOUBLEBUFFER,        GLX_DOUBLEBUFFER        );
194     GLX_QUERY( GLUT_WINDOW_BUFFER_SIZE,         GLX_BUFFER_SIZE         );
195     GLX_QUERY( GLUT_WINDOW_STENCIL_SIZE,        GLX_STENCIL_SIZE        );
196     GLX_QUERY( GLUT_WINDOW_DEPTH_SIZE,          GLX_DEPTH_SIZE          );
197     GLX_QUERY( GLUT_WINDOW_RED_SIZE,            GLX_RED_SIZE            );
198     GLX_QUERY( GLUT_WINDOW_GREEN_SIZE,          GLX_GREEN_SIZE          );
199     GLX_QUERY( GLUT_WINDOW_BLUE_SIZE,           GLX_BLUE_SIZE           );
200     GLX_QUERY( GLUT_WINDOW_ALPHA_SIZE,          GLX_ALPHA_SIZE          );
201     GLX_QUERY( GLUT_WINDOW_ACCUM_RED_SIZE,      GLX_ACCUM_RED_SIZE      );
202     GLX_QUERY( GLUT_WINDOW_ACCUM_GREEN_SIZE,    GLX_ACCUM_GREEN_SIZE    );
203     GLX_QUERY( GLUT_WINDOW_ACCUM_BLUE_SIZE,     GLX_ACCUM_BLUE_SIZE     );
204     GLX_QUERY( GLUT_WINDOW_ACCUM_ALPHA_SIZE,    GLX_ACCUM_ALPHA_SIZE    );
205     GLX_QUERY( GLUT_WINDOW_STEREO,              GLX_STEREO              );
206
207 #   undef GLX_QUERY
208
209     /* Colormap size is handled in a bit different way than all the rest */
210     case GLUT_WINDOW_COLORMAP_SIZE:
211         if( (fghGetConfig( GLX_RGBA )) || (fgStructure.CurrentWindow == NULL) )
212         {
213             /*
214              * We've got a RGBA visual, so there is no colormap at all.
215              * The other possibility is that we have no current window set.
216              */
217             return 0;
218         }
219         else
220         {
221           const GLXFBConfig * fbconfig =
222                 fgStructure.CurrentWindow->Window.FBConfig;
223
224           XVisualInfo * visualInfo =
225                 glXGetVisualFromFBConfig( fgDisplay.Display, *fbconfig );
226
227           const int result = visualInfo->visual->map_entries;
228
229           XFree(visualInfo);
230
231           return result;
232         }
233
234     /*
235      * Those calls are somewhat similiar, as they use XGetWindowAttributes()
236      * function
237      */
238     case GLUT_WINDOW_X:
239     case GLUT_WINDOW_Y:
240     case GLUT_WINDOW_BORDER_WIDTH:
241     case GLUT_WINDOW_HEADER_HEIGHT:
242     {
243         int x, y;
244         Window w;
245
246         if( fgStructure.CurrentWindow == NULL )
247             return 0;
248
249         XTranslateCoordinates(
250             fgDisplay.Display,
251             fgStructure.CurrentWindow->Window.Handle,
252             fgDisplay.RootWindow,
253             0, 0, &x, &y, &w);
254
255         switch ( eWhat )
256         {
257         case GLUT_WINDOW_X: return x;
258         case GLUT_WINDOW_Y: return y;
259         }
260
261         if ( w == 0 )
262             return 0;
263         XTranslateCoordinates(
264             fgDisplay.Display,
265             fgStructure.CurrentWindow->Window.Handle,
266             w, 0, 0, &x, &y, &w);
267
268         switch ( eWhat )
269         {
270         case GLUT_WINDOW_BORDER_WIDTH:  return x;
271         case GLUT_WINDOW_HEADER_HEIGHT: return y;
272         }
273     }
274
275     case GLUT_WINDOW_WIDTH:
276     case GLUT_WINDOW_HEIGHT:
277     {
278         XWindowAttributes winAttributes;
279
280         if( fgStructure.CurrentWindow == NULL )
281             return 0;
282         XGetWindowAttributes(
283             fgDisplay.Display,
284             fgStructure.CurrentWindow->Window.Handle,
285             &winAttributes
286         );
287         switch ( eWhat )
288         {
289         case GLUT_WINDOW_WIDTH:            return winAttributes.width ;
290         case GLUT_WINDOW_HEIGHT:           return winAttributes.height ;
291         }
292     }
293
294     /* I do not know yet if there will be a fgChooseVisual() function for Win32 */
295     case GLUT_DISPLAY_MODE_POSSIBLE:
296     {
297         /*  We should not have to call fgChooseFBConfig again here.  */
298         GLXFBConfig * fbconfig;
299         int isPossible;
300
301         fbconfig = fgChooseFBConfig();
302
303         if (fbconfig == NULL)
304         {
305             isPossible = 0;
306         }
307         else
308         {
309             isPossible = 1;
310             XFree(fbconfig);
311         }
312
313         return isPossible;
314     }
315
316     /* This is system-dependant */
317     case GLUT_WINDOW_FORMAT_ID:
318         if( fgStructure.CurrentWindow == NULL )
319             return 0;
320
321         return fghGetConfig( GLX_VISUAL_ID );
322
323 #elif TARGET_HOST_MS_WINDOWS
324
325     case GLUT_WINDOW_NUM_SAMPLES:
326       glGetIntegerv(WGL_SAMPLES_ARB, &nsamples);
327       return nsamples;
328
329     /* Handle the OpenGL inquiries */
330     case GLUT_WINDOW_RGBA:
331       glGetBooleanv ( GL_RGBA_MODE, &boolValue );
332       returnValue = boolValue ? 1 : 0;
333       return returnValue;
334     case GLUT_WINDOW_DOUBLEBUFFER:
335       glGetBooleanv ( GL_DOUBLEBUFFER, &boolValue );
336       returnValue = boolValue ? 1 : 0;
337       return returnValue;
338     case GLUT_WINDOW_STEREO:
339       glGetBooleanv ( GL_STEREO, &boolValue );
340       returnValue = boolValue ? 1 : 0;
341       return returnValue;
342
343     case GLUT_WINDOW_RED_SIZE:
344       glGetIntegerv ( GL_RED_BITS, &returnValue );
345       return returnValue;
346     case GLUT_WINDOW_GREEN_SIZE:
347       glGetIntegerv ( GL_GREEN_BITS, &returnValue );
348       return returnValue;
349     case GLUT_WINDOW_BLUE_SIZE:
350       glGetIntegerv ( GL_BLUE_BITS, &returnValue );
351       return returnValue;
352     case GLUT_WINDOW_ALPHA_SIZE:
353       glGetIntegerv ( GL_ALPHA_BITS, &returnValue );
354       return returnValue;
355     case GLUT_WINDOW_ACCUM_RED_SIZE:
356       glGetIntegerv ( GL_ACCUM_RED_BITS, &returnValue );
357       return returnValue;
358     case GLUT_WINDOW_ACCUM_GREEN_SIZE:
359       glGetIntegerv ( GL_ACCUM_GREEN_BITS, &returnValue );
360       return returnValue;
361     case GLUT_WINDOW_ACCUM_BLUE_SIZE:
362       glGetIntegerv ( GL_ACCUM_BLUE_BITS, &returnValue );
363       return returnValue;
364     case GLUT_WINDOW_ACCUM_ALPHA_SIZE:
365       glGetIntegerv ( GL_ACCUM_ALPHA_BITS, &returnValue );
366       return returnValue;
367     case GLUT_WINDOW_DEPTH_SIZE:
368       glGetIntegerv ( GL_DEPTH_BITS, &returnValue );
369       return returnValue;
370
371     case GLUT_WINDOW_BUFFER_SIZE:
372       returnValue = 1 ;                                      /* ????? */
373       return returnValue;
374     case GLUT_WINDOW_STENCIL_SIZE:
375       returnValue = 0 ;                                      /* ????? */
376       return returnValue;
377
378     case GLUT_WINDOW_X:
379     case GLUT_WINDOW_Y:
380     case GLUT_WINDOW_WIDTH:
381     case GLUT_WINDOW_HEIGHT:
382     {
383         /*
384          *  There is considerable confusion about the "right thing to
385          *  do" concerning window  size and position.  GLUT itself is
386          *  not consistent between Windows and UNIX/X11; since
387          *  platform independence is a virtue for "freeglut", we
388          *  decided to break with GLUT's behaviour.
389          *
390          *  Under UNIX/X11, it is apparently not possible to get the
391          *  window border sizes in order to subtract them off the
392          *  window's initial position until some time after the window
393          *  has been created.  Therefore we decided on the following
394          *  behaviour, both under Windows and under UNIX/X11:
395          *  - When you create a window with position (x,y) and size
396          *    (w,h), the upper left hand corner of the outside of the
397          *    window is at (x,y) and the size of the drawable area  is
398          *    (w,h).
399          *  - When you query the size and position of the window--as
400          *    is happening here for Windows--"freeglut" will return
401          *    the size of the drawable area--the (w,h) that you
402          *    specified when you created the window--and the coordinates
403          *    of the upper left hand corner of the drawable
404          *    area--which is NOT the (x,y) you specified.
405          */
406
407         RECT winRect;
408
409         freeglut_return_val_if_fail( fgStructure.CurrentWindow != NULL, 0 );
410
411         /*
412          * We need to call GetWindowRect() first...
413          *  (this returns the pixel coordinates of the outside of the window)
414          */
415         GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect );
416
417         /* ...then we've got to correct the results we've just received... */
418
419 #if !defined(_WIN32_WCE)
420         if ( ( fgStructure.GameModeWindow != fgStructure.CurrentWindow ) && ( fgStructure.CurrentWindow->Parent == NULL ) &&
421              ( ! fgStructure.CurrentWindow->IsMenu ) )
422         {
423           winRect.left   += GetSystemMetrics( SM_CXSIZEFRAME );
424           winRect.right  -= GetSystemMetrics( SM_CXSIZEFRAME );
425           winRect.top    += GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION );
426           winRect.bottom -= GetSystemMetrics( SM_CYSIZEFRAME );
427         }
428 #endif /* !defined(_WIN32_WCE) */
429
430         switch( eWhat )
431         {
432         case GLUT_WINDOW_X:      return winRect.left                ;
433         case GLUT_WINDOW_Y:      return winRect.top                 ;
434         case GLUT_WINDOW_WIDTH:  return winRect.right - winRect.left;
435         case GLUT_WINDOW_HEIGHT: return winRect.bottom - winRect.top;
436         }
437     }
438     break;
439
440     case GLUT_WINDOW_BORDER_WIDTH :
441 #if defined(_WIN32_WCE)
442         return 0;
443 #else
444         return GetSystemMetrics( SM_CXSIZEFRAME );
445 #endif /* !defined(_WIN32_WCE) */
446
447     case GLUT_WINDOW_HEADER_HEIGHT :
448 #if defined(_WIN32_WCE)
449         return 0;
450 #else
451         return GetSystemMetrics( SM_CYCAPTION );
452 #endif /* defined(_WIN32_WCE) */
453
454     case GLUT_DISPLAY_MODE_POSSIBLE:
455 #if defined(_WIN32_WCE)
456         return 0;
457 #else
458         return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE,
459                                     PFD_MAIN_PLANE );
460 #endif /* defined(_WIN32_WCE) */
461
462
463     case GLUT_WINDOW_FORMAT_ID:
464 #if !defined(_WIN32_WCE)
465         if( fgStructure.CurrentWindow != NULL )
466             return GetPixelFormat( fgStructure.CurrentWindow->Window.Device );
467 #endif /* defined(_WIN32_WCE) */
468         return 0;
469
470 #endif
471
472     /* The window structure queries */
473     case GLUT_WINDOW_PARENT:
474         if( fgStructure.CurrentWindow         == NULL ) return 0;
475         if( fgStructure.CurrentWindow->Parent == NULL ) return 0;
476         return fgStructure.CurrentWindow->Parent->ID;
477
478     case GLUT_WINDOW_NUM_CHILDREN:
479         if( fgStructure.CurrentWindow == NULL )
480             return 0;
481         return fgListLength( &fgStructure.CurrentWindow->Children );
482
483     case GLUT_WINDOW_CURSOR:
484         if( fgStructure.CurrentWindow == NULL )
485             return 0;
486         return fgStructure.CurrentWindow->State.Cursor;
487
488     case GLUT_MENU_NUM_ITEMS:
489         if( fgStructure.CurrentMenu == NULL )
490             return 0;
491         return fgListLength( &fgStructure.CurrentMenu->Entries );
492
493     case GLUT_ACTION_ON_WINDOW_CLOSE:
494         return fgState.ActionOnWindowClose;
495
496     case GLUT_VERSION :
497         return VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH;
498
499     case GLUT_RENDERING_CONTEXT:
500         return fgState.UseCurrentContext ? GLUT_USE_CURRENT_CONTEXT
501                                          : GLUT_CREATE_NEW_CONTEXT;
502
503     case GLUT_DIRECT_RENDERING:
504         return fgState.DirectContext;
505         break;
506
507     default:
508         fgWarning( "glutGet(): missing enum handle %d", eWhat );
509         break;
510     }
511     return -1;
512 }
513
514 /*
515  * Returns various device information.
516  */
517 int FGAPIENTRY glutDeviceGet( GLenum eWhat )
518 {
519     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDeviceGet" );
520
521     /* XXX WARNING: we are mostly lying in this function. */
522     switch( eWhat )
523     {
524     case GLUT_HAS_KEYBOARD:
525         /*
526          * Win32 is assumed a keyboard, and this cannot be queried,
527          * except for WindowsCE.
528          *
529          * X11 has a core keyboard by definition, although it can
530          * be present as a virtual/dummy keyboard. For now, there
531          * is no reliable way to tell if a real keyboard is present.
532          */
533 #if defined(_WIN32_CE)
534         return ( GetKeyboardStatus() & KBDI_KEYBOARD_PRESENT ) ? 1 : 0;
535 #   if FREEGLUT_LIB_PRAGMAS
536 #       pragma comment (lib,"Kbdui.lib")
537 #   endif
538
539 #else
540         return 1;
541 #endif
542
543 #if TARGET_HOST_POSIX_X11
544
545     /* X11 has a mouse by definition */
546     case GLUT_HAS_MOUSE:
547         return 1 ;
548
549     case GLUT_NUM_MOUSE_BUTTONS:
550         /* We should be able to pass NULL when the last argument is zero,
551          * but at least one X server has a bug where this causes a segfault.
552          *
553          * In XFree86/Xorg servers, a mouse wheel is seen as two buttons
554          * rather than an Axis; "freeglut_main.c" expects this when
555          * checking for a wheel event.
556          */
557         {
558             unsigned char map;
559             int nbuttons = XGetPointerMapping(fgDisplay.Display, &map,0);
560             return nbuttons;
561         }
562
563 #elif TARGET_HOST_MS_WINDOWS
564
565     case GLUT_HAS_MOUSE:
566         /*
567          * MS Windows can be booted without a mouse.
568          */
569         return GetSystemMetrics( SM_MOUSEPRESENT );
570
571     case GLUT_NUM_MOUSE_BUTTONS:
572 #  if defined(_WIN32_WCE)
573         return 1;
574 #  else
575         return GetSystemMetrics( SM_CMOUSEBUTTONS );
576 #  endif
577 #endif
578
579     case GLUT_HAS_JOYSTICK:
580         return fgJoystickDetect ();
581
582     case GLUT_OWNS_JOYSTICK:
583         return fgState.JoysticksInitialised;
584
585     case GLUT_JOYSTICK_POLL_RATE:
586         return fgStructure.CurrentWindow ? fgStructure.CurrentWindow->State.JoystickPollRate : 0;
587
588     /* XXX The following two are only for Joystick 0 but this is an improvement */
589     case GLUT_JOYSTICK_BUTTONS:
590         return glutJoystickGetNumButtons ( 0 );
591
592     case GLUT_JOYSTICK_AXES:
593         return glutJoystickGetNumAxes ( 0 );
594
595     case GLUT_HAS_DIAL_AND_BUTTON_BOX:
596         return fgInputDeviceDetect ();
597
598     case GLUT_NUM_DIALS:
599         if ( fgState.InputDevsInitialised ) return 8;
600         return 0;
601  
602     case GLUT_NUM_BUTTON_BOX_BUTTONS:
603         return 0;
604
605     case GLUT_HAS_SPACEBALL:
606     case GLUT_HAS_TABLET:
607         return 0;
608
609     case GLUT_NUM_SPACEBALL_BUTTONS:
610     case GLUT_NUM_TABLET_BUTTONS:
611         return 0;
612
613     case GLUT_DEVICE_IGNORE_KEY_REPEAT:
614         return fgStructure.CurrentWindow ? fgStructure.CurrentWindow->State.IgnoreKeyRepeat : 0;
615
616     case GLUT_DEVICE_KEY_REPEAT:
617         return fgState.KeyRepeat;
618
619     default:
620         fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat );
621         break;
622     }
623
624     /* And now -- the failure. */
625     return -1;
626 }
627
628 /*
629  * This should return the current state of ALT, SHIFT and CTRL keys.
630  */
631 int FGAPIENTRY glutGetModifiers( void )
632 {
633     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetModifiers" );
634     if( fgState.Modifiers == INVALID_MODIFIERS )
635     {
636         fgWarning( "glutGetModifiers() called outside an input callback" );
637         return 0;
638     }
639
640     return fgState.Modifiers;
641 }
642
643 /*
644  * Return the state of the GLUT API overlay subsystem. A misery ;-)
645  */
646 int FGAPIENTRY glutLayerGet( GLenum eWhat )
647 {
648     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLayerGet" );
649
650     /*
651      * This is easy as layers are not implemented ;-)
652      *
653      * XXX Can we merge the UNIX/X11 and WIN32 sections?  Or
654      * XXX is overlay support planned?
655      */
656     switch( eWhat )
657     {
658
659 #if TARGET_HOST_POSIX_X11
660
661     case GLUT_OVERLAY_POSSIBLE:
662         return 0;
663
664     case GLUT_LAYER_IN_USE:
665         return GLUT_NORMAL;
666
667     case GLUT_HAS_OVERLAY:
668         return 0;
669
670     case GLUT_TRANSPARENT_INDEX:
671         /*
672          * Return just anything, which is always defined as zero
673          *
674          * XXX HUH?
675          */
676         return 0;
677
678     case GLUT_NORMAL_DAMAGED:
679         /* XXX Actually I do not know. Maybe. */
680         return 0;
681
682     case GLUT_OVERLAY_DAMAGED:
683         return -1;
684
685 #elif TARGET_HOST_MS_WINDOWS
686
687     case GLUT_OVERLAY_POSSIBLE:
688 /*      return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE,
689                                    PFD_OVERLAY_PLANE ); */
690       return 0 ;
691
692     case GLUT_LAYER_IN_USE:
693         return GLUT_NORMAL;
694
695     case GLUT_HAS_OVERLAY:
696         return 0;
697
698     case GLUT_TRANSPARENT_INDEX:
699         /*
700          * Return just anything, which is always defined as zero
701          *
702          * XXX HUH?
703          */
704         return 0;
705
706     case GLUT_NORMAL_DAMAGED:
707         /* XXX Actually I do not know. Maybe. */
708         return 0;
709
710     case GLUT_OVERLAY_DAMAGED:
711         return -1;
712 #endif
713
714     default:
715         fgWarning( "glutLayerGet(): missing enum handle %d", eWhat );
716         break;
717     }
718
719     /* And fail. That's good. Programs do love failing. */
720     return -1;
721 }
722
723 /*** END OF FILE ***/