• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef USE_DUMMPY_XINPUT2
641         _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
642             _glfwPlatformGetModuleSymbol(_glfw.x11.xi.handle, "XISelectEvents");
643 #endif
644 
645         if (XQueryExtension(_glfw.x11.display,
646                             "XInputExtension",
647                             &_glfw.x11.xi.majorOpcode,
648                             &_glfw.x11.xi.eventBase,
649                             &_glfw.x11.xi.errorBase))
650         {
651             _glfw.x11.xi.major = 2;
652             _glfw.x11.xi.minor = 0;
653 
654             if (XIQueryVersion(_glfw.x11.display,
655                                &_glfw.x11.xi.major,
656                                &_glfw.x11.xi.minor) == Success)
657             {
658                 _glfw.x11.xi.available = GLFW_TRUE;
659             }
660         }
661     }
662 
663 #if defined(__CYGWIN__)
664     _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so");
665 #elif defined(__OpenBSD__) || defined(__NetBSD__)
666     _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so");
667 #else
668     _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2");
669 #endif
670     if (_glfw.x11.randr.handle)
671     {
672         _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma)
673             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRAllocGamma");
674         _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
675             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeGamma");
676         _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo)
677             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeCrtcInfo");
678         _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
679             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeGamma");
680         _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo)
681             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeOutputInfo");
682         _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources)
683             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeScreenResources");
684         _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma)
685             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcGamma");
686         _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize)
687             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
688         _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo)
689             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcInfo");
690         _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo)
691             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetOutputInfo");
692         _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary)
693             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetOutputPrimary");
694         _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent)
695             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent");
696         _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension)
697             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRQueryExtension");
698         _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion)
699             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRQueryVersion");
700         _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput)
701             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSelectInput");
702         _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig)
703             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSetCrtcConfig");
704         _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma)
705             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSetCrtcGamma");
706         _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration)
707             _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRUpdateConfiguration");
708 
709         if (XRRQueryExtension(_glfw.x11.display,
710                               &_glfw.x11.randr.eventBase,
711                               &_glfw.x11.randr.errorBase))
712         {
713             if (XRRQueryVersion(_glfw.x11.display,
714                                 &_glfw.x11.randr.major,
715                                 &_glfw.x11.randr.minor))
716             {
717                 // The GLFW RandR path requires at least version 1.3
718                 if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3)
719                     _glfw.x11.randr.available = GLFW_TRUE;
720             }
721             else
722             {
723                 _glfwInputError(GLFW_PLATFORM_ERROR,
724                                 "X11: Failed to query RandR version");
725             }
726         }
727     }
728 
729     if (_glfw.x11.randr.available)
730     {
731         XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
732                                                               _glfw.x11.root);
733 
734         if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0]))
735         {
736             // This is likely an older Nvidia driver with broken gamma support
737             // Flag it as useless and fall back to xf86vm gamma, if available
738             _glfw.x11.randr.gammaBroken = GLFW_TRUE;
739         }
740 
741         if (!sr->ncrtc)
742         {
743             // A system without CRTCs is likely a system with broken RandR
744             // Disable the RandR monitor path and fall back to core functions
745             _glfw.x11.randr.monitorBroken = GLFW_TRUE;
746         }
747 
748         XRRFreeScreenResources(sr);
749     }
750 
751     if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
752     {
753         XRRSelectInput(_glfw.x11.display, _glfw.x11.root,
754                        RROutputChangeNotifyMask);
755     }
756 
757 #if defined(__CYGWIN__)
758     _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so");
759 #elif defined(__OpenBSD__) || defined(__NetBSD__)
760     _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so");
761 #else
762     _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1");
763 #endif
764     if (_glfw.x11.xcursor.handle)
765     {
766         _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate)
767             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageCreate");
768         _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy)
769             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
770         _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
771             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
772         _glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme)
773             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorGetTheme");
774         _glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize)
775             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize");
776         _glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage)
777             _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage");
778     }
779 
780 #if defined(__CYGWIN__)
781     _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so");
782 #elif defined(__OpenBSD__) || defined(__NetBSD__)
783     _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so");
784 #else
785     _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1");
786 #endif
787     if (_glfw.x11.xinerama.handle)
788     {
789         _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive)
790             _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaIsActive");
791         _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension)
792             _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaQueryExtension");
793         _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens)
794             _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaQueryScreens");
795 
796         if (XineramaQueryExtension(_glfw.x11.display,
797                                    &_glfw.x11.xinerama.major,
798                                    &_glfw.x11.xinerama.minor))
799         {
800             if (XineramaIsActive(_glfw.x11.display))
801                 _glfw.x11.xinerama.available = GLFW_TRUE;
802         }
803     }
804 
805     _glfw.x11.xkb.major = 1;
806     _glfw.x11.xkb.minor = 0;
807     _glfw.x11.xkb.available =
808         XkbQueryExtension(_glfw.x11.display,
809                           &_glfw.x11.xkb.majorOpcode,
810                           &_glfw.x11.xkb.eventBase,
811                           &_glfw.x11.xkb.errorBase,
812                           &_glfw.x11.xkb.major,
813                           &_glfw.x11.xkb.minor);
814 
815     if (_glfw.x11.xkb.available)
816     {
817         Bool supported;
818 
819         if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported))
820         {
821             if (supported)
822                 _glfw.x11.xkb.detectable = GLFW_TRUE;
823         }
824 
825         XkbStateRec state;
826         if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success)
827             _glfw.x11.xkb.group = (unsigned int)state.group;
828 
829         XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify,
830                               XkbGroupStateMask, XkbGroupStateMask);
831     }
832 
833     if (_glfw.hints.init.x11.xcbVulkanSurface)
834     {
835 #if defined(__CYGWIN__)
836         _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb-1.so");
837 #elif defined(__OpenBSD__) || defined(__NetBSD__)
838         _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so");
839 #else
840         _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1");
841 #endif
842     }
843 
844     if (_glfw.x11.x11xcb.handle)
845     {
846         _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection)
847             _glfwPlatformGetModuleSymbol(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
848     }
849 
850 #if defined(__CYGWIN__)
851     _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so");
852 #elif defined(__OpenBSD__) || defined(__NetBSD__)
853     _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so");
854 #else
855     _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1");
856 #endif
857     if (_glfw.x11.xrender.handle)
858     {
859         _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension)
860             _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderQueryExtension");
861         _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion)
862             _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderQueryVersion");
863         _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat)
864             _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderFindVisualFormat");
865 
866         if (XRenderQueryExtension(_glfw.x11.display,
867                                   &_glfw.x11.xrender.errorBase,
868                                   &_glfw.x11.xrender.eventBase))
869         {
870             if (XRenderQueryVersion(_glfw.x11.display,
871                                     &_glfw.x11.xrender.major,
872                                     &_glfw.x11.xrender.minor))
873             {
874                 _glfw.x11.xrender.available = GLFW_TRUE;
875             }
876         }
877     }
878 
879 #if defined(__CYGWIN__)
880     _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext-6.so");
881 #elif defined(__OpenBSD__) || defined(__NetBSD__)
882     _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so");
883 #else
884     _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6");
885 #endif
886     if (_glfw.x11.xshape.handle)
887     {
888         _glfw.x11.xshape.QueryExtension = (PFN_XShapeQueryExtension)
889             _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeQueryExtension");
890         _glfw.x11.xshape.ShapeCombineRegion = (PFN_XShapeCombineRegion)
891             _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeCombineRegion");
892         _glfw.x11.xshape.QueryVersion = (PFN_XShapeQueryVersion)
893             _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeQueryVersion");
894         _glfw.x11.xshape.ShapeCombineMask = (PFN_XShapeCombineMask)
895             _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeCombineMask");
896 
897         if (XShapeQueryExtension(_glfw.x11.display,
898             &_glfw.x11.xshape.errorBase,
899             &_glfw.x11.xshape.eventBase))
900         {
901             if (XShapeQueryVersion(_glfw.x11.display,
902                 &_glfw.x11.xshape.major,
903                 &_glfw.x11.xshape.minor))
904             {
905                 _glfw.x11.xshape.available = GLFW_TRUE;
906             }
907         }
908     }
909 
910     // Update the key code LUT
911     // FIXME: We should listen to XkbMapNotify events to track changes to
912     // the keyboard mapping.
913     createKeyTables();
914 
915     // String format atoms
916     _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
917     _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
918     _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);
919 
920     // Custom selection property atom
921     _glfw.x11.GLFW_SELECTION =
922         XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False);
923 
924     // ICCCM standard clipboard atoms
925     _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
926     _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
927     _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False);
928     _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False);
929     _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
930 
931     // Clipboard manager atoms
932     _glfw.x11.CLIPBOARD_MANAGER =
933         XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False);
934     _glfw.x11.SAVE_TARGETS =
935         XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
936 
937     // Xdnd (drag and drop) atoms
938     _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False);
939     _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
940     _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
941     _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False);
942     _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
943     _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
944     _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
945     _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
946     _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
947     _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);
948 
949     // ICCCM, EWMH and Motif window property atoms
950     // These can be set safely even without WM support
951     // The EWMH atoms that require WM support are handled in detectEWMH
952     _glfw.x11.WM_PROTOCOLS =
953         XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False);
954     _glfw.x11.WM_STATE =
955         XInternAtom(_glfw.x11.display, "WM_STATE", False);
956     _glfw.x11.WM_DELETE_WINDOW =
957         XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
958     _glfw.x11.NET_SUPPORTED =
959         XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
960     _glfw.x11.NET_SUPPORTING_WM_CHECK =
961         XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
962     _glfw.x11.NET_WM_ICON =
963         XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
964     _glfw.x11.NET_WM_PING =
965         XInternAtom(_glfw.x11.display, "_NET_WM_PING", False);
966     _glfw.x11.NET_WM_PID =
967         XInternAtom(_glfw.x11.display, "_NET_WM_PID", False);
968     _glfw.x11.NET_WM_NAME =
969         XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False);
970     _glfw.x11.NET_WM_ICON_NAME =
971         XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False);
972     _glfw.x11.NET_WM_BYPASS_COMPOSITOR =
973         XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False);
974     _glfw.x11.NET_WM_WINDOW_OPACITY =
975         XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False);
976     _glfw.x11.MOTIF_WM_HINTS =
977         XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);
978 
979     // The compositing manager selection name contains the screen number
980     {
981         char name[32];
982         snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen);
983         _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False);
984     }
985 
986     // Detect whether an EWMH-conformant window manager is running
987     detectEWMH();
988 
989     return GLFW_TRUE;
990 }
991 
992 // Retrieve system content scale via folklore heuristics
993 //
getSystemContentScale(float * xscale,float * yscale)994 static void getSystemContentScale(float* xscale, float* yscale)
995 {
996     // Start by assuming the default X11 DPI
997     // NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it
998     //       would be set to 96, so assume that is the case if we cannot find it
999     float xdpi = 96.f, ydpi = 96.f;
1000 
1001     // NOTE: Basing the scale on Xft.dpi where available should provide the most
1002     //       consistent user experience (matches Qt, Gtk, etc), although not
1003     //       always the most accurate one
1004     char* rms = XResourceManagerString(_glfw.x11.display);
1005     if (rms)
1006     {
1007         XrmDatabase db = XrmGetStringDatabase(rms);
1008         if (db)
1009         {
1010             XrmValue value;
1011             char* type = NULL;
1012 
1013             if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value))
1014             {
1015                 if (type && strcmp(type, "String") == 0)
1016                     xdpi = ydpi = atof(value.addr);
1017             }
1018 
1019             XrmDestroyDatabase(db);
1020         }
1021     }
1022 
1023     *xscale = xdpi / 96.f;
1024     *yscale = ydpi / 96.f;
1025 }
1026 
1027 // Create a blank cursor for hidden and disabled cursor modes
1028 //
createHiddenCursor(void)1029 static Cursor createHiddenCursor(void)
1030 {
1031     unsigned char pixels[16 * 16 * 4] = { 0 };
1032     GLFWimage image = { 16, 16, pixels };
1033     return _glfwCreateNativeCursorX11(&image, 0, 0);
1034 }
1035 
1036 // Create a helper window for IPC
1037 //
createHelperWindow(void)1038 static Window createHelperWindow(void)
1039 {
1040     XSetWindowAttributes wa;
1041     wa.event_mask = PropertyChangeMask;
1042 
1043     return XCreateWindow(_glfw.x11.display, _glfw.x11.root,
1044                          0, 0, 1, 1, 0, 0,
1045                          InputOnly,
1046                          DefaultVisual(_glfw.x11.display, _glfw.x11.screen),
1047                          CWEventMask, &wa);
1048 }
1049 
1050 // Create the pipe for empty events without assumuing the OS has pipe2(2)
1051 //
createEmptyEventPipe(void)1052 static GLFWbool createEmptyEventPipe(void)
1053 {
1054     if (pipe(_glfw.x11.emptyEventPipe) != 0)
1055     {
1056         _glfwInputError(GLFW_PLATFORM_ERROR,
1057                         "X11: Failed to create empty event pipe: %s",
1058                         strerror(errno));
1059         return GLFW_FALSE;
1060     }
1061 
1062     for (int i = 0; i < 2; i++)
1063     {
1064         const int sf = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFL, 0);
1065         const int df = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFD, 0);
1066 
1067         if (sf == -1 || df == -1 ||
1068             fcntl(_glfw.x11.emptyEventPipe[i], F_SETFL, sf | O_NONBLOCK) == -1 ||
1069             fcntl(_glfw.x11.emptyEventPipe[i], F_SETFD, df | FD_CLOEXEC) == -1)
1070         {
1071             _glfwInputError(GLFW_PLATFORM_ERROR,
1072                             "X11: Failed to set flags for empty event pipe: %s",
1073                             strerror(errno));
1074             return GLFW_FALSE;
1075         }
1076     }
1077 
1078     return GLFW_TRUE;
1079 }
1080 
1081 // X error handler
1082 //
errorHandler(Display * display,XErrorEvent * event)1083 static int errorHandler(Display *display, XErrorEvent* event)
1084 {
1085     if (_glfw.x11.display != display)
1086         return 0;
1087 
1088     _glfw.x11.errorCode = event->error_code;
1089     return 0;
1090 }
1091 
1092 
1093 //////////////////////////////////////////////////////////////////////////
1094 //////                       GLFW internal API                      //////
1095 //////////////////////////////////////////////////////////////////////////
1096 
1097 // Sets the X error handler callback
1098 //
_glfwGrabErrorHandlerX11(void)1099 void _glfwGrabErrorHandlerX11(void)
1100 {
1101     assert(_glfw.x11.errorHandler == NULL);
1102     _glfw.x11.errorCode = Success;
1103     _glfw.x11.errorHandler = XSetErrorHandler(errorHandler);
1104 }
1105 
1106 // Clears the X error handler callback
1107 //
_glfwReleaseErrorHandlerX11(void)1108 void _glfwReleaseErrorHandlerX11(void)
1109 {
1110     // Synchronize to make sure all commands are processed
1111     XSync(_glfw.x11.display, False);
1112     XSetErrorHandler(_glfw.x11.errorHandler);
1113     _glfw.x11.errorHandler = NULL;
1114 }
1115 
1116 // Reports the specified error, appending information about the last X error
1117 //
_glfwInputErrorX11(int error,const char * message)1118 void _glfwInputErrorX11(int error, const char* message)
1119 {
1120     char buffer[_GLFW_MESSAGE_SIZE];
1121     XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode,
1122                   buffer, sizeof(buffer));
1123 
1124     _glfwInputError(error, "%s: %s", message, buffer);
1125 }
1126 
1127 // Creates a native cursor object from the specified image and hotspot
1128 //
_glfwCreateNativeCursorX11(const GLFWimage * image,int xhot,int yhot)1129 Cursor _glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot)
1130 {
1131     Cursor cursor;
1132 
1133     if (!_glfw.x11.xcursor.handle)
1134         return None;
1135 
1136     XcursorImage* native = XcursorImageCreate(image->width, image->height);
1137     if (native == NULL)
1138         return None;
1139 
1140     native->xhot = xhot;
1141     native->yhot = yhot;
1142 
1143     unsigned char* source = (unsigned char*) image->pixels;
1144     XcursorPixel* target = native->pixels;
1145 
1146     for (int i = 0;  i < image->width * image->height;  i++, target++, source += 4)
1147     {
1148         unsigned int alpha = source[3];
1149 
1150         *target = (alpha << 24) |
1151                   ((unsigned char) ((source[0] * alpha) / 255) << 16) |
1152                   ((unsigned char) ((source[1] * alpha) / 255) <<  8) |
1153                   ((unsigned char) ((source[2] * alpha) / 255) <<  0);
1154     }
1155 
1156     cursor = XcursorImageLoadCursor(_glfw.x11.display, native);
1157     XcursorImageDestroy(native);
1158 
1159     return cursor;
1160 }
1161 
1162 
1163 //////////////////////////////////////////////////////////////////////////
1164 //////                       GLFW platform API                      //////
1165 //////////////////////////////////////////////////////////////////////////
1166 
_glfwConnectX11(int platformID,_GLFWplatform * platform)1167 GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
1168 {
1169     const _GLFWplatform x11 =
1170     {
1171         .platformID = GLFW_PLATFORM_X11,
1172         .init = _glfwInitX11,
1173         .terminate = _glfwTerminateX11,
1174         .getCursorPos = _glfwGetCursorPosX11,
1175         .setCursorPos = _glfwSetCursorPosX11,
1176         .setCursorMode = _glfwSetCursorModeX11,
1177         .setRawMouseMotion = _glfwSetRawMouseMotionX11,
1178         .rawMouseMotionSupported = _glfwRawMouseMotionSupportedX11,
1179         .createCursor = _glfwCreateCursorX11,
1180         .createStandardCursor = _glfwCreateStandardCursorX11,
1181         .destroyCursor = _glfwDestroyCursorX11,
1182         .setCursor = _glfwSetCursorX11,
1183         .getScancodeName = _glfwGetScancodeNameX11,
1184         .getKeyScancode = _glfwGetKeyScancodeX11,
1185         .setClipboardString = _glfwSetClipboardStringX11,
1186         .getClipboardString = _glfwGetClipboardStringX11,
1187 #if defined(GLFW_BUILD_LINUX_JOYSTICK)
1188         .initJoysticks = _glfwInitJoysticksLinux,
1189         .terminateJoysticks = _glfwTerminateJoysticksLinux,
1190         .pollJoystick = _glfwPollJoystickLinux,
1191         .getMappingName = _glfwGetMappingNameLinux,
1192         .updateGamepadGUID = _glfwUpdateGamepadGUIDLinux,
1193 #else
1194         .initJoysticks = _glfwInitJoysticksNull,
1195         .terminateJoysticks = _glfwTerminateJoysticksNull,
1196         .pollJoystick = _glfwPollJoystickNull,
1197         .getMappingName = _glfwGetMappingNameNull,
1198         .updateGamepadGUID = _glfwUpdateGamepadGUIDNull,
1199 #endif
1200         .freeMonitor = _glfwFreeMonitorX11,
1201         .getMonitorPos = _glfwGetMonitorPosX11,
1202         .getMonitorContentScale = _glfwGetMonitorContentScaleX11,
1203         .getMonitorWorkarea = _glfwGetMonitorWorkareaX11,
1204         .getVideoModes = _glfwGetVideoModesX11,
1205         .getVideoMode = _glfwGetVideoModeX11,
1206         .getGammaRamp = _glfwGetGammaRampX11,
1207         .setGammaRamp = _glfwSetGammaRampX11,
1208         .createWindow = _glfwCreateWindowX11,
1209         .destroyWindow = _glfwDestroyWindowX11,
1210         .setWindowTitle = _glfwSetWindowTitleX11,
1211         .setWindowIcon = _glfwSetWindowIconX11,
1212         .getWindowPos = _glfwGetWindowPosX11,
1213         .setWindowPos = _glfwSetWindowPosX11,
1214         .getWindowSize = _glfwGetWindowSizeX11,
1215         .setWindowSize = _glfwSetWindowSizeX11,
1216         .setWindowSizeLimits = _glfwSetWindowSizeLimitsX11,
1217         .setWindowAspectRatio = _glfwSetWindowAspectRatioX11,
1218         .getFramebufferSize = _glfwGetFramebufferSizeX11,
1219         .getWindowFrameSize = _glfwGetWindowFrameSizeX11,
1220         .getWindowContentScale = _glfwGetWindowContentScaleX11,
1221         .iconifyWindow = _glfwIconifyWindowX11,
1222         .restoreWindow = _glfwRestoreWindowX11,
1223         .maximizeWindow = _glfwMaximizeWindowX11,
1224         .showWindow = _glfwShowWindowX11,
1225         .hideWindow = _glfwHideWindowX11,
1226         .requestWindowAttention = _glfwRequestWindowAttentionX11,
1227         .focusWindow = _glfwFocusWindowX11,
1228         .setWindowMonitor = _glfwSetWindowMonitorX11,
1229         .windowFocused = _glfwWindowFocusedX11,
1230         .windowIconified = _glfwWindowIconifiedX11,
1231         .windowVisible = _glfwWindowVisibleX11,
1232         .windowMaximized = _glfwWindowMaximizedX11,
1233         .windowHovered = _glfwWindowHoveredX11,
1234         .framebufferTransparent = _glfwFramebufferTransparentX11,
1235         .getWindowOpacity = _glfwGetWindowOpacityX11,
1236         .setWindowResizable = _glfwSetWindowResizableX11,
1237         .setWindowDecorated = _glfwSetWindowDecoratedX11,
1238         .setWindowFloating = _glfwSetWindowFloatingX11,
1239         .setWindowOpacity = _glfwSetWindowOpacityX11,
1240         .setWindowMousePassthrough = _glfwSetWindowMousePassthroughX11,
1241         .pollEvents = _glfwPollEventsX11,
1242         .waitEvents = _glfwWaitEventsX11,
1243         .waitEventsTimeout = _glfwWaitEventsTimeoutX11,
1244         .postEmptyEvent = _glfwPostEmptyEventX11,
1245         .getEGLPlatform = _glfwGetEGLPlatformX11,
1246         .getEGLNativeDisplay = _glfwGetEGLNativeDisplayX11,
1247         .getEGLNativeWindow = _glfwGetEGLNativeWindowX11,
1248         .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsX11,
1249         .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportX11,
1250         .createWindowSurface = _glfwCreateWindowSurfaceX11
1251     };
1252 
1253     // HACK: If the application has left the locale as "C" then both wide
1254     //       character text input and explicit UTF-8 input via XIM will break
1255     //       This sets the CTYPE part of the current locale from the environment
1256     //       in the hope that it is set to something more sane than "C"
1257     if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0)
1258         setlocale(LC_CTYPE, "");
1259 
1260 #if defined(__CYGWIN__)
1261     void* module = _glfwPlatformLoadModule("libX11-6.so");
1262 #elif defined(__OpenBSD__) || defined(__NetBSD__)
1263     void* module = _glfwPlatformLoadModule("libX11.so");
1264 #else
1265     void* module = _glfwPlatformLoadModule("libX11.so.6");
1266 #endif
1267     if (!module)
1268     {
1269         if (platformID == GLFW_PLATFORM_X11)
1270             _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib");
1271 
1272         return GLFW_FALSE;
1273     }
1274 
1275     PFN_XInitThreads XInitThreads = (PFN_XInitThreads)
1276         _glfwPlatformGetModuleSymbol(module, "XInitThreads");
1277     PFN_XrmInitialize XrmInitialize = (PFN_XrmInitialize)
1278         _glfwPlatformGetModuleSymbol(module, "XrmInitialize");
1279     PFN_XOpenDisplay XOpenDisplay = (PFN_XOpenDisplay)
1280         _glfwPlatformGetModuleSymbol(module, "XOpenDisplay");
1281     if (!XInitThreads || !XrmInitialize || !XOpenDisplay)
1282     {
1283         if (platformID == GLFW_PLATFORM_X11)
1284             _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to load Xlib entry point");
1285 
1286         _glfwPlatformFreeModule(module);
1287         return GLFW_FALSE;
1288     }
1289 
1290     XInitThreads();
1291     XrmInitialize();
1292 
1293     Display* display = XOpenDisplay(NULL);
1294     if (!display)
1295     {
1296         if (platformID == GLFW_PLATFORM_X11)
1297         {
1298             const char* name = getenv("DISPLAY");
1299             if (name)
1300             {
1301                 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
1302                                 "X11: Failed to open display %s", name);
1303             }
1304             else
1305             {
1306                 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
1307                                 "X11: The DISPLAY environment variable is missing");
1308             }
1309         }
1310 
1311         _glfwPlatformFreeModule(module);
1312         return GLFW_FALSE;
1313     }
1314 
1315     _glfw.x11.display = display;
1316     _glfw.x11.xlib.handle = module;
1317 
1318     *platform = x11;
1319     return GLFW_TRUE;
1320 }
1321 
_glfwInitX11(void)1322 int _glfwInitX11(void)
1323 {
1324     _glfw.x11.xlib.AllocClassHint = (PFN_XAllocClassHint)
1325         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocClassHint");
1326     _glfw.x11.xlib.AllocSizeHints = (PFN_XAllocSizeHints)
1327         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocSizeHints");
1328     _glfw.x11.xlib.AllocWMHints = (PFN_XAllocWMHints)
1329         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XAllocWMHints");
1330     _glfw.x11.xlib.ChangeProperty = (PFN_XChangeProperty)
1331         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XChangeProperty");
1332     _glfw.x11.xlib.ChangeWindowAttributes = (PFN_XChangeWindowAttributes)
1333         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XChangeWindowAttributes");
1334     _glfw.x11.xlib.CheckIfEvent = (PFN_XCheckIfEvent)
1335         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCheckIfEvent");
1336     _glfw.x11.xlib.CheckTypedWindowEvent = (PFN_XCheckTypedWindowEvent)
1337         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCheckTypedWindowEvent");
1338     _glfw.x11.xlib.CloseDisplay = (PFN_XCloseDisplay)
1339         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCloseDisplay");
1340     _glfw.x11.xlib.CloseIM = (PFN_XCloseIM)
1341         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCloseIM");
1342     _glfw.x11.xlib.ConvertSelection = (PFN_XConvertSelection)
1343         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XConvertSelection");
1344     _glfw.x11.xlib.CreateColormap = (PFN_XCreateColormap)
1345         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateColormap");
1346     _glfw.x11.xlib.CreateFontCursor = (PFN_XCreateFontCursor)
1347         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateFontCursor");
1348     _glfw.x11.xlib.CreateIC = (PFN_XCreateIC)
1349         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateIC");
1350     _glfw.x11.xlib.CreateRegion = (PFN_XCreateRegion)
1351         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateRegion");
1352     _glfw.x11.xlib.CreateWindow = (PFN_XCreateWindow)
1353         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XCreateWindow");
1354     _glfw.x11.xlib.DefineCursor = (PFN_XDefineCursor)
1355         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDefineCursor");
1356     _glfw.x11.xlib.DeleteContext = (PFN_XDeleteContext)
1357         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDeleteContext");
1358     _glfw.x11.xlib.DeleteProperty = (PFN_XDeleteProperty)
1359         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDeleteProperty");
1360     _glfw.x11.xlib.DestroyIC = (PFN_XDestroyIC)
1361         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyIC");
1362     _glfw.x11.xlib.DestroyRegion = (PFN_XDestroyRegion)
1363         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyRegion");
1364     _glfw.x11.xlib.DestroyWindow = (PFN_XDestroyWindow)
1365         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDestroyWindow");
1366     _glfw.x11.xlib.DisplayKeycodes = (PFN_XDisplayKeycodes)
1367         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XDisplayKeycodes");
1368     _glfw.x11.xlib.EventsQueued = (PFN_XEventsQueued)
1369         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XEventsQueued");
1370     _glfw.x11.xlib.FilterEvent = (PFN_XFilterEvent)
1371         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFilterEvent");
1372     _glfw.x11.xlib.FindContext = (PFN_XFindContext)
1373         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFindContext");
1374     _glfw.x11.xlib.Flush = (PFN_XFlush)
1375         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFlush");
1376     _glfw.x11.xlib.Free = (PFN_XFree)
1377         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFree");
1378     _glfw.x11.xlib.FreeColormap = (PFN_XFreeColormap)
1379         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeColormap");
1380     _glfw.x11.xlib.FreeCursor = (PFN_XFreeCursor)
1381         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeCursor");
1382     _glfw.x11.xlib.FreeEventData = (PFN_XFreeEventData)
1383         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XFreeEventData");
1384     _glfw.x11.xlib.GetErrorText = (PFN_XGetErrorText)
1385         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetErrorText");
1386     _glfw.x11.xlib.GetEventData = (PFN_XGetEventData)
1387         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetEventData");
1388     _glfw.x11.xlib.GetICValues = (PFN_XGetICValues)
1389         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetICValues");
1390     _glfw.x11.xlib.GetIMValues = (PFN_XGetIMValues)
1391         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetIMValues");
1392     _glfw.x11.xlib.GetInputFocus = (PFN_XGetInputFocus)
1393         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetInputFocus");
1394     _glfw.x11.xlib.GetKeyboardMapping = (PFN_XGetKeyboardMapping)
1395         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetKeyboardMapping");
1396     _glfw.x11.xlib.GetScreenSaver = (PFN_XGetScreenSaver)
1397         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetScreenSaver");
1398     _glfw.x11.xlib.GetSelectionOwner = (PFN_XGetSelectionOwner)
1399         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetSelectionOwner");
1400     _glfw.x11.xlib.GetVisualInfo = (PFN_XGetVisualInfo)
1401         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetVisualInfo");
1402     _glfw.x11.xlib.GetWMNormalHints = (PFN_XGetWMNormalHints)
1403         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWMNormalHints");
1404     _glfw.x11.xlib.GetWindowAttributes = (PFN_XGetWindowAttributes)
1405         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWindowAttributes");
1406     _glfw.x11.xlib.GetWindowProperty = (PFN_XGetWindowProperty)
1407         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetWindowProperty");
1408     _glfw.x11.xlib.GrabPointer = (PFN_XGrabPointer)
1409         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGrabPointer");
1410     _glfw.x11.xlib.IconifyWindow = (PFN_XIconifyWindow)
1411         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XIconifyWindow");
1412     _glfw.x11.xlib.InternAtom = (PFN_XInternAtom)
1413         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XInternAtom");
1414     _glfw.x11.xlib.LookupString = (PFN_XLookupString)
1415         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XLookupString");
1416     _glfw.x11.xlib.MapRaised = (PFN_XMapRaised)
1417         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMapRaised");
1418     _glfw.x11.xlib.MapWindow = (PFN_XMapWindow)
1419         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMapWindow");
1420     _glfw.x11.xlib.MoveResizeWindow = (PFN_XMoveResizeWindow)
1421         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMoveResizeWindow");
1422     _glfw.x11.xlib.MoveWindow = (PFN_XMoveWindow)
1423         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XMoveWindow");
1424     _glfw.x11.xlib.NextEvent = (PFN_XNextEvent)
1425         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XNextEvent");
1426     _glfw.x11.xlib.OpenIM = (PFN_XOpenIM)
1427         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XOpenIM");
1428     _glfw.x11.xlib.PeekEvent = (PFN_XPeekEvent)
1429         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XPeekEvent");
1430     _glfw.x11.xlib.Pending = (PFN_XPending)
1431         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XPending");
1432     _glfw.x11.xlib.QueryExtension = (PFN_XQueryExtension)
1433         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XQueryExtension");
1434     _glfw.x11.xlib.QueryPointer = (PFN_XQueryPointer)
1435         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XQueryPointer");
1436     _glfw.x11.xlib.RaiseWindow = (PFN_XRaiseWindow)
1437         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XRaiseWindow");
1438     _glfw.x11.xlib.RegisterIMInstantiateCallback = (PFN_XRegisterIMInstantiateCallback)
1439         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XRegisterIMInstantiateCallback");
1440     _glfw.x11.xlib.ResizeWindow = (PFN_XResizeWindow)
1441         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XResizeWindow");
1442     _glfw.x11.xlib.ResourceManagerString = (PFN_XResourceManagerString)
1443         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XResourceManagerString");
1444     _glfw.x11.xlib.SaveContext = (PFN_XSaveContext)
1445         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSaveContext");
1446     _glfw.x11.xlib.SelectInput = (PFN_XSelectInput)
1447         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSelectInput");
1448     _glfw.x11.xlib.SendEvent = (PFN_XSendEvent)
1449         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSendEvent");
1450     _glfw.x11.xlib.SetClassHint = (PFN_XSetClassHint)
1451         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetClassHint");
1452     _glfw.x11.xlib.SetErrorHandler = (PFN_XSetErrorHandler)
1453         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetErrorHandler");
1454     _glfw.x11.xlib.SetICFocus = (PFN_XSetICFocus)
1455         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetICFocus");
1456     _glfw.x11.xlib.SetIMValues = (PFN_XSetIMValues)
1457         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetIMValues");
1458     _glfw.x11.xlib.SetInputFocus = (PFN_XSetInputFocus)
1459         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetInputFocus");
1460     _glfw.x11.xlib.SetLocaleModifiers = (PFN_XSetLocaleModifiers)
1461         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetLocaleModifiers");
1462     _glfw.x11.xlib.SetScreenSaver = (PFN_XSetScreenSaver)
1463         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetScreenSaver");
1464     _glfw.x11.xlib.SetSelectionOwner = (PFN_XSetSelectionOwner)
1465         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetSelectionOwner");
1466     _glfw.x11.xlib.SetWMHints = (PFN_XSetWMHints)
1467         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMHints");
1468     _glfw.x11.xlib.SetWMNormalHints = (PFN_XSetWMNormalHints)
1469         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMNormalHints");
1470     _glfw.x11.xlib.SetWMProtocols = (PFN_XSetWMProtocols)
1471         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSetWMProtocols");
1472     _glfw.x11.xlib.SupportsLocale = (PFN_XSupportsLocale)
1473         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSupportsLocale");
1474     _glfw.x11.xlib.Sync = (PFN_XSync)
1475         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XSync");
1476     _glfw.x11.xlib.TranslateCoordinates = (PFN_XTranslateCoordinates)
1477         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XTranslateCoordinates");
1478     _glfw.x11.xlib.UndefineCursor = (PFN_XUndefineCursor)
1479         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUndefineCursor");
1480     _glfw.x11.xlib.UngrabPointer = (PFN_XUngrabPointer)
1481         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUngrabPointer");
1482     _glfw.x11.xlib.UnmapWindow = (PFN_XUnmapWindow)
1483         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnmapWindow");
1484     _glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus)
1485         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnsetICFocus");
1486     _glfw.x11.xlib.VisualIDFromVisual = (PFN_XVisualIDFromVisual)
1487         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XVisualIDFromVisual");
1488     _glfw.x11.xlib.WarpPointer = (PFN_XWarpPointer)
1489         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XWarpPointer");
1490     _glfw.x11.xkb.FreeKeyboard = (PFN_XkbFreeKeyboard)
1491         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbFreeKeyboard");
1492     _glfw.x11.xkb.FreeNames = (PFN_XkbFreeNames)
1493         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbFreeNames");
1494     _glfw.x11.xkb.GetMap = (PFN_XkbGetMap)
1495         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetMap");
1496     _glfw.x11.xkb.GetNames = (PFN_XkbGetNames)
1497         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetNames");
1498     _glfw.x11.xkb.GetState = (PFN_XkbGetState)
1499         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbGetState");
1500     _glfw.x11.xkb.KeycodeToKeysym = (PFN_XkbKeycodeToKeysym)
1501         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbKeycodeToKeysym");
1502     _glfw.x11.xkb.QueryExtension = (PFN_XkbQueryExtension)
1503         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbQueryExtension");
1504     _glfw.x11.xkb.SelectEventDetails = (PFN_XkbSelectEventDetails)
1505         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbSelectEventDetails");
1506     _glfw.x11.xkb.SetDetectableAutoRepeat = (PFN_XkbSetDetectableAutoRepeat)
1507         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XkbSetDetectableAutoRepeat");
1508     _glfw.x11.xrm.DestroyDatabase = (PFN_XrmDestroyDatabase)
1509         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmDestroyDatabase");
1510     _glfw.x11.xrm.GetResource = (PFN_XrmGetResource)
1511         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmGetResource");
1512     _glfw.x11.xrm.GetStringDatabase = (PFN_XrmGetStringDatabase)
1513         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmGetStringDatabase");
1514     _glfw.x11.xrm.UniqueQuark = (PFN_XrmUniqueQuark)
1515         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XrmUniqueQuark");
1516     _glfw.x11.xlib.UnregisterIMInstantiateCallback = (PFN_XUnregisterIMInstantiateCallback)
1517         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XUnregisterIMInstantiateCallback");
1518     _glfw.x11.xlib.utf8LookupString = (PFN_Xutf8LookupString)
1519         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "Xutf8LookupString");
1520     _glfw.x11.xlib.utf8SetWMProperties = (PFN_Xutf8SetWMProperties)
1521         _glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "Xutf8SetWMProperties");
1522 
1523     if (_glfw.x11.xlib.utf8LookupString && _glfw.x11.xlib.utf8SetWMProperties)
1524         _glfw.x11.xlib.utf8 = GLFW_TRUE;
1525 
1526     _glfw.x11.screen = DefaultScreen(_glfw.x11.display);
1527     _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen);
1528     _glfw.x11.context = XUniqueContext();
1529 
1530     getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY);
1531 
1532     if (!createEmptyEventPipe())
1533         return GLFW_FALSE;
1534 
1535     if (!initExtensions())
1536         return GLFW_FALSE;
1537 
1538     _glfw.x11.helperWindowHandle = createHelperWindow();
1539     _glfw.x11.hiddenCursorHandle = createHiddenCursor();
1540 
1541     if (XSupportsLocale() && _glfw.x11.xlib.utf8)
1542     {
1543         XSetLocaleModifiers("");
1544 
1545         // If an IM is already present our callback will be called right away
1546         XRegisterIMInstantiateCallback(_glfw.x11.display,
1547                                        NULL, NULL, NULL,
1548                                        inputMethodInstantiateCallback,
1549                                        NULL);
1550     }
1551 
1552     _glfwPollMonitorsX11();
1553     return GLFW_TRUE;
1554 }
1555 
_glfwTerminateX11(void)1556 void _glfwTerminateX11(void)
1557 {
1558     if (_glfw.x11.helperWindowHandle)
1559     {
1560         if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) ==
1561             _glfw.x11.helperWindowHandle)
1562         {
1563             _glfwPushSelectionToManagerX11();
1564         }
1565 
1566         XDestroyWindow(_glfw.x11.display, _glfw.x11.helperWindowHandle);
1567         _glfw.x11.helperWindowHandle = None;
1568     }
1569 
1570     if (_glfw.x11.hiddenCursorHandle)
1571     {
1572         XFreeCursor(_glfw.x11.display, _glfw.x11.hiddenCursorHandle);
1573         _glfw.x11.hiddenCursorHandle = (Cursor) 0;
1574     }
1575 
1576     _glfw_free(_glfw.x11.primarySelectionString);
1577     _glfw_free(_glfw.x11.clipboardString);
1578 
1579     XUnregisterIMInstantiateCallback(_glfw.x11.display,
1580                                      NULL, NULL, NULL,
1581                                      inputMethodInstantiateCallback,
1582                                      NULL);
1583 
1584     if (_glfw.x11.im)
1585     {
1586         XCloseIM(_glfw.x11.im);
1587         _glfw.x11.im = NULL;
1588     }
1589 
1590     if (_glfw.x11.display)
1591     {
1592         XCloseDisplay(_glfw.x11.display);
1593         _glfw.x11.display = NULL;
1594     }
1595 
1596     if (_glfw.x11.x11xcb.handle)
1597     {
1598         _glfwPlatformFreeModule(_glfw.x11.x11xcb.handle);
1599         _glfw.x11.x11xcb.handle = NULL;
1600     }
1601 
1602     if (_glfw.x11.xcursor.handle)
1603     {
1604         _glfwPlatformFreeModule(_glfw.x11.xcursor.handle);
1605         _glfw.x11.xcursor.handle = NULL;
1606     }
1607 
1608     if (_glfw.x11.randr.handle)
1609     {
1610         _glfwPlatformFreeModule(_glfw.x11.randr.handle);
1611         _glfw.x11.randr.handle = NULL;
1612     }
1613 
1614     if (_glfw.x11.xinerama.handle)
1615     {
1616         _glfwPlatformFreeModule(_glfw.x11.xinerama.handle);
1617         _glfw.x11.xinerama.handle = NULL;
1618     }
1619 
1620     if (_glfw.x11.xrender.handle)
1621     {
1622         _glfwPlatformFreeModule(_glfw.x11.xrender.handle);
1623         _glfw.x11.xrender.handle = NULL;
1624     }
1625 
1626     if (_glfw.x11.vidmode.handle)
1627     {
1628         _glfwPlatformFreeModule(_glfw.x11.vidmode.handle);
1629         _glfw.x11.vidmode.handle = NULL;
1630     }
1631 
1632     if (_glfw.x11.xi.handle)
1633     {
1634         _glfwPlatformFreeModule(_glfw.x11.xi.handle);
1635         _glfw.x11.xi.handle = NULL;
1636     }
1637 
1638     _glfwTerminateOSMesa();
1639     // NOTE: These need to be unloaded after XCloseDisplay, as they register
1640     //       cleanup callbacks that get called by that function
1641     _glfwTerminateEGL();
1642     _glfwTerminateGLX();
1643 
1644     if (_glfw.x11.xlib.handle)
1645     {
1646         _glfwPlatformFreeModule(_glfw.x11.xlib.handle);
1647         _glfw.x11.xlib.handle = NULL;
1648     }
1649 
1650     if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1])
1651     {
1652         close(_glfw.x11.emptyEventPipe[0]);
1653         close(_glfw.x11.emptyEventPipe[1]);
1654     }
1655 }
1656 
1657 #endif // _GLFW_X11
1658 
1659