9126c4fdda1ae3d46e9d9c7c1a5d1043a18653ce
[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         {
473           winRect.left   += GetSystemMetrics( SM_CXSIZEFRAME );
474           winRect.right  -= GetSystemMetrics( SM_CXSIZEFRAME );
475           winRect.top    += GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION );
476           winRect.bottom -= GetSystemMetrics( SM_CYSIZEFRAME );
477         }
478 #endif /* !defined(_WIN32_WCE) */
479
480         switch( eWhat )
481         {
482         case GLUT_WINDOW_X:      return winRect.left                ;
483         case GLUT_WINDOW_Y:      return winRect.top                 ;
484         case GLUT_WINDOW_WIDTH:  return winRect.right - winRect.left;
485         case GLUT_WINDOW_HEIGHT: return winRect.bottom - winRect.top;
486         }
487     }
488     break;
489
490     case GLUT_WINDOW_BORDER_WIDTH :
491 #if defined(_WIN32_WCE)
492         return 0;
493 #else
494         return GetSystemMetrics( SM_CXSIZEFRAME );
495 #endif /* !defined(_WIN32_WCE) */
496
497     case GLUT_WINDOW_HEADER_HEIGHT :
498 #if defined(_WIN32_WCE)
499         return 0;
500 #else
501         return GetSystemMetrics( SM_CYCAPTION );
502 #endif /* defined(_WIN32_WCE) */
503
504     case GLUT_DISPLAY_MODE_POSSIBLE:
505 #if defined(_WIN32_WCE)
506         return 0;
507 #else
508         return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE,
509                                     PFD_MAIN_PLANE );
510 #endif /* defined(_WIN32_WCE) */
511
512
513     case GLUT_WINDOW_FORMAT_ID:
514 #if !defined(_WIN32_WCE)
515         if( fgStructure.CurrentWindow != NULL )
516             return GetPixelFormat( fgStructure.CurrentWindow->Window.Device );
517 #endif /* defined(_WIN32_WCE) */
518         return 0;
519
520 #endif
521
522     /* The window structure queries */
523     case GLUT_WINDOW_PARENT:
524         if( fgStructure.CurrentWindow         == NULL ) return 0;
525         if( fgStructure.CurrentWindow->Parent == NULL ) return 0;
526         return fgStructure.CurrentWindow->Parent->ID;
527
528     case GLUT_WINDOW_NUM_CHILDREN:
529         if( fgStructure.CurrentWindow == NULL )
530             return 0;
531         return fgListLength( &fgStructure.CurrentWindow->Children );
532
533     case GLUT_WINDOW_CURSOR:
534         if( fgStructure.CurrentWindow == NULL )
535             return 0;
536         return fgStructure.CurrentWindow->State.Cursor;
537
538     case GLUT_MENU_NUM_ITEMS:
539         if( fgStructure.CurrentMenu == NULL )
540             return 0;
541         return fgListLength( &fgStructure.CurrentMenu->Entries );
542
543     case GLUT_ACTION_ON_WINDOW_CLOSE:
544         return fgState.ActionOnWindowClose;
545
546     case GLUT_VERSION :
547         return VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH;
548
549     case GLUT_RENDERING_CONTEXT:
550         return fgState.UseCurrentContext ? GLUT_USE_CURRENT_CONTEXT
551                                          : GLUT_CREATE_NEW_CONTEXT;
552
553     case GLUT_DIRECT_RENDERING:
554         return fgState.DirectContext;
555
556     case GLUT_FULL_SCREEN:
557         return fghCheckFullScreen();
558
559     case GLUT_AUX:
560       return fgState.AuxiliaryBufferNumber;
561
562     case GLUT_MULTISAMPLE:
563       return fgState.SampleNumber;
564
565     default:
566         fgWarning( "glutGet(): missing enum handle %d", eWhat );
567         break;
568     }
569     return -1;
570 }
571
572 /*
573  * Returns various device information.
574  */
575 int FGAPIENTRY glutDeviceGet( GLenum eWhat )
576 {
577     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDeviceGet" );
578
579     /* XXX WARNING: we are mostly lying in this function. */
580     switch( eWhat )
581     {
582     case GLUT_HAS_KEYBOARD:
583         /*
584          * Win32 is assumed a keyboard, and this cannot be queried,
585          * except for WindowsCE.
586          *
587          * X11 has a core keyboard by definition, although it can
588          * be present as a virtual/dummy keyboard. For now, there
589          * is no reliable way to tell if a real keyboard is present.
590          */
591 #if defined(_WIN32_CE)
592         return ( GetKeyboardStatus() & KBDI_KEYBOARD_PRESENT ) ? 1 : 0;
593 #   if FREEGLUT_LIB_PRAGMAS
594 #       pragma comment (lib,"Kbdui.lib")
595 #   endif
596
597 #else
598         return 1;
599 #endif
600
601 #if TARGET_HOST_POSIX_X11
602
603     /* X11 has a mouse by definition */
604     case GLUT_HAS_MOUSE:
605         return 1 ;
606
607     case GLUT_NUM_MOUSE_BUTTONS:
608         /* We should be able to pass NULL when the last argument is zero,
609          * but at least one X server has a bug where this causes a segfault.
610          *
611          * In XFree86/Xorg servers, a mouse wheel is seen as two buttons
612          * rather than an Axis; "freeglut_main.c" expects this when
613          * checking for a wheel event.
614          */
615         {
616             unsigned char map;
617             int nbuttons = XGetPointerMapping(fgDisplay.Display, &map,0);
618             return nbuttons;
619         }
620
621 #elif TARGET_HOST_MS_WINDOWS
622
623     case GLUT_HAS_MOUSE:
624         /*
625          * MS Windows can be booted without a mouse.
626          */
627         return GetSystemMetrics( SM_MOUSEPRESENT );
628
629     case GLUT_NUM_MOUSE_BUTTONS:
630 #  if defined(_WIN32_WCE)
631         return 1;
632 #  else
633         return GetSystemMetrics( SM_CMOUSEBUTTONS );
634 #  endif
635 #endif
636
637     case GLUT_HAS_JOYSTICK:
638         return fgJoystickDetect ();
639
640     case GLUT_OWNS_JOYSTICK:
641         return fgState.JoysticksInitialised;
642
643     case GLUT_JOYSTICK_POLL_RATE:
644         return fgStructure.CurrentWindow ? fgStructure.CurrentWindow->State.JoystickPollRate : 0;
645
646     /* XXX The following two are only for Joystick 0 but this is an improvement */
647     case GLUT_JOYSTICK_BUTTONS:
648         return glutJoystickGetNumButtons ( 0 );
649
650     case GLUT_JOYSTICK_AXES:
651         return glutJoystickGetNumAxes ( 0 );
652
653     case GLUT_HAS_DIAL_AND_BUTTON_BOX:
654         return fgInputDeviceDetect ();
655
656     case GLUT_NUM_DIALS:
657         if ( fgState.InputDevsInitialised ) return 8;
658         return 0;
659  
660     case GLUT_NUM_BUTTON_BOX_BUTTONS:
661         return 0;
662
663     case GLUT_HAS_SPACEBALL:
664         return fgHasSpaceball();
665
666     case GLUT_HAS_TABLET:
667         return 0;
668
669     case GLUT_NUM_SPACEBALL_BUTTONS:
670         return fgSpaceballNumButtons();
671
672     case GLUT_NUM_TABLET_BUTTONS:
673         return 0;
674
675     case GLUT_DEVICE_IGNORE_KEY_REPEAT:
676         return fgStructure.CurrentWindow ? fgStructure.CurrentWindow->State.IgnoreKeyRepeat : 0;
677
678     case GLUT_DEVICE_KEY_REPEAT:
679         return fgState.KeyRepeat;
680
681     default:
682         fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat );
683         break;
684     }
685
686     /* And now -- the failure. */
687     return -1;
688 }
689
690 /*
691  * This should return the current state of ALT, SHIFT and CTRL keys.
692  */
693 int FGAPIENTRY glutGetModifiers( void )
694 {
695     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetModifiers" );
696     if( fgState.Modifiers == INVALID_MODIFIERS )
697     {
698         fgWarning( "glutGetModifiers() called outside an input callback" );
699         return 0;
700     }
701
702     return fgState.Modifiers;
703 }
704
705 /*
706  * Return the state of the GLUT API overlay subsystem. A misery ;-)
707  */
708 int FGAPIENTRY glutLayerGet( GLenum eWhat )
709 {
710     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLayerGet" );
711
712     /*
713      * This is easy as layers are not implemented ;-)
714      *
715      * XXX Can we merge the UNIX/X11 and WIN32 sections?  Or
716      * XXX is overlay support planned?
717      */
718     switch( eWhat )
719     {
720
721 #if TARGET_HOST_POSIX_X11
722
723     case GLUT_OVERLAY_POSSIBLE:
724         return 0;
725
726     case GLUT_LAYER_IN_USE:
727         return GLUT_NORMAL;
728
729     case GLUT_HAS_OVERLAY:
730         return 0;
731
732     case GLUT_TRANSPARENT_INDEX:
733         /*
734          * Return just anything, which is always defined as zero
735          *
736          * XXX HUH?
737          */
738         return 0;
739
740     case GLUT_NORMAL_DAMAGED:
741         /* XXX Actually I do not know. Maybe. */
742         return 0;
743
744     case GLUT_OVERLAY_DAMAGED:
745         return -1;
746
747 #elif TARGET_HOST_MS_WINDOWS
748
749     case GLUT_OVERLAY_POSSIBLE:
750 /*      return fgSetupPixelFormat( fgStructure.CurrentWindow, GL_TRUE,
751                                    PFD_OVERLAY_PLANE ); */
752       return 0 ;
753
754     case GLUT_LAYER_IN_USE:
755         return GLUT_NORMAL;
756
757     case GLUT_HAS_OVERLAY:
758         return 0;
759
760     case GLUT_TRANSPARENT_INDEX:
761         /*
762          * Return just anything, which is always defined as zero
763          *
764          * XXX HUH?
765          */
766         return 0;
767
768     case GLUT_NORMAL_DAMAGED:
769         /* XXX Actually I do not know. Maybe. */
770         return 0;
771
772     case GLUT_OVERLAY_DAMAGED:
773         return -1;
774 #endif
775
776     default:
777         fgWarning( "glutLayerGet(): missing enum handle %d", eWhat );
778         break;
779     }
780
781     /* And fail. That's good. Programs do love failing. */
782     return -1;
783 }
784
785 int * FGAPIENTRY glutGetModeValues(GLenum eWhat, int * size)
786 {
787   int * array;
788
789 #if TARGET_HOST_POSIX_X11
790   int attributes[9];
791   GLXFBConfig * fbconfigArray;  /*  Array of FBConfigs  */
792   int fbconfigArraySize;        /*  Number of FBConfigs in the array  */
793   int attribute_name = 0;
794 #endif
795
796   FREEGLUT_EXIT_IF_NOT_INITIALISED("glutGetModeValues");
797
798   array = NULL;
799   *size = 0;
800
801   switch (eWhat)
802     {
803 #if TARGET_HOST_POSIX_X11
804     case GLUT_AUX:
805     case GLUT_MULTISAMPLE:
806
807       attributes[0] = GLX_BUFFER_SIZE;
808       attributes[1] = GLX_DONT_CARE;
809
810       switch (eWhat)
811         {
812         case GLUT_AUX:
813           /*
814             FBConfigs are now sorted by increasing number of auxiliary
815             buffers.  We want at least one buffer.
816           */
817           attributes[2] = GLX_AUX_BUFFERS;
818           attributes[3] = 1;
819           attributes[4] = None;
820
821           attribute_name = GLX_AUX_BUFFERS;
822
823           break;
824
825
826         case GLUT_MULTISAMPLE:
827           attributes[2] = GLX_AUX_BUFFERS;
828           attributes[3] = GLX_DONT_CARE;
829           attributes[4] = GLX_SAMPLE_BUFFERS;
830           attributes[5] = 1;
831           /*
832             FBConfigs are now sorted by increasing number of samples per
833             pixel.  We want at least one sample.
834           */
835           attributes[6] = GLX_SAMPLES;
836           attributes[7] = 1;
837           attributes[8] = None;
838
839           attribute_name = GLX_SAMPLES;
840
841           break;
842         }
843
844       fbconfigArray = glXChooseFBConfig(fgDisplay.Display,
845                                         fgDisplay.Screen,
846                                         attributes,
847                                         &fbconfigArraySize);
848
849       if (fbconfigArray != NULL)
850         {
851           int * temp_array;
852           int result;   /*  Returned by glXGetFBConfigAttrib. Not checked.  */
853           int previous_value;
854           int i;
855
856           temp_array = malloc(sizeof(int) * fbconfigArraySize);
857           previous_value = 0;
858
859           for (i = 0; i < fbconfigArraySize; i++)
860             {
861               int value;
862
863               result = glXGetFBConfigAttrib(fgDisplay.Display,
864                                             fbconfigArray[i],
865                                             attribute_name,
866                                             &value);
867               if (value > previous_value)
868                 {
869                   temp_array[*size] = value;
870                   previous_value = value;
871                   (*size)++;
872                 }
873             }
874
875           array = malloc(sizeof(int) * (*size));
876           for (i = 0; i < *size; i++)
877             {
878               array[i] = temp_array[i];
879             }
880
881           free(temp_array);
882           XFree(fbconfigArray);
883         }
884
885       break;
886 #endif      
887
888     default:
889       break;
890     }
891
892   return array;
893 }
894
895 /*** END OF FILE ***/