1/*
2 * fg_init_x11.c
3 *
4 * Various freeglut initialization functions.
5 *
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Copied for Platform code by Evan Felix <karcaw at gmail.com>
9 * Creation date: Thur Feb 2 2012
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#define FREEGLUT_BUILDING_LIB
30#include <limits.h> /* LONG_MAX */
31#include <GL/freeglut.h>
32#include "fg_internal.h"
33#include "fg_init.h"
34#include "egl/fg_init_egl.h"
35
36#include <locale.h>
37
38/* Return the atom associated with "name". */
39static Atom fghGetAtom(const char * name)
40{
41 return XInternAtom(fgDisplay.pDisplay.Display, name, False);
42}
43
44char *fgClipboardBuffer[3] = { NULL, NULL, NULL };
45
46/*
47 * Check if "property" is set on "window". The property's values are returned
48 * through "data". If the property is set and is of type "type", return the
49 * number of elements in "data". Return zero otherwise. In both cases, use
50 * "Xfree()" to free "data".
51 */
52static int fghGetWindowProperty(Window window,
53 Atom property,
54 Atom type,
55 unsigned char ** data)
56{
57 /*
58 * Caller always has to use "Xfree()" to free "data", since
59 * "XGetWindowProperty() always allocates one extra byte in prop_return
60 * [i.e. "data"] (even if the property is zero length) [..]".
61 */
62
63 int status; /* Returned by "XGetWindowProperty". */
64
65 Atom type_returned;
66 int temp_format; /* Not used. */
67 unsigned long number_of_elements;
68 unsigned long temp_bytes_after; /* Not used. */
69
70
71 status = XGetWindowProperty(fgDisplay.pDisplay.Display,
72 window,
73 property,
74 0,
75 LONG_MAX,
76 False,
77 type,
78 &type_returned,
79 &temp_format,
80 &number_of_elements,
81 &temp_bytes_after,
82 data);
83
84 FREEGLUT_INTERNAL_ERROR_EXIT(status == Success,
85 "XGetWindowProperty failled",
86 "fghGetWindowProperty");
87
88 if (type_returned != type)
89 {
90 number_of_elements = 0;
91 }
92
93 return number_of_elements;
94}
95
96/* Check if the window manager is NET WM compliant. */
97static int fghNetWMSupported(void)
98{
99 Atom wm_check;
100 Window ** window_ptr_1;
101
102 int number_of_windows;
103 int net_wm_supported;
104
105
106 net_wm_supported = 0;
107
108 wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK");
109 window_ptr_1 = malloc(sizeof(Window *));
110
111 /*
112 * Check that the window manager has set this property on the root window.
113 * The property must be the ID of a child window.
114 */
115 number_of_windows = fghGetWindowProperty(fgDisplay.pDisplay.RootWindow,
116 wm_check,
117 XA_WINDOW,
118 (unsigned char **) window_ptr_1);
119 if (number_of_windows == 1)
120 {
121 Window ** window_ptr_2;
122
123 window_ptr_2 = malloc(sizeof(Window *));
124
125 /* Check that the window has the same property set to the same value. */
126 number_of_windows = fghGetWindowProperty(**window_ptr_1,
127 wm_check,
128 XA_WINDOW,
129 (unsigned char **) window_ptr_2);
130 if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2))
131 {
132 /* NET WM compliant */
133 net_wm_supported = 1;
134 }
135
136 XFree(*window_ptr_2);
137 free(window_ptr_2);
138 }
139
140 XFree(*window_ptr_1);
141 free(window_ptr_1);
142
143 return net_wm_supported;
144}
145
146/* Check if "hint" is present in "property" for "window". */
147int fgHintPresent(Window window, Atom property, Atom hint)
148{
149 Atom *atoms;
150 int number_of_atoms;
151 int supported;
152 int i;
153
154 supported = 0;
155
156 number_of_atoms = fghGetWindowProperty(window,
157 property,
158 XA_ATOM,
159 (unsigned char **) &atoms);
160 for (i = 0; i < number_of_atoms; i++)
161 {
162 if (atoms[i] == hint)
163 {
164 supported = 1;
165 break;
166 }
167 }
168
169 XFree(atoms);
170 return supported;
171}
172
173/*
174 * A call to this function should initialize all the display stuff...
175 */
176void fgPlatformInitialize( const char* displayName )
177{
178 fgDisplay.pDisplay.Display = XOpenDisplay( displayName );
179
180 if( fgDisplay.pDisplay.Display == NULL )
181 fgError( "failed to open display '%s'", XDisplayName( displayName ) );
182
183 if ( fgState.XSyncSwitch )
184 XSynchronize(fgDisplay.pDisplay.Display, True);
185
186#ifdef EGL_VERSION_1_0
187 fghPlatformInitializeEGL();
188#else
189 if( !glXQueryExtension( fgDisplay.pDisplay.Display, NULL, NULL ) )
190 fgError( "OpenGL GLX extension not supported by display '%s'",
191 XDisplayName( displayName ) );
192
193 /* This forces AMD Catalyst drivers to initialize and register a shutdown
194 * function, which must be done before our own call to atexit to prevent
195 * a crash if glutMainLoop is not called or is not exited cleanly.
196 * (see bug #206)
197 */
198 glXQueryExtensionsString( fgDisplay.pDisplay.Display,
199 DefaultScreen( fgDisplay.pDisplay.Display ));
200#endif
201
202 fgDisplay.pDisplay.Screen = DefaultScreen( fgDisplay.pDisplay.Display );
203 fgDisplay.pDisplay.RootWindow = RootWindow(
204 fgDisplay.pDisplay.Display,
205 fgDisplay.pDisplay.Screen
206 );
207
208 fgDisplay.ScreenWidth = DisplayWidth(
209 fgDisplay.pDisplay.Display,
210 fgDisplay.pDisplay.Screen
211 );
212 fgDisplay.ScreenHeight = DisplayHeight(
213 fgDisplay.pDisplay.Display,
214 fgDisplay.pDisplay.Screen
215 );
216
217 fgDisplay.ScreenWidthMM = DisplayWidthMM(
218 fgDisplay.pDisplay.Display,
219 fgDisplay.pDisplay.Screen
220 );
221 fgDisplay.ScreenHeightMM = DisplayHeightMM(
222 fgDisplay.pDisplay.Display,
223 fgDisplay.pDisplay.Screen
224 );
225
226 fgDisplay.pDisplay.Connection = ConnectionNumber( fgDisplay.pDisplay.Display );
227
228 /* Create the window deletion atom */
229 fgDisplay.pDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW");
230
231 /* Create the state and full screen atoms */
232 fgDisplay.pDisplay.State = None;
233 fgDisplay.pDisplay.StateFullScreen = None;
234 fgDisplay.pDisplay.NetWMPid = None;
235 fgDisplay.pDisplay.ClientMachine = None;
236
237 fgDisplay.pDisplay.NetWMSupported = fghNetWMSupported();
238
239 if (fgDisplay.pDisplay.NetWMSupported)
240 {
241 const Atom supported = fghGetAtom("_NET_SUPPORTED");
242 const Atom state = fghGetAtom("_NET_WM_STATE");
243
244 /* Check if the state hint is supported. */
245 if (fgHintPresent(fgDisplay.pDisplay.RootWindow, supported, state))
246 {
247 const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN");
248
249 fgDisplay.pDisplay.State = state;
250
251 /* Check if the window manager supports full screen. */
252 /** Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/
253 if (fgHintPresent(fgDisplay.pDisplay.RootWindow, supported, full_screen))
254 {
255 fgDisplay.pDisplay.StateFullScreen = full_screen;
256 }
257 }
258
259 fgDisplay.pDisplay.NetWMPid = fghGetAtom("_NET_WM_PID");
260 fgDisplay.pDisplay.ClientMachine = fghGetAtom("WM_CLIENT_MACHINE");
261 }
262
263 /* Open an input method */
264 setlocale(LC_ALL, ""); /* ugh! but we can't force the client to do it for us... */
265 if (!XSupportsLocale())
266 fgWarning("X doesn't support the current locale.");
267 if (!XSetLocaleModifiers(""))
268 fgWarning("Couldn't set X locale modifiers.");
269 fgDisplay.pDisplay.IM = XOpenIM(fgDisplay.pDisplay.Display, NULL, NULL, NULL);
270 if (!fgDisplay.pDisplay.IM)
271 fgWarning("Couldn't open X input method.");
272 else
273 {
274 XIMStyles *styles;
275 XIMStyle supported = XIMPreeditNothing | XIMStatusNothing;
276 XIMStyle best = 0;
277 unsigned int i;
278 char *res = XGetIMValues(fgDisplay.pDisplay.IM, XNQueryInputStyle, &styles, NULL);
279 if (res)
280 fgWarning("Couldn't get input method style: %s.", res);
281 else
282 {
283 for (i = 0; i < styles->count_styles; ++i)
284 {
285 XIMStyle style = styles->supported_styles[i];
286 if ((style & supported) == style)
287 best = style;
288 }
289 fgDisplay.pDisplay.InputStyle = best;
290 }
291 XFree(styles);
292 if (best == 0)
293 {
294 fgWarning("Couldn't find a usable input method style.");
295 XCloseIM(fgDisplay.pDisplay.IM);
296 fgDisplay.pDisplay.IM = NULL;
297 }
298 }
299
300 /* Get start time */
301 fgState.Time = fgSystemTime();
302
303 fgState.Initialised = GL_TRUE;
304
305 atexit(fgDeinitialize);
306
307 /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */
308 fgInitialiseInputDevices();
309}
310
311void fgPlatformDeinitialiseInputDevices ( void )
312{
313 fghCloseInputDevices ();
314
315 fgState.JoysticksInitialised = GL_FALSE;
316 fgState.InputDevsInitialised = GL_FALSE;
317}
318
319
320void fgPlatformCloseDisplay ( void )
321{
322 int i;
323
324 /*
325 * Make sure all X-client data we have created will be destroyed on
326 * display closing
327 */
328 XSetCloseDownMode( fgDisplay.pDisplay.Display, DestroyAll );
329
330 if (fgDisplay.pDisplay.IM)
331 XCloseIM(fgDisplay.pDisplay.IM);
332
333 /*
334 * Close the display connection, destroying all windows we have
335 * created so far
336 */
337 XCloseDisplay( fgDisplay.pDisplay.Display );
338
339 for (i = 0; i < 3; ++i)
340 {
341 free(fgClipboardBuffer[i]);
342 fgClipboardBuffer[i] = NULL;
343 }
344}
345
346
347#ifndef EGL_VERSION_1_0
348void fgPlatformDestroyContext ( SFG_PlatformDisplay pDisplay, SFG_WindowContextType MContext )
349{
350 /* Note that the MVisualInfo is not owned by the MenuContext! */
351 glXDestroyContext( pDisplay.Display, MContext );
352}
353#endif
354