1 //========================================================================
2 // GLFW 3.5 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 
28 #include "internal.h"
29 
30 #if defined(_GLFW_X11)
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 #include <fcntl.h>
39 #include <errno.h>
40 #include <assert.h>
41 
42 
43 // Translate the X11 KeySyms for a key to a GLFW key code
44 // NOTE: This is only used as a fallback, in case the XKB method fails
45 //       It is layout-dependent and will fail partially on most non-US layouts
46 //
translateKeySyms(const KeySym* keysyms, int width)47 static int translateKeySyms(const KeySym* keysyms, int width)
48 {
49     if (width > 1)
50     {
51         switch (keysyms[1])
52         {
53             case XK_KP_0:           return GLFW_KEY_KP_0;
54             case XK_KP_1:           return GLFW_KEY_KP_1;
55             case XK_KP_2:           return GLFW_KEY_KP_2;
56             case XK_KP_3:           return GLFW_KEY_KP_3;
57             case XK_KP_4:           return GLFW_KEY_KP_4;
58             case XK_KP_5:           return GLFW_KEY_KP_5;
59             case XK_KP_6:           return GLFW_KEY_KP_6;
60             case XK_KP_7:           return GLFW_KEY_KP_7;
61             case XK_KP_8:           return GLFW_KEY_KP_8;
62             case XK_KP_9:           return GLFW_KEY_KP_9;
63             case XK_KP_Separator:
64             case XK_KP_Decimal:     return GLFW_KEY_KP_DECIMAL;
65             case XK_KP_Equal:       return GLFW_KEY_KP_EQUAL;
66             case XK_KP_Enter:       return GLFW_KEY_KP_ENTER;
67             default:                break;
68         }
69     }
70 
71     switch (keysyms[0])
72     {
73         case XK_Escape:         return GLFW_KEY_ESCAPE;
74         case XK_Tab:            return GLFW_KEY_TAB;
75         case XK_Shift_L:        return GLFW_KEY_LEFT_SHIFT;
76         case XK_Shift_R:        return GLFW_KEY_RIGHT_SHIFT;
77         case XK_Control_L:      return GLFW_KEY_LEFT_CONTROL;
78         case XK_Control_R:      return GLFW_KEY_RIGHT_CONTROL;
79         case XK_Meta_L:
80         case XK_Alt_L:          return GLFW_KEY_LEFT_ALT;
81         case XK_Mode_switch: // Mapped to Alt_R on many keyboards
82         case XK_ISO_Level3_Shift: // AltGr on at least some machines
83         case XK_Meta_R:
84         case XK_Alt_R:          return GLFW_KEY_RIGHT_ALT;
85         case XK_Super_L:        return GLFW_KEY_LEFT_SUPER;
86         case XK_Super_R:        return GLFW_KEY_RIGHT_SUPER;
87         case XK_Menu:           return GLFW_KEY_MENU;
88         case XK_Num_Lock:       return GLFW_KEY_NUM_LOCK;
89         case XK_Caps_Lock:      return GLFW_KEY_CAPS_LOCK;
90         case XK_Print:          return GLFW_KEY_PRINT_SCREEN;
91         case XK_Scroll_Lock:    return GLFW_KEY_SCROLL_LOCK;
92         case XK_Pause:          return GLFW_KEY_PAUSE;
93         case XK_Delete:         return GLFW_KEY_DELETE;
94         case XK_BackSpace:      return GLFW_KEY_BACKSPACE;
95         case XK_Return:         return GLFW_KEY_ENTER;
96         case XK_Home:           return GLFW_KEY_HOME;
97         case XK_End:            return GLFW_KEY_END;
98         case XK_Page_Up:        return GLFW_KEY_PAGE_UP;
99         case XK_Page_Down:      return GLFW_KEY_PAGE_DOWN;
100         case XK_Insert:         return GLFW_KEY_INSERT;
101         case XK_Left:           return GLFW_KEY_LEFT;
102         case XK_Right:          return GLFW_KEY_RIGHT;
103         case XK_Down:           return GLFW_KEY_DOWN;
104         case XK_Up:             return GLFW_KEY_UP;
105         case XK_F1:             return GLFW_KEY_F1;
106         case XK_F2:             return GLFW_KEY_F2;
107         case XK_F3:             return GLFW_KEY_F3;
108         case XK_F4:             return GLFW_KEY_F4;
109         case XK_F5:             return GLFW_KEY_F5;
110         case XK_F6:             return GLFW_KEY_F6;
111         case XK_F7:             return GLFW_KEY_F7;
112         case XK_F8:             return GLFW_KEY_F8;
113         case XK_F9:             return GLFW_KEY_F9;
114         case XK_F10:            return GLFW_KEY_F10;
115         case XK_F11:            return GLFW_KEY_F11;
116         case XK_F12:            return GLFW_KEY_F12;
117         case XK_F13:            return GLFW_KEY_F13;
118         case XK_F14:            return GLFW_KEY_F14;
119         case XK_F15:            return GLFW_KEY_F15;
120         case XK_F16:            return GLFW_KEY_F16;
121         case XK_F17:            return GLFW_KEY_F17;
122         case XK_F18:            return GLFW_KEY_F18;
123         case XK_F19:            return GLFW_KEY_F19;
124         case XK_F20:            return GLFW_KEY_F20;
125         case XK_F21:            return GLFW_KEY_F21;
126         case XK_F22:            return GLFW_KEY_F22;
127         case XK_F23:            return GLFW_KEY_F23;
128         case XK_F24:            return GLFW_KEY_F24;
129         case XK_F25:            return GLFW_KEY_F25;
130 
131         // Numeric keypad
132         case XK_KP_Divide:      return GLFW_KEY_KP_DIVIDE;
133         case XK_KP_Multiply:    return GLFW_KEY_KP_MULTIPLY;
134         case XK_KP_Subtract:    return GLFW_KEY_KP_SUBTRACT;
135         case XK_KP_Add:         return GLFW_KEY_KP_ADD;
136 
137         // These should have been detected in secondary keysym test above!
138         case XK_KP_Insert:      return GLFW_KEY_KP_0;
139         case XK_KP_End:         return GLFW_KEY_KP_1;
140         case XK_KP_Down:        return GLFW_KEY_KP_2;
141         case XK_KP_Page_Down:   return GLFW_KEY_KP_3;
142         case XK_KP_Left:        return GLFW_KEY_KP_4;
143         case XK_KP_Right:       return GLFW_KEY_KP_6;
144         case XK_KP_Home:        return GLFW_KEY_KP_7;
145         case XK_KP_Up:          return GLFW_KEY_KP_8;
146         case XK_KP_Page_Up:     return GLFW_KEY_KP_9;
147         case XK_KP_Delete:      return GLFW_KEY_KP_DECIMAL;
148         case XK_KP_Equal:       return GLFW_KEY_KP_EQUAL;
149         case XK_KP_Enter:       return GLFW_KEY_KP_ENTER;
150 
151         // Last resort: Check for printable keys (should not happen if the XKB
152         // extension is available). This will give a layout dependent mapping
153         // (which is wrong, and we may miss some keys, especially on non-US
154         // keyboards), but it's better than nothing...
155         case XK_a:              return GLFW_KEY_A;
156         case XK_b:              return GLFW_KEY_B;
157         case XK_c:              return GLFW_KEY_C;
158         case XK_d:              return GLFW_KEY_D;
159         case XK_e:              return GLFW_KEY_E;
160         case XK_f:              return GLFW_KEY_F;
161         case XK_g:              return GLFW_KEY_G;
162         case XK_h:              return GLFW_KEY_H;
163         case XK_i:              return GLFW_KEY_I;
164         case XK_j:              return GLFW_KEY_J;
165         case XK_k:              return GLFW_KEY_K;
166         case XK_l:              return GLFW_KEY_L;
167         case XK_m:              return GLFW_KEY_M;
168         case XK_n:              return GLFW_KEY_N;
169         case XK_o:              return GLFW_KEY_O;
170         case XK_p:              return GLFW_KEY_P;
171         case XK_q:              return GLFW_KEY_Q;
172         case XK_r:              return GLFW_KEY_R;
173         case XK_s:              return GLFW_KEY_S;
174         case XK_t:              return GLFW_KEY_T;
175         case XK_u:              return GLFW_KEY_U;
176         case XK_v:              return GLFW_KEY_V;
177         case XK_w:              return GLFW_KEY_W;
178         case XK_x:              return GLFW_KEY_X;
179         case XK_y:              return GLFW_KEY_Y;
180         case XK_z:              return GLFW_KEY_Z;
181         case XK_1:              return GLFW_KEY_1;
182         case XK_2:              return GLFW_KEY_2;
183         case XK_3:              return GLFW_KEY_3;
184         case XK_4:              return GLFW_KEY_4;
185         case XK_5:              return GLFW_KEY_5;
186         case XK_6:              return GLFW_KEY_6;
187         case XK_7:              return GLFW_KEY_7;
188         case XK_8:              return GLFW_KEY_8;
189         case XK_9:              return GLFW_KEY_9;
190         case XK_0:              return GLFW_KEY_0;
191         case XK_space:          return GLFW_KEY_SPACE;
192         case XK_minus:          return GLFW_KEY_MINUS;
193         case XK_equal:          return GLFW_KEY_EQUAL;
194         case XK_bracketleft:    return GLFW_KEY_LEFT_BRACKET;
195         case XK_bracketright:   return GLFW_KEY_RIGHT_BRACKET;
196         case XK_backslash:      return GLFW_KEY_BACKSLASH;
197         case XK_semicolon:      return GLFW_KEY_SEMICOLON;
198         case XK_apostrophe:     return GLFW_KEY_APOSTROPHE;
199         case XK_grave:          return GLFW_KEY_GRAVE_ACCENT;
200         case XK_comma:          return GLFW_KEY_COMMA;
201         case XK_period:         return GLFW_KEY_PERIOD;
202         case XK_slash:          return GLFW_KEY_SLASH;
203         case XK_less:           return GLFW_KEY_WORLD_1; // At least in some layouts...
204         default:                break;
205     }
206 
207     // No matching translation was found
208     return GLFW_KEY_UNKNOWN;
209 }
210 
211 // Create key code translation tables
212 //
createKeyTables(void)213 static void createKeyTables(void)
214 {
215     int scancodeMin, scancodeMax;
216 
217     memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes));
218     memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes));
219 
220     if (_glfw.x11.xkb.available)
221     {
222         // Use XKB to determine physical key locations independently of the
223         // current keyboard layout
224 
225         XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd);
226         XkbGetNames(_glfw.x11.display, XkbKeyNamesMask | XkbKeyAliasesMask, desc);
227 
228         scancodeMin = desc->min_key_code;
229         scancodeMax = desc->max_key_code;
230 
231         const struct
232         {
233             int key;
234             char* name;
235         } keymap[] =
236         {
237             { GLFW_KEY_GRAVE_ACCENT, "TLDE" },
238             { GLFW_KEY_1, "AE01" },
239             { GLFW_KEY_2, "AE02" },
240             { GLFW_KEY_3, "AE03" },
241             { GLFW_KEY_4, "AE04" },
242             { GLFW_KEY_5, "AE05" },
243             { GLFW_KEY_6, "AE06" },
244             { GLFW_KEY_7, "AE07" },
245             { GLFW_KEY_8, "AE08" },
246             { GLFW_KEY_9, "AE09" },
247             { GLFW_KEY_0, "AE10" },
248             { GLFW_KEY_MINUS, "AE11" },
249             { GLFW_KEY_EQUAL, "AE12" },
250             { GLFW_KEY_Q, "AD01" },
251             { GLFW_KEY_W, "AD02" },
252             { GLFW_KEY_E, "AD03" },
253             { GLFW_KEY_R, "AD04" },
254             { GLFW_KEY_T, "AD05" },
255             { GLFW_KEY_Y, "AD06" },
256             { GLFW_KEY_U, "AD07" },
257             { GLFW_KEY_I, "AD08" },
258             { GLFW_KEY_O, "AD09" },
259             { GLFW_KEY_P, "AD10" },
260             { GLFW_KEY_LEFT_BRACKET, "AD11" },
261             { GLFW_KEY_RIGHT_BRACKET, "AD12" },
262             { GLFW_KEY_A, "AC01" },
263             { GLFW_KEY_S, "AC02" },
264             { GLFW_KEY_D, "AC03" },
265             { GLFW_KEY_F, "AC04" },
266             { GLFW_KEY_G, "AC05" },
267             { GLFW_KEY_H, "AC06" },
268             { GLFW_KEY_J, "AC07" },
269             { GLFW_KEY_K, "AC08" },
270             { GLFW_KEY_L, "AC09" },
271             { GLFW_KEY_SEMICOLON, "AC10" },
272             { GLFW_KEY_APOSTROPHE, "AC11" },
273             { GLFW_KEY_Z, "AB01" },
274             { GLFW_KEY_X, "AB02" },
275             { GLFW_KEY_C, "AB03" },
276             { GLFW_KEY_V, "AB04" },
277             { GLFW_KEY_B, "AB05" },
278             { GLFW_KEY_N, "AB06" },
279             { GLFW_KEY_M, "AB07" },
280             { GLFW_KEY_COMMA, "AB08" },
281             { GLFW_KEY_PERIOD, "AB09" },
282             { GLFW_KEY_SLASH, "AB10" },
283             { GLFW_KEY_BACKSLASH, "BKSL" },
284             { GLFW_KEY_WORLD_1, "LSGT" },
285             { GLFW_KEY_SPACE, "SPCE" },
286             { GLFW_KEY_ESCAPE, "ESC" },
287             { GLFW_KEY_ENTER, "RTRN" },
288             { GLFW_KEY_TAB, "TAB" },
289             { GLFW_KEY_BACKSPACE, "BKSP" },
290             { GLFW_KEY_INSERT, "INS" },
291             { GLFW_KEY_DELETE, "DELE" },
292             { GLFW_KEY_RIGHT, "RGHT" },
293             { GLFW_KEY_LEFT, "LEFT" },
294             { GLFW_KEY_DOWN, "DOWN" },
295             { GLFW_KEY_UP, "UP" },
296             { GLFW_KEY_PAGE_UP, "PGUP" },
297             { GLFW_KEY_PAGE_DOWN, "PGDN" },
298             { GLFW_KEY_HOME, "HOME" },
299             { GLFW_KEY_END, "END" },
300             { GLFW_KEY_CAPS_LOCK, "CAPS" },
301             { GLFW_KEY_SCROLL_LOCK, "SCLK" },
302             { GLFW_KEY_NUM_LOCK, "NMLK" },
303             { GLFW_KEY_PRINT_SCREEN, "PRSC" },
304             { GLFW_KEY_PAUSE, "PAUS" },
305             { GLFW_KEY_F1, "FK01" },
306             { GLFW_KEY_F2, "FK02" },
307             { GLFW_KEY_F3, "FK03" },
308             { GLFW_KEY_F4, "FK04" },
309             { GLFW_KEY_F5, "FK05" },
310             { GLFW_KEY_F6, "FK06" },
311             { GLFW_KEY_F7, "FK07" },
312             { GLFW_KEY_F8, "FK08" },
313             { GLFW_KEY_F9, "FK09" },
314             { GLFW_KEY_F10, "FK10" },
315             { GLFW_KEY_F11, "FK11" },
316             { GLFW_KEY_F12, "FK12" },
317             { GLFW_KEY_F13, "FK13" },
318             { GLFW_KEY_F14, "FK14" },
319             { GLFW_KEY_F15, "FK15" },
320             { GLFW_KEY_F16, "FK16" },
321             { GLFW_KEY_F17, "FK17" },
322             { GLFW_KEY_F18, "FK18" },
323             { GLFW_KEY_F19, "FK19" },
324             { GLFW_KEY_F20, "FK20" },
325             { GLFW_KEY_F21, "FK21" },
326             { GLFW_KEY_F22, "FK22" },
327             { GLFW_KEY_F23, "FK23" },
328             { GLFW_KEY_F24, "FK24" },
329             { GLFW_KEY_F25, "FK25" },
330             { GLFW_KEY_KP_0, "KP0" },
331             { GLFW_KEY_KP_1, "KP1" },
332             { GLFW_KEY_KP_2, "KP2" },
333             { GLFW_KEY_KP_3, "KP3" },
334             { GLFW_KEY_KP_4, "KP4" },
335             { GLFW_KEY_KP_5, "KP5" },
336             { GLFW_KEY_KP_6, "KP6" },
337             { GLFW_KEY_KP_7, "KP7" },
338             { GLFW_KEY_KP_8, "KP8" },
339             { GLFW_KEY_KP_9, "KP9" },
340             { GLFW_KEY_KP_DECIMAL, "KPDL" },
341             { GLFW_KEY_KP_DIVIDE, "KPDV" },
342             { GLFW_KEY_KP_MULTIPLY, "KPMU" },
343             { GLFW_KEY_KP_SUBTRACT, "KPSU" },
344             { GLFW_KEY_KP_ADD, "KPAD" },
345             { GLFW_KEY_KP_ENTER, "KPEN" },
346             { GLFW_KEY_KP_EQUAL, "KPEQ" },
347             { GLFW_KEY_LEFT_SHIFT, "LFSH" },
348             { GLFW_KEY_LEFT_CONTROL, "LCTL" },
349             { GLFW_KEY_LEFT_ALT, "LALT" },
350             { GLFW_KEY_LEFT_SUPER, "LWIN" },
351             { GLFW_KEY_RIGHT_SHIFT, "RTSH" },
352             { GLFW_KEY_RIGHT_CONTROL, "RCTL" },
353             { GLFW_KEY_RIGHT_ALT, "RALT" },
354             { GLFW_KEY_RIGHT_ALT, "LVL3" },
355             { GLFW_KEY_RIGHT_ALT, "MDSW" },
356             { GLFW_KEY_RIGHT_SUPER, "RWIN" },
357             { GLFW_KEY_MENU, "MENU" }
358         };
359 
360         // Find the X11 key code -> GLFW key code mapping
361         for (int scancode = scancodeMin;  scancode <= scancodeMax;  scancode++)
362         {
363             int key = GLFW_KEY_UNKNOWN;
364 
365             // Map the key name to a GLFW key code. Note: We use the US
366             // keyboard layout. Because function keys aren't mapped correctly
367             // when using traditional KeySym translations, they are mapped
368             // here instead.
369             for (int i = 0;  i < sizeof(keymap) / sizeof(keymap[0]);  i++)
370             {
371                 if (strncmp(desc->names->keys[scancode].name,
372                             keymap[i].name,
373                             XkbKeyNameLength) == 0)
374                 {
375                     key = keymap[i].key;
376                     break;
377                 }
378             }
379 
380             // Fall back to key aliases in case the key name did not match
381             for (int i = 0;  i < desc->names->num_key_aliases;  i++)
382             {
383                 if (key != GLFW_KEY_UNKNOWN)
384                     break;
385 
386                 if (strncmp(desc->names->key_aliases[i].real,
387                             desc->names->keys[scancode].name,
388                             XkbKeyNameLength) != 0)
389                 {
390                     continue;
391                 }
392 
393                 for (int j = 0;  j < sizeof(keymap) / sizeof(keymap[0]);  j++)
394                 {
395                     if (strncmp(desc->names->key_aliases[i].alias,
396                                 keymap[j].name,
397                                 XkbKeyNameLength) == 0)
398                     {
399                         key = keymap[j].key;
400                         break;
401                     }
402                 }
403             }
404 
405             _glfw.x11.keycodes[scancode] = key;
406         }
407 
408         XkbFreeNames(desc, XkbKeyNamesMask, True);
409         XkbFreeKeyboard(desc, 0, True);
410     }
411     else
412         XDisplayKeycodes(_glfw.x11.display, &scancodeMin, &scancodeMax);
413 
414     int width;
415     KeySym* keysyms = XGetKeyboardMapping(_glfw.x11.display,
416                                           scancodeMin,
417                                           scancodeMax - scancodeMin + 1,
418                                           &width);
419 
420     for (int scancode = scancodeMin;  scancode <= scancodeMax;  scancode++)
421     {
422         // Translate the un-translated key codes using traditional X11 KeySym
423         // lookups
424         if (_glfw.x11.keycodes[scancode] < 0)
425         {
426             const size_t base = (scancode - scancodeMin) * width;
427             _glfw.x11.keycodes[scancode] = translateKeySyms(&keysyms[base], width);
428         }
429 
430         // Store the reverse translation for faster key name lookup
431         if (_glfw.x11.keycodes[scancode] > 0)
432             _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode;
433     }
434 
435     XFree(keysyms);
436 }
437 
438 // Check whether the IM has a usable style
439 //
hasUsableInputMethodStyle(void)440 static GLFWbool hasUsableInputMethodStyle(void)
441 {
442     GLFWbool found = GLFW_FALSE;
443     XIMStyles* styles = NULL;
444 
445     if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
446         return GLFW_FALSE;
447 
448     for (unsigned int i = 0;  i < styles->count_styles;  i++)
449     {
450         if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing))
451         {
452             found = GLFW_TRUE;
453             break;
454         }
455     }
456 
457     XFree(styles);
458     return found;
459 }
460 
inputMethodDestroyCallback(XIM im, XPointer clientData, XPointer callData)461 static void inputMethodDestroyCallback(XIM im, XPointer clientData, XPointer callData)
462 {
463     _glfw.x11.im = NULL;
464 }
465 
inputMethodInstantiateCallback(Display* display, XPointer clientData, XPointer callData)466 static void inputMethodInstantiateCallback(Display* display,
467                                            XPointer clientData,
468                                            XPointer callData)
469 {
470     if (_glfw.x11.im)
471         return;
472 
473     _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL);
474     if (_glfw.x11.im)
475     {
476         if (!hasUsableInputMethodStyle())
477         {
478             XCloseIM(_glfw.x11.im);
479             _glfw.x11.im = NULL;
480         }
481     }
482 
483     if (_glfw.x11.im)
484     {
485         XIMCallback callback;
486         callback.callback = (XIMProc) inputMethodDestroyCallback;
487         callback.client_data = NULL;
488         XSetIMValues(_glfw.x11.im, XNDestroyCallback, &callback, NULL);
489 
490         for (_GLFWwindow* window = _glfw.windowListHead;  window;  window = window->next)
491             _glfwCreateInputContextX11(window);
492     }
493 }
494 
495 // Return the atom ID only if it is listed in the specified array
496 //
getAtomIfSupported(Atom* supportedAtoms, unsigned long atomCount, const char* atomName)497 static Atom getAtomIfSupported(Atom* supportedAtoms,
498                                unsigned long atomCount,
499                                const char* atomName)
500 {
501     const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
502 
503     for (unsigned long i = 0;  i < atomCount;  i++)
504     {
505         if (supportedAtoms[i] == atom)
506             return atom;
507     }
508 
509     return None;
510 }
511 
512 // Check whether the running window manager is EWMH-compliant
513 //
detectEWMH(void)514 static void detectEWMH(void)
515 {
516     // First we read the _NET_SUPPORTING_WM_CHECK property on the root window
517 
518     Window* windowFromRoot = NULL;
519     if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
520                                    _glfw.x11.NET_SUPPORTING_WM_CHECK,
521                                    XA_WINDOW,
522                                    (unsigned char**) &windowFromRoot))
523     {
524         return;
525     }
526 
527     _glfwGrabErrorHandlerX11();
528 
529     // If it exists, it should be the XID of a top-level window
530     // Then we look for the same property on that window
531 
532     Window* windowFromChild = NULL;
533     if (!_glfwGetWindowPropertyX11(*windowFromRoot,
534                                    _glfw.x11.NET_SUPPORTING_WM_CHECK,
535                                    XA_WINDOW,
536                                    (unsigned char**) &windowFromChild))
537     {
538         XFree(windowFromRoot);
539         return;
540     }
541 
542     _glfwReleaseErrorHandlerX11();
543 
544     // If the property exists, it should contain the XID of the window
545 
546     if (*windowFromRoot != *windowFromChild)
547     {
548         XFree(windowFromRoot);
549         XFree(windowFromChild);
550         return;
551     }
552 
553     XFree(windowFromRoot);
554     XFree(windowFromChild);
555 
556     // We are now fairly sure that an EWMH-compliant WM is currently running
557     // We can now start querying the WM about what features it supports by
558     // looking in the _NET_SUPPORTED property on the root window
559     // It should contain a list of supported EWMH protocol and state atoms
560 
561     Atom* supportedAtoms = NULL;
562     const unsigned long atomCount =
563         _glfwGetWindowPropertyX11(_glfw.x11.root,
564                                   _glfw.x11.NET_SUPPORTED,
565                                   XA_ATOM,
566                                   (unsigned char**) &supportedAtoms);
567 
568     // See which of the atoms we support that are supported by the WM
569 
570     _glfw.x11.NET_WM_STATE =
571         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE");
572     _glfw.x11.NET_WM_STATE_ABOVE =
573         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
574     _glfw.x11.NET_WM_STATE_FULLSCREEN =
575         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
576     _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT =
577         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");
578     _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ =
579         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");
580     _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION =
581         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION");
582     _glfw.x11.NET_WM_FULLSCREEN_MONITORS =
583         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
584     _glfw.x11.NET_WM_WINDOW_TYPE =
585         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
586     _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =
587         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
588     _glfw.x11.NET_WORKAREA =
589         getAtomIfSupported(supportedAtoms, atomCount, "_NET_WORKAREA");
590     _glfw.x11.NET_CURRENT_DESKTOP =
591         getAtomIfSupported(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP");
592     _glfw.x11.NET_ACTIVE_WINDOW =
593         getAtomIfSupported(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
594     _glfw.x11.NET_FRAME_EXTENTS =
595         getAtomIfSupported(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");
596     _glfw.x11.NET_REQUEST_FRAME_EXTENTS =
597         getAtomIfSupported(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
598 
599     if (supportedAtoms)
600         XFree(supportedAtoms);
601 }
602 
603 // Look for and initialize supported X11 extensions
604 //
initExtensions(void)605 static GLFWbool initExtensions(void)
606 {
607 #if defined(__OpenBSD__) || defined(__NetBSD__)
608     _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so");
609 #else
610     _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so.1");
611 #endif
612     if (_glfw.x11.vidmode.handle)
613     {
614         _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension)
615             _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
616         _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp)
617             _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
618         _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp)
619             _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp");
620         _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize)
621             _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize");
622 
623         _glfw.x11.vidmode.available =
624             XF86VidModeQueryExtension(_glfw.x11.display,
625                                       &_glfw.x11.vidmode.eventBase,
626                                       &_glfw.x11.vidmode.errorBase);
627     }
628 
629 #if defined(__CYGWIN__)
630     _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi-6.so");
631 #elif defined(__OpenBSD__) || defined(__NetBSD__)
632     _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so");
633 #else
634     _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so.6");
635 #endif
636     if (_glfw.x11.xi.handle)
637     {
638         _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion)
639             _glfwPlatformGetModuleSymbol(_glfw.x11.xi.handle, "XIQueryVersion");
640         _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
641             _glfwPlatformGetModuleSymbol(_glfw.x11.xi.handle, "XISelectEvents");
642 
643         if (XQueryExtension(_glfw.x11.display,
644                             "XInputExtension",
645                             &_glfw.x11.xi.majorOpcode,
646                             &_glfw.x11.xi.eventBase,
647                             &_glfw.x11.xi.errorBase))
648         {
649             _glfw.x11.xi.major = 2;
650             _glfw.x11.xi.minor = 0;
651 
652             if (XIQueryVersion(_glfw.x11.display,
653                                &_glfw.x11.xi.major,
654                                &_glfw.x11.xi.minor) == Success)
655             {
656                 _glfw.x11.xi.available = GLFW_TRUE;
657             }
658         }
659     }
660 
661 #if defined(__CYGWIN__)
662     _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so");
663 #elif defined(__OpenBSD__) || defined(__NetBSD__)
664     _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so");
665 #else
666     _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2");
667 #endif
668     if (_glfw.x11.randr.handle)
669     {
670         _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma)
671             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRAllocGamma");
672         _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
673             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeGamma");
674         _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo)
675             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeCrtcInfo");
676         _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
677             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeGamma");
678         _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo)
679             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeOutputInfo");
680         _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources)
681             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeScreenResources");
682         _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma)
683             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcGamma");
684         _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize)
685             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
686         _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo)
687             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcInfo");
688         _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo)
689             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetOutputInfo");
690         _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary)
691             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetOutputPrimary");
692         _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent)
693             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent");
694         _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension)
695             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRQueryExtension");
696         _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion)
697             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRQueryVersion");
698         _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput)
699             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSelectInput");
700         _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig)
701             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSetCrtcConfig");
702         _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma)
703             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSetCrtcGamma");
704         _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration)
705             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRUpdateConfiguration");
706 
707         if (XRRQueryExtension(_glfw.x11.display,
708                               &_glfw.x11.randr.eventBase,
709                               &_glfw.x11.randr.errorBase))
710         {
711             if (XRRQueryVersion(_glfw.x11.display,
712                                 &_glfw.x11.randr.major,
713                                 &_glfw.x11.randr.minor))
714             {
715                 // The GLFW RandR path requires at least version 1.3
716                 if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3)
717                     _glfw.x11.randr.available = GLFW_TRUE;
718             }
719             else
720             {
721                 _glfwInputError(GLFW_PLATFORM_ERROR,
722                                 "X11: Failed to query RandR version");
723             }
724         }
725     }
726 
727     if (_glfw.x11.randr.available)
728     {
729         XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
730                                                               _glfw.x11.root);
731 
732         if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0]))
733         {
734             // This is likely an older Nvidia driver with broken gamma support
735             // Flag it as useless and fall back to xf86vm gamma, if available
736             _glfw.x11.randr.gammaBroken = GLFW_TRUE;
737         }
738 
739         if (!sr->ncrtc)
740         {
741             // A system without CRTCs is likely a system with broken RandR
742             // Disable the RandR monitor path and fall back to core functions
743             _glfw.x11.randr.monitorBroken = GLFW_TRUE;
744         }
745 
746         XRRFreeScreenResources(sr);
747     }
748 
749     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
750     {
751         XRRSelectInput(_glfw.x11.display, _glfw.x11.root,
752                        RROutputChangeNotifyMask);
753     }
754 
755 #if defined(__CYGWIN__)
756     _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so");
757 #elif defined(__OpenBSD__) || defined(__NetBSD__)
758     _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so");
759 #else
760     _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1");
761 #endif
762     if (_glfw.x11.xcursor.handle)
763     {
764         _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate)
765             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageCreate");
766         _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy)
767             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
768         _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
769             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
770         _glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme)
771             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorGetTheme");
772         _glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize)
773             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize");
774         _glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage)
775             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage");
776     }
777 
778 #if defined(__CYGWIN__)
779     _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so");
780 #elif defined(__OpenBSD__) || defined(__NetBSD__)
781     _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so");
782 #else
783     _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1");
784 #endif
785     if (_glfw.x11.xinerama.handle)
786     {
787         _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive)
788             _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaIsActive");
789         _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension)
790             _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaQueryExtension");
791         _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens)
792             _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaQueryScreens");
793 
794         if (XineramaQueryExtension(_glfw.x11.display,
795                                    &_glfw.x11.xinerama.major,
796                                    &_glfw.x11.xinerama.minor))
797         {
798             if (XineramaIsActive(_glfw.x11.display))
799                 _glfw.x11.xinerama.available = GLFW_TRUE;
800         }
801     }
802 
803     _glfw.x11.xkb.major = 1;
804     _glfw.x11.xkb.minor = 0;
805     _glfw.x11.xkb.available =
806         XkbQueryExtension(_glfw.x11.display,
807                           &_glfw.x11.xkb.majorOpcode,
808                           &_glfw.x11.xkb.eventBase,
809                           &_glfw.x11.xkb.errorBase,
810                           &_glfw.x11.xkb.major,
811                           &_glfw.x11.xkb.minor);
812 
813     if (_glfw.x11.xkb.available)
814     {
815         Bool supported;
816 
817         if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported))
818         {
819             if (supported)
820                 _glfw.x11.xkb.detectable = GLFW_TRUE;
821         }
822 
823         XkbStateRec state;
824         if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success)
825             _glfw.x11.xkb.group = (unsigned int)state.group;
826 
827         XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify,
828                               XkbGroupStateMask, XkbGroupStateMask);
829     }
830 
831     if (_glfw.hints.init.x11.xcbVulkanSurface)
832     {
833 #if defined(__CYGWIN__)
834         _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb-1.so");
835 #elif defined(__OpenBSD__) || defined(__NetBSD__)
836         _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so");
837 #else
838         _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1");
839 #endif
840     }
841 
842     if (_glfw.x11.x11xcb.handle)
843     {
844         _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection)
845             _glfwPlatformGetModuleSymbol(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
846     }
847 
848 #if defined(__CYGWIN__)
849     _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so");
850 #elif defined(__OpenBSD__) || defined(__NetBSD__)
851     _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so");
852 #else
853     _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1");
854 #endif
855     if (_glfw.x11.xrender.handle)
856     {
857         _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension)
858             _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderQueryExtension");
859         _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion)
860             _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderQueryVersion");
861         _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat)
862             _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderFindVisualFormat");
863 
864         if (XRenderQueryExtension(_glfw.x11.display,
865                                   &_glfw.x11.xrender.errorBase,
866                                   &_glfw.x11.xrender.eventBase))
867         {
868             if (XRenderQueryVersion(_glfw.x11.display,
869                                     &_glfw.x11.xrender.major,
870                                     &_glfw.x11.xrender.minor))
871             {
872                 _glfw.x11.xrender.available = GLFW_TRUE;
873             }
874         }
875     }
876 
877 #if defined(__CYGWIN__)
878     _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext-6.so");
879 #elif defined(__OpenBSD__) || defined(__NetBSD__)
880     _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so");
881 #else
882     _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6");
883 #endif
884     if (_glfw.x11.xshape.handle)
885     {
886         _glfw.x11.xshape.QueryExtension = (PFN_XShapeQueryExtension)
887             _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeQueryExtension");
888         _glfw.x11.xshape.ShapeCombineRegion = (PFN_XShapeCombineRegion)
889             _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeCombineRegion");
890         _glfw.x11.xshape.QueryVersion = (PFN_XShapeQueryVersion)
891             _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeQueryVersion");
892         _glfw.x11.xshape.ShapeCombineMask = (PFN_XShapeCombineMask)
893             _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeCombineMask");
894 
895         if (XShapeQueryExtension(_glfw.x11.display,
896             &_glfw.x11.xshape.errorBase,
897             &_glfw.x11.xshape.eventBase))
898         {
899             if (XShapeQueryVersion(_glfw.x11.display,
900                 &_glfw.x11.xshape.major,
901                 &_glfw.x11.xshape.minor))
902             {
903                 _glfw.x11.xshape.available = GLFW_TRUE;
904             }
905         }
906     }
907 
908     // Update the key code LUT
909     // FIXME: We should listen to XkbMapNotify events to track changes to
910     // the keyboard mapping.
911     createKeyTables();
912 
913     // String format atoms
914     _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
915     _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
916     _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);
917 
918     // Custom selection property atom
919     _glfw.x11.GLFW_SELECTION =
920         XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False);
921 
922     // ICCCM standard clipboard atoms
923     _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
924     _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
925     _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False);
926     _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False);
927     _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
928 
929     // Clipboard manager atoms
930     _glfw.x11.CLIPBOARD_MANAGER =
931         XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False);
932     _glfw.x11.SAVE_TARGETS =
933         XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
934 
935     // Xdnd (drag and drop) atoms
936     _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False);
937     _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
938     _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
939     _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False);
940     _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
941     _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
942     _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
943     _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
944     _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
945     _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);
946 
947     // ICCCM, EWMH and Motif window property atoms
948     // These can be set safely even without WM support
949     // The EWMH atoms that require WM support are handled in detectEWMH
950     _glfw.x11.WM_PROTOCOLS =
951         XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False);
952     _glfw.x11.WM_STATE =
953         XInternAtom(_glfw.x11.display, "WM_STATE", False);
954     _glfw.x11.WM_DELETE_WINDOW =
955         XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
956     _glfw.x11.NET_SUPPORTED =
957         XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
958     _glfw.x11.NET_SUPPORTING_WM_CHECK =
959         XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
960     _glfw.x11.NET_WM_ICON =
961         XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
962     _glfw.x11.NET_WM_PING =
963         XInternAtom(_glfw.x11.display, "_NET_WM_PING", False);
964     _glfw.x11.NET_WM_PID =
965         XInternAtom(_glfw.x11.display, "_NET_WM_PID", False);
966     _glfw.x11.NET_WM_NAME =
967         XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False);
968     _glfw.x11.NET_WM_ICON_NAME =
969         XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False);
970     _glfw.x11.NET_WM_BYPASS_COMPOSITOR =
971         XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False);
972     _glfw.x11.NET_WM_WINDOW_OPACITY =
973         XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False);
974     _glfw.x11.MOTIF_WM_HINTS =
975         XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);
976 
977     // The compositing manager selection name contains the screen number
978     {
979         char name[32];
980         snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen);
981         _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False);
982     }
983 
984     // Detect whether an EWMH-conformant window manager is running
985     detectEWMH();
986 
987     return GLFW_TRUE;
988 }
989 
990 // Retrieve system content scale via folklore heuristics
991 //
getSystemContentScale(float* xscale, float* yscale)992 static void getSystemContentScale(float* xscale, float* yscale)
993 {
994     // Start by assuming the default X11 DPI
995     // NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it
996     //       would be set to 96, so assume that is the case if we cannot find it
997     float xdpi = 96.f, ydpi = 96.f;
998 
999     // NOTE: Basing the scale on Xft.dpi where available should provide the most
1000     //       consistent user experience (matches Qt, Gtk, etc), although not
1001     //       always the most accurate one
1002     char* rms = XResourceManagerString(_glfw.x11.display);
1003     if (rms)
1004     {
1005         XrmDatabase db = XrmGetStringDatabase(rms);
1006         if (db)
1007         {
1008             XrmValue value;
1009             char* type = NULL;
1010 
1011             if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value))
1012             {
1013                 if (type && strcmp(type, "String") == 0)
1014                     xdpi = ydpi = atof(value.addr);
1015             }
1016 
1017             XrmDestroyDatabase(db);
1018         }
1019     }
1020 
1021     *xscale = xdpi / 96.f;
1022     *yscale = ydpi / 96.f;
1023 }
1024 
1025 // Create a blank cursor for hidden and disabled cursor modes
1026 //
createHiddenCursor(void)1027 static Cursor createHiddenCursor(void)
1028 {
1029     unsigned char pixels[16 * 16 * 4] = { 0 };
1030     GLFWimage image = { 16, 16, pixels };
1031     return _glfwCreateNativeCursorX11(&image, 0, 0);
1032 }
1033 
1034 // Create a helper window for IPC
1035 //
createHelperWindow(void)1036 static Window createHelperWindow(void)
1037 {
1038     XSetWindowAttributes wa;
1039     wa.event_mask = PropertyChangeMask;
1040 
1041     return XCreateWindow(_glfw.x11.display, _glfw.x11.root,
1042                          0, 0, 1, 1, 0, 0,
1043                          InputOnly,
1044                          DefaultVisual(_glfw.x11.display, _glfw.x11.screen),
1045                          CWEventMask, &wa);
1046 }
1047 
1048 // Create the pipe for empty events without assumuing the OS has pipe2(2)
1049 //
createEmptyEventPipe(void)1050 static GLFWbool createEmptyEventPipe(void)
1051 {
1052     if (pipe(_glfw.x11.emptyEventPipe) != 0)
1053     {
1054         _glfwInputError(GLFW_PLATFORM_ERROR,
1055                         "X11: Failed to create empty event pipe: %s",
1056                         strerror(errno));
1057         return GLFW_FALSE;
1058     }
1059 
1060     for (int i = 0; i < 2; i++)
1061     {
1062         const int sf = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFL, 0);
1063         const int df = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFD, 0);
1064 
1065         if (sf == -1 || df == -1 ||
1066             fcntl(_glfw.x11.emptyEventPipe[i], F_SETFL, sf | O_NONBLOCK) == -1 ||
1067             fcntl(_glfw.x11.emptyEventPipe[i], F_SETFD, df | FD_CLOEXEC) == -1)
1068         {
1069             _glfwInputError(GLFW_PLATFORM_ERROR,
1070                             "X11: Failed to set flags for empty event pipe: %s",
1071                             strerror(errno));
1072             return GLFW_FALSE;
1073         }
1074     }
1075 
1076     return GLFW_TRUE;
1077 }
1078 
1079 // X error handler
1080 //
errorHandler(Display *display, XErrorEvent* event)1081 static int errorHandler(Display *display, XErrorEvent* event)
1082 {
1083     if (_glfw.x11.display != display)
1084         return 0;
1085 
1086     _glfw.x11.errorCode = event->error_code;
1087     return 0;
1088 }
1089 
1090 
1091 //////////////////////////////////////////////////////////////////////////
1092 //////                       GLFW internal API                      //////
1093 //////////////////////////////////////////////////////////////////////////
1094 
1095 // Sets the X error handler callback
1096 //
_glfwGrabErrorHandlerX11(void)1097 void _glfwGrabErrorHandlerX11(void)
1098 {
1099     assert(_glfw.x11.errorHandler == NULL);
1100     _glfw.x11.errorCode = Success;
1101     _glfw.x11.errorHandler = XSetErrorHandler(errorHandler);
1102 }
1103 
1104 // Clears the X error handler callback
1105 //
_glfwReleaseErrorHandlerX11(void)1106 void _glfwReleaseErrorHandlerX11(void)
1107 {
1108     // Synchronize to make sure all commands are processed
1109     XSync(_glfw.x11.display, False);
1110     XSetErrorHandler(_glfw.x11.errorHandler);
1111     _glfw.x11.errorHandler = NULL;
1112 }
1113 
1114 // Reports the specified error, appending information about the last X error
1115 //
_glfwInputErrorX11(int error, const char* message)1116 void _glfwInputErrorX11(int error, const char* message)
1117 {
1118     char buffer[_GLFW_MESSAGE_SIZE];
1119     XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode,
1120                   buffer, sizeof(buffer));
1121 
1122     _glfwInputError(error, "%s: %s", message, buffer);
1123 }
1124 
1125 // Creates a native cursor object from the specified image and hotspot
1126 //
_glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot)1127 Cursor _glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot)
1128 {
1129     Cursor cursor;
1130 
1131     if (!_glfw.x11.xcursor.handle)
1132         return None;
1133 
1134     XcursorImage* native = XcursorImageCreate(image->width, image->height);
1135     if (native == NULL)
1136         return None;
1137 
1138     native->xhot = xhot;
1139     native->yhot = yhot;
1140 
1141     unsigned char* source = (unsigned char*) image->pixels;
1142     XcursorPixel* target = native->pixels;
1143 
1144     for (int i = 0;  i < image->width * image->height;  i++, target++, source += 4)
1145     {
1146         unsigned int alpha = source[3];
1147 
1148         *target = (alpha << 24) |
1149                   ((unsigned char) ((source[0] * alpha) / 255) << 16) |
1150                   ((unsigned char) ((source[1] * alpha) / 255) <<  8) |
1151                   ((unsigned char) ((source[2] * alpha) / 255) <<  0);
1152     }
1153 
1154     cursor = XcursorImageLoadCursor(_glfw.x11.display, native);
1155     XcursorImageDestroy(native);
1156 
1157     return cursor;
1158 }
1159 
1160 
1161 //////////////////////////////////////////////////////////////////////////
1162 //////                       GLFW platform API                      //////
1163 //////////////////////////////////////////////////////////////////////////
1164 
_glfwConnectX11(int platformID, _GLFWplatform* platform)1165 GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
1166 {
1167     const _GLFWplatform x11 =
1168     {
1169         .platformID = GLFW_PLATFORM_X11,
1170         .init = _glfwInitX11,
1171         .terminate = _glfwTerminateX11,
1172         .getCursorPos = _glfwGetCursorPosX11,
1173         .setCursorPos = _glfwSetCursorPosX11,
1174         .setCursorMode = _glfwSetCursorModeX11,
1175         .setRawMouseMotion = _glfwSetRawMouseMotionX11,
1176         .rawMouseMotionSupported = _glfwRawMouseMotionSupportedX11,
1177         .createCursor = _glfwCreateCursorX11,
1178         .createStandardCursor = _glfwCreateStandardCursorX11,
1179         .destroyCursor = _glfwDestroyCursorX11,
1180         .setCursor = _glfwSetCursorX11,
1181         .getScancodeName = _glfwGetScancodeNameX11,
1182         .getKeyScancode = _glfwGetKeyScancodeX11,
1183         .setClipboardString = _glfwSetClipboardStringX11,
1184         .getClipboardString = _glfwGetClipboardStringX11,
1185 #if defined(GLFW_BUILD_LINUX_JOYSTICK)
1186         .initJoysticks = _glfwInitJoysticksLinux,
1187         .terminateJoysticks = _glfwTerminateJoysticksLinux,
1188         .pollJoystick = _glfwPollJoystickLinux,
1189         .getMappingName = _glfwGetMappingNameLinux,
1190         .updateGamepadGUID = _glfwUpdateGamepadGUIDLinux,
1191 #else
1192         .initJoysticks = _glfwInitJoysticksNull,
1193         .terminateJoysticks = _glfwTerminateJoysticksNull,
1194         .pollJoystick = _glfwPollJoystickNull,
1195         .getMappingName = _glfwGetMappingNameNull,
1196         .updateGamepadGUID = _glfwUpdateGamepadGUIDNull,
1197 #endif
1198         .freeMonitor = _glfwFreeMonitorX11,
1199         .getMonitorPos = _glfwGetMonitorPosX11,
1200         .getMonitorContentScale = _glfwGetMonitorContentScaleX11,
1201         .getMonitorWorkarea = _glfwGetMonitorWorkareaX11,
1202         .getVideoModes = _glfwGetVideoModesX11,
1203         .getVideoMode = _glfwGetVideoModeX11,
1204         .getGammaRamp = _glfwGetGammaRampX11,
1205         .setGammaRamp = _glfwSetGammaRampX11,
1206         .createWindow = _glfwCreateWindowX11,
1207         .destroyWindow = _glfwDestroyWindowX11,
1208         .setWindowTitle = _glfwSetWindowTitleX11,
1209         .setWindowIcon = _glfwSetWindowIconX11,
1210         .getWindowPos = _glfwGetWindowPosX11,
1211         .setWindowPos = _glfwSetWindowPosX11,
1212         .getWindowSize = _glfwGetWindowSizeX11,
1213         .setWindowSize = _glfwSetWindowSizeX11,
1214         .setWindowSizeLimits = _glfwSetWindowSizeLimitsX11,
1215         .setWindowAspectRatio = _glfwSetWindowAspectRatioX11,
1216         .getFramebufferSize = _glfwGetFramebufferSizeX11,
1217         .getWindowFrameSize = _glfwGetWindowFrameSizeX11,
1218         .getWindowContentScale = _glfwGetWindowContentScaleX11,
1219         .iconifyWindow = _glfwIconifyWindowX11,
1220         .restoreWindow = _glfwRestoreWindowX11,
1221         .maximizeWindow = _glfwMaximizeWindowX11,
1222         .showWindow = _glfwShowWindowX11,
1223         .hideWindow = _glfwHideWindowX11,
1224         .requestWindowAttention = _glfwRequestWindowAttentionX11,
1225         .focusWindow = _glfwFocusWindowX11,
1226         .setWindowMonitor = _glfwSetWindowMonitorX11,
1227         .windowFocused = _glfwWindowFocusedX11,
1228         .windowIconified = _glfwWindowIconifiedX11,
1229         .windowVisible = _glfwWindowVisibleX11,
1230         .windowMaximized = _glfwWindowMaximizedX11,
1231         .windowHovered = _glfwWindowHoveredX11,
1232         .framebufferTransparent = _glfwFramebufferTransparentX11,
1233         .getWindowOpacity = _glfwGetWindowOpacityX11,
1234         .setWindowResizable = _glfwSetWindowResizableX11,
1235         .setWindowDecorated = _glfwSetWindowDecoratedX11,
1236         .setWindowFloating = _glfwSetWindowFloatingX11,
1237         .setWindowOpacity = _glfwSetWindowOpacityX11,
1238         .setWindowMousePassthrough = _glfwSetWindowMousePassthroughX11,
1239         .pollEvents = _glfwPollEventsX11,
1240         .waitEvents = _glfwWaitEventsX11,
1241         .waitEventsTimeout = _glfwWaitEventsTimeoutX11,
1242         .postEmptyEvent = _glfwPostEmptyEventX11,
1243         .getEGLPlatform = _glfwGetEGLPlatformX11,
1244         .getEGLNativeDisplay = _glfwGetEGLNativeDisplayX11,
1245         .getEGLNativeWindow = _glfwGetEGLNativeWindowX11,
1246         .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsX11,
1247         .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportX11,
1248         .createWindowSurface = _glfwCreateWindowSurfaceX11
1249     };
1250 
1251     // HACK: If the application has left the locale as "C" then both wide
1252     //       character text input and explicit UTF-8 input via XIM will break
1253     //       This sets the CTYPE part of the current locale from the environment
1254     //       in the hope that it is set to something more sane than "C"
1255     if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0)
1256         setlocale(LC_CTYPE, "");
1257 
1258 #if defined(__CYGWIN__)
1259     void* module = _glfwPlatformLoadModule("libX11-6.so");
1260 #elif defined(__OpenBSD__) || defined(__NetBSD__)
1261     void* module = _glfwPlatformLoadModule("libX11.so");
1262 #else
1263     void* module = _glfwPlatformLoadModule("libX11.so.6");
1264 #endif
1265     if (!module)
1266     {
1267         if (platformID == GLFW_PLATFORM_X11)
1268             _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib");
1269 
1270         return GLFW_FALSE;
1271     }
1272 
1273     PFN_XInitThreads XInitThreads = (PFN_XInitThreads)
1274         _glfwPlatformGetModuleSymbol(module, "XInitThreads");
1275     PFN_XrmInitialize XrmInitialize = (PFN_XrmInitialize)
1276         _glfwPlatformGetModuleSymbol(module, "XrmInitialize");
1277     PFN_XOpenDisplay XOpenDisplay = (PFN_XOpenDisplay)
1278         _glfwPlatformGetModuleSymbol(module, "XOpenDisplay");
1279     if (!XInitThreads || !XrmInitialize || !XOpenDisplay)
1280     {
1281         if (platformID == GLFW_PLATFORM_X11)
1282             _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib entry point");
1283 
1284         _glfwPlatformFreeModule(module);
1285         return GLFW_FALSE;
1286     }
1287 
1288     XInitThreads();
1289     XrmInitialize();
1290 
1291     Display* display = XOpenDisplay(NULL);
1292     if (!display)
1293     {
1294         if (platformID == GLFW_PLATFORM_X11)
1295         {
1296             const char* name = getenv("DISPLAY");
1297             if (name)
1298             {
1299                 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
1300                                 "X11: Failed to open display %s", name);
1301             }
1302             else
1303             {
1304                 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
1305                                 "X11: The DISPLAY environment variable is missing");
1306             }
1307         }
1308 
1309         _glfwPlatformFreeModule(module);
1310         return GLFW_FALSE;
1311     }
1312 
1313     _glfw.x11.display = display;
1314     _glfw.x11.xlib.handle = module;
1315 
1316     *platform = x11;
1317     return GLFW_TRUE;
1318 }
1319 
_glfwInitX11(void)1320 int _glfwInitX11(void)
1321 {
1322     _glfw.x11.xlib.AllocClassHint = (PFN_XAllocClassHint)
1323         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocClassHint");
1324     _glfw.x11.xlib.AllocSizeHints = (PFN_XAllocSizeHints)
1325         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocSizeHints");
1326     _glfw.x11.xlib.AllocWMHints = (PFN_XAllocWMHints)
1327         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocWMHints");
1328     _glfw.x11.xlib.ChangeProperty = (PFN_XChangeProperty)
1329         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XChangeProperty");
1330     _glfw.x11.xlib.ChangeWindowAttributes = (PFN_XChangeWindowAttributes)
1331         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XChangeWindowAttributes");
1332     _glfw.x11.xlib.CheckIfEvent = (PFN_XCheckIfEvent)
1333         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCheckIfEvent");
1334     _glfw.x11.xlib.CheckTypedWindowEvent = (PFN_XCheckTypedWindowEvent)
1335         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCheckTypedWindowEvent");
1336     _glfw.x11.xlib.CloseDisplay = (PFN_XCloseDisplay)
1337         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCloseDisplay");
1338     _glfw.x11.xlib.CloseIM = (PFN_XCloseIM)
1339         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCloseIM");
1340     _glfw.x11.xlib.ConvertSelection = (PFN_XConvertSelection)
1341         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XConvertSelection");
1342     _glfw.x11.xlib.CreateColormap = (PFN_XCreateColormap)
1343         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateColormap");
1344     _glfw.x11.xlib.CreateFontCursor = (PFN_XCreateFontCursor)
1345         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateFontCursor");
1346     _glfw.x11.xlib.CreateIC = (PFN_XCreateIC)
1347         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateIC");
1348     _glfw.x11.xlib.CreateRegion = (PFN_XCreateRegion)
1349         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateRegion");
1350     _glfw.x11.xlib.CreateWindow = (PFN_XCreateWindow)
1351         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateWindow");
1352     _glfw.x11.xlib.DefineCursor = (PFN_XDefineCursor)
1353         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDefineCursor");
1354     _glfw.x11.xlib.DeleteContext = (PFN_XDeleteContext)
1355         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDeleteContext");
1356     _glfw.x11.xlib.DeleteProperty = (PFN_XDeleteProperty)
1357         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDeleteProperty");
1358     _glfw.x11.xlib.DestroyIC = (PFN_XDestroyIC)
1359         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyIC");
1360     _glfw.x11.xlib.DestroyRegion = (PFN_XDestroyRegion)
1361         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyRegion");
1362     _glfw.x11.xlib.DestroyWindow = (PFN_XDestroyWindow)
1363         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyWindow");
1364     _glfw.x11.xlib.DisplayKeycodes = (PFN_XDisplayKeycodes)
1365         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDisplayKeycodes");
1366     _glfw.x11.xlib.EventsQueued = (PFN_XEventsQueued)
1367         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XEventsQueued");
1368     _glfw.x11.xlib.FilterEvent = (PFN_XFilterEvent)
1369         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFilterEvent");
1370     _glfw.x11.xlib.FindContext = (PFN_XFindContext)
1371         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFindContext");
1372     _glfw.x11.xlib.Flush = (PFN_XFlush)
1373         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFlush");
1374     _glfw.x11.xlib.Free = (PFN_XFree)
1375         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFree");
1376     _glfw.x11.xlib.FreeColormap = (PFN_XFreeColormap)
1377         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeColormap");
1378     _glfw.x11.xlib.FreeCursor = (PFN_XFreeCursor)
1379         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeCursor");
1380     _glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData)
1381         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeEventData");
1382     _glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText)
1383         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetErrorText");
1384     _glfw.x11.xlib.GetEventData = (PFN_XGetEventData)
1385         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetEventData");
1386     _glfw.x11.xlib.GetICValues = (PFN_XGetICValues)
1387         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetICValues");
1388     _glfw.x11.xlib.GetIMValues = (PFN_XGetIMValues)
1389         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetIMValues");
1390     _glfw.x11.xlib.GetInputFocus = (PFN_XGetInputFocus)
1391         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetInputFocus");
1392     _glfw.x11.xlib.GetKeyboardMapping = (PFN_XGetKeyboardMapping)
1393         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetKeyboardMapping");
1394     _glfw.x11.xlib.GetScreenSaver = (PFN_XGetScreenSaver)
1395         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetScreenSaver");
1396     _glfw.x11.xlib.GetSelectionOwner = (PFN_XGetSelectionOwner)
1397         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetSelectionOwner");
1398     _glfw.x11.xlib.GetVisualInfo = (PFN_XGetVisualInfo)
1399         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetVisualInfo");
1400     _glfw.x11.xlib.GetWMNormalHints = (PFN_XGetWMNormalHints)
1401         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWMNormalHints");
1402     _glfw.x11.xlib.GetWindowAttributes = (PFN_XGetWindowAttributes)
1403         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWindowAttributes");
1404     _glfw.x11.xlib.GetWindowProperty = (PFN_XGetWindowProperty)
1405         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWindowProperty");
1406     _glfw.x11.xlib.GrabPointer = (PFN_XGrabPointer)
1407         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGrabPointer");
1408     _glfw.x11.xlib.IconifyWindow = (PFN_XIconifyWindow)
1409         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XIconifyWindow");
1410     _glfw.x11.xlib.InternAtom = (PFN_XInternAtom)
1411         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XInternAtom");
1412     _glfw.x11.xlib.LookupString = (PFN_XLookupString)
1413         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XLookupString");
1414     _glfw.x11.xlib.MapRaised = (PFN_XMapRaised)
1415         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMapRaised");
1416     _glfw.x11.xlib.MapWindow = (PFN_XMapWindow)
1417         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMapWindow");
1418     _glfw.x11.xlib.MoveResizeWindow = (PFN_XMoveResizeWindow)
1419         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMoveResizeWindow");
1420     _glfw.x11.xlib.MoveWindow = (PFN_XMoveWindow)
1421         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMoveWindow");
1422     _glfw.x11.xlib.NextEvent = (PFN_XNextEvent)
1423         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XNextEvent");
1424     _glfw.x11.xlib.OpenIM = (PFN_XOpenIM)
1425         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XOpenIM");
1426     _glfw.x11.xlib.PeekEvent = (PFN_XPeekEvent)
1427         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XPeekEvent");
1428     _glfw.x11.xlib.Pending = (PFN_XPending)
1429         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XPending");
1430     _glfw.x11.xlib.QueryExtension = (PFN_XQueryExtension)
1431         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XQueryExtension");
1432     _glfw.x11.xlib.QueryPointer = (PFN_XQueryPointer)
1433         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XQueryPointer");
1434     _glfw.x11.xlib.RaiseWindow = (PFN_XRaiseWindow)
1435         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XRaiseWindow");
1436     _glfw.x11.xlib.RegisterIMInstantiateCallback = (PFN_XRegisterIMInstantiateCallback)
1437         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XRegisterIMInstantiateCallback");
1438     _glfw.x11.xlib.ResizeWindow = (PFN_XResizeWindow)
1439         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XResizeWindow");
1440     _glfw.x11.xlib.ResourceManagerString = (PFN_XResourceManagerString)
1441         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XResourceManagerString");
1442     _glfw.x11.xlib.SaveContext = (PFN_XSaveContext)
1443         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSaveContext");
1444     _glfw.x11.xlib.SelectInput = (PFN_XSelectInput)
1445         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSelectInput");
1446     _glfw.x11.xlib.SendEvent = (PFN_XSendEvent)
1447         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSendEvent");
1448     _glfw.x11.xlib.SetClassHint = (PFN_XSetClassHint)
1449         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetClassHint");
1450     _glfw.x11.xlib.SetErrorHandler = (PFN_XSetErrorHandler)
1451         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetErrorHandler");
1452     _glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus)
1453         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetICFocus");
1454     _glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues)
1455         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetIMValues");
1456     _glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus)
1457         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetInputFocus");
1458     _glfw.x11.xlib.SetLocaleModifiers = (PFN_XSetLocaleModifiers)
1459         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetLocaleModifiers");
1460     _glfw.x11.xlib.SetScreenSaver = (PFN_XSetScreenSaver)
1461         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetScreenSaver");
1462     _glfw.x11.xlib.SetSelectionOwner = (PFN_XSetSelectionOwner)
1463         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetSelectionOwner");
1464     _glfw.x11.xlib.SetWMHints = (PFN_XSetWMHints)
1465         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMHints");
1466     _glfw.x11.xlib.SetWMNormalHints = (PFN_XSetWMNormalHints)
1467         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMNormalHints");
1468     _glfw.x11.xlib.SetWMProtocols = (PFN_XSetWMProtocols)
1469         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMProtocols");
1470     _glfw.x11.xlib.SupportsLocale = (PFN_XSupportsLocale)
1471         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSupportsLocale");
1472     _glfw.x11.xlib.Sync = (PFN_XSync)
1473         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSync");
1474     _glfw.x11.xlib.TranslateCoordinates = (PFN_XTranslateCoordinates)
1475         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XTranslateCoordinates");
1476     _glfw.x11.xlib.UndefineCursor = (PFN_XUndefineCursor)
1477         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUndefineCursor");
1478     _glfw.x11.xlib.UngrabPointer = (PFN_XUngrabPointer)
1479         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUngrabPointer");
1480     _glfw.x11.xlib.UnmapWindow = (PFN_XUnmapWindow)
1481         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnmapWindow");
1482     _glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus)
1483         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnsetICFocus");
1484     _glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual)
1485         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XVisualIDFromVisual");
1486     _glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer)
1487         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XWarpPointer");
1488     _glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard)
1489         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbFreeKeyboard");
1490     _glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames)
1491         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbFreeNames");
1492     _glfw.x11.xkb.GetMap = (PFN_XkbGetMap)
1493         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetMap");
1494     _glfw.x11.xkb.GetNames = (PFN_XkbGetNames)
1495         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetNames");
1496     _glfw.x11.xkb.GetState = (PFN_XkbGetState)
1497         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetState");
1498     _glfw.x11.xkb.KeycodeToKeysym = (PFN_XkbKeycodeToKeysym)
1499         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbKeycodeToKeysym");
1500     _glfw.x11.xkb.QueryExtension = (PFN_XkbQueryExtension)
1501         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbQueryExtension");
1502     _glfw.x11.xkb.SelectEventDetails = (PFN_XkbSelectEventDetails)
1503         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbSelectEventDetails");
1504     _glfw.x11.xkb.SetDetectableAutoRepeat = (PFN_XkbSetDetectableAutoRepeat)
1505         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbSetDetectableAutoRepeat");
1506     _glfw.x11.xrm.DestroyDatabase = (PFN_XrmDestroyDatabase)
1507         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmDestroyDatabase");
1508     _glfw.x11.xrm.GetResource = (PFN_XrmGetResource)
1509         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmGetResource");
1510     _glfw.x11.xrm.GetStringDatabase = (PFN_XrmGetStringDatabase)
1511         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmGetStringDatabase");
1512     _glfw.x11.xrm.UniqueQuark = (PFN_XrmUniqueQuark)
1513         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmUniqueQuark");
1514     _glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback)
1515         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback");
1516     _glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString)
1517         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "Xutf8LookupString");
1518     _glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties)
1519         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "Xutf8SetWMProperties");
1520 
1521     if (_glfw.x11.xlib.utf8LookupString && _glfw.x11.xlib.utf8SetWMProperties)
1522         _glfw.x11.xlib.utf8 = GLFW_TRUE;
1523 
1524     _glfw.x11.screen = DefaultScreen(_glfw.x11.display);
1525     _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen);
1526     _glfw.x11.context = XUniqueContext();
1527 
1528     getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY);
1529 
1530     if (!createEmptyEventPipe())
1531         return GLFW_FALSE;
1532 
1533     if (!initExtensions())
1534         return GLFW_FALSE;
1535 
1536     _glfw.x11.helperWindowHandle = createHelperWindow();
1537     _glfw.x11.hiddenCursorHandle = createHiddenCursor();
1538 
1539     if (XSupportsLocale() && _glfw.x11.xlib.utf8)
1540     {
1541         XSetLocaleModifiers("");
1542 
1543         // If an IM is already present our callback will be called right away
1544         XRegisterIMInstantiateCallback(_glfw.x11.display,
1545                                        NULL, NULL, NULL,
1546                                        inputMethodInstantiateCallback,
1547                                        NULL);
1548     }
1549 
1550     _glfwPollMonitorsX11();
1551     return GLFW_TRUE;
1552 }
1553 
_glfwTerminateX11(void)1554 void _glfwTerminateX11(void)
1555 {
1556     if (_glfw.x11.helperWindowHandle)
1557     {
1558         if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) ==
1559             _glfw.x11.helperWindowHandle)
1560         {
1561             _glfwPushSelectionToManagerX11();
1562         }
1563 
1564         XDestroyWindow(_glfw.x11.display, _glfw.x11.helperWindowHandle);
1565         _glfw.x11.helperWindowHandle = None;
1566     }
1567 
1568     if (_glfw.x11.hiddenCursorHandle)
1569     {
1570         XFreeCursor(_glfw.x11.display, _glfw.x11.hiddenCursorHandle);
1571         _glfw.x11.hiddenCursorHandle = (Cursor) 0;
1572     }
1573 
1574     _glfw_free(_glfw.x11.primarySelectionString);
1575     _glfw_free(_glfw.x11.clipboardString);
1576 
1577     XUnregisterIMInstantiateCallback(_glfw.x11.display,
1578                                      NULL, NULL, NULL,
1579                                      inputMethodInstantiateCallback,
1580                                      NULL);
1581 
1582     if (_glfw.x11.im)
1583     {
1584         XCloseIM(_glfw.x11.im);
1585         _glfw.x11.im = NULL;
1586     }
1587 
1588     if (_glfw.x11.display)
1589     {
1590         XCloseDisplay(_glfw.x11.display);
1591         _glfw.x11.display = NULL;
1592     }
1593 
1594     if (_glfw.x11.x11xcb.handle)
1595     {
1596         _glfwPlatformFreeModule(_glfw.x11.x11xcb.handle);
1597         _glfw.x11.x11xcb.handle = NULL;
1598     }
1599 
1600     if (_glfw.x11.xcursor.handle)
1601     {
1602         _glfwPlatformFreeModule(_glfw.x11.xcursor.handle);
1603         _glfw.x11.xcursor.handle = NULL;
1604     }
1605 
1606     if (_glfw.x11.randr.handle)
1607     {
1608         _glfwPlatformFreeModule(_glfw.x11.randr.handle);
1609         _glfw.x11.randr.handle = NULL;
1610     }
1611 
1612     if (_glfw.x11.xinerama.handle)
1613     {
1614         _glfwPlatformFreeModule(_glfw.x11.xinerama.handle);
1615         _glfw.x11.xinerama.handle = NULL;
1616     }
1617 
1618     if (_glfw.x11.xrender.handle)
1619     {
1620         _glfwPlatformFreeModule(_glfw.x11.xrender.handle);
1621         _glfw.x11.xrender.handle = NULL;
1622     }
1623 
1624     if (_glfw.x11.vidmode.handle)
1625     {
1626         _glfwPlatformFreeModule(_glfw.x11.vidmode.handle);
1627         _glfw.x11.vidmode.handle = NULL;
1628     }
1629 
1630     if (_glfw.x11.xi.handle)
1631     {
1632         _glfwPlatformFreeModule(_glfw.x11.xi.handle);
1633         _glfw.x11.xi.handle = NULL;
1634     }
1635 
1636     _glfwTerminateOSMesa();
1637     // NOTE: These need to be unloaded after XCloseDisplay, as they register
1638     //       cleanup callbacks that get called by that function
1639     _glfwTerminateEGL();
1640     _glfwTerminateGLX();
1641 
1642     if (_glfw.x11.xlib.handle)
1643     {
1644         _glfwPlatformFreeModule(_glfw.x11.xlib.handle);
1645         _glfw.x11.xlib.handle = NULL;
1646     }
1647 
1648     if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1])
1649     {
1650         close(_glfw.x11.emptyEventPipe[0]);
1651         close(_glfw.x11.emptyEventPipe[1]);
1652     }
1653 }
1654 
1655 #endif // _GLFW_X11
1656 
1657