2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_DRIVER_X11
25 #include <unistd.h> /* For getpid() and readlink() */
27 #include "SDL_video.h"
28 #include "SDL_mouse.h"
29 #include "../SDL_sysvideo.h"
30 #include "../SDL_pixels_c.h"
32 #include "SDL_x11video.h"
33 #include "SDL_x11framebuffer.h"
34 #include "SDL_x11shape.h"
35 #include "SDL_x11touch.h"
36 #include "SDL_x11xinput2.h"
38 #if SDL_VIDEO_OPENGL_EGL
39 #include "SDL_x11opengles.h"
42 /* Initialization/Query functions */
43 static int X11_VideoInit(_THIS);
44 static void X11_VideoQuit(_THIS);
46 /* Find out what class name we should use */
51 #if defined(__LINUX__) || defined(__FREEBSD__)
57 /* First allow environment variable override */
58 spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS");
60 return SDL_strdup(spot);
63 /* Next look at the application's executable name */
64 #if defined(__LINUX__) || defined(__FREEBSD__)
65 #if defined(__LINUX__)
66 SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid());
67 #elif defined(__FREEBSD__)
68 SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file",
71 #error Where can we find the executable name?
73 linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
75 linkfile[linksize] = '\0';
76 spot = SDL_strrchr(linkfile, '/');
78 return SDL_strdup(spot + 1);
80 return SDL_strdup(linkfile);
83 #endif /* __LINUX__ || __FREEBSD__ */
85 /* Finally use the default we've used forever */
86 return SDL_strdup("SDL_App");
89 /* X11 driver bootstrap functions */
94 Display *display = NULL;
95 if (SDL_X11_LoadSymbols()) {
96 display = X11_XOpenDisplay(NULL);
97 if (display != NULL) {
98 X11_XCloseDisplay(display);
100 SDL_X11_UnloadSymbols();
102 return (display != NULL);
106 X11_DeleteDevice(SDL_VideoDevice * device)
108 SDL_VideoData *data = (SDL_VideoData *) device->driverdata;
110 X11_XCloseDisplay(data->display);
112 SDL_free(data->windowlist);
113 SDL_free(device->driverdata);
116 SDL_X11_UnloadSymbols();
119 /* An error handler to reset the vidmode and then call the default handler. */
120 static SDL_bool safety_net_triggered = SDL_FALSE;
121 static int (*orig_x11_errhandler) (Display *, XErrorEvent *) = NULL;
123 X11_SafetyNetErrHandler(Display * d, XErrorEvent * e)
125 SDL_VideoDevice *device = NULL;
126 /* if we trigger an error in our error handler, don't try again. */
127 if (!safety_net_triggered) {
128 safety_net_triggered = SDL_TRUE;
129 device = SDL_GetVideoDevice();
130 if (device != NULL) {
132 for (i = 0; i < device->num_displays; i++) {
133 SDL_VideoDisplay *display = &device->displays[i];
134 if (SDL_memcmp(&display->current_mode, &display->desktop_mode,
135 sizeof (SDL_DisplayMode)) != 0) {
136 X11_SetDisplayMode(device, display, &display->desktop_mode);
142 if (orig_x11_errhandler != NULL) {
143 return orig_x11_errhandler(d, e); /* probably terminate. */
149 static SDL_VideoDevice *
150 X11_CreateDevice(int devindex)
152 SDL_VideoDevice *device;
154 const char *display = NULL; /* Use the DISPLAY environment variable */
156 if (!SDL_X11_LoadSymbols()) {
160 /* Need for threading gl calls. This is also required for the proprietary
161 nVidia driver to be threaded. */
164 /* Initialize all variables that we clean on shutdown */
165 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
170 data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
176 device->driverdata = data;
178 /* FIXME: Do we need this?
179 if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) ||
180 (SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) {
186 data->display = X11_XOpenDisplay(display);
187 #if defined(__osf__) && defined(SDL_VIDEO_DRIVER_X11_DYNAMIC)
188 /* On Tru64 if linking without -lX11, it fails and you get following message.
189 * Xlib: connection to ":0.0" refused by server
190 * Xlib: XDM authorization key matches an existing client!
192 * It succeeds if retrying 1 second later
193 * or if running xhost +localhost on shell.
195 if (data->display == NULL) {
197 data->display = X11_XOpenDisplay(display);
200 if (data->display == NULL) {
201 SDL_free(device->driverdata);
203 SDL_SetError("Couldn't open X11 display");
207 X11_XSynchronize(data->display, True);
210 /* Hook up an X11 error handler to recover the desktop resolution. */
211 safety_net_triggered = SDL_FALSE;
212 orig_x11_errhandler = X11_XSetErrorHandler(X11_SafetyNetErrHandler);
214 /* Set the function pointers */
215 device->VideoInit = X11_VideoInit;
216 device->VideoQuit = X11_VideoQuit;
217 device->GetDisplayModes = X11_GetDisplayModes;
218 device->GetDisplayBounds = X11_GetDisplayBounds;
219 device->GetDisplayDPI = X11_GetDisplayDPI;
220 device->SetDisplayMode = X11_SetDisplayMode;
221 device->SuspendScreenSaver = X11_SuspendScreenSaver;
222 device->PumpEvents = X11_PumpEvents;
224 device->CreateWindow = X11_CreateWindow;
225 device->CreateWindowFrom = X11_CreateWindowFrom;
226 device->SetWindowTitle = X11_SetWindowTitle;
227 device->SetWindowIcon = X11_SetWindowIcon;
228 device->SetWindowPosition = X11_SetWindowPosition;
229 device->SetWindowSize = X11_SetWindowSize;
230 device->SetWindowMinimumSize = X11_SetWindowMinimumSize;
231 device->SetWindowMaximumSize = X11_SetWindowMaximumSize;
232 device->ShowWindow = X11_ShowWindow;
233 device->HideWindow = X11_HideWindow;
234 device->RaiseWindow = X11_RaiseWindow;
235 device->MaximizeWindow = X11_MaximizeWindow;
236 device->MinimizeWindow = X11_MinimizeWindow;
237 device->RestoreWindow = X11_RestoreWindow;
238 device->SetWindowBordered = X11_SetWindowBordered;
239 device->SetWindowFullscreen = X11_SetWindowFullscreen;
240 device->SetWindowGammaRamp = X11_SetWindowGammaRamp;
241 device->SetWindowGrab = X11_SetWindowGrab;
242 device->DestroyWindow = X11_DestroyWindow;
243 device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer;
244 device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer;
245 device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer;
246 device->GetWindowWMInfo = X11_GetWindowWMInfo;
247 device->SetWindowHitTest = X11_SetWindowHitTest;
249 device->shape_driver.CreateShaper = X11_CreateShaper;
250 device->shape_driver.SetWindowShape = X11_SetWindowShape;
251 device->shape_driver.ResizeWindowShape = X11_ResizeWindowShape;
253 #if SDL_VIDEO_OPENGL_GLX
254 device->GL_LoadLibrary = X11_GL_LoadLibrary;
255 device->GL_GetProcAddress = X11_GL_GetProcAddress;
256 device->GL_UnloadLibrary = X11_GL_UnloadLibrary;
257 device->GL_CreateContext = X11_GL_CreateContext;
258 device->GL_MakeCurrent = X11_GL_MakeCurrent;
259 device->GL_SetSwapInterval = X11_GL_SetSwapInterval;
260 device->GL_GetSwapInterval = X11_GL_GetSwapInterval;
261 device->GL_SwapWindow = X11_GL_SwapWindow;
262 device->GL_DeleteContext = X11_GL_DeleteContext;
263 #elif SDL_VIDEO_OPENGL_EGL
264 device->GL_LoadLibrary = X11_GLES_LoadLibrary;
265 device->GL_GetProcAddress = X11_GLES_GetProcAddress;
266 device->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
267 device->GL_CreateContext = X11_GLES_CreateContext;
268 device->GL_MakeCurrent = X11_GLES_MakeCurrent;
269 device->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
270 device->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
271 device->GL_SwapWindow = X11_GLES_SwapWindow;
272 device->GL_DeleteContext = X11_GLES_DeleteContext;
275 device->SetClipboardText = X11_SetClipboardText;
276 device->GetClipboardText = X11_GetClipboardText;
277 device->HasClipboardText = X11_HasClipboardText;
278 device->StartTextInput = X11_StartTextInput;
279 device->StopTextInput = X11_StopTextInput;
280 device->SetTextInputRect = X11_SetTextInputRect;
282 device->free = X11_DeleteDevice;
287 VideoBootStrap X11_bootstrap = {
288 "x11", "SDL X11 video driver",
289 X11_Available, X11_CreateDevice
292 static int (*handler) (Display *, XErrorEvent *) = NULL;
294 X11_CheckWindowManagerErrorHandler(Display * d, XErrorEvent * e)
296 if (e->error_code == BadWindow) {
299 return (handler(d, e));
304 X11_CheckWindowManager(_THIS)
306 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
307 Display *display = data->display;
308 Atom _NET_SUPPORTING_WM_CHECK;
309 int status, real_format;
311 unsigned long items_read = 0, items_left = 0;
312 unsigned char *propdata = NULL;
313 Window wm_window = 0;
314 #ifdef DEBUG_WINDOW_MANAGER
318 /* Set up a handler to gracefully catch errors */
319 X11_XSync(display, False);
320 handler = X11_XSetErrorHandler(X11_CheckWindowManagerErrorHandler);
322 _NET_SUPPORTING_WM_CHECK = X11_XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
323 status = X11_XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
324 if (status == Success) {
326 wm_window = ((Window*)propdata)[0];
335 status = X11_XGetWindowProperty(display, wm_window, _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
336 if (status != Success || !items_read || wm_window != ((Window*)propdata)[0]) {
339 if (status == Success && propdata) {
345 /* Reset the error handler, we're done checking */
346 X11_XSync(display, False);
347 X11_XSetErrorHandler(handler);
350 #ifdef DEBUG_WINDOW_MANAGER
351 printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n");
355 data->net_wm = SDL_TRUE;
357 #ifdef DEBUG_WINDOW_MANAGER
358 wm_name = X11_GetWindowTitle(_this, wm_window);
359 printf("Window manager: %s\n", wm_name);
368 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
370 /* Get the window class name, usually the name of the application */
371 data->classname = get_classname();
373 /* Get the process PID to be associated to the window */
374 data->pid = getpid();
376 /* Open a connection to the X input manager */
377 #ifdef X_HAVE_UTF8_STRING
378 if (SDL_X11_HAVE_UTF8) {
380 X11_XOpenIM(data->display, NULL, data->classname, data->classname);
384 /* Look up some useful Atoms */
385 #define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False)
386 GET_ATOM(WM_PROTOCOLS);
387 GET_ATOM(WM_DELETE_WINDOW);
388 GET_ATOM(_NET_WM_STATE);
389 GET_ATOM(_NET_WM_STATE_HIDDEN);
390 GET_ATOM(_NET_WM_STATE_FOCUSED);
391 GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
392 GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
393 GET_ATOM(_NET_WM_STATE_FULLSCREEN);
394 GET_ATOM(_NET_WM_ALLOWED_ACTIONS);
395 GET_ATOM(_NET_WM_ACTION_FULLSCREEN);
396 GET_ATOM(_NET_WM_NAME);
397 GET_ATOM(_NET_WM_ICON_NAME);
398 GET_ATOM(_NET_WM_ICON);
399 GET_ATOM(_NET_WM_PING);
400 GET_ATOM(_NET_ACTIVE_WINDOW);
401 GET_ATOM(UTF8_STRING);
404 GET_ATOM(XdndPosition);
405 GET_ATOM(XdndStatus);
406 GET_ATOM(XdndTypeList);
407 GET_ATOM(XdndActionCopy);
409 GET_ATOM(XdndFinished);
410 GET_ATOM(XdndSelection);
411 GET_ATOM(XKLAVIER_STATE);
413 /* Detect the window manager */
414 X11_CheckWindowManager(_this);
416 if (X11_InitModes(_this) < 0) {
420 X11_InitXinput2(_this);
422 if (X11_InitKeyboard(_this) != 0) {
425 X11_InitMouse(_this);
427 X11_InitTouch(_this);
439 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
441 SDL_free(data->classname);
442 #ifdef X_HAVE_UTF8_STRING
444 X11_XCloseIM(data->im);
448 X11_QuitModes(_this);
449 X11_QuitKeyboard(_this);
450 X11_QuitMouse(_this);
451 X11_QuitTouch(_this);
459 X11_UseDirectColorVisuals(void)
461 return SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ? SDL_FALSE : SDL_TRUE;
464 #endif /* SDL_VIDEO_DRIVER_X11 */
466 /* vim: set ts=4 sw=4 expandtab: */