diff options
Diffstat (limited to 'source/3rd-party/SDL2/src/video/x11/SDL_x11video.c')
-rw-r--r-- | source/3rd-party/SDL2/src/video/x11/SDL_x11video.c | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/video/x11/SDL_x11video.c b/source/3rd-party/SDL2/src/video/x11/SDL_x11video.c new file mode 100644 index 0000000..b3b1a70 --- /dev/null +++ b/source/3rd-party/SDL2/src/video/x11/SDL_x11video.c @@ -0,0 +1,497 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_X11 + +#include <unistd.h> /* For getpid() and readlink() */ + +#include "SDL_video.h" +#include "SDL_mouse.h" +#include "SDL_timer.h" +#include "../SDL_sysvideo.h" +#include "../SDL_pixels_c.h" + +#include "SDL_x11video.h" +#include "SDL_x11framebuffer.h" +#include "SDL_x11shape.h" +#include "SDL_x11touch.h" +#include "SDL_x11xinput2.h" + +#if SDL_VIDEO_OPENGL_EGL +#include "SDL_x11opengles.h" +#endif + +#include "SDL_x11vulkan.h" + +/* Initialization/Query functions */ +static int X11_VideoInit(_THIS); +static void X11_VideoQuit(_THIS); + +/* Find out what class name we should use */ +static char * +get_classname() +{ + char *spot; +#if defined(__LINUX__) || defined(__FREEBSD__) + char procfile[1024]; + char linkfile[1024]; + int linksize; +#endif + + /* First allow environment variable override */ + spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS"); + if (spot) { + return SDL_strdup(spot); + } + + /* Next look at the application's executable name */ +#if defined(__LINUX__) || defined(__FREEBSD__) +#if defined(__LINUX__) + SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid()); +#elif defined(__FREEBSD__) + SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file", + getpid()); +#else +#error Where can we find the executable name? +#endif + linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1); + if (linksize > 0) { + linkfile[linksize] = '\0'; + spot = SDL_strrchr(linkfile, '/'); + if (spot) { + return SDL_strdup(spot + 1); + } else { + return SDL_strdup(linkfile); + } + } +#endif /* __LINUX__ || __FREEBSD__ */ + + /* Finally use the default we've used forever */ + return SDL_strdup("SDL_App"); +} + +/* X11 driver bootstrap functions */ + +static int +X11_Available(void) +{ + Display *display = NULL; + if (SDL_X11_LoadSymbols()) { + display = X11_XOpenDisplay(NULL); + if (display != NULL) { + X11_XCloseDisplay(display); + } + SDL_X11_UnloadSymbols(); + } + return (display != NULL); +} + +static void +X11_DeleteDevice(SDL_VideoDevice * device) +{ + SDL_VideoData *data = (SDL_VideoData *) device->driverdata; + if (device->vulkan_config.loader_handle) { + device->Vulkan_UnloadLibrary(device); + } + if (data->display) { + X11_XCloseDisplay(data->display); + } + SDL_free(data->windowlist); + SDL_free(device->driverdata); + SDL_free(device); + + SDL_X11_UnloadSymbols(); +} + +/* An error handler to reset the vidmode and then call the default handler. */ +static SDL_bool safety_net_triggered = SDL_FALSE; +static int (*orig_x11_errhandler) (Display *, XErrorEvent *) = NULL; +static int +X11_SafetyNetErrHandler(Display * d, XErrorEvent * e) +{ + SDL_VideoDevice *device = NULL; + /* if we trigger an error in our error handler, don't try again. */ + if (!safety_net_triggered) { + safety_net_triggered = SDL_TRUE; + device = SDL_GetVideoDevice(); + if (device != NULL) { + int i; + for (i = 0; i < device->num_displays; i++) { + SDL_VideoDisplay *display = &device->displays[i]; + if (SDL_memcmp(&display->current_mode, &display->desktop_mode, + sizeof (SDL_DisplayMode)) != 0) { + X11_SetDisplayMode(device, display, &display->desktop_mode); + } + } + } + } + + if (orig_x11_errhandler != NULL) { + return orig_x11_errhandler(d, e); /* probably terminate. */ + } + + return 0; +} + +static SDL_VideoDevice * +X11_CreateDevice(int devindex) +{ + SDL_VideoDevice *device; + SDL_VideoData *data; + const char *display = NULL; /* Use the DISPLAY environment variable */ + + if (!SDL_X11_LoadSymbols()) { + return NULL; + } + + /* Need for threading gl calls. This is also required for the proprietary + nVidia driver to be threaded. */ + X11_XInitThreads(); + + /* Initialize all variables that we clean on shutdown */ + device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (!device) { + SDL_OutOfMemory(); + return NULL; + } + data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); + if (!data) { + SDL_free(device); + SDL_OutOfMemory(); + return NULL; + } + device->driverdata = data; + + data->global_mouse_changed = SDL_TRUE; + + /* FIXME: Do we need this? + if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) || + (SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) { + local_X11 = 1; + } else { + local_X11 = 0; + } + */ + data->display = X11_XOpenDisplay(display); +#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC + /* On some systems if linking without -lX11, it fails and you get following message. + * Xlib: connection to ":0.0" refused by server + * Xlib: XDM authorization key matches an existing client! + * + * It succeeds if retrying 1 second later + * or if running xhost +localhost on shell. + */ + if (data->display == NULL) { + SDL_Delay(1000); + data->display = X11_XOpenDisplay(display); + } +#endif + if (data->display == NULL) { + SDL_free(device->driverdata); + SDL_free(device); + SDL_SetError("Couldn't open X11 display"); + return NULL; + } +#ifdef X11_DEBUG + X11_XSynchronize(data->display, True); +#endif + + /* Hook up an X11 error handler to recover the desktop resolution. */ + safety_net_triggered = SDL_FALSE; + orig_x11_errhandler = X11_XSetErrorHandler(X11_SafetyNetErrHandler); + + /* Set the function pointers */ + device->VideoInit = X11_VideoInit; + device->VideoQuit = X11_VideoQuit; + device->ResetTouch = X11_ResetTouch; + device->GetDisplayModes = X11_GetDisplayModes; + device->GetDisplayBounds = X11_GetDisplayBounds; + device->GetDisplayUsableBounds = X11_GetDisplayUsableBounds; + device->GetDisplayDPI = X11_GetDisplayDPI; + device->SetDisplayMode = X11_SetDisplayMode; + device->SuspendScreenSaver = X11_SuspendScreenSaver; + device->PumpEvents = X11_PumpEvents; + + device->CreateSDLWindow = X11_CreateWindow; + device->CreateSDLWindowFrom = X11_CreateWindowFrom; + device->SetWindowTitle = X11_SetWindowTitle; + device->SetWindowIcon = X11_SetWindowIcon; + device->SetWindowPosition = X11_SetWindowPosition; + device->SetWindowSize = X11_SetWindowSize; + device->SetWindowMinimumSize = X11_SetWindowMinimumSize; + device->SetWindowMaximumSize = X11_SetWindowMaximumSize; + device->GetWindowBordersSize = X11_GetWindowBordersSize; + device->SetWindowOpacity = X11_SetWindowOpacity; + device->SetWindowModalFor = X11_SetWindowModalFor; + device->SetWindowInputFocus = X11_SetWindowInputFocus; + device->ShowWindow = X11_ShowWindow; + device->HideWindow = X11_HideWindow; + device->RaiseWindow = X11_RaiseWindow; + device->MaximizeWindow = X11_MaximizeWindow; + device->MinimizeWindow = X11_MinimizeWindow; + device->RestoreWindow = X11_RestoreWindow; + device->SetWindowBordered = X11_SetWindowBordered; + device->SetWindowResizable = X11_SetWindowResizable; + device->SetWindowFullscreen = X11_SetWindowFullscreen; + device->SetWindowGammaRamp = X11_SetWindowGammaRamp; + device->SetWindowGrab = X11_SetWindowGrab; + device->DestroyWindow = X11_DestroyWindow; + device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer; + device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer; + device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer; + device->GetWindowWMInfo = X11_GetWindowWMInfo; + device->SetWindowHitTest = X11_SetWindowHitTest; + device->AcceptDragAndDrop = X11_AcceptDragAndDrop; + + device->shape_driver.CreateShaper = X11_CreateShaper; + device->shape_driver.SetWindowShape = X11_SetWindowShape; + device->shape_driver.ResizeWindowShape = X11_ResizeWindowShape; + +#if SDL_VIDEO_OPENGL_GLX + device->GL_LoadLibrary = X11_GL_LoadLibrary; + device->GL_GetProcAddress = X11_GL_GetProcAddress; + device->GL_UnloadLibrary = X11_GL_UnloadLibrary; + device->GL_CreateContext = X11_GL_CreateContext; + device->GL_MakeCurrent = X11_GL_MakeCurrent; + device->GL_SetSwapInterval = X11_GL_SetSwapInterval; + device->GL_GetSwapInterval = X11_GL_GetSwapInterval; + device->GL_SwapWindow = X11_GL_SwapWindow; + device->GL_DeleteContext = X11_GL_DeleteContext; +#elif SDL_VIDEO_OPENGL_EGL + device->GL_LoadLibrary = X11_GLES_LoadLibrary; + device->GL_GetProcAddress = X11_GLES_GetProcAddress; + device->GL_UnloadLibrary = X11_GLES_UnloadLibrary; + device->GL_CreateContext = X11_GLES_CreateContext; + device->GL_MakeCurrent = X11_GLES_MakeCurrent; + device->GL_SetSwapInterval = X11_GLES_SetSwapInterval; + device->GL_GetSwapInterval = X11_GLES_GetSwapInterval; + device->GL_SwapWindow = X11_GLES_SwapWindow; + device->GL_DeleteContext = X11_GLES_DeleteContext; +#endif + + device->SetClipboardText = X11_SetClipboardText; + device->GetClipboardText = X11_GetClipboardText; + device->HasClipboardText = X11_HasClipboardText; + device->StartTextInput = X11_StartTextInput; + device->StopTextInput = X11_StopTextInput; + device->SetTextInputRect = X11_SetTextInputRect; + + device->free = X11_DeleteDevice; + +#if SDL_VIDEO_VULKAN + device->Vulkan_LoadLibrary = X11_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = X11_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = X11_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = X11_Vulkan_CreateSurface; +#endif + + return device; +} + +VideoBootStrap X11_bootstrap = { + "x11", "SDL X11 video driver", + X11_Available, X11_CreateDevice +}; + +static int (*handler) (Display *, XErrorEvent *) = NULL; +static int +X11_CheckWindowManagerErrorHandler(Display * d, XErrorEvent * e) +{ + if (e->error_code == BadWindow) { + return (0); + } else { + return (handler(d, e)); + } +} + +static void +X11_CheckWindowManager(_THIS) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + Display *display = data->display; + Atom _NET_SUPPORTING_WM_CHECK; + int status, real_format; + Atom real_type; + unsigned long items_read = 0, items_left = 0; + unsigned char *propdata = NULL; + Window wm_window = 0; +#ifdef DEBUG_WINDOW_MANAGER + char *wm_name; +#endif + + /* Set up a handler to gracefully catch errors */ + X11_XSync(display, False); + handler = X11_XSetErrorHandler(X11_CheckWindowManagerErrorHandler); + + _NET_SUPPORTING_WM_CHECK = X11_XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); + status = X11_XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata); + if (status == Success) { + if (items_read) { + wm_window = ((Window*)propdata)[0]; + } + if (propdata) { + X11_XFree(propdata); + propdata = NULL; + } + } + + if (wm_window) { + status = X11_XGetWindowProperty(display, wm_window, _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata); + if (status != Success || !items_read || wm_window != ((Window*)propdata)[0]) { + wm_window = None; + } + if (status == Success && propdata) { + X11_XFree(propdata); + propdata = NULL; + } + } + + /* Reset the error handler, we're done checking */ + X11_XSync(display, False); + X11_XSetErrorHandler(handler); + + if (!wm_window) { +#ifdef DEBUG_WINDOW_MANAGER + printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n"); +#endif + return; + } + data->net_wm = SDL_TRUE; + +#ifdef DEBUG_WINDOW_MANAGER + wm_name = X11_GetWindowTitle(_this, wm_window); + printf("Window manager: %s\n", wm_name); + SDL_free(wm_name); +#endif +} + + +int +X11_VideoInit(_THIS) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + + /* Get the window class name, usually the name of the application */ + data->classname = get_classname(); + + /* Get the process PID to be associated to the window */ + data->pid = getpid(); + + /* I have no idea how random this actually is, or has to be. */ + data->window_group = (XID) (((size_t) data->pid) ^ ((size_t) _this)); + + /* Look up some useful Atoms */ +#define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False) + GET_ATOM(WM_PROTOCOLS); + GET_ATOM(WM_DELETE_WINDOW); + GET_ATOM(WM_TAKE_FOCUS); + GET_ATOM(_NET_WM_STATE); + GET_ATOM(_NET_WM_STATE_HIDDEN); + GET_ATOM(_NET_WM_STATE_FOCUSED); + GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); + GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); + GET_ATOM(_NET_WM_STATE_FULLSCREEN); + GET_ATOM(_NET_WM_STATE_ABOVE); + GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR); + GET_ATOM(_NET_WM_STATE_SKIP_PAGER); + GET_ATOM(_NET_WM_ALLOWED_ACTIONS); + GET_ATOM(_NET_WM_ACTION_FULLSCREEN); + GET_ATOM(_NET_WM_NAME); + GET_ATOM(_NET_WM_ICON_NAME); + GET_ATOM(_NET_WM_ICON); + GET_ATOM(_NET_WM_PING); + GET_ATOM(_NET_WM_WINDOW_OPACITY); + GET_ATOM(_NET_WM_USER_TIME); + GET_ATOM(_NET_ACTIVE_WINDOW); + GET_ATOM(_NET_FRAME_EXTENTS); + GET_ATOM(UTF8_STRING); + GET_ATOM(PRIMARY); + GET_ATOM(XdndEnter); + GET_ATOM(XdndPosition); + GET_ATOM(XdndStatus); + GET_ATOM(XdndTypeList); + GET_ATOM(XdndActionCopy); + GET_ATOM(XdndDrop); + GET_ATOM(XdndFinished); + GET_ATOM(XdndSelection); + GET_ATOM(XKLAVIER_STATE); + + /* Detect the window manager */ + X11_CheckWindowManager(_this); + + if (X11_InitModes(_this) < 0) { + return -1; + } + + X11_InitXinput2(_this); + + if (X11_InitKeyboard(_this) != 0) { + return -1; + } + X11_InitMouse(_this); + + X11_InitTouch(_this); + +#if SDL_USE_LIBDBUS + SDL_DBus_Init(); +#endif + + return 0; +} + +void +X11_VideoQuit(_THIS) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + + if (data->clipboard_window) { + X11_XDestroyWindow(data->display, data->clipboard_window); + } + + SDL_free(data->classname); +#ifdef X_HAVE_UTF8_STRING + if (data->im) { + X11_XCloseIM(data->im); + } +#endif + + X11_QuitModes(_this); + X11_QuitKeyboard(_this); + X11_QuitMouse(_this); + X11_QuitTouch(_this); + +/* !!! FIXME: other subsystems use D-Bus, so we shouldn't quit it here; + have SDL.c do this at a higher level, or add refcounting. */ +#if SDL_USE_LIBDBUS + SDL_DBus_Quit(); +#endif +} + +SDL_bool +X11_UseDirectColorVisuals(void) +{ + return SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ? SDL_FALSE : SDL_TRUE; +} + +#endif /* SDL_VIDEO_DRIVER_X11 */ + +/* vim: set ts=4 sw=4 expandtab: */ |