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