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 similar, 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 | } |
252 | |