x11_init.c (56843B)
1 //======================================================================== 2 // GLFW 3.4 X11 - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org> 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // 11 // Permission is granted to anyone to use this software for any purpose, 12 // including commercial applications, and to alter it and redistribute it 13 // freely, subject to the following restrictions: 14 // 15 // 1. The origin of this software must not be misrepresented; you must not 16 // claim that you wrote the original software. If you use this software 17 // in a product, an acknowledgment in the product documentation would 18 // be appreciated but is not required. 19 // 20 // 2. Altered source versions must be plainly marked as such, and must not 21 // be misrepresented as being the original software. 22 // 23 // 3. This notice may not be removed or altered from any source 24 // distribution. 25 // 26 //======================================================================== 27 // It is fine to use C99 in this file because it will not be built with VS 28 //======================================================================== 29 30 #include "internal.h" 31 32 #include <stdlib.h> 33 #include <string.h> 34 #include <limits.h> 35 #include <stdio.h> 36 #include <locale.h> 37 #include <unistd.h> 38 39 40 // Translate an X11 key code to a GLFW key code. 41 // 42 static int translateKeyCode(int scancode) 43 { 44 int keySym; 45 46 // Valid key code range is [8,255], according to the Xlib manual 47 if (scancode < 8 || scancode > 255) 48 return GLFW_KEY_UNKNOWN; 49 50 if (_glfw.x11.xkb.available) 51 { 52 // Try secondary keysym, for numeric keypad keys 53 // Note: This way we always force "NumLock = ON", which is intentional 54 // since the returned key code should correspond to a physical 55 // location. 56 keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 1); 57 switch (keySym) 58 { 59 case XK_KP_0: return GLFW_KEY_KP_0; 60 case XK_KP_1: return GLFW_KEY_KP_1; 61 case XK_KP_2: return GLFW_KEY_KP_2; 62 case XK_KP_3: return GLFW_KEY_KP_3; 63 case XK_KP_4: return GLFW_KEY_KP_4; 64 case XK_KP_5: return GLFW_KEY_KP_5; 65 case XK_KP_6: return GLFW_KEY_KP_6; 66 case XK_KP_7: return GLFW_KEY_KP_7; 67 case XK_KP_8: return GLFW_KEY_KP_8; 68 case XK_KP_9: return GLFW_KEY_KP_9; 69 case XK_KP_Separator: 70 case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; 71 case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; 72 case XK_KP_Enter: return GLFW_KEY_KP_ENTER; 73 default: break; 74 } 75 76 // Now try primary keysym for function keys (non-printable keys) 77 // These should not depend on the current keyboard layout 78 keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0); 79 } 80 else 81 { 82 int dummy; 83 KeySym* keySyms; 84 85 keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy); 86 keySym = keySyms[0]; 87 XFree(keySyms); 88 } 89 90 switch (keySym) 91 { 92 case XK_Escape: return GLFW_KEY_ESCAPE; 93 case XK_Tab: return GLFW_KEY_TAB; 94 case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT; 95 case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT; 96 case XK_Control_L: return GLFW_KEY_LEFT_CONTROL; 97 case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL; 98 case XK_Meta_L: 99 case XK_Alt_L: return GLFW_KEY_LEFT_ALT; 100 case XK_Mode_switch: // Mapped to Alt_R on many keyboards 101 case XK_ISO_Level3_Shift: // AltGr on at least some machines 102 case XK_Meta_R: 103 case XK_Alt_R: return GLFW_KEY_RIGHT_ALT; 104 case XK_Super_L: return GLFW_KEY_LEFT_SUPER; 105 case XK_Super_R: return GLFW_KEY_RIGHT_SUPER; 106 case XK_Menu: return GLFW_KEY_MENU; 107 case XK_Num_Lock: return GLFW_KEY_NUM_LOCK; 108 case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; 109 case XK_Print: return GLFW_KEY_PRINT_SCREEN; 110 case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; 111 case XK_Pause: return GLFW_KEY_PAUSE; 112 case XK_Delete: return GLFW_KEY_DELETE; 113 case XK_BackSpace: return GLFW_KEY_BACKSPACE; 114 case XK_Return: return GLFW_KEY_ENTER; 115 case XK_Home: return GLFW_KEY_HOME; 116 case XK_End: return GLFW_KEY_END; 117 case XK_Page_Up: return GLFW_KEY_PAGE_UP; 118 case XK_Page_Down: return GLFW_KEY_PAGE_DOWN; 119 case XK_Insert: return GLFW_KEY_INSERT; 120 case XK_Left: return GLFW_KEY_LEFT; 121 case XK_Right: return GLFW_KEY_RIGHT; 122 case XK_Down: return GLFW_KEY_DOWN; 123 case XK_Up: return GLFW_KEY_UP; 124 case XK_F1: return GLFW_KEY_F1; 125 case XK_F2: return GLFW_KEY_F2; 126 case XK_F3: return GLFW_KEY_F3; 127 case XK_F4: return GLFW_KEY_F4; 128 case XK_F5: return GLFW_KEY_F5; 129 case XK_F6: return GLFW_KEY_F6; 130 case XK_F7: return GLFW_KEY_F7; 131 case XK_F8: return GLFW_KEY_F8; 132 case XK_F9: return GLFW_KEY_F9; 133 case XK_F10: return GLFW_KEY_F10; 134 case XK_F11: return GLFW_KEY_F11; 135 case XK_F12: return GLFW_KEY_F12; 136 case XK_F13: return GLFW_KEY_F13; 137 case XK_F14: return GLFW_KEY_F14; 138 case XK_F15: return GLFW_KEY_F15; 139 case XK_F16: return GLFW_KEY_F16; 140 case XK_F17: return GLFW_KEY_F17; 141 case XK_F18: return GLFW_KEY_F18; 142 case XK_F19: return GLFW_KEY_F19; 143 case XK_F20: return GLFW_KEY_F20; 144 case XK_F21: return GLFW_KEY_F21; 145 case XK_F22: return GLFW_KEY_F22; 146 case XK_F23: return GLFW_KEY_F23; 147 case XK_F24: return GLFW_KEY_F24; 148 case XK_F25: return GLFW_KEY_F25; 149 150 // Numeric keypad 151 case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; 152 case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; 153 case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; 154 case XK_KP_Add: return GLFW_KEY_KP_ADD; 155 156 // These should have been detected in secondary keysym test above! 157 case XK_KP_Insert: return GLFW_KEY_KP_0; 158 case XK_KP_End: return GLFW_KEY_KP_1; 159 case XK_KP_Down: return GLFW_KEY_KP_2; 160 case XK_KP_Page_Down: return GLFW_KEY_KP_3; 161 case XK_KP_Left: return GLFW_KEY_KP_4; 162 case XK_KP_Right: return GLFW_KEY_KP_6; 163 case XK_KP_Home: return GLFW_KEY_KP_7; 164 case XK_KP_Up: return GLFW_KEY_KP_8; 165 case XK_KP_Page_Up: return GLFW_KEY_KP_9; 166 case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL; 167 case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; 168 case XK_KP_Enter: return GLFW_KEY_KP_ENTER; 169 170 // Last resort: Check for printable keys (should not happen if the XKB 171 // extension is available). This will give a layout dependent mapping 172 // (which is wrong, and we may miss some keys, especially on non-US 173 // keyboards), but it's better than nothing... 174 case XK_a: return GLFW_KEY_A; 175 case XK_b: return GLFW_KEY_B; 176 case XK_c: return GLFW_KEY_C; 177 case XK_d: return GLFW_KEY_D; 178 case XK_e: return GLFW_KEY_E; 179 case XK_f: return GLFW_KEY_F; 180 case XK_g: return GLFW_KEY_G; 181 case XK_h: return GLFW_KEY_H; 182 case XK_i: return GLFW_KEY_I; 183 case XK_j: return GLFW_KEY_J; 184 case XK_k: return GLFW_KEY_K; 185 case XK_l: return GLFW_KEY_L; 186 case XK_m: return GLFW_KEY_M; 187 case XK_n: return GLFW_KEY_N; 188 case XK_o: return GLFW_KEY_O; 189 case XK_p: return GLFW_KEY_P; 190 case XK_q: return GLFW_KEY_Q; 191 case XK_r: return GLFW_KEY_R; 192 case XK_s: return GLFW_KEY_S; 193 case XK_t: return GLFW_KEY_T; 194 case XK_u: return GLFW_KEY_U; 195 case XK_v: return GLFW_KEY_V; 196 case XK_w: return GLFW_KEY_W; 197 case XK_x: return GLFW_KEY_X; 198 case XK_y: return GLFW_KEY_Y; 199 case XK_z: return GLFW_KEY_Z; 200 case XK_1: return GLFW_KEY_1; 201 case XK_2: return GLFW_KEY_2; 202 case XK_3: return GLFW_KEY_3; 203 case XK_4: return GLFW_KEY_4; 204 case XK_5: return GLFW_KEY_5; 205 case XK_6: return GLFW_KEY_6; 206 case XK_7: return GLFW_KEY_7; 207 case XK_8: return GLFW_KEY_8; 208 case XK_9: return GLFW_KEY_9; 209 case XK_0: return GLFW_KEY_0; 210 case XK_space: return GLFW_KEY_SPACE; 211 case XK_minus: return GLFW_KEY_MINUS; 212 case XK_equal: return GLFW_KEY_EQUAL; 213 case XK_bracketleft: return GLFW_KEY_LEFT_BRACKET; 214 case XK_bracketright: return GLFW_KEY_RIGHT_BRACKET; 215 case XK_backslash: return GLFW_KEY_BACKSLASH; 216 case XK_semicolon: return GLFW_KEY_SEMICOLON; 217 case XK_apostrophe: return GLFW_KEY_APOSTROPHE; 218 case XK_grave: return GLFW_KEY_GRAVE_ACCENT; 219 case XK_comma: return GLFW_KEY_COMMA; 220 case XK_period: return GLFW_KEY_PERIOD; 221 case XK_slash: return GLFW_KEY_SLASH; 222 case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts... 223 default: break; 224 } 225 226 // No matching translation was found 227 return GLFW_KEY_UNKNOWN; 228 } 229 230 // Create key code translation tables 231 // 232 static void createKeyTables(void) 233 { 234 int scancode, key; 235 236 memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); 237 memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes)); 238 239 if (_glfw.x11.xkb.available) 240 { 241 // Use XKB to determine physical key locations independently of the 242 // current keyboard layout 243 244 char name[XkbKeyNameLength + 1]; 245 XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); 246 XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); 247 248 // Find the X11 key code -> GLFW key code mapping 249 for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++) 250 { 251 memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength); 252 name[XkbKeyNameLength] = '\0'; 253 254 // Map the key name to a GLFW key code. Note: We only map printable 255 // keys here, and we use the US keyboard layout. The rest of the 256 // keys (function keys) are mapped using traditional KeySym 257 // translations. 258 if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; 259 else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; 260 else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; 261 else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; 262 else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; 263 else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; 264 else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; 265 else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; 266 else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; 267 else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; 268 else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0; 269 else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS; 270 else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL; 271 else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q; 272 else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W; 273 else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E; 274 else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R; 275 else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T; 276 else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y; 277 else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U; 278 else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I; 279 else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O; 280 else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P; 281 else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; 282 else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; 283 else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A; 284 else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S; 285 else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D; 286 else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F; 287 else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G; 288 else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H; 289 else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J; 290 else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K; 291 else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L; 292 else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON; 293 else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; 294 else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z; 295 else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X; 296 else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C; 297 else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V; 298 else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B; 299 else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N; 300 else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M; 301 else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA; 302 else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD; 303 else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH; 304 else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; 305 else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1; 306 else key = GLFW_KEY_UNKNOWN; 307 308 if ((scancode >= 0) && (scancode < 256)) 309 _glfw.x11.keycodes[scancode] = key; 310 } 311 312 XkbFreeNames(desc, XkbKeyNamesMask, True); 313 XkbFreeKeyboard(desc, 0, True); 314 } 315 316 for (scancode = 0; scancode < 256; scancode++) 317 { 318 // Translate the un-translated key codes using traditional X11 KeySym 319 // lookups 320 if (_glfw.x11.keycodes[scancode] < 0) 321 _glfw.x11.keycodes[scancode] = translateKeyCode(scancode); 322 323 // Store the reverse translation for faster key name lookup 324 if (_glfw.x11.keycodes[scancode] > 0) 325 _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; 326 } 327 } 328 329 // Check whether the IM has a usable style 330 // 331 static GLFWbool hasUsableInputMethodStyle(void) 332 { 333 GLFWbool found = GLFW_FALSE; 334 XIMStyles* styles = NULL; 335 336 if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL) 337 return GLFW_FALSE; 338 339 for (unsigned int i = 0; i < styles->count_styles; i++) 340 { 341 if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) 342 { 343 found = GLFW_TRUE; 344 break; 345 } 346 } 347 348 XFree(styles); 349 return found; 350 } 351 352 static void inputMethodDestroyCallback(XIM im, XPointer clientData, XPointer callData) 353 { 354 _glfw.x11.im = NULL; 355 } 356 357 static void inputMethodInstantiateCallback(Display* display, 358 XPointer clientData, 359 XPointer callData) 360 { 361 if (_glfw.x11.im) 362 return; 363 364 _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL); 365 if (_glfw.x11.im) 366 { 367 if (!hasUsableInputMethodStyle()) 368 { 369 XCloseIM(_glfw.x11.im); 370 _glfw.x11.im = NULL; 371 } 372 } 373 374 if (_glfw.x11.im) 375 { 376 XIMCallback callback; 377 callback.callback = (XIMProc) inputMethodDestroyCallback; 378 callback.client_data = NULL; 379 XSetIMValues(_glfw.x11.im, XNDestroyCallback, &callback, NULL); 380 381 for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) 382 _glfwCreateInputContextX11(window); 383 } 384 } 385 386 // Check whether the specified atom is supported 387 // 388 static Atom getSupportedAtom(Atom* supportedAtoms, 389 unsigned long atomCount, 390 const char* atomName) 391 { 392 const Atom atom = XInternAtom(_glfw.x11.display, atomName, False); 393 394 for (unsigned int i = 0; i < atomCount; i++) 395 { 396 if (supportedAtoms[i] == atom) 397 return atom; 398 } 399 400 return None; 401 } 402 403 // Check whether the running window manager is EWMH-compliant 404 // 405 static void detectEWMH(void) 406 { 407 // First we read the _NET_SUPPORTING_WM_CHECK property on the root window 408 409 Window* windowFromRoot = NULL; 410 if (!_glfwGetWindowPropertyX11(_glfw.x11.root, 411 _glfw.x11.NET_SUPPORTING_WM_CHECK, 412 XA_WINDOW, 413 (unsigned char**) &windowFromRoot)) 414 { 415 return; 416 } 417 418 _glfwGrabErrorHandlerX11(); 419 420 // If it exists, it should be the XID of a top-level window 421 // Then we look for the same property on that window 422 423 Window* windowFromChild = NULL; 424 if (!_glfwGetWindowPropertyX11(*windowFromRoot, 425 _glfw.x11.NET_SUPPORTING_WM_CHECK, 426 XA_WINDOW, 427 (unsigned char**) &windowFromChild)) 428 { 429 XFree(windowFromRoot); 430 return; 431 } 432 433 _glfwReleaseErrorHandlerX11(); 434 435 // If the property exists, it should contain the XID of the window 436 437 if (*windowFromRoot != *windowFromChild) 438 { 439 XFree(windowFromRoot); 440 XFree(windowFromChild); 441 return; 442 } 443 444 XFree(windowFromRoot); 445 XFree(windowFromChild); 446 447 // We are now fairly sure that an EWMH-compliant WM is currently running 448 // We can now start querying the WM about what features it supports by 449 // looking in the _NET_SUPPORTED property on the root window 450 // It should contain a list of supported EWMH protocol and state atoms 451 452 Atom* supportedAtoms = NULL; 453 const unsigned long atomCount = 454 _glfwGetWindowPropertyX11(_glfw.x11.root, 455 _glfw.x11.NET_SUPPORTED, 456 XA_ATOM, 457 (unsigned char**) &supportedAtoms); 458 459 // See which of the atoms we support that are supported by the WM 460 461 _glfw.x11.NET_WM_STATE = 462 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); 463 _glfw.x11.NET_WM_STATE_ABOVE = 464 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); 465 _glfw.x11.NET_WM_STATE_FULLSCREEN = 466 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); 467 _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = 468 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); 469 _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = 470 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); 471 _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = 472 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); 473 _glfw.x11.NET_WM_FULLSCREEN_MONITORS = 474 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); 475 _glfw.x11.NET_WM_WINDOW_TYPE = 476 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); 477 _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = 478 getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); 479 _glfw.x11.NET_WORKAREA = 480 getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA"); 481 _glfw.x11.NET_CURRENT_DESKTOP = 482 getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP"); 483 _glfw.x11.NET_ACTIVE_WINDOW = 484 getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); 485 _glfw.x11.NET_FRAME_EXTENTS = 486 getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); 487 _glfw.x11.NET_REQUEST_FRAME_EXTENTS = 488 getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); 489 490 if (supportedAtoms) 491 XFree(supportedAtoms); 492 } 493 494 // Look for and initialize supported X11 extensions 495 // 496 static GLFWbool initExtensions(void) 497 { 498 _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1"); 499 if (_glfw.x11.vidmode.handle) 500 { 501 _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension) 502 _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); 503 _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp) 504 _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); 505 _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp) 506 _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); 507 _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize) 508 _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); 509 510 _glfw.x11.vidmode.available = 511 XF86VidModeQueryExtension(_glfw.x11.display, 512 &_glfw.x11.vidmode.eventBase, 513 &_glfw.x11.vidmode.errorBase); 514 } 515 516 #if defined(__CYGWIN__) 517 _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so"); 518 #else 519 _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6"); 520 #endif 521 if (_glfw.x11.xi.handle) 522 { 523 _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) 524 _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); 525 _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents) 526 _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents"); 527 528 if (XQueryExtension(_glfw.x11.display, 529 "XInputExtension", 530 &_glfw.x11.xi.majorOpcode, 531 &_glfw.x11.xi.eventBase, 532 &_glfw.x11.xi.errorBase)) 533 { 534 _glfw.x11.xi.major = 2; 535 _glfw.x11.xi.minor = 0; 536 537 if (XIQueryVersion(_glfw.x11.display, 538 &_glfw.x11.xi.major, 539 &_glfw.x11.xi.minor) == Success) 540 { 541 _glfw.x11.xi.available = GLFW_TRUE; 542 } 543 } 544 } 545 546 #if defined(__CYGWIN__) 547 _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so"); 548 #else 549 _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2"); 550 #endif 551 if (_glfw.x11.randr.handle) 552 { 553 _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) 554 _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); 555 _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) 556 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); 557 _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) 558 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); 559 _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) 560 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); 561 _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) 562 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); 563 _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) 564 _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); 565 _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) 566 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); 567 _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) 568 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); 569 _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) 570 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); 571 _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) 572 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); 573 _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) 574 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); 575 _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) 576 _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); 577 _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) 578 _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); 579 _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) 580 _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); 581 _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) 582 _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); 583 _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) 584 _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); 585 _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) 586 _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); 587 _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) 588 _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); 589 590 if (XRRQueryExtension(_glfw.x11.display, 591 &_glfw.x11.randr.eventBase, 592 &_glfw.x11.randr.errorBase)) 593 { 594 if (XRRQueryVersion(_glfw.x11.display, 595 &_glfw.x11.randr.major, 596 &_glfw.x11.randr.minor)) 597 { 598 // The GLFW RandR path requires at least version 1.3 599 if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) 600 _glfw.x11.randr.available = GLFW_TRUE; 601 } 602 else 603 { 604 _glfwInputError(GLFW_PLATFORM_ERROR, 605 "X11: Failed to query RandR version"); 606 } 607 } 608 } 609 610 if (_glfw.x11.randr.available) 611 { 612 XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, 613 _glfw.x11.root); 614 615 if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0])) 616 { 617 // This is likely an older Nvidia driver with broken gamma support 618 // Flag it as useless and fall back to xf86vm gamma, if available 619 _glfw.x11.randr.gammaBroken = GLFW_TRUE; 620 } 621 622 if (!sr->ncrtc) 623 { 624 // A system without CRTCs is likely a system with broken RandR 625 // Disable the RandR monitor path and fall back to core functions 626 _glfw.x11.randr.monitorBroken = GLFW_TRUE; 627 } 628 629 XRRFreeScreenResources(sr); 630 } 631 632 if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) 633 { 634 XRRSelectInput(_glfw.x11.display, _glfw.x11.root, 635 RROutputChangeNotifyMask); 636 } 637 638 #if defined(__CYGWIN__) 639 _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so"); 640 #else 641 _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1"); 642 #endif 643 if (_glfw.x11.xcursor.handle) 644 { 645 _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate) 646 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); 647 _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy) 648 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); 649 _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) 650 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); 651 _glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme) 652 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetTheme"); 653 _glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize) 654 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize"); 655 _glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage) 656 _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage"); 657 } 658 659 #if defined(__CYGWIN__) 660 _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so"); 661 #else 662 _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1"); 663 #endif 664 if (_glfw.x11.xinerama.handle) 665 { 666 _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive) 667 _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); 668 _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension) 669 _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); 670 _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens) 671 _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); 672 673 if (XineramaQueryExtension(_glfw.x11.display, 674 &_glfw.x11.xinerama.major, 675 &_glfw.x11.xinerama.minor)) 676 { 677 if (XineramaIsActive(_glfw.x11.display)) 678 _glfw.x11.xinerama.available = GLFW_TRUE; 679 } 680 } 681 682 _glfw.x11.xkb.major = 1; 683 _glfw.x11.xkb.minor = 0; 684 _glfw.x11.xkb.available = 685 XkbQueryExtension(_glfw.x11.display, 686 &_glfw.x11.xkb.majorOpcode, 687 &_glfw.x11.xkb.eventBase, 688 &_glfw.x11.xkb.errorBase, 689 &_glfw.x11.xkb.major, 690 &_glfw.x11.xkb.minor); 691 692 if (_glfw.x11.xkb.available) 693 { 694 Bool supported; 695 696 if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) 697 { 698 if (supported) 699 _glfw.x11.xkb.detectable = GLFW_TRUE; 700 } 701 702 _glfw.x11.xkb.group = 0; 703 XkbStateRec state; 704 if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success) 705 { 706 XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask); 707 _glfw.x11.xkb.group = (unsigned int)state.group; 708 } 709 } 710 711 #if defined(__CYGWIN__) 712 _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so"); 713 #else 714 _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); 715 #endif 716 if (_glfw.x11.x11xcb.handle) 717 { 718 _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) 719 _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); 720 } 721 722 #if defined(__CYGWIN__) 723 _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so"); 724 #else 725 _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); 726 #endif 727 if (_glfw.x11.xrender.handle) 728 { 729 _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension) 730 _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); 731 _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion) 732 _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); 733 _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat) 734 _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); 735 736 if (XRenderQueryExtension(_glfw.x11.display, 737 &_glfw.x11.xrender.errorBase, 738 &_glfw.x11.xrender.eventBase)) 739 { 740 if (XRenderQueryVersion(_glfw.x11.display, 741 &_glfw.x11.xrender.major, 742 &_glfw.x11.xrender.minor)) 743 { 744 _glfw.x11.xrender.available = GLFW_TRUE; 745 } 746 } 747 } 748 749 // Update the key code LUT 750 // FIXME: We should listen to XkbMapNotify events to track changes to 751 // the keyboard mapping. 752 createKeyTables(); 753 754 // String format atoms 755 _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); 756 _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False); 757 _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); 758 759 // Custom selection property atom 760 _glfw.x11.GLFW_SELECTION = 761 XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); 762 763 // ICCCM standard clipboard atoms 764 _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); 765 _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); 766 _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False); 767 _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False); 768 _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); 769 770 // Clipboard manager atoms 771 _glfw.x11.CLIPBOARD_MANAGER = 772 XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); 773 _glfw.x11.SAVE_TARGETS = 774 XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); 775 776 // Xdnd (drag and drop) atoms 777 _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False); 778 _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); 779 _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); 780 _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False); 781 _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False); 782 _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False); 783 _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); 784 _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); 785 _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False); 786 _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False); 787 788 // ICCCM, EWMH and Motif window property atoms 789 // These can be set safely even without WM support 790 // The EWMH atoms that require WM support are handled in detectEWMH 791 _glfw.x11.WM_PROTOCOLS = 792 XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False); 793 _glfw.x11.WM_STATE = 794 XInternAtom(_glfw.x11.display, "WM_STATE", False); 795 _glfw.x11.WM_DELETE_WINDOW = 796 XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False); 797 _glfw.x11.NET_SUPPORTED = 798 XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); 799 _glfw.x11.NET_SUPPORTING_WM_CHECK = 800 XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); 801 _glfw.x11.NET_WM_ICON = 802 XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); 803 _glfw.x11.NET_WM_PING = 804 XInternAtom(_glfw.x11.display, "_NET_WM_PING", False); 805 _glfw.x11.NET_WM_PID = 806 XInternAtom(_glfw.x11.display, "_NET_WM_PID", False); 807 _glfw.x11.NET_WM_NAME = 808 XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False); 809 _glfw.x11.NET_WM_ICON_NAME = 810 XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); 811 _glfw.x11.NET_WM_BYPASS_COMPOSITOR = 812 XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); 813 _glfw.x11.NET_WM_WINDOW_OPACITY = 814 XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False); 815 _glfw.x11.MOTIF_WM_HINTS = 816 XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); 817 818 // The compositing manager selection name contains the screen number 819 { 820 char name[32]; 821 snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); 822 _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False); 823 } 824 825 // Detect whether an EWMH-conformant window manager is running 826 detectEWMH(); 827 828 return GLFW_TRUE; 829 } 830 831 // Retrieve system content scale via folklore heuristics 832 // 833 static void getSystemContentScale(float* xscale, float* yscale) 834 { 835 // Start by assuming the default X11 DPI 836 // NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it 837 // would be set to 96, so assume that is the case if we cannot find it 838 float xdpi = 96.f, ydpi = 96.f; 839 840 // NOTE: Basing the scale on Xft.dpi where available should provide the most 841 // consistent user experience (matches Qt, Gtk, etc), although not 842 // always the most accurate one 843 char* rms = XResourceManagerString(_glfw.x11.display); 844 if (rms) 845 { 846 XrmDatabase db = XrmGetStringDatabase(rms); 847 if (db) 848 { 849 XrmValue value; 850 char* type = NULL; 851 852 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) 853 { 854 if (type && strcmp(type, "String") == 0) 855 xdpi = ydpi = atof(value.addr); 856 } 857 858 XrmDestroyDatabase(db); 859 } 860 } 861 862 *xscale = xdpi / 96.f; 863 *yscale = ydpi / 96.f; 864 } 865 866 // Create a blank cursor for hidden and disabled cursor modes 867 // 868 static Cursor createHiddenCursor(void) 869 { 870 unsigned char pixels[16 * 16 * 4] = { 0 }; 871 GLFWimage image = { 16, 16, pixels }; 872 return _glfwCreateCursorX11(&image, 0, 0); 873 } 874 875 // Create a helper window for IPC 876 // 877 static Window createHelperWindow(void) 878 { 879 XSetWindowAttributes wa; 880 wa.event_mask = PropertyChangeMask; 881 882 return XCreateWindow(_glfw.x11.display, _glfw.x11.root, 883 0, 0, 1, 1, 0, 0, 884 InputOnly, 885 DefaultVisual(_glfw.x11.display, _glfw.x11.screen), 886 CWEventMask, &wa); 887 } 888 889 // X error handler 890 // 891 static int errorHandler(Display *display, XErrorEvent* event) 892 { 893 _glfw.x11.errorCode = event->error_code; 894 return 0; 895 } 896 897 898 ////////////////////////////////////////////////////////////////////////// 899 ////// GLFW internal API ////// 900 ////////////////////////////////////////////////////////////////////////// 901 902 // Sets the X error handler callback 903 // 904 void _glfwGrabErrorHandlerX11(void) 905 { 906 _glfw.x11.errorCode = Success; 907 XSetErrorHandler(errorHandler); 908 } 909 910 // Clears the X error handler callback 911 // 912 void _glfwReleaseErrorHandlerX11(void) 913 { 914 // Synchronize to make sure all commands are processed 915 XSync(_glfw.x11.display, False); 916 XSetErrorHandler(NULL); 917 } 918 919 // Reports the specified error, appending information about the last X error 920 // 921 void _glfwInputErrorX11(int error, const char* message) 922 { 923 char buffer[_GLFW_MESSAGE_SIZE]; 924 XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode, 925 buffer, sizeof(buffer)); 926 927 _glfwInputError(error, "%s: %s", message, buffer); 928 } 929 930 // Creates a native cursor object from the specified image and hotspot 931 // 932 Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) 933 { 934 int i; 935 Cursor cursor; 936 937 if (!_glfw.x11.xcursor.handle) 938 return None; 939 940 XcursorImage* native = XcursorImageCreate(image->width, image->height); 941 if (native == NULL) 942 return None; 943 944 native->xhot = xhot; 945 native->yhot = yhot; 946 947 unsigned char* source = (unsigned char*) image->pixels; 948 XcursorPixel* target = native->pixels; 949 950 for (i = 0; i < image->width * image->height; i++, target++, source += 4) 951 { 952 unsigned int alpha = source[3]; 953 954 *target = (alpha << 24) | 955 ((unsigned char) ((source[0] * alpha) / 255) << 16) | 956 ((unsigned char) ((source[1] * alpha) / 255) << 8) | 957 ((unsigned char) ((source[2] * alpha) / 255) << 0); 958 } 959 960 cursor = XcursorImageLoadCursor(_glfw.x11.display, native); 961 XcursorImageDestroy(native); 962 963 return cursor; 964 } 965 966 967 ////////////////////////////////////////////////////////////////////////// 968 ////// GLFW platform API ////// 969 ////////////////////////////////////////////////////////////////////////// 970 971 int _glfwPlatformInit(void) 972 { 973 // HACK: If the application has left the locale as "C" then both wide 974 // character text input and explicit UTF-8 input via XIM will break 975 // This sets the CTYPE part of the current locale from the environment 976 // in the hope that it is set to something more sane than "C" 977 if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) 978 setlocale(LC_CTYPE, ""); 979 980 #if defined(__CYGWIN__) 981 _glfw.x11.xlib.handle = _glfw_dlopen("libX11-6.so"); 982 #else 983 _glfw.x11.xlib.handle = _glfw_dlopen("libX11.so.6"); 984 #endif 985 if (!_glfw.x11.xlib.handle) 986 { 987 _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib"); 988 return GLFW_FALSE; 989 } 990 991 _glfw.x11.xlib.AllocClassHint = (PFN_XAllocClassHint) 992 _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocClassHint"); 993 _glfw.x11.xlib.AllocSizeHints = (PFN_XAllocSizeHints) 994 _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocSizeHints"); 995 _glfw.x11.xlib.AllocWMHints = (PFN_XAllocWMHints) 996 _glfw_dlsym(_glfw.x11.xlib.handle, "XAllocWMHints"); 997 _glfw.x11.xlib.ChangeProperty = (PFN_XChangeProperty) 998 _glfw_dlsym(_glfw.x11.xlib.handle, "XChangeProperty"); 999 _glfw.x11.xlib.ChangeWindowAttributes = (PFN_XChangeWindowAttributes) 1000 _glfw_dlsym(_glfw.x11.xlib.handle, "XChangeWindowAttributes"); 1001 _glfw.x11.xlib.CheckIfEvent = (PFN_XCheckIfEvent) 1002 _glfw_dlsym(_glfw.x11.xlib.handle, "XCheckIfEvent"); 1003 _glfw.x11.xlib.CheckTypedWindowEvent = (PFN_XCheckTypedWindowEvent) 1004 _glfw_dlsym(_glfw.x11.xlib.handle, "XCheckTypedWindowEvent"); 1005 _glfw.x11.xlib.CloseDisplay = (PFN_XCloseDisplay) 1006 _glfw_dlsym(_glfw.x11.xlib.handle, "XCloseDisplay"); 1007 _glfw.x11.xlib.CloseIM = (PFN_XCloseIM) 1008 _glfw_dlsym(_glfw.x11.xlib.handle, "XCloseIM"); 1009 _glfw.x11.xlib.ConvertSelection = (PFN_XConvertSelection) 1010 _glfw_dlsym(_glfw.x11.xlib.handle, "XConvertSelection"); 1011 _glfw.x11.xlib.CreateColormap = (PFN_XCreateColormap) 1012 _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateColormap"); 1013 _glfw.x11.xlib.CreateFontCursor = (PFN_XCreateFontCursor) 1014 _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateFontCursor"); 1015 _glfw.x11.xlib.CreateIC = (PFN_XCreateIC) 1016 _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateIC"); 1017 _glfw.x11.xlib.CreateWindow = (PFN_XCreateWindow) 1018 _glfw_dlsym(_glfw.x11.xlib.handle, "XCreateWindow"); 1019 _glfw.x11.xlib.DefineCursor = (PFN_XDefineCursor) 1020 _glfw_dlsym(_glfw.x11.xlib.handle, "XDefineCursor"); 1021 _glfw.x11.xlib.DeleteContext = (PFN_XDeleteContext) 1022 _glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteContext"); 1023 _glfw.x11.xlib.DeleteProperty = (PFN_XDeleteProperty) 1024 _glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteProperty"); 1025 _glfw.x11.xlib.DestroyIC = (PFN_XDestroyIC) 1026 _glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyIC"); 1027 _glfw.x11.xlib.DestroyWindow = (PFN_XDestroyWindow) 1028 _glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyWindow"); 1029 _glfw.x11.xlib.EventsQueued = (PFN_XEventsQueued) 1030 _glfw_dlsym(_glfw.x11.xlib.handle, "XEventsQueued"); 1031 _glfw.x11.xlib.FilterEvent = (PFN_XFilterEvent) 1032 _glfw_dlsym(_glfw.x11.xlib.handle, "XFilterEvent"); 1033 _glfw.x11.xlib.FindContext = (PFN_XFindContext) 1034 _glfw_dlsym(_glfw.x11.xlib.handle, "XFindContext"); 1035 _glfw.x11.xlib.Flush = (PFN_XFlush) 1036 _glfw_dlsym(_glfw.x11.xlib.handle, "XFlush"); 1037 _glfw.x11.xlib.Free = (PFN_XFree) 1038 _glfw_dlsym(_glfw.x11.xlib.handle, "XFree"); 1039 _glfw.x11.xlib.FreeColormap = (PFN_XFreeColormap) 1040 _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeColormap"); 1041 _glfw.x11.xlib.FreeCursor = (PFN_XFreeCursor) 1042 _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeCursor"); 1043 _glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData) 1044 _glfw_dlsym(_glfw.x11.xlib.handle, "XFreeEventData"); 1045 _glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText) 1046 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetErrorText"); 1047 _glfw.x11.xlib.GetEventData = (PFN_XGetEventData) 1048 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetEventData"); 1049 _glfw.x11.xlib.GetICValues = (PFN_XGetICValues) 1050 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetICValues"); 1051 _glfw.x11.xlib.GetIMValues = (PFN_XGetIMValues) 1052 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetIMValues"); 1053 _glfw.x11.xlib.GetInputFocus = (PFN_XGetInputFocus) 1054 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetInputFocus"); 1055 _glfw.x11.xlib.GetKeyboardMapping = (PFN_XGetKeyboardMapping) 1056 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetKeyboardMapping"); 1057 _glfw.x11.xlib.GetScreenSaver = (PFN_XGetScreenSaver) 1058 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetScreenSaver"); 1059 _glfw.x11.xlib.GetSelectionOwner = (PFN_XGetSelectionOwner) 1060 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetSelectionOwner"); 1061 _glfw.x11.xlib.GetVisualInfo = (PFN_XGetVisualInfo) 1062 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetVisualInfo"); 1063 _glfw.x11.xlib.GetWMNormalHints = (PFN_XGetWMNormalHints) 1064 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWMNormalHints"); 1065 _glfw.x11.xlib.GetWindowAttributes = (PFN_XGetWindowAttributes) 1066 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWindowAttributes"); 1067 _glfw.x11.xlib.GetWindowProperty = (PFN_XGetWindowProperty) 1068 _glfw_dlsym(_glfw.x11.xlib.handle, "XGetWindowProperty"); 1069 _glfw.x11.xlib.GrabPointer = (PFN_XGrabPointer) 1070 _glfw_dlsym(_glfw.x11.xlib.handle, "XGrabPointer"); 1071 _glfw.x11.xlib.IconifyWindow = (PFN_XIconifyWindow) 1072 _glfw_dlsym(_glfw.x11.xlib.handle, "XIconifyWindow"); 1073 _glfw.x11.xlib.InitThreads = (PFN_XInitThreads) 1074 _glfw_dlsym(_glfw.x11.xlib.handle, "XInitThreads"); 1075 _glfw.x11.xlib.InternAtom = (PFN_XInternAtom) 1076 _glfw_dlsym(_glfw.x11.xlib.handle, "XInternAtom"); 1077 _glfw.x11.xlib.LookupString = (PFN_XLookupString) 1078 _glfw_dlsym(_glfw.x11.xlib.handle, "XLookupString"); 1079 _glfw.x11.xlib.MapRaised = (PFN_XMapRaised) 1080 _glfw_dlsym(_glfw.x11.xlib.handle, "XMapRaised"); 1081 _glfw.x11.xlib.MapWindow = (PFN_XMapWindow) 1082 _glfw_dlsym(_glfw.x11.xlib.handle, "XMapWindow"); 1083 _glfw.x11.xlib.MoveResizeWindow = (PFN_XMoveResizeWindow) 1084 _glfw_dlsym(_glfw.x11.xlib.handle, "XMoveResizeWindow"); 1085 _glfw.x11.xlib.MoveWindow = (PFN_XMoveWindow) 1086 _glfw_dlsym(_glfw.x11.xlib.handle, "XMoveWindow"); 1087 _glfw.x11.xlib.NextEvent = (PFN_XNextEvent) 1088 _glfw_dlsym(_glfw.x11.xlib.handle, "XNextEvent"); 1089 _glfw.x11.xlib.OpenDisplay = (PFN_XOpenDisplay) 1090 _glfw_dlsym(_glfw.x11.xlib.handle, "XOpenDisplay"); 1091 _glfw.x11.xlib.OpenIM = (PFN_XOpenIM) 1092 _glfw_dlsym(_glfw.x11.xlib.handle, "XOpenIM"); 1093 _glfw.x11.xlib.PeekEvent = (PFN_XPeekEvent) 1094 _glfw_dlsym(_glfw.x11.xlib.handle, "XPeekEvent"); 1095 _glfw.x11.xlib.Pending = (PFN_XPending) 1096 _glfw_dlsym(_glfw.x11.xlib.handle, "XPending"); 1097 _glfw.x11.xlib.QueryExtension = (PFN_XQueryExtension) 1098 _glfw_dlsym(_glfw.x11.xlib.handle, "XQueryExtension"); 1099 _glfw.x11.xlib.QueryPointer = (PFN_XQueryPointer) 1100 _glfw_dlsym(_glfw.x11.xlib.handle, "XQueryPointer"); 1101 _glfw.x11.xlib.RaiseWindow = (PFN_XRaiseWindow) 1102 _glfw_dlsym(_glfw.x11.xlib.handle, "XRaiseWindow"); 1103 _glfw.x11.xlib.RegisterIMInstantiateCallback = (PFN_XRegisterIMInstantiateCallback) 1104 _glfw_dlsym(_glfw.x11.xlib.handle, "XRegisterIMInstantiateCallback"); 1105 _glfw.x11.xlib.ResizeWindow = (PFN_XResizeWindow) 1106 _glfw_dlsym(_glfw.x11.xlib.handle, "XResizeWindow"); 1107 _glfw.x11.xlib.ResourceManagerString = (PFN_XResourceManagerString) 1108 _glfw_dlsym(_glfw.x11.xlib.handle, "XResourceManagerString"); 1109 _glfw.x11.xlib.SaveContext = (PFN_XSaveContext) 1110 _glfw_dlsym(_glfw.x11.xlib.handle, "XSaveContext"); 1111 _glfw.x11.xlib.SelectInput = (PFN_XSelectInput) 1112 _glfw_dlsym(_glfw.x11.xlib.handle, "XSelectInput"); 1113 _glfw.x11.xlib.SendEvent = (PFN_XSendEvent) 1114 _glfw_dlsym(_glfw.x11.xlib.handle, "XSendEvent"); 1115 _glfw.x11.xlib.SetClassHint = (PFN_XSetClassHint) 1116 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetClassHint"); 1117 _glfw.x11.xlib.SetErrorHandler = (PFN_XSetErrorHandler) 1118 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetErrorHandler"); 1119 _glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus) 1120 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetICFocus"); 1121 _glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues) 1122 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetIMValues"); 1123 _glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus) 1124 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetInputFocus"); 1125 _glfw.x11.xlib.SetLocaleModifiers = (PFN_XSetLocaleModifiers) 1126 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetLocaleModifiers"); 1127 _glfw.x11.xlib.SetScreenSaver = (PFN_XSetScreenSaver) 1128 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetScreenSaver"); 1129 _glfw.x11.xlib.SetSelectionOwner = (PFN_XSetSelectionOwner) 1130 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetSelectionOwner"); 1131 _glfw.x11.xlib.SetWMHints = (PFN_XSetWMHints) 1132 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMHints"); 1133 _glfw.x11.xlib.SetWMNormalHints = (PFN_XSetWMNormalHints) 1134 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMNormalHints"); 1135 _glfw.x11.xlib.SetWMProtocols = (PFN_XSetWMProtocols) 1136 _glfw_dlsym(_glfw.x11.xlib.handle, "XSetWMProtocols"); 1137 _glfw.x11.xlib.SupportsLocale = (PFN_XSupportsLocale) 1138 _glfw_dlsym(_glfw.x11.xlib.handle, "XSupportsLocale"); 1139 _glfw.x11.xlib.Sync = (PFN_XSync) 1140 _glfw_dlsym(_glfw.x11.xlib.handle, "XSync"); 1141 _glfw.x11.xlib.TranslateCoordinates = (PFN_XTranslateCoordinates) 1142 _glfw_dlsym(_glfw.x11.xlib.handle, "XTranslateCoordinates"); 1143 _glfw.x11.xlib.UndefineCursor = (PFN_XUndefineCursor) 1144 _glfw_dlsym(_glfw.x11.xlib.handle, "XUndefineCursor"); 1145 _glfw.x11.xlib.UngrabPointer = (PFN_XUngrabPointer) 1146 _glfw_dlsym(_glfw.x11.xlib.handle, "XUngrabPointer"); 1147 _glfw.x11.xlib.UnmapWindow = (PFN_XUnmapWindow) 1148 _glfw_dlsym(_glfw.x11.xlib.handle, "XUnmapWindow"); 1149 _glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus) 1150 _glfw_dlsym(_glfw.x11.xlib.handle, "XUnsetICFocus"); 1151 _glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual) 1152 _glfw_dlsym(_glfw.x11.xlib.handle, "XVisualIDFromVisual"); 1153 _glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer) 1154 _glfw_dlsym(_glfw.x11.xlib.handle, "XWarpPointer"); 1155 _glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard) 1156 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeKeyboard"); 1157 _glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames) 1158 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbFreeNames"); 1159 _glfw.x11.xkb.GetMap = (PFN_XkbGetMap) 1160 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetMap"); 1161 _glfw.x11.xkb.GetNames = (PFN_XkbGetNames) 1162 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetNames"); 1163 _glfw.x11.xkb.GetState = (PFN_XkbGetState) 1164 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbGetState"); 1165 _glfw.x11.xkb.KeycodeToKeysym = (PFN_XkbKeycodeToKeysym) 1166 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbKeycodeToKeysym"); 1167 _glfw.x11.xkb.QueryExtension = (PFN_XkbQueryExtension) 1168 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbQueryExtension"); 1169 _glfw.x11.xkb.SelectEventDetails = (PFN_XkbSelectEventDetails) 1170 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbSelectEventDetails"); 1171 _glfw.x11.xkb.SetDetectableAutoRepeat = (PFN_XkbSetDetectableAutoRepeat) 1172 _glfw_dlsym(_glfw.x11.xlib.handle, "XkbSetDetectableAutoRepeat"); 1173 _glfw.x11.xrm.DestroyDatabase = (PFN_XrmDestroyDatabase) 1174 _glfw_dlsym(_glfw.x11.xlib.handle, "XrmDestroyDatabase"); 1175 _glfw.x11.xrm.GetResource = (PFN_XrmGetResource) 1176 _glfw_dlsym(_glfw.x11.xlib.handle, "XrmGetResource"); 1177 _glfw.x11.xrm.GetStringDatabase = (PFN_XrmGetStringDatabase) 1178 _glfw_dlsym(_glfw.x11.xlib.handle, "XrmGetStringDatabase"); 1179 _glfw.x11.xrm.Initialize = (PFN_XrmInitialize) 1180 _glfw_dlsym(_glfw.x11.xlib.handle, "XrmInitialize"); 1181 _glfw.x11.xrm.UniqueQuark = (PFN_XrmUniqueQuark) 1182 _glfw_dlsym(_glfw.x11.xlib.handle, "XrmUniqueQuark"); 1183 _glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback) 1184 _glfw_dlsym(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback"); 1185 _glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString) 1186 _glfw_dlsym(_glfw.x11.xlib.handle, "Xutf8LookupString"); 1187 _glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties) 1188 _glfw_dlsym(_glfw.x11.xlib.handle, "Xutf8SetWMProperties"); 1189 1190 XInitThreads(); 1191 XrmInitialize(); 1192 1193 _glfw.x11.display = XOpenDisplay(NULL); 1194 if (!_glfw.x11.display) 1195 { 1196 const char* display = getenv("DISPLAY"); 1197 if (display) 1198 { 1199 _glfwInputError(GLFW_PLATFORM_ERROR, 1200 "X11: Failed to open display %s", display); 1201 } 1202 else 1203 { 1204 _glfwInputError(GLFW_PLATFORM_ERROR, 1205 "X11: The DISPLAY environment variable is missing"); 1206 } 1207 1208 return GLFW_FALSE; 1209 } 1210 1211 _glfw.x11.screen = DefaultScreen(_glfw.x11.display); 1212 _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); 1213 _glfw.x11.context = XUniqueContext(); 1214 1215 getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY); 1216 1217 if (!initExtensions()) 1218 return GLFW_FALSE; 1219 1220 _glfw.x11.helperWindowHandle = createHelperWindow(); 1221 _glfw.x11.hiddenCursorHandle = createHiddenCursor(); 1222 1223 if (XSupportsLocale()) 1224 { 1225 XSetLocaleModifiers(""); 1226 1227 // If an IM is already present our callback will be called right away 1228 XRegisterIMInstantiateCallback(_glfw.x11.display, 1229 NULL, NULL, NULL, 1230 inputMethodInstantiateCallback, 1231 NULL); 1232 } 1233 1234 #if defined(__linux__) 1235 if (!_glfwInitJoysticksLinux()) 1236 return GLFW_FALSE; 1237 #endif 1238 1239 _glfwInitTimerPOSIX(); 1240 1241 _glfwPollMonitorsX11(); 1242 return GLFW_TRUE; 1243 } 1244 1245 void _glfwPlatformTerminate(void) 1246 { 1247 if (_glfw.x11.helperWindowHandle) 1248 { 1249 if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == 1250 _glfw.x11.helperWindowHandle) 1251 { 1252 _glfwPushSelectionToManagerX11(); 1253 } 1254 1255 XDestroyWindow(_glfw.x11.display, _glfw.x11.helperWindowHandle); 1256 _glfw.x11.helperWindowHandle = None; 1257 } 1258 1259 if (_glfw.x11.hiddenCursorHandle) 1260 { 1261 XFreeCursor(_glfw.x11.display, _glfw.x11.hiddenCursorHandle); 1262 _glfw.x11.hiddenCursorHandle = (Cursor) 0; 1263 } 1264 1265 free(_glfw.x11.primarySelectionString); 1266 free(_glfw.x11.clipboardString); 1267 1268 XUnregisterIMInstantiateCallback(_glfw.x11.display, 1269 NULL, NULL, NULL, 1270 inputMethodInstantiateCallback, 1271 NULL); 1272 1273 if (_glfw.x11.im) 1274 { 1275 XCloseIM(_glfw.x11.im); 1276 _glfw.x11.im = NULL; 1277 } 1278 1279 if (_glfw.x11.display) 1280 { 1281 XCloseDisplay(_glfw.x11.display); 1282 _glfw.x11.display = NULL; 1283 } 1284 1285 if (_glfw.x11.x11xcb.handle) 1286 { 1287 _glfw_dlclose(_glfw.x11.x11xcb.handle); 1288 _glfw.x11.x11xcb.handle = NULL; 1289 } 1290 1291 if (_glfw.x11.xcursor.handle) 1292 { 1293 _glfw_dlclose(_glfw.x11.xcursor.handle); 1294 _glfw.x11.xcursor.handle = NULL; 1295 } 1296 1297 if (_glfw.x11.randr.handle) 1298 { 1299 _glfw_dlclose(_glfw.x11.randr.handle); 1300 _glfw.x11.randr.handle = NULL; 1301 } 1302 1303 if (_glfw.x11.xinerama.handle) 1304 { 1305 _glfw_dlclose(_glfw.x11.xinerama.handle); 1306 _glfw.x11.xinerama.handle = NULL; 1307 } 1308 1309 if (_glfw.x11.xrender.handle) 1310 { 1311 _glfw_dlclose(_glfw.x11.xrender.handle); 1312 _glfw.x11.xrender.handle = NULL; 1313 } 1314 1315 if (_glfw.x11.vidmode.handle) 1316 { 1317 _glfw_dlclose(_glfw.x11.vidmode.handle); 1318 _glfw.x11.vidmode.handle = NULL; 1319 } 1320 1321 if (_glfw.x11.xi.handle) 1322 { 1323 _glfw_dlclose(_glfw.x11.xi.handle); 1324 _glfw.x11.xi.handle = NULL; 1325 } 1326 1327 // NOTE: These need to be unloaded after XCloseDisplay, as they register 1328 // cleanup callbacks that get called by that function 1329 _glfwTerminateEGL(); 1330 _glfwTerminateGLX(); 1331 1332 #if defined(__linux__) 1333 _glfwTerminateJoysticksLinux(); 1334 #endif 1335 1336 if (_glfw.x11.xlib.handle) 1337 { 1338 _glfw_dlclose(_glfw.x11.xlib.handle); 1339 _glfw.x11.xlib.handle = NULL; 1340 } 1341 } 1342 1343 const char* _glfwPlatformGetVersionString(void) 1344 { 1345 return _GLFW_VERSION_NUMBER " X11 GLX EGL OSMesa" 1346 #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) 1347 " clock_gettime" 1348 #else 1349 " gettimeofday" 1350 #endif 1351 #if defined(__linux__) 1352 " evdev" 1353 #endif 1354 #if defined(_GLFW_BUILD_DLL) 1355 " shared" 1356 #endif 1357 ; 1358 } 1359