2b9f6d45c7be501ac2fda9814b4008f50408374a
[freeglut] / src / x11 / fg_state_x11.c
1 /*
2  * fg_state_x11.c
3  *
4  * X11-specific freeglut state query methods.
5  *
6  * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
7  * Written by John F. Fay, <fayjf@sourceforge.net>
8  * Creation date: Sat Feb 4 2012
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 "fg_internal.h"
30 #ifdef EGL_VERSION_1_0
31 #include "egl/fg_state_egl.h"
32 #else
33 #include "x11/fg_state_x11_glx.h"
34 #endif
35
36 int fgPlatformGlutDeviceGet ( GLenum eWhat )
37 {
38     switch( eWhat )
39     {
40     case GLUT_HAS_KEYBOARD:
41         /*
42          * X11 has a core keyboard by definition, although it can
43          * be present as a virtual/dummy keyboard. For now, there
44          * is no reliable way to tell if a real keyboard is present.
45          */
46         return 1;
47
48     /* X11 has a mouse by definition */
49     case GLUT_HAS_MOUSE:
50         return 1 ;
51
52     case GLUT_NUM_MOUSE_BUTTONS:
53         /* We should be able to pass NULL when the last argument is zero,
54          * but at least one X server has a bug where this causes a segfault.
55          *
56          * In XFree86/Xorg servers, a mouse wheel is seen as two buttons
57          * rather than an Axis; "fg_main.c" expects this when
58          * checking for a wheel event.
59          */
60         {
61             unsigned char map;
62             int nbuttons = XGetPointerMapping(fgDisplay.pDisplay.Display, &map,0);
63             return nbuttons;
64         }
65
66     default:
67         fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat );
68         break;
69     }
70
71     /* And now -- the failure. */
72     return -1;
73 }
74
75
76 int fgPlatformGlutGet ( GLenum eWhat )
77 {
78     switch( eWhat )
79     {
80
81     /*
82      * Those calls are somewhat similiar, as they use XGetWindowAttributes()
83      * function
84      */
85     case GLUT_WINDOW_X:
86     case GLUT_WINDOW_Y:
87     {
88         int x, y;
89         Window p,w;
90
91         if( fgStructure.CurrentWindow == NULL )
92             return 0;
93
94         if (fgStructure.CurrentWindow->Parent)
95             /* For child window, we should return relative to upper-left
96              * of parent's client area.
97              */
98             p = fgStructure.CurrentWindow->Parent->Window.Handle;
99         else
100             p = fgDisplay.pDisplay.RootWindow;
101             
102         XTranslateCoordinates(
103             fgDisplay.pDisplay.Display,
104             fgStructure.CurrentWindow->Window.Handle,
105             p,
106             0, 0, &x, &y, &w);
107
108         switch ( eWhat )
109         {
110         case GLUT_WINDOW_X: return x;
111         case GLUT_WINDOW_Y: return y;
112         }
113     }
114     
115     case GLUT_WINDOW_BORDER_WIDTH:
116     case GLUT_WINDOW_HEADER_HEIGHT:
117     {
118         Atom actual_type, net_extents;
119         int actual_format;
120         unsigned long nitems, bytes_after;
121         unsigned char *data = NULL;
122         int result, top, left;
123         
124         if (fgStructure.CurrentWindow == NULL || fgStructure.CurrentWindow->Parent)
125             /* can't get widths/heights if no current window
126              * and child windows don't have borders */
127             return 0;
128         
129         /* try to get through _NET_FRAME_EXTENTS */
130         net_extents = XInternAtom(fgDisplay.pDisplay.Display, "_NET_FRAME_EXTENTS", False);
131         
132         result = XGetWindowProperty(
133             fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle, net_extents,
134             0, 4, False, AnyPropertyType, 
135             &actual_type, &actual_format, 
136             &nitems, &bytes_after, &data);
137
138         if (result == Success && nitems == 4 && bytes_after == 0)
139             /* got the data we expected, here's to hoping that
140              * _NET_FRAME_EXTENTS is supported and the data
141              * contain sensible values */
142         {
143             long *extents = (long *)data;
144             left = (int) extents[0]; /* we take left as border width, consistent with old logic. bottom and right better be the same... */
145             top  = (int) extents[2];
146         }
147         else
148         {
149             /* try in the previous way as fall-back */
150             Window w;
151             int x,y;
152             
153             XTranslateCoordinates(
154                 fgDisplay.pDisplay.Display,
155                 fgStructure.CurrentWindow->Window.Handle,
156                 fgDisplay.pDisplay.RootWindow,
157                 0, 0, &x, &y, &w);
158             
159             if (w == 0)
160                 /* logic below needs w */
161                 return 0;
162             
163             XTranslateCoordinates(
164                 fgDisplay.pDisplay.Display,
165                 fgStructure.CurrentWindow->Window.Handle,
166                 w, 0, 0, &x, &y, &w);  
167             
168             left = x;
169             top  = y;
170         }
171         if (result == Success)
172             XFree(data);
173
174         switch ( eWhat )
175         {
176         case GLUT_WINDOW_BORDER_WIDTH:  return left;
177         case GLUT_WINDOW_HEADER_HEIGHT: return top;
178         }
179     }
180
181     case GLUT_WINDOW_WIDTH:
182     case GLUT_WINDOW_HEIGHT:
183     {
184         XWindowAttributes winAttributes;
185
186         if( fgStructure.CurrentWindow == NULL )
187             return 0;
188         XGetWindowAttributes(
189             fgDisplay.pDisplay.Display,
190             fgStructure.CurrentWindow->Window.Handle,
191             &winAttributes
192         );
193         switch ( eWhat )
194         {
195         case GLUT_WINDOW_WIDTH:            return winAttributes.width ;
196         case GLUT_WINDOW_HEIGHT:           return winAttributes.height ;
197         }
198     }
199     
200     /* Colormap size is handled in a bit different way than all the rest */
201     case GLUT_WINDOW_COLORMAP_SIZE:
202         if(
203 #ifndef EGL_VERSION_1_0
204            fgPlatformGetConfig( GLX_RGBA ) ||
205 #endif
206            fgStructure.CurrentWindow == NULL)
207         {
208             /*
209              * We've got a RGBA visual, so there is no colormap at all.
210              * The other possibility is that we have no current window set.
211              */
212             return 0;
213         }
214         else
215         {
216           XVisualInfo * visualInfo;
217                   int result;
218 #ifdef EGL_VERSION_1_0
219           EGLint vid = 0;
220           XVisualInfo visualTemplate;
221           int num_visuals;
222           if (!eglGetConfigAttrib(fgDisplay.pDisplay.egl.Display,
223                                   fgStructure.CurrentWindow->Window.pContext.egl.Config,
224                                   EGL_NATIVE_VISUAL_ID, &vid))
225             fgError("eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID) failed");
226           visualTemplate.visualid = vid;
227           visualInfo = XGetVisualInfo(fgDisplay.pDisplay.Display, VisualIDMask, &visualTemplate, &num_visuals);
228 #else
229           {
230           const GLXFBConfig fbconfig =
231                 fgStructure.CurrentWindow->Window.pContext.FBConfig;
232
233           visualInfo =
234                 glXGetVisualFromFBConfig( fgDisplay.pDisplay.Display, fbconfig );
235           }
236 #endif
237           result = visualInfo->visual->map_entries;
238
239           XFree(visualInfo);
240
241           return result;
242         }
243
244     default:
245 #ifdef EGL_VERSION_1_0
246       return fghPlatformGlutGetEGL(eWhat);
247 #else
248       return fghPlatformGlutGetGLX(eWhat);
249 #endif
250     }
251 }