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