Atlas - SDL_x11video.c

Home / ext / SDL / src / video / x11 Lines: 3 | Size: 16090 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 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. 8 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: 12 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. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_DRIVER_X11 24 25#include <unistd.h> // For getpid() and readlink() 26 27#include "../../core/linux/SDL_system_theme.h" 28#include "../../core/linux/SDL_progressbar.h" 29#include "../../events/SDL_keyboard_c.h" 30#include "../../events/SDL_mouse_c.h" 31#include "../SDL_pixels_c.h" 32#include "../SDL_sysvideo.h" 33 34#include "SDL_x11framebuffer.h" 35#include "SDL_x11pen.h" 36#include "SDL_x11touch.h" 37#include "SDL_x11video.h" 38#include "SDL_x11xfixes.h" 39#include "SDL_x11xinput2.h" 40#include "SDL_x11messagebox.h" 41#include "SDL_x11shape.h" 42#include "SDL_x11xsync.h" 43#include "SDL_x11xtest.h" 44 45#ifdef SDL_VIDEO_OPENGL_EGL 46#include "SDL_x11opengles.h" 47#endif 48 49// Initialization/Query functions 50static bool X11_VideoInit(SDL_VideoDevice *_this); 51static void X11_VideoQuit(SDL_VideoDevice *_this); 52 53// X11 driver bootstrap functions 54 55static void X11_DeleteDevice(SDL_VideoDevice *device) 56{ 57 SDL_VideoData *data = device->internal; 58 if (device->vulkan_config.loader_handle) { 59 device->Vulkan_UnloadLibrary(device); 60 } 61 if (data->display) { 62 X11_XCloseDisplay(data->display); 63 } 64 if (data->request_display) { 65 X11_XCloseDisplay(data->request_display); 66 } 67 SDL_free(data->windowlist); 68 SDL_free(device->internal); 69 SDL_free(device); 70 71 SDL_X11_UnloadSymbols(); 72} 73 74static bool X11_IsXWayland(Display *d) 75{ 76 int opcode, event, error; 77 return X11_XQueryExtension(d, "XWAYLAND", &opcode, &event, &error) == True; 78} 79 80static SDL_VideoDevice *X11_CreateDevice(void) 81{ 82 SDL_VideoDevice *device; 83 SDL_VideoData *data; 84 const char *display = NULL; // Use the DISPLAY environment variable 85 Display *x11_display = NULL; 86 87 if (!SDL_X11_LoadSymbols()) { 88 return NULL; 89 } 90 91 /* Need for threading gl calls. This is also required for the proprietary 92 nVidia driver to be threaded. */ 93 X11_XInitThreads(); 94 95 // Open the display first to be sure that X11 is available 96 x11_display = X11_XOpenDisplay(display); 97 98 if (!x11_display) { 99 SDL_X11_UnloadSymbols(); 100 return NULL; 101 } 102 103 // Initialize all variables that we clean on shutdown 104 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); 105 if (!device) { 106 return NULL; 107 } 108 data = (struct SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData)); 109 if (!data) { 110 SDL_free(device); 111 return NULL; 112 } 113 device->internal = data; 114 115 data->global_mouse_changed = true; 116 117#ifdef SDL_VIDEO_DRIVER_X11_XFIXES 118 data->active_cursor_confined_window = NULL; 119#endif // SDL_VIDEO_DRIVER_X11_XFIXES 120 121 data->display = x11_display; 122 data->request_display = X11_XOpenDisplay(display); 123 if (!data->request_display) { 124 X11_XCloseDisplay(data->display); 125 SDL_free(device->internal); 126 SDL_free(device); 127 SDL_X11_UnloadSymbols(); 128 return NULL; 129 } 130 131#ifdef X11_DEBUG 132 X11_XSynchronize(data->display, True); 133#endif 134 135 /* Steam Deck will have an on-screen keyboard, so check their environment 136 * variable so we can make use of SDL_StartTextInput. 137 */ 138 data->is_steam_deck = SDL_GetHintBoolean("SteamDeck", false); 139 140 // Set the function pointers 141 device->VideoInit = X11_VideoInit; 142 device->VideoQuit = X11_VideoQuit; 143 device->ResetTouch = X11_ResetTouch; 144 device->GetDisplayModes = X11_GetDisplayModes; 145 device->GetDisplayBounds = X11_GetDisplayBounds; 146 device->GetDisplayUsableBounds = X11_GetDisplayUsableBounds; 147 device->GetWindowICCProfile = X11_GetWindowICCProfile; 148 device->SetDisplayMode = X11_SetDisplayMode; 149 device->SuspendScreenSaver = X11_SuspendScreenSaver; 150 device->PumpEvents = X11_PumpEvents; 151 device->WaitEventTimeout = X11_WaitEventTimeout; 152 device->SendWakeupEvent = X11_SendWakeupEvent; 153 154 device->CreateSDLWindow = X11_CreateWindow; 155 device->SetWindowTitle = X11_SetWindowTitle; 156 device->SetWindowIcon = X11_SetWindowIcon; 157 device->SetWindowPosition = X11_SetWindowPosition; 158 device->SetWindowSize = X11_SetWindowSize; 159 device->SetWindowMinimumSize = X11_SetWindowMinimumSize; 160 device->SetWindowMaximumSize = X11_SetWindowMaximumSize; 161 device->SetWindowAspectRatio = X11_SetWindowAspectRatio; 162 device->GetWindowBordersSize = X11_GetWindowBordersSize; 163 device->SetWindowOpacity = X11_SetWindowOpacity; 164 device->SetWindowParent = X11_SetWindowParent; 165 device->SetWindowModal = X11_SetWindowModal; 166 device->ShowWindow = X11_ShowWindow; 167 device->HideWindow = X11_HideWindow; 168 device->RaiseWindow = X11_RaiseWindow; 169 device->MaximizeWindow = X11_MaximizeWindow; 170 device->MinimizeWindow = X11_MinimizeWindow; 171 device->RestoreWindow = X11_RestoreWindow; 172 device->SetWindowBordered = X11_SetWindowBordered; 173 device->SetWindowResizable = X11_SetWindowResizable; 174 device->SetWindowAlwaysOnTop = X11_SetWindowAlwaysOnTop; 175 device->SetWindowFullscreen = X11_SetWindowFullscreen; 176 device->SetWindowMouseGrab = X11_SetWindowMouseGrab; 177 device->SetWindowKeyboardGrab = X11_SetWindowKeyboardGrab; 178 device->DestroyWindow = X11_DestroyWindow; 179 device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer; 180 device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer; 181 device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer; 182 device->SetWindowHitTest = X11_SetWindowHitTest; 183 device->AcceptDragAndDrop = X11_AcceptDragAndDrop; 184 device->UpdateWindowShape = X11_UpdateWindowShape; 185 device->FlashWindow = X11_FlashWindow; 186#ifdef SDL_USE_LIBDBUS 187 device->ApplyWindowProgress = DBUS_ApplyWindowProgress; 188#endif // SDL_USE_LIBDBUS 189 device->ShowWindowSystemMenu = X11_ShowWindowSystemMenu; 190 device->SetWindowFocusable = X11_SetWindowFocusable; 191 device->SyncWindow = X11_SyncWindow; 192 193#ifdef SDL_VIDEO_DRIVER_X11_XFIXES 194 device->SetWindowMouseRect = X11_SetWindowMouseRect; 195#endif // SDL_VIDEO_DRIVER_X11_XFIXES 196 197#ifdef SDL_VIDEO_OPENGL_GLX 198 device->GL_LoadLibrary = X11_GL_LoadLibrary; 199 device->GL_GetProcAddress = X11_GL_GetProcAddress; 200 device->GL_UnloadLibrary = X11_GL_UnloadLibrary; 201 device->GL_CreateContext = X11_GL_CreateContext; 202 device->GL_MakeCurrent = X11_GL_MakeCurrent; 203 device->GL_SetSwapInterval = X11_GL_SetSwapInterval; 204 device->GL_GetSwapInterval = X11_GL_GetSwapInterval; 205 device->GL_SwapWindow = X11_GL_SwapWindow; 206 device->GL_DestroyContext = X11_GL_DestroyContext; 207 device->GL_GetEGLSurface = NULL; 208#endif 209#ifdef SDL_VIDEO_OPENGL_EGL 210#ifdef SDL_VIDEO_OPENGL_GLX 211 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, false)) { 212#endif 213 device->GL_LoadLibrary = X11_GLES_LoadLibrary; 214 device->GL_GetProcAddress = X11_GLES_GetProcAddress; 215 device->GL_UnloadLibrary = X11_GLES_UnloadLibrary; 216 device->GL_CreateContext = X11_GLES_CreateContext; 217 device->GL_MakeCurrent = X11_GLES_MakeCurrent; 218 device->GL_SetSwapInterval = X11_GLES_SetSwapInterval; 219 device->GL_GetSwapInterval = X11_GLES_GetSwapInterval; 220 device->GL_SwapWindow = X11_GLES_SwapWindow; 221 device->GL_DestroyContext = X11_GLES_DestroyContext; 222 device->GL_GetEGLSurface = X11_GLES_GetEGLSurface; 223#ifdef SDL_VIDEO_OPENGL_GLX 224 } 225#endif 226#endif 227 228 device->GetTextMimeTypes = X11_GetTextMimeTypes; 229 device->SetClipboardData = X11_SetClipboardData; 230 device->GetClipboardData = X11_GetClipboardData; 231 device->HasClipboardData = X11_HasClipboardData; 232 device->SetPrimarySelectionText = X11_SetPrimarySelectionText; 233 device->GetPrimarySelectionText = X11_GetPrimarySelectionText; 234 device->HasPrimarySelectionText = X11_HasPrimarySelectionText; 235 device->StartTextInput = X11_StartTextInput; 236 device->StopTextInput = X11_StopTextInput; 237 device->UpdateTextInputArea = X11_UpdateTextInputArea; 238 device->HasScreenKeyboardSupport = X11_HasScreenKeyboardSupport; 239 device->ShowScreenKeyboard = X11_ShowScreenKeyboard; 240 device->HideScreenKeyboard = X11_HideScreenKeyboard; 241 242 device->free = X11_DeleteDevice; 243 244#ifdef SDL_VIDEO_VULKAN 245 device->Vulkan_LoadLibrary = X11_Vulkan_LoadLibrary; 246 device->Vulkan_UnloadLibrary = X11_Vulkan_UnloadLibrary; 247 device->Vulkan_GetInstanceExtensions = X11_Vulkan_GetInstanceExtensions; 248 device->Vulkan_CreateSurface = X11_Vulkan_CreateSurface; 249 device->Vulkan_DestroySurface = X11_Vulkan_DestroySurface; 250 device->Vulkan_GetPresentationSupport = X11_Vulkan_GetPresentationSupport; 251#endif 252 253#ifdef SDL_USE_LIBDBUS 254 if (SDL_SystemTheme_Init()) 255 device->system_theme = SDL_SystemTheme_Get(); 256#endif 257 258 device->device_caps = VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT; 259 260 data->is_xwayland = X11_IsXWayland(x11_display); 261 if (data->is_xwayland) { 262 SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "Detected XWayland"); 263 264 device->device_caps |= VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED | 265 VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS; 266 } 267 268 return device; 269} 270 271VideoBootStrap X11_bootstrap = { 272 "x11", "SDL X11 video driver", 273 X11_CreateDevice, 274 X11_ShowMessageBox, 275 false 276}; 277 278static int (*handler)(Display *, XErrorEvent *) = NULL; 279static int X11_CheckWindowManagerErrorHandler(Display *d, XErrorEvent *e) 280{ 281 if (e->error_code == BadWindow) { 282 return 0; 283 } else { 284 return handler(d, e); 285 } 286} 287 288static void X11_CheckWindowManager(SDL_VideoDevice *_this) 289{ 290 SDL_VideoData *data = _this->internal; 291 Display *display = data->display; 292 Atom _NET_SUPPORTING_WM_CHECK; 293 int status, real_format; 294 Atom real_type; 295 unsigned long items_read = 0, items_left = 0; 296 unsigned char *propdata = NULL; 297 Window wm_window = 0; 298#ifdef DEBUG_WINDOW_MANAGER 299 char *wm_name; 300#endif 301 302 // Set up a handler to gracefully catch errors 303 X11_XSync(display, False); 304 handler = X11_XSetErrorHandler(X11_CheckWindowManagerErrorHandler); 305 306 _NET_SUPPORTING_WM_CHECK = X11_XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); 307 status = X11_XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata); 308 if (status == Success) { 309 if (items_read) { 310 wm_window = ((Window *)propdata)[0]; 311 } 312 if (propdata) { 313 X11_XFree(propdata); 314 propdata = NULL; 315 } 316 } 317 318 if (wm_window) { 319 status = X11_XGetWindowProperty(display, wm_window, _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata); 320 if (status != Success || !items_read || wm_window != ((Window *)propdata)[0]) { 321 wm_window = None; 322 } 323 if (status == Success && propdata) { 324 X11_XFree(propdata); 325 propdata = NULL; 326 } 327 } 328 329 // Reset the error handler, we're done checking 330 X11_XSync(display, False); 331 X11_XSetErrorHandler(handler); 332 333 if (!wm_window) { 334#ifdef DEBUG_WINDOW_MANAGER 335 printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n"); 336#endif 337 return; 338 } 339 data->net_wm = true; 340 341#ifdef DEBUG_WINDOW_MANAGER 342 wm_name = X11_GetWindowTitle(_this, wm_window); 343 printf("Window manager: %s\n", wm_name); 344 SDL_free(wm_name); 345#endif 346} 347 348static bool X11_VideoInit(SDL_VideoDevice *_this) 349{ 350 SDL_VideoData *data = _this->internal; 351 352 // Get the process PID to be associated to the window 353 data->pid = getpid(); 354 355 // I have no idea how random this actually is, or has to be. 356 data->window_group = (XID)(((size_t)data->pid) ^ ((size_t)_this)); 357 358 // Look up some useful Atoms 359#define GET_ATOM(X) data->atoms.X = X11_XInternAtom(data->display, #X, False) 360 GET_ATOM(WM_PROTOCOLS); 361 GET_ATOM(WM_DELETE_WINDOW); 362 GET_ATOM(WM_TAKE_FOCUS); 363 GET_ATOM(WM_NAME); 364 GET_ATOM(WM_TRANSIENT_FOR); 365 GET_ATOM(_NET_WM_STATE); 366 GET_ATOM(_NET_WM_STATE_HIDDEN); 367 GET_ATOM(_NET_WM_STATE_FOCUSED); 368 GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); 369 GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); 370 GET_ATOM(_NET_WM_STATE_FULLSCREEN); 371 GET_ATOM(_NET_WM_STATE_ABOVE); 372 GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR); 373 GET_ATOM(_NET_WM_STATE_SKIP_PAGER); 374 GET_ATOM(_NET_WM_MOVERESIZE); 375 GET_ATOM(_NET_WM_STATE_MODAL); 376 GET_ATOM(_NET_WM_ALLOWED_ACTIONS); 377 GET_ATOM(_NET_WM_ACTION_FULLSCREEN); 378 GET_ATOM(_NET_WM_NAME); 379 GET_ATOM(_NET_WM_ICON_NAME); 380 GET_ATOM(_NET_WM_ICON); 381 GET_ATOM(_NET_WM_PING); 382 GET_ATOM(_NET_WM_SYNC_REQUEST); 383 GET_ATOM(_NET_WM_SYNC_REQUEST_COUNTER); 384 GET_ATOM(_NET_WM_WINDOW_OPACITY); 385 GET_ATOM(_NET_WM_USER_TIME); 386 GET_ATOM(_NET_ACTIVE_WINDOW); 387 GET_ATOM(_NET_FRAME_EXTENTS); 388 GET_ATOM(_SDL_WAKEUP); 389 GET_ATOM(UTF8_STRING); 390 GET_ATOM(PRIMARY); 391 GET_ATOM(CLIPBOARD); 392 GET_ATOM(INCR); 393 GET_ATOM(SDL_SELECTION); 394 GET_ATOM(TARGETS); 395 GET_ATOM(SDL_FORMATS); 396 GET_ATOM(RESOURCE_MANAGER); 397 GET_ATOM(XdndAware); 398 GET_ATOM(XdndEnter); 399 GET_ATOM(XdndLeave); 400 GET_ATOM(XdndPosition); 401 GET_ATOM(XdndStatus); 402 GET_ATOM(XdndTypeList); 403 GET_ATOM(XdndActionCopy); 404 GET_ATOM(XdndDrop); 405 GET_ATOM(XdndFinished); 406 GET_ATOM(XdndSelection); 407 GET_ATOM(XKLAVIER_STATE); 408 409 // Detect the window manager 410 X11_CheckWindowManager(_this); 411 412 if (!X11_InitModes(_this)) { 413 return false; 414 } 415 416 if (!X11_InitXinput2(_this)) { 417 // Assume a mouse and keyboard are attached 418 SDL_AddKeyboard(SDL_DEFAULT_KEYBOARD_ID, NULL); 419 SDL_AddMouse(SDL_DEFAULT_MOUSE_ID, NULL); 420 } 421 422#ifdef SDL_VIDEO_DRIVER_X11_XFIXES 423 X11_InitXfixes(_this); 424#endif 425 426 X11_InitXsettings(_this); 427 428#ifdef SDL_VIDEO_DRIVER_X11_XSYNC 429 X11_InitXsync(_this); 430#endif 431 432#ifdef SDL_VIDEO_DRIVER_X11_XTEST 433 X11_InitXTest(_this); 434#endif 435 436#ifndef X_HAVE_UTF8_STRING 437#warning X server does not support UTF8_STRING, a feature introduced in 2000! This is likely to become a hard error in a future libSDL3. 438#endif 439 440 if (!X11_InitKeyboard(_this)) { 441 return false; 442 } 443 X11_InitMouse(_this); 444 445 X11_InitTouch(_this); 446 447 X11_InitPen(_this); 448 449 // Request currently available mime-types in the clipboard. 450 X11_XConvertSelection(data->display, data->atoms.CLIPBOARD, data->atoms.TARGETS, 451 data->atoms.SDL_FORMATS, GetWindow(_this), CurrentTime); 452 453 return true; 454} 455 456void X11_VideoQuit(SDL_VideoDevice *_this) 457{ 458 SDL_VideoData *data = _this->internal; 459 460 if (data->clipboard_window) { 461 X11_XDestroyWindow(data->display, data->clipboard_window); 462 } 463 464 if (data->xsettings_window) { 465 X11_XDestroyWindow(data->display, data->xsettings_window); 466 } 467 468#ifdef X_HAVE_UTF8_STRING 469 if (data->im) { 470 X11_XCloseIM(data->im); 471 } 472#endif 473 474 X11_QuitXinput2(_this); 475 X11_QuitModes(_this); 476 X11_QuitKeyboard(_this); 477 X11_QuitMouse(_this); 478 X11_QuitTouch(_this); 479 X11_QuitPen(_this); 480 X11_QuitClipboard(_this); 481 X11_QuitXsettings(_this); 482} 483 484bool X11_UseDirectColorVisuals(void) 485{ 486 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NODIRECTCOLOR, false)) { 487 return false; 488 } 489 return true; 490} 491 492#endif // SDL_VIDEO_DRIVER_X11 493
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.