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