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