1b877906bSopenharmony_ci//========================================================================
2b877906bSopenharmony_ci// GLFW 3.5 X11 - www.glfw.org
3b877906bSopenharmony_ci//------------------------------------------------------------------------
4b877906bSopenharmony_ci// Copyright (c) 2002-2006 Marcus Geelnard
5b877906bSopenharmony_ci// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
6b877906bSopenharmony_ci//
7b877906bSopenharmony_ci// This software is provided 'as-is', without any express or implied
8b877906bSopenharmony_ci// warranty. In no event will the authors be held liable for any damages
9b877906bSopenharmony_ci// arising from the use of this software.
10b877906bSopenharmony_ci//
11b877906bSopenharmony_ci// Permission is granted to anyone to use this software for any purpose,
12b877906bSopenharmony_ci// including commercial applications, and to alter it and redistribute it
13b877906bSopenharmony_ci// freely, subject to the following restrictions:
14b877906bSopenharmony_ci//
15b877906bSopenharmony_ci// 1. The origin of this software must not be misrepresented; you must not
16b877906bSopenharmony_ci//    claim that you wrote the original software. If you use this software
17b877906bSopenharmony_ci//    in a product, an acknowledgment in the product documentation would
18b877906bSopenharmony_ci//    be appreciated but is not required.
19b877906bSopenharmony_ci//
20b877906bSopenharmony_ci// 2. Altered source versions must be plainly marked as such, and must not
21b877906bSopenharmony_ci//    be misrepresented as being the original software.
22b877906bSopenharmony_ci//
23b877906bSopenharmony_ci// 3. This notice may not be removed or altered from any source
24b877906bSopenharmony_ci//    distribution.
25b877906bSopenharmony_ci//
26b877906bSopenharmony_ci//========================================================================
27b877906bSopenharmony_ci
28b877906bSopenharmony_ci#include "internal.h"
29b877906bSopenharmony_ci
30b877906bSopenharmony_ci#if defined(_GLFW_X11)
31b877906bSopenharmony_ci
32b877906bSopenharmony_ci#include <X11/cursorfont.h>
33b877906bSopenharmony_ci#include <X11/Xmd.h>
34b877906bSopenharmony_ci
35b877906bSopenharmony_ci#include <poll.h>
36b877906bSopenharmony_ci
37b877906bSopenharmony_ci#include <string.h>
38b877906bSopenharmony_ci#include <stdio.h>
39b877906bSopenharmony_ci#include <stdlib.h>
40b877906bSopenharmony_ci#include <limits.h>
41b877906bSopenharmony_ci#include <errno.h>
42b877906bSopenharmony_ci#include <assert.h>
43b877906bSopenharmony_ci
44b877906bSopenharmony_ci// Action for EWMH client messages
45b877906bSopenharmony_ci#define _NET_WM_STATE_REMOVE        0
46b877906bSopenharmony_ci#define _NET_WM_STATE_ADD           1
47b877906bSopenharmony_ci#define _NET_WM_STATE_TOGGLE        2
48b877906bSopenharmony_ci
49b877906bSopenharmony_ci// Additional mouse button names for XButtonEvent
50b877906bSopenharmony_ci#define Button6            6
51b877906bSopenharmony_ci#define Button7            7
52b877906bSopenharmony_ci
53b877906bSopenharmony_ci// Motif WM hints flags
54b877906bSopenharmony_ci#define MWM_HINTS_DECORATIONS   2
55b877906bSopenharmony_ci#define MWM_DECOR_ALL           1
56b877906bSopenharmony_ci
57b877906bSopenharmony_ci#define _GLFW_XDND_VERSION 5
58b877906bSopenharmony_ci
59b877906bSopenharmony_ci// Wait for event data to arrive on the X11 display socket
60b877906bSopenharmony_ci// This avoids blocking other threads via the per-display Xlib lock that also
61b877906bSopenharmony_ci// covers GLX functions
62b877906bSopenharmony_ci//
63b877906bSopenharmony_cistatic GLFWbool waitForX11Event(double* timeout)
64b877906bSopenharmony_ci{
65b877906bSopenharmony_ci    struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN };
66b877906bSopenharmony_ci
67b877906bSopenharmony_ci    while (!XPending(_glfw.x11.display))
68b877906bSopenharmony_ci    {
69b877906bSopenharmony_ci        if (!_glfwPollPOSIX(&fd, 1, timeout))
70b877906bSopenharmony_ci            return GLFW_FALSE;
71b877906bSopenharmony_ci    }
72b877906bSopenharmony_ci
73b877906bSopenharmony_ci    return GLFW_TRUE;
74b877906bSopenharmony_ci}
75b877906bSopenharmony_ci
76b877906bSopenharmony_ci// Wait for event data to arrive on any event file descriptor
77b877906bSopenharmony_ci// This avoids blocking other threads via the per-display Xlib lock that also
78b877906bSopenharmony_ci// covers GLX functions
79b877906bSopenharmony_ci//
80b877906bSopenharmony_cistatic GLFWbool waitForAnyEvent(double* timeout)
81b877906bSopenharmony_ci{
82b877906bSopenharmony_ci    enum { XLIB_FD, PIPE_FD, INOTIFY_FD };
83b877906bSopenharmony_ci    struct pollfd fds[] =
84b877906bSopenharmony_ci    {
85b877906bSopenharmony_ci        [XLIB_FD] = { ConnectionNumber(_glfw.x11.display), POLLIN },
86b877906bSopenharmony_ci        [PIPE_FD] = { _glfw.x11.emptyEventPipe[0], POLLIN },
87b877906bSopenharmony_ci        [INOTIFY_FD] = { -1, POLLIN }
88b877906bSopenharmony_ci    };
89b877906bSopenharmony_ci
90b877906bSopenharmony_ci#if defined(GLFW_BUILD_LINUX_JOYSTICK)
91b877906bSopenharmony_ci    if (_glfw.joysticksInitialized)
92b877906bSopenharmony_ci        fds[INOTIFY_FD].fd = _glfw.linjs.inotify;
93b877906bSopenharmony_ci#endif
94b877906bSopenharmony_ci
95b877906bSopenharmony_ci    while (!XPending(_glfw.x11.display))
96b877906bSopenharmony_ci    {
97b877906bSopenharmony_ci        if (!_glfwPollPOSIX(fds, sizeof(fds) / sizeof(fds[0]), timeout))
98b877906bSopenharmony_ci            return GLFW_FALSE;
99b877906bSopenharmony_ci
100b877906bSopenharmony_ci        for (int i = 1; i < sizeof(fds) / sizeof(fds[0]); i++)
101b877906bSopenharmony_ci        {
102b877906bSopenharmony_ci            if (fds[i].revents & POLLIN)
103b877906bSopenharmony_ci                return GLFW_TRUE;
104b877906bSopenharmony_ci        }
105b877906bSopenharmony_ci    }
106b877906bSopenharmony_ci
107b877906bSopenharmony_ci    return GLFW_TRUE;
108b877906bSopenharmony_ci}
109b877906bSopenharmony_ci
110b877906bSopenharmony_ci// Writes a byte to the empty event pipe
111b877906bSopenharmony_ci//
112b877906bSopenharmony_cistatic void writeEmptyEvent(void)
113b877906bSopenharmony_ci{
114b877906bSopenharmony_ci    for (;;)
115b877906bSopenharmony_ci    {
116b877906bSopenharmony_ci        const char byte = 0;
117b877906bSopenharmony_ci        const ssize_t result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);
118b877906bSopenharmony_ci        if (result == 1 || (result == -1 && errno != EINTR))
119b877906bSopenharmony_ci            break;
120b877906bSopenharmony_ci    }
121b877906bSopenharmony_ci}
122b877906bSopenharmony_ci
123b877906bSopenharmony_ci// Drains available data from the empty event pipe
124b877906bSopenharmony_ci//
125b877906bSopenharmony_cistatic void drainEmptyEvents(void)
126b877906bSopenharmony_ci{
127b877906bSopenharmony_ci    for (;;)
128b877906bSopenharmony_ci    {
129b877906bSopenharmony_ci        char dummy[64];
130b877906bSopenharmony_ci        const ssize_t result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));
131b877906bSopenharmony_ci        if (result == -1 && errno != EINTR)
132b877906bSopenharmony_ci            break;
133b877906bSopenharmony_ci    }
134b877906bSopenharmony_ci}
135b877906bSopenharmony_ci
136b877906bSopenharmony_ci// Waits until a VisibilityNotify event arrives for the specified window or the
137b877906bSopenharmony_ci// timeout period elapses (ICCCM section 4.2.2)
138b877906bSopenharmony_ci//
139b877906bSopenharmony_cistatic GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
140b877906bSopenharmony_ci{
141b877906bSopenharmony_ci    XEvent dummy;
142b877906bSopenharmony_ci    double timeout = 0.1;
143b877906bSopenharmony_ci
144b877906bSopenharmony_ci    while (!XCheckTypedWindowEvent(_glfw.x11.display,
145b877906bSopenharmony_ci                                   window->x11.handle,
146b877906bSopenharmony_ci                                   VisibilityNotify,
147b877906bSopenharmony_ci                                   &dummy))
148b877906bSopenharmony_ci    {
149b877906bSopenharmony_ci        if (!waitForX11Event(&timeout))
150b877906bSopenharmony_ci            return GLFW_FALSE;
151b877906bSopenharmony_ci    }
152b877906bSopenharmony_ci
153b877906bSopenharmony_ci    return GLFW_TRUE;
154b877906bSopenharmony_ci}
155b877906bSopenharmony_ci
156b877906bSopenharmony_ci// Returns whether the window is iconified
157b877906bSopenharmony_ci//
158b877906bSopenharmony_cistatic int getWindowState(_GLFWwindow* window)
159b877906bSopenharmony_ci{
160b877906bSopenharmony_ci    int result = WithdrawnState;
161b877906bSopenharmony_ci    struct {
162b877906bSopenharmony_ci        CARD32 state;
163b877906bSopenharmony_ci        Window icon;
164b877906bSopenharmony_ci    } *state = NULL;
165b877906bSopenharmony_ci
166b877906bSopenharmony_ci    if (_glfwGetWindowPropertyX11(window->x11.handle,
167b877906bSopenharmony_ci                                  _glfw.x11.WM_STATE,
168b877906bSopenharmony_ci                                  _glfw.x11.WM_STATE,
169b877906bSopenharmony_ci                                  (unsigned char**) &state) >= 2)
170b877906bSopenharmony_ci    {
171b877906bSopenharmony_ci        result = state->state;
172b877906bSopenharmony_ci    }
173b877906bSopenharmony_ci
174b877906bSopenharmony_ci    if (state)
175b877906bSopenharmony_ci        XFree(state);
176b877906bSopenharmony_ci
177b877906bSopenharmony_ci    return result;
178b877906bSopenharmony_ci}
179b877906bSopenharmony_ci
180b877906bSopenharmony_ci// Returns whether the event is a selection event
181b877906bSopenharmony_ci//
182b877906bSopenharmony_cistatic Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
183b877906bSopenharmony_ci{
184b877906bSopenharmony_ci    if (event->xany.window != _glfw.x11.helperWindowHandle)
185b877906bSopenharmony_ci        return False;
186b877906bSopenharmony_ci
187b877906bSopenharmony_ci    return event->type == SelectionRequest ||
188b877906bSopenharmony_ci           event->type == SelectionNotify ||
189b877906bSopenharmony_ci           event->type == SelectionClear;
190b877906bSopenharmony_ci}
191b877906bSopenharmony_ci
192b877906bSopenharmony_ci// Returns whether it is a _NET_FRAME_EXTENTS event for the specified window
193b877906bSopenharmony_ci//
194b877906bSopenharmony_cistatic Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer)
195b877906bSopenharmony_ci{
196b877906bSopenharmony_ci    _GLFWwindow* window = (_GLFWwindow*) pointer;
197b877906bSopenharmony_ci    return event->type == PropertyNotify &&
198b877906bSopenharmony_ci           event->xproperty.state == PropertyNewValue &&
199b877906bSopenharmony_ci           event->xproperty.window == window->x11.handle &&
200b877906bSopenharmony_ci           event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS;
201b877906bSopenharmony_ci}
202b877906bSopenharmony_ci
203b877906bSopenharmony_ci// Returns whether it is a property event for the specified selection transfer
204b877906bSopenharmony_ci//
205b877906bSopenharmony_cistatic Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer pointer)
206b877906bSopenharmony_ci{
207b877906bSopenharmony_ci    XEvent* notification = (XEvent*) pointer;
208b877906bSopenharmony_ci    return event->type == PropertyNotify &&
209b877906bSopenharmony_ci           event->xproperty.state == PropertyNewValue &&
210b877906bSopenharmony_ci           event->xproperty.window == notification->xselection.requestor &&
211b877906bSopenharmony_ci           event->xproperty.atom == notification->xselection.property;
212b877906bSopenharmony_ci}
213b877906bSopenharmony_ci
214b877906bSopenharmony_ci// Translates an X event modifier state mask
215b877906bSopenharmony_ci//
216b877906bSopenharmony_cistatic int translateState(int state)
217b877906bSopenharmony_ci{
218b877906bSopenharmony_ci    int mods = 0;
219b877906bSopenharmony_ci
220b877906bSopenharmony_ci    if (state & ShiftMask)
221b877906bSopenharmony_ci        mods |= GLFW_MOD_SHIFT;
222b877906bSopenharmony_ci    if (state & ControlMask)
223b877906bSopenharmony_ci        mods |= GLFW_MOD_CONTROL;
224b877906bSopenharmony_ci    if (state & Mod1Mask)
225b877906bSopenharmony_ci        mods |= GLFW_MOD_ALT;
226b877906bSopenharmony_ci    if (state & Mod4Mask)
227b877906bSopenharmony_ci        mods |= GLFW_MOD_SUPER;
228b877906bSopenharmony_ci    if (state & LockMask)
229b877906bSopenharmony_ci        mods |= GLFW_MOD_CAPS_LOCK;
230b877906bSopenharmony_ci    if (state & Mod2Mask)
231b877906bSopenharmony_ci        mods |= GLFW_MOD_NUM_LOCK;
232b877906bSopenharmony_ci
233b877906bSopenharmony_ci    return mods;
234b877906bSopenharmony_ci}
235b877906bSopenharmony_ci
236b877906bSopenharmony_ci// Translates an X11 key code to a GLFW key token
237b877906bSopenharmony_ci//
238b877906bSopenharmony_cistatic int translateKey(int scancode)
239b877906bSopenharmony_ci{
240b877906bSopenharmony_ci    // Use the pre-filled LUT (see createKeyTables() in x11_init.c)
241b877906bSopenharmony_ci    if (scancode < 0 || scancode > 255)
242b877906bSopenharmony_ci        return GLFW_KEY_UNKNOWN;
243b877906bSopenharmony_ci
244b877906bSopenharmony_ci    return _glfw.x11.keycodes[scancode];
245b877906bSopenharmony_ci}
246b877906bSopenharmony_ci
247b877906bSopenharmony_ci// Sends an EWMH or ICCCM event to the window manager
248b877906bSopenharmony_ci//
249b877906bSopenharmony_cistatic void sendEventToWM(_GLFWwindow* window, Atom type,
250b877906bSopenharmony_ci                          long a, long b, long c, long d, long e)
251b877906bSopenharmony_ci{
252b877906bSopenharmony_ci    XEvent event = { ClientMessage };
253b877906bSopenharmony_ci    event.xclient.window = window->x11.handle;
254b877906bSopenharmony_ci    event.xclient.format = 32; // Data is 32-bit longs
255b877906bSopenharmony_ci    event.xclient.message_type = type;
256b877906bSopenharmony_ci    event.xclient.data.l[0] = a;
257b877906bSopenharmony_ci    event.xclient.data.l[1] = b;
258b877906bSopenharmony_ci    event.xclient.data.l[2] = c;
259b877906bSopenharmony_ci    event.xclient.data.l[3] = d;
260b877906bSopenharmony_ci    event.xclient.data.l[4] = e;
261b877906bSopenharmony_ci
262b877906bSopenharmony_ci    XSendEvent(_glfw.x11.display, _glfw.x11.root,
263b877906bSopenharmony_ci               False,
264b877906bSopenharmony_ci               SubstructureNotifyMask | SubstructureRedirectMask,
265b877906bSopenharmony_ci               &event);
266b877906bSopenharmony_ci}
267b877906bSopenharmony_ci
268b877906bSopenharmony_ci// Updates the normal hints according to the window settings
269b877906bSopenharmony_ci//
270b877906bSopenharmony_cistatic void updateNormalHints(_GLFWwindow* window, int width, int height)
271b877906bSopenharmony_ci{
272b877906bSopenharmony_ci    XSizeHints* hints = XAllocSizeHints();
273b877906bSopenharmony_ci
274b877906bSopenharmony_ci    long supplied;
275b877906bSopenharmony_ci    XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied);
276b877906bSopenharmony_ci
277b877906bSopenharmony_ci    hints->flags &= ~(PMinSize | PMaxSize | PAspect);
278b877906bSopenharmony_ci
279b877906bSopenharmony_ci    if (!window->monitor)
280b877906bSopenharmony_ci    {
281b877906bSopenharmony_ci        if (window->resizable)
282b877906bSopenharmony_ci        {
283b877906bSopenharmony_ci            if (window->minwidth != GLFW_DONT_CARE &&
284b877906bSopenharmony_ci                window->minheight != GLFW_DONT_CARE)
285b877906bSopenharmony_ci            {
286b877906bSopenharmony_ci                hints->flags |= PMinSize;
287b877906bSopenharmony_ci                hints->min_width = window->minwidth;
288b877906bSopenharmony_ci                hints->min_height = window->minheight;
289b877906bSopenharmony_ci            }
290b877906bSopenharmony_ci
291b877906bSopenharmony_ci            if (window->maxwidth != GLFW_DONT_CARE &&
292b877906bSopenharmony_ci                window->maxheight != GLFW_DONT_CARE)
293b877906bSopenharmony_ci            {
294b877906bSopenharmony_ci                hints->flags |= PMaxSize;
295b877906bSopenharmony_ci                hints->max_width = window->maxwidth;
296b877906bSopenharmony_ci                hints->max_height = window->maxheight;
297b877906bSopenharmony_ci            }
298b877906bSopenharmony_ci
299b877906bSopenharmony_ci            if (window->numer != GLFW_DONT_CARE &&
300b877906bSopenharmony_ci                window->denom != GLFW_DONT_CARE)
301b877906bSopenharmony_ci            {
302b877906bSopenharmony_ci                hints->flags |= PAspect;
303b877906bSopenharmony_ci                hints->min_aspect.x = hints->max_aspect.x = window->numer;
304b877906bSopenharmony_ci                hints->min_aspect.y = hints->max_aspect.y = window->denom;
305b877906bSopenharmony_ci            }
306b877906bSopenharmony_ci        }
307b877906bSopenharmony_ci        else
308b877906bSopenharmony_ci        {
309b877906bSopenharmony_ci            hints->flags |= (PMinSize | PMaxSize);
310b877906bSopenharmony_ci            hints->min_width  = hints->max_width  = width;
311b877906bSopenharmony_ci            hints->min_height = hints->max_height = height;
312b877906bSopenharmony_ci        }
313b877906bSopenharmony_ci    }
314b877906bSopenharmony_ci
315b877906bSopenharmony_ci    XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
316b877906bSopenharmony_ci    XFree(hints);
317b877906bSopenharmony_ci}
318b877906bSopenharmony_ci
319b877906bSopenharmony_ci// Updates the full screen status of the window
320b877906bSopenharmony_ci//
321b877906bSopenharmony_cistatic void updateWindowMode(_GLFWwindow* window)
322b877906bSopenharmony_ci{
323b877906bSopenharmony_ci    if (window->monitor)
324b877906bSopenharmony_ci    {
325b877906bSopenharmony_ci        if (_glfw.x11.xinerama.available &&
326b877906bSopenharmony_ci            _glfw.x11.NET_WM_FULLSCREEN_MONITORS)
327b877906bSopenharmony_ci        {
328b877906bSopenharmony_ci            sendEventToWM(window,
329b877906bSopenharmony_ci                          _glfw.x11.NET_WM_FULLSCREEN_MONITORS,
330b877906bSopenharmony_ci                          window->monitor->x11.index,
331b877906bSopenharmony_ci                          window->monitor->x11.index,
332b877906bSopenharmony_ci                          window->monitor->x11.index,
333b877906bSopenharmony_ci                          window->monitor->x11.index,
334b877906bSopenharmony_ci                          0);
335b877906bSopenharmony_ci        }
336b877906bSopenharmony_ci
337b877906bSopenharmony_ci        if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
338b877906bSopenharmony_ci        {
339b877906bSopenharmony_ci            sendEventToWM(window,
340b877906bSopenharmony_ci                          _glfw.x11.NET_WM_STATE,
341b877906bSopenharmony_ci                          _NET_WM_STATE_ADD,
342b877906bSopenharmony_ci                          _glfw.x11.NET_WM_STATE_FULLSCREEN,
343b877906bSopenharmony_ci                          0, 1, 0);
344b877906bSopenharmony_ci        }
345b877906bSopenharmony_ci        else
346b877906bSopenharmony_ci        {
347b877906bSopenharmony_ci            // This is the butcher's way of removing window decorations
348b877906bSopenharmony_ci            // Setting the override-redirect attribute on a window makes the
349b877906bSopenharmony_ci            // window manager ignore the window completely (ICCCM, section 4)
350b877906bSopenharmony_ci            // The good thing is that this makes undecorated full screen windows
351b877906bSopenharmony_ci            // easy to do; the bad thing is that we have to do everything
352b877906bSopenharmony_ci            // manually and some things (like iconify/restore) won't work at
353b877906bSopenharmony_ci            // all, as those are tasks usually performed by the window manager
354b877906bSopenharmony_ci
355b877906bSopenharmony_ci            XSetWindowAttributes attributes;
356b877906bSopenharmony_ci            attributes.override_redirect = True;
357b877906bSopenharmony_ci            XChangeWindowAttributes(_glfw.x11.display,
358b877906bSopenharmony_ci                                    window->x11.handle,
359b877906bSopenharmony_ci                                    CWOverrideRedirect,
360b877906bSopenharmony_ci                                    &attributes);
361b877906bSopenharmony_ci
362b877906bSopenharmony_ci            window->x11.overrideRedirect = GLFW_TRUE;
363b877906bSopenharmony_ci        }
364b877906bSopenharmony_ci
365b877906bSopenharmony_ci        // Enable compositor bypass
366b877906bSopenharmony_ci        if (!window->x11.transparent)
367b877906bSopenharmony_ci        {
368b877906bSopenharmony_ci            const unsigned long value = 1;
369b877906bSopenharmony_ci
370b877906bSopenharmony_ci            XChangeProperty(_glfw.x11.display,  window->x11.handle,
371b877906bSopenharmony_ci                            _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
372b877906bSopenharmony_ci                            PropModeReplace, (unsigned char*) &value, 1);
373b877906bSopenharmony_ci        }
374b877906bSopenharmony_ci    }
375b877906bSopenharmony_ci    else
376b877906bSopenharmony_ci    {
377b877906bSopenharmony_ci        if (_glfw.x11.xinerama.available &&
378b877906bSopenharmony_ci            _glfw.x11.NET_WM_FULLSCREEN_MONITORS)
379b877906bSopenharmony_ci        {
380b877906bSopenharmony_ci            XDeleteProperty(_glfw.x11.display, window->x11.handle,
381b877906bSopenharmony_ci                            _glfw.x11.NET_WM_FULLSCREEN_MONITORS);
382b877906bSopenharmony_ci        }
383b877906bSopenharmony_ci
384b877906bSopenharmony_ci        if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
385b877906bSopenharmony_ci        {
386b877906bSopenharmony_ci            sendEventToWM(window,
387b877906bSopenharmony_ci                          _glfw.x11.NET_WM_STATE,
388b877906bSopenharmony_ci                          _NET_WM_STATE_REMOVE,
389b877906bSopenharmony_ci                          _glfw.x11.NET_WM_STATE_FULLSCREEN,
390b877906bSopenharmony_ci                          0, 1, 0);
391b877906bSopenharmony_ci        }
392b877906bSopenharmony_ci        else
393b877906bSopenharmony_ci        {
394b877906bSopenharmony_ci            XSetWindowAttributes attributes;
395b877906bSopenharmony_ci            attributes.override_redirect = False;
396b877906bSopenharmony_ci            XChangeWindowAttributes(_glfw.x11.display,
397b877906bSopenharmony_ci                                    window->x11.handle,
398b877906bSopenharmony_ci                                    CWOverrideRedirect,
399b877906bSopenharmony_ci                                    &attributes);
400b877906bSopenharmony_ci
401b877906bSopenharmony_ci            window->x11.overrideRedirect = GLFW_FALSE;
402b877906bSopenharmony_ci        }
403b877906bSopenharmony_ci
404b877906bSopenharmony_ci        // Disable compositor bypass
405b877906bSopenharmony_ci        if (!window->x11.transparent)
406b877906bSopenharmony_ci        {
407b877906bSopenharmony_ci            XDeleteProperty(_glfw.x11.display, window->x11.handle,
408b877906bSopenharmony_ci                            _glfw.x11.NET_WM_BYPASS_COMPOSITOR);
409b877906bSopenharmony_ci        }
410b877906bSopenharmony_ci    }
411b877906bSopenharmony_ci}
412b877906bSopenharmony_ci
413b877906bSopenharmony_ci// Decode a Unicode code point from a UTF-8 stream
414b877906bSopenharmony_ci// Based on cutef8 by Jeff Bezanson (Public Domain)
415b877906bSopenharmony_ci//
416b877906bSopenharmony_cistatic uint32_t decodeUTF8(const char** s)
417b877906bSopenharmony_ci{
418b877906bSopenharmony_ci    uint32_t codepoint = 0, count = 0;
419b877906bSopenharmony_ci    static const uint32_t offsets[] =
420b877906bSopenharmony_ci    {
421b877906bSopenharmony_ci        0x00000000u, 0x00003080u, 0x000e2080u,
422b877906bSopenharmony_ci        0x03c82080u, 0xfa082080u, 0x82082080u
423b877906bSopenharmony_ci    };
424b877906bSopenharmony_ci
425b877906bSopenharmony_ci    do
426b877906bSopenharmony_ci    {
427b877906bSopenharmony_ci        codepoint = (codepoint << 6) + (unsigned char) **s;
428b877906bSopenharmony_ci        (*s)++;
429b877906bSopenharmony_ci        count++;
430b877906bSopenharmony_ci    } while ((**s & 0xc0) == 0x80);
431b877906bSopenharmony_ci
432b877906bSopenharmony_ci    assert(count <= 6);
433b877906bSopenharmony_ci    return codepoint - offsets[count - 1];
434b877906bSopenharmony_ci}
435b877906bSopenharmony_ci
436b877906bSopenharmony_ci// Convert the specified Latin-1 string to UTF-8
437b877906bSopenharmony_ci//
438b877906bSopenharmony_cistatic char* convertLatin1toUTF8(const char* source)
439b877906bSopenharmony_ci{
440b877906bSopenharmony_ci    size_t size = 1;
441b877906bSopenharmony_ci    const char* sp;
442b877906bSopenharmony_ci
443b877906bSopenharmony_ci    for (sp = source;  *sp;  sp++)
444b877906bSopenharmony_ci        size += (*sp & 0x80) ? 2 : 1;
445b877906bSopenharmony_ci
446b877906bSopenharmony_ci    char* target = _glfw_calloc(size, 1);
447b877906bSopenharmony_ci    char* tp = target;
448b877906bSopenharmony_ci
449b877906bSopenharmony_ci    for (sp = source;  *sp;  sp++)
450b877906bSopenharmony_ci        tp += _glfwEncodeUTF8(tp, *sp);
451b877906bSopenharmony_ci
452b877906bSopenharmony_ci    return target;
453b877906bSopenharmony_ci}
454b877906bSopenharmony_ci
455b877906bSopenharmony_ci// Updates the cursor image according to its cursor mode
456b877906bSopenharmony_ci//
457b877906bSopenharmony_cistatic void updateCursorImage(_GLFWwindow* window)
458b877906bSopenharmony_ci{
459b877906bSopenharmony_ci    if (window->cursorMode == GLFW_CURSOR_NORMAL ||
460b877906bSopenharmony_ci        window->cursorMode == GLFW_CURSOR_CAPTURED)
461b877906bSopenharmony_ci    {
462b877906bSopenharmony_ci        if (window->cursor)
463b877906bSopenharmony_ci        {
464b877906bSopenharmony_ci            XDefineCursor(_glfw.x11.display, window->x11.handle,
465b877906bSopenharmony_ci                          window->cursor->x11.handle);
466b877906bSopenharmony_ci        }
467b877906bSopenharmony_ci        else
468b877906bSopenharmony_ci            XUndefineCursor(_glfw.x11.display, window->x11.handle);
469b877906bSopenharmony_ci    }
470b877906bSopenharmony_ci    else
471b877906bSopenharmony_ci    {
472b877906bSopenharmony_ci        XDefineCursor(_glfw.x11.display, window->x11.handle,
473b877906bSopenharmony_ci                      _glfw.x11.hiddenCursorHandle);
474b877906bSopenharmony_ci    }
475b877906bSopenharmony_ci}
476b877906bSopenharmony_ci
477b877906bSopenharmony_ci// Grabs the cursor and confines it to the window
478b877906bSopenharmony_ci//
479b877906bSopenharmony_cistatic void captureCursor(_GLFWwindow* window)
480b877906bSopenharmony_ci{
481b877906bSopenharmony_ci    XGrabPointer(_glfw.x11.display, window->x11.handle, True,
482b877906bSopenharmony_ci                 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
483b877906bSopenharmony_ci                 GrabModeAsync, GrabModeAsync,
484b877906bSopenharmony_ci                 window->x11.handle,
485b877906bSopenharmony_ci                 None,
486b877906bSopenharmony_ci                 CurrentTime);
487b877906bSopenharmony_ci}
488b877906bSopenharmony_ci
489b877906bSopenharmony_ci// Ungrabs the cursor
490b877906bSopenharmony_ci//
491b877906bSopenharmony_cistatic void releaseCursor(void)
492b877906bSopenharmony_ci{
493b877906bSopenharmony_ci    XUngrabPointer(_glfw.x11.display, CurrentTime);
494b877906bSopenharmony_ci}
495b877906bSopenharmony_ci
496b877906bSopenharmony_ci// Enable XI2 raw mouse motion events
497b877906bSopenharmony_ci//
498b877906bSopenharmony_cistatic void enableRawMouseMotion(_GLFWwindow* window)
499b877906bSopenharmony_ci{
500b877906bSopenharmony_ci    XIEventMask em;
501b877906bSopenharmony_ci    unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
502b877906bSopenharmony_ci
503b877906bSopenharmony_ci    em.deviceid = XIAllMasterDevices;
504b877906bSopenharmony_ci    em.mask_len = sizeof(mask);
505b877906bSopenharmony_ci    em.mask = mask;
506b877906bSopenharmony_ci    XISetMask(mask, XI_RawMotion);
507b877906bSopenharmony_ci
508b877906bSopenharmony_ci    XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
509b877906bSopenharmony_ci}
510b877906bSopenharmony_ci
511b877906bSopenharmony_ci// Disable XI2 raw mouse motion events
512b877906bSopenharmony_ci//
513b877906bSopenharmony_cistatic void disableRawMouseMotion(_GLFWwindow* window)
514b877906bSopenharmony_ci{
515b877906bSopenharmony_ci    XIEventMask em;
516b877906bSopenharmony_ci    unsigned char mask[] = { 0 };
517b877906bSopenharmony_ci
518b877906bSopenharmony_ci    em.deviceid = XIAllMasterDevices;
519b877906bSopenharmony_ci    em.mask_len = sizeof(mask);
520b877906bSopenharmony_ci    em.mask = mask;
521b877906bSopenharmony_ci
522b877906bSopenharmony_ci    XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1);
523b877906bSopenharmony_ci}
524b877906bSopenharmony_ci
525b877906bSopenharmony_ci// Apply disabled cursor mode to a focused window
526b877906bSopenharmony_ci//
527b877906bSopenharmony_cistatic void disableCursor(_GLFWwindow* window)
528b877906bSopenharmony_ci{
529b877906bSopenharmony_ci    if (window->rawMouseMotion)
530b877906bSopenharmony_ci        enableRawMouseMotion(window);
531b877906bSopenharmony_ci
532b877906bSopenharmony_ci    _glfw.x11.disabledCursorWindow = window;
533b877906bSopenharmony_ci    _glfwGetCursorPosX11(window,
534b877906bSopenharmony_ci                         &_glfw.x11.restoreCursorPosX,
535b877906bSopenharmony_ci                         &_glfw.x11.restoreCursorPosY);
536b877906bSopenharmony_ci    updateCursorImage(window);
537b877906bSopenharmony_ci    _glfwCenterCursorInContentArea(window);
538b877906bSopenharmony_ci    captureCursor(window);
539b877906bSopenharmony_ci}
540b877906bSopenharmony_ci
541b877906bSopenharmony_ci// Exit disabled cursor mode for the specified window
542b877906bSopenharmony_ci//
543b877906bSopenharmony_cistatic void enableCursor(_GLFWwindow* window)
544b877906bSopenharmony_ci{
545b877906bSopenharmony_ci    if (window->rawMouseMotion)
546b877906bSopenharmony_ci        disableRawMouseMotion(window);
547b877906bSopenharmony_ci
548b877906bSopenharmony_ci    _glfw.x11.disabledCursorWindow = NULL;
549b877906bSopenharmony_ci    releaseCursor();
550b877906bSopenharmony_ci    _glfwSetCursorPosX11(window,
551b877906bSopenharmony_ci                         _glfw.x11.restoreCursorPosX,
552b877906bSopenharmony_ci                         _glfw.x11.restoreCursorPosY);
553b877906bSopenharmony_ci    updateCursorImage(window);
554b877906bSopenharmony_ci}
555b877906bSopenharmony_ci
556b877906bSopenharmony_ci// Clear its handle when the input context has been destroyed
557b877906bSopenharmony_ci//
558b877906bSopenharmony_cistatic void inputContextDestroyCallback(XIC ic, XPointer clientData, XPointer callData)
559b877906bSopenharmony_ci{
560b877906bSopenharmony_ci    _GLFWwindow* window = (_GLFWwindow*) clientData;
561b877906bSopenharmony_ci    window->x11.ic = NULL;
562b877906bSopenharmony_ci}
563b877906bSopenharmony_ci
564b877906bSopenharmony_ci// Create the X11 window (and its colormap)
565b877906bSopenharmony_ci//
566b877906bSopenharmony_cistatic GLFWbool createNativeWindow(_GLFWwindow* window,
567b877906bSopenharmony_ci                                   const _GLFWwndconfig* wndconfig,
568b877906bSopenharmony_ci                                   Visual* visual, int depth)
569b877906bSopenharmony_ci{
570b877906bSopenharmony_ci    int width = wndconfig->width;
571b877906bSopenharmony_ci    int height = wndconfig->height;
572b877906bSopenharmony_ci
573b877906bSopenharmony_ci    if (wndconfig->scaleToMonitor)
574b877906bSopenharmony_ci    {
575b877906bSopenharmony_ci        width *= _glfw.x11.contentScaleX;
576b877906bSopenharmony_ci        height *= _glfw.x11.contentScaleY;
577b877906bSopenharmony_ci    }
578b877906bSopenharmony_ci
579b877906bSopenharmony_ci    int xpos = 0, ypos = 0;
580b877906bSopenharmony_ci
581b877906bSopenharmony_ci    if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
582b877906bSopenharmony_ci    {
583b877906bSopenharmony_ci        xpos = wndconfig->xpos;
584b877906bSopenharmony_ci        ypos = wndconfig->ypos;
585b877906bSopenharmony_ci    }
586b877906bSopenharmony_ci
587b877906bSopenharmony_ci    // Create a colormap based on the visual used by the current context
588b877906bSopenharmony_ci    window->x11.colormap = XCreateColormap(_glfw.x11.display,
589b877906bSopenharmony_ci                                           _glfw.x11.root,
590b877906bSopenharmony_ci                                           visual,
591b877906bSopenharmony_ci                                           AllocNone);
592b877906bSopenharmony_ci
593b877906bSopenharmony_ci    window->x11.transparent = _glfwIsVisualTransparentX11(visual);
594b877906bSopenharmony_ci
595b877906bSopenharmony_ci    XSetWindowAttributes wa = { 0 };
596b877906bSopenharmony_ci    wa.colormap = window->x11.colormap;
597b877906bSopenharmony_ci    wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
598b877906bSopenharmony_ci                    PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
599b877906bSopenharmony_ci                    ExposureMask | FocusChangeMask | VisibilityChangeMask |
600b877906bSopenharmony_ci                    EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
601b877906bSopenharmony_ci
602b877906bSopenharmony_ci    _glfwGrabErrorHandlerX11();
603b877906bSopenharmony_ci
604b877906bSopenharmony_ci    window->x11.parent = _glfw.x11.root;
605b877906bSopenharmony_ci    window->x11.handle = XCreateWindow(_glfw.x11.display,
606b877906bSopenharmony_ci                                       _glfw.x11.root,
607b877906bSopenharmony_ci                                       xpos, ypos,
608b877906bSopenharmony_ci                                       width, height,
609b877906bSopenharmony_ci                                       0,      // Border width
610b877906bSopenharmony_ci                                       depth,  // Color depth
611b877906bSopenharmony_ci                                       InputOutput,
612b877906bSopenharmony_ci                                       visual,
613b877906bSopenharmony_ci                                       CWBorderPixel | CWColormap | CWEventMask,
614b877906bSopenharmony_ci                                       &wa);
615b877906bSopenharmony_ci
616b877906bSopenharmony_ci    _glfwReleaseErrorHandlerX11();
617b877906bSopenharmony_ci
618b877906bSopenharmony_ci    if (!window->x11.handle)
619b877906bSopenharmony_ci    {
620b877906bSopenharmony_ci        _glfwInputErrorX11(GLFW_PLATFORM_ERROR,
621b877906bSopenharmony_ci                           "X11: Failed to create window");
622b877906bSopenharmony_ci        return GLFW_FALSE;
623b877906bSopenharmony_ci    }
624b877906bSopenharmony_ci
625b877906bSopenharmony_ci    XSaveContext(_glfw.x11.display,
626b877906bSopenharmony_ci                 window->x11.handle,
627b877906bSopenharmony_ci                 _glfw.x11.context,
628b877906bSopenharmony_ci                 (XPointer) window);
629b877906bSopenharmony_ci
630b877906bSopenharmony_ci    if (!wndconfig->decorated)
631b877906bSopenharmony_ci        _glfwSetWindowDecoratedX11(window, GLFW_FALSE);
632b877906bSopenharmony_ci
633b877906bSopenharmony_ci    if (_glfw.x11.NET_WM_STATE && !window->monitor)
634b877906bSopenharmony_ci    {
635b877906bSopenharmony_ci        Atom states[3];
636b877906bSopenharmony_ci        int count = 0;
637b877906bSopenharmony_ci
638b877906bSopenharmony_ci        if (wndconfig->floating)
639b877906bSopenharmony_ci        {
640b877906bSopenharmony_ci            if (_glfw.x11.NET_WM_STATE_ABOVE)
641b877906bSopenharmony_ci                states[count++] = _glfw.x11.NET_WM_STATE_ABOVE;
642b877906bSopenharmony_ci        }
643b877906bSopenharmony_ci
644b877906bSopenharmony_ci        if (wndconfig->maximized)
645b877906bSopenharmony_ci        {
646b877906bSopenharmony_ci            if (_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
647b877906bSopenharmony_ci                _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
648b877906bSopenharmony_ci            {
649b877906bSopenharmony_ci                states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT;
650b877906bSopenharmony_ci                states[count++] = _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ;
651b877906bSopenharmony_ci                window->x11.maximized = GLFW_TRUE;
652b877906bSopenharmony_ci            }
653b877906bSopenharmony_ci        }
654b877906bSopenharmony_ci
655b877906bSopenharmony_ci        if (count)
656b877906bSopenharmony_ci        {
657b877906bSopenharmony_ci            XChangeProperty(_glfw.x11.display, window->x11.handle,
658b877906bSopenharmony_ci                            _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
659b877906bSopenharmony_ci                            PropModeReplace, (unsigned char*) states, count);
660b877906bSopenharmony_ci        }
661b877906bSopenharmony_ci    }
662b877906bSopenharmony_ci
663b877906bSopenharmony_ci    // Declare the WM protocols supported by GLFW
664b877906bSopenharmony_ci    {
665b877906bSopenharmony_ci        Atom protocols[] =
666b877906bSopenharmony_ci        {
667b877906bSopenharmony_ci            _glfw.x11.WM_DELETE_WINDOW,
668b877906bSopenharmony_ci            _glfw.x11.NET_WM_PING
669b877906bSopenharmony_ci        };
670b877906bSopenharmony_ci
671b877906bSopenharmony_ci        XSetWMProtocols(_glfw.x11.display, window->x11.handle,
672b877906bSopenharmony_ci                        protocols, sizeof(protocols) / sizeof(Atom));
673b877906bSopenharmony_ci    }
674b877906bSopenharmony_ci
675b877906bSopenharmony_ci    // Declare our PID
676b877906bSopenharmony_ci    {
677b877906bSopenharmony_ci        const long pid = getpid();
678b877906bSopenharmony_ci
679b877906bSopenharmony_ci        XChangeProperty(_glfw.x11.display,  window->x11.handle,
680b877906bSopenharmony_ci                        _glfw.x11.NET_WM_PID, XA_CARDINAL, 32,
681b877906bSopenharmony_ci                        PropModeReplace,
682b877906bSopenharmony_ci                        (unsigned char*) &pid, 1);
683b877906bSopenharmony_ci    }
684b877906bSopenharmony_ci
685b877906bSopenharmony_ci    if (_glfw.x11.NET_WM_WINDOW_TYPE && _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL)
686b877906bSopenharmony_ci    {
687b877906bSopenharmony_ci        Atom type = _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL;
688b877906bSopenharmony_ci        XChangeProperty(_glfw.x11.display,  window->x11.handle,
689b877906bSopenharmony_ci                        _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32,
690b877906bSopenharmony_ci                        PropModeReplace, (unsigned char*) &type, 1);
691b877906bSopenharmony_ci    }
692b877906bSopenharmony_ci
693b877906bSopenharmony_ci    // Set ICCCM WM_HINTS property
694b877906bSopenharmony_ci    {
695b877906bSopenharmony_ci        XWMHints* hints = XAllocWMHints();
696b877906bSopenharmony_ci        if (!hints)
697b877906bSopenharmony_ci        {
698b877906bSopenharmony_ci            _glfwInputError(GLFW_OUT_OF_MEMORY,
699b877906bSopenharmony_ci                            "X11: Failed to allocate WM hints");
700b877906bSopenharmony_ci            return GLFW_FALSE;
701b877906bSopenharmony_ci        }
702b877906bSopenharmony_ci
703b877906bSopenharmony_ci        hints->flags = StateHint;
704b877906bSopenharmony_ci        hints->initial_state = NormalState;
705b877906bSopenharmony_ci
706b877906bSopenharmony_ci        XSetWMHints(_glfw.x11.display, window->x11.handle, hints);
707b877906bSopenharmony_ci        XFree(hints);
708b877906bSopenharmony_ci    }
709b877906bSopenharmony_ci
710b877906bSopenharmony_ci    // Set ICCCM WM_NORMAL_HINTS property
711b877906bSopenharmony_ci    {
712b877906bSopenharmony_ci        XSizeHints* hints = XAllocSizeHints();
713b877906bSopenharmony_ci        if (!hints)
714b877906bSopenharmony_ci        {
715b877906bSopenharmony_ci            _glfwInputError(GLFW_OUT_OF_MEMORY, "X11: Failed to allocate size hints");
716b877906bSopenharmony_ci            return GLFW_FALSE;
717b877906bSopenharmony_ci        }
718b877906bSopenharmony_ci
719b877906bSopenharmony_ci        if (!wndconfig->resizable)
720b877906bSopenharmony_ci        {
721b877906bSopenharmony_ci            hints->flags |= (PMinSize | PMaxSize);
722b877906bSopenharmony_ci            hints->min_width  = hints->max_width  = width;
723b877906bSopenharmony_ci            hints->min_height = hints->max_height = height;
724b877906bSopenharmony_ci        }
725b877906bSopenharmony_ci
726b877906bSopenharmony_ci        // HACK: Explicitly setting PPosition to any value causes some WMs, notably
727b877906bSopenharmony_ci        //       Compiz and Metacity, to honor the position of unmapped windows
728b877906bSopenharmony_ci        if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
729b877906bSopenharmony_ci        {
730b877906bSopenharmony_ci            hints->flags |= PPosition;
731b877906bSopenharmony_ci            hints->x = 0;
732b877906bSopenharmony_ci            hints->y = 0;
733b877906bSopenharmony_ci        }
734b877906bSopenharmony_ci
735b877906bSopenharmony_ci        hints->flags |= PWinGravity;
736b877906bSopenharmony_ci        hints->win_gravity = StaticGravity;
737b877906bSopenharmony_ci
738b877906bSopenharmony_ci        XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
739b877906bSopenharmony_ci        XFree(hints);
740b877906bSopenharmony_ci    }
741b877906bSopenharmony_ci
742b877906bSopenharmony_ci    // Set ICCCM WM_CLASS property
743b877906bSopenharmony_ci    {
744b877906bSopenharmony_ci        XClassHint* hint = XAllocClassHint();
745b877906bSopenharmony_ci
746b877906bSopenharmony_ci        if (strlen(wndconfig->x11.instanceName) &&
747b877906bSopenharmony_ci            strlen(wndconfig->x11.className))
748b877906bSopenharmony_ci        {
749b877906bSopenharmony_ci            hint->res_name = (char*) wndconfig->x11.instanceName;
750b877906bSopenharmony_ci            hint->res_class = (char*) wndconfig->x11.className;
751b877906bSopenharmony_ci        }
752b877906bSopenharmony_ci        else
753b877906bSopenharmony_ci        {
754b877906bSopenharmony_ci            const char* resourceName = getenv("RESOURCE_NAME");
755b877906bSopenharmony_ci            if (resourceName && strlen(resourceName))
756b877906bSopenharmony_ci                hint->res_name = (char*) resourceName;
757b877906bSopenharmony_ci            else if (strlen(wndconfig->title))
758b877906bSopenharmony_ci                hint->res_name = (char*) wndconfig->title;
759b877906bSopenharmony_ci            else
760b877906bSopenharmony_ci                hint->res_name = (char*) "glfw-application";
761b877906bSopenharmony_ci
762b877906bSopenharmony_ci            if (strlen(wndconfig->title))
763b877906bSopenharmony_ci                hint->res_class = (char*) wndconfig->title;
764b877906bSopenharmony_ci            else
765b877906bSopenharmony_ci                hint->res_class = (char*) "GLFW-Application";
766b877906bSopenharmony_ci        }
767b877906bSopenharmony_ci
768b877906bSopenharmony_ci        XSetClassHint(_glfw.x11.display, window->x11.handle, hint);
769b877906bSopenharmony_ci        XFree(hint);
770b877906bSopenharmony_ci    }
771b877906bSopenharmony_ci
772b877906bSopenharmony_ci    // Announce support for Xdnd (drag and drop)
773b877906bSopenharmony_ci    {
774b877906bSopenharmony_ci        const Atom version = _GLFW_XDND_VERSION;
775b877906bSopenharmony_ci        XChangeProperty(_glfw.x11.display, window->x11.handle,
776b877906bSopenharmony_ci                        _glfw.x11.XdndAware, XA_ATOM, 32,
777b877906bSopenharmony_ci                        PropModeReplace, (unsigned char*) &version, 1);
778b877906bSopenharmony_ci    }
779b877906bSopenharmony_ci
780b877906bSopenharmony_ci    if (_glfw.x11.im)
781b877906bSopenharmony_ci        _glfwCreateInputContextX11(window);
782b877906bSopenharmony_ci
783b877906bSopenharmony_ci    _glfwSetWindowTitleX11(window, wndconfig->title);
784b877906bSopenharmony_ci    _glfwGetWindowPosX11(window, &window->x11.xpos, &window->x11.ypos);
785b877906bSopenharmony_ci    _glfwGetWindowSizeX11(window, &window->x11.width, &window->x11.height);
786b877906bSopenharmony_ci
787b877906bSopenharmony_ci    return GLFW_TRUE;
788b877906bSopenharmony_ci}
789b877906bSopenharmony_ci
790b877906bSopenharmony_ci// Set the specified property to the selection converted to the requested target
791b877906bSopenharmony_ci//
792b877906bSopenharmony_cistatic Atom writeTargetToProperty(const XSelectionRequestEvent* request)
793b877906bSopenharmony_ci{
794b877906bSopenharmony_ci    char* selectionString = NULL;
795b877906bSopenharmony_ci    const Atom formats[] = { _glfw.x11.UTF8_STRING, XA_STRING };
796b877906bSopenharmony_ci    const int formatCount = sizeof(formats) / sizeof(formats[0]);
797b877906bSopenharmony_ci
798b877906bSopenharmony_ci    if (request->selection == _glfw.x11.PRIMARY)
799b877906bSopenharmony_ci        selectionString = _glfw.x11.primarySelectionString;
800b877906bSopenharmony_ci    else
801b877906bSopenharmony_ci        selectionString = _glfw.x11.clipboardString;
802b877906bSopenharmony_ci
803b877906bSopenharmony_ci    if (request->property == None)
804b877906bSopenharmony_ci    {
805b877906bSopenharmony_ci        // The requester is a legacy client (ICCCM section 2.2)
806b877906bSopenharmony_ci        // We don't support legacy clients, so fail here
807b877906bSopenharmony_ci        return None;
808b877906bSopenharmony_ci    }
809b877906bSopenharmony_ci
810b877906bSopenharmony_ci    if (request->target == _glfw.x11.TARGETS)
811b877906bSopenharmony_ci    {
812b877906bSopenharmony_ci        // The list of supported targets was requested
813b877906bSopenharmony_ci
814b877906bSopenharmony_ci        const Atom targets[] = { _glfw.x11.TARGETS,
815b877906bSopenharmony_ci                                 _glfw.x11.MULTIPLE,
816b877906bSopenharmony_ci                                 _glfw.x11.UTF8_STRING,
817b877906bSopenharmony_ci                                 XA_STRING };
818b877906bSopenharmony_ci
819b877906bSopenharmony_ci        XChangeProperty(_glfw.x11.display,
820b877906bSopenharmony_ci                        request->requestor,
821b877906bSopenharmony_ci                        request->property,
822b877906bSopenharmony_ci                        XA_ATOM,
823b877906bSopenharmony_ci                        32,
824b877906bSopenharmony_ci                        PropModeReplace,
825b877906bSopenharmony_ci                        (unsigned char*) targets,
826b877906bSopenharmony_ci                        sizeof(targets) / sizeof(targets[0]));
827b877906bSopenharmony_ci
828b877906bSopenharmony_ci        return request->property;
829b877906bSopenharmony_ci    }
830b877906bSopenharmony_ci
831b877906bSopenharmony_ci    if (request->target == _glfw.x11.MULTIPLE)
832b877906bSopenharmony_ci    {
833b877906bSopenharmony_ci        // Multiple conversions were requested
834b877906bSopenharmony_ci
835b877906bSopenharmony_ci        Atom* targets;
836b877906bSopenharmony_ci        const unsigned long count =
837b877906bSopenharmony_ci            _glfwGetWindowPropertyX11(request->requestor,
838b877906bSopenharmony_ci                                      request->property,
839b877906bSopenharmony_ci                                      _glfw.x11.ATOM_PAIR,
840b877906bSopenharmony_ci                                      (unsigned char**) &targets);
841b877906bSopenharmony_ci
842b877906bSopenharmony_ci        for (unsigned long i = 0;  i < count;  i += 2)
843b877906bSopenharmony_ci        {
844b877906bSopenharmony_ci            int j;
845b877906bSopenharmony_ci
846b877906bSopenharmony_ci            for (j = 0;  j < formatCount;  j++)
847b877906bSopenharmony_ci            {
848b877906bSopenharmony_ci                if (targets[i] == formats[j])
849b877906bSopenharmony_ci                    break;
850b877906bSopenharmony_ci            }
851b877906bSopenharmony_ci
852b877906bSopenharmony_ci            if (j < formatCount)
853b877906bSopenharmony_ci            {
854b877906bSopenharmony_ci                XChangeProperty(_glfw.x11.display,
855b877906bSopenharmony_ci                                request->requestor,
856b877906bSopenharmony_ci                                targets[i + 1],
857b877906bSopenharmony_ci                                targets[i],
858b877906bSopenharmony_ci                                8,
859b877906bSopenharmony_ci                                PropModeReplace,
860b877906bSopenharmony_ci                                (unsigned char *) selectionString,
861b877906bSopenharmony_ci                                strlen(selectionString));
862b877906bSopenharmony_ci            }
863b877906bSopenharmony_ci            else
864b877906bSopenharmony_ci                targets[i + 1] = None;
865b877906bSopenharmony_ci        }
866b877906bSopenharmony_ci
867b877906bSopenharmony_ci        XChangeProperty(_glfw.x11.display,
868b877906bSopenharmony_ci                        request->requestor,
869b877906bSopenharmony_ci                        request->property,
870b877906bSopenharmony_ci                        _glfw.x11.ATOM_PAIR,
871b877906bSopenharmony_ci                        32,
872b877906bSopenharmony_ci                        PropModeReplace,
873b877906bSopenharmony_ci                        (unsigned char*) targets,
874b877906bSopenharmony_ci                        count);
875b877906bSopenharmony_ci
876b877906bSopenharmony_ci        XFree(targets);
877b877906bSopenharmony_ci
878b877906bSopenharmony_ci        return request->property;
879b877906bSopenharmony_ci    }
880b877906bSopenharmony_ci
881b877906bSopenharmony_ci    if (request->target == _glfw.x11.SAVE_TARGETS)
882b877906bSopenharmony_ci    {
883b877906bSopenharmony_ci        // The request is a check whether we support SAVE_TARGETS
884b877906bSopenharmony_ci        // It should be handled as a no-op side effect target
885b877906bSopenharmony_ci
886b877906bSopenharmony_ci        XChangeProperty(_glfw.x11.display,
887b877906bSopenharmony_ci                        request->requestor,
888b877906bSopenharmony_ci                        request->property,
889b877906bSopenharmony_ci                        _glfw.x11.NULL_,
890b877906bSopenharmony_ci                        32,
891b877906bSopenharmony_ci                        PropModeReplace,
892b877906bSopenharmony_ci                        NULL,
893b877906bSopenharmony_ci                        0);
894b877906bSopenharmony_ci
895b877906bSopenharmony_ci        return request->property;
896b877906bSopenharmony_ci    }
897b877906bSopenharmony_ci
898b877906bSopenharmony_ci    // Conversion to a data target was requested
899b877906bSopenharmony_ci
900b877906bSopenharmony_ci    for (int i = 0;  i < formatCount;  i++)
901b877906bSopenharmony_ci    {
902b877906bSopenharmony_ci        if (request->target == formats[i])
903b877906bSopenharmony_ci        {
904b877906bSopenharmony_ci            // The requested target is one we support
905b877906bSopenharmony_ci
906b877906bSopenharmony_ci            XChangeProperty(_glfw.x11.display,
907b877906bSopenharmony_ci                            request->requestor,
908b877906bSopenharmony_ci                            request->property,
909b877906bSopenharmony_ci                            request->target,
910b877906bSopenharmony_ci                            8,
911b877906bSopenharmony_ci                            PropModeReplace,
912b877906bSopenharmony_ci                            (unsigned char *) selectionString,
913b877906bSopenharmony_ci                            strlen(selectionString));
914b877906bSopenharmony_ci
915b877906bSopenharmony_ci            return request->property;
916b877906bSopenharmony_ci        }
917b877906bSopenharmony_ci    }
918b877906bSopenharmony_ci
919b877906bSopenharmony_ci    // The requested target is not supported
920b877906bSopenharmony_ci
921b877906bSopenharmony_ci    return None;
922b877906bSopenharmony_ci}
923b877906bSopenharmony_ci
924b877906bSopenharmony_cistatic void handleSelectionRequest(XEvent* event)
925b877906bSopenharmony_ci{
926b877906bSopenharmony_ci    const XSelectionRequestEvent* request = &event->xselectionrequest;
927b877906bSopenharmony_ci
928b877906bSopenharmony_ci    XEvent reply = { SelectionNotify };
929b877906bSopenharmony_ci    reply.xselection.property = writeTargetToProperty(request);
930b877906bSopenharmony_ci    reply.xselection.display = request->display;
931b877906bSopenharmony_ci    reply.xselection.requestor = request->requestor;
932b877906bSopenharmony_ci    reply.xselection.selection = request->selection;
933b877906bSopenharmony_ci    reply.xselection.target = request->target;
934b877906bSopenharmony_ci    reply.xselection.time = request->time;
935b877906bSopenharmony_ci
936b877906bSopenharmony_ci    XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply);
937b877906bSopenharmony_ci}
938b877906bSopenharmony_ci
939b877906bSopenharmony_cistatic const char* getSelectionString(Atom selection)
940b877906bSopenharmony_ci{
941b877906bSopenharmony_ci    char** selectionString = NULL;
942b877906bSopenharmony_ci    const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING };
943b877906bSopenharmony_ci    const size_t targetCount = sizeof(targets) / sizeof(targets[0]);
944b877906bSopenharmony_ci
945b877906bSopenharmony_ci    if (selection == _glfw.x11.PRIMARY)
946b877906bSopenharmony_ci        selectionString = &_glfw.x11.primarySelectionString;
947b877906bSopenharmony_ci    else
948b877906bSopenharmony_ci        selectionString = &_glfw.x11.clipboardString;
949b877906bSopenharmony_ci
950b877906bSopenharmony_ci    if (XGetSelectionOwner(_glfw.x11.display, selection) ==
951b877906bSopenharmony_ci        _glfw.x11.helperWindowHandle)
952b877906bSopenharmony_ci    {
953b877906bSopenharmony_ci        // Instead of doing a large number of X round-trips just to put this
954b877906bSopenharmony_ci        // string into a window property and then read it back, just return it
955b877906bSopenharmony_ci        return *selectionString;
956b877906bSopenharmony_ci    }
957b877906bSopenharmony_ci
958b877906bSopenharmony_ci    _glfw_free(*selectionString);
959b877906bSopenharmony_ci    *selectionString = NULL;
960b877906bSopenharmony_ci
961b877906bSopenharmony_ci    for (size_t i = 0;  i < targetCount;  i++)
962b877906bSopenharmony_ci    {
963b877906bSopenharmony_ci        char* data;
964b877906bSopenharmony_ci        Atom actualType;
965b877906bSopenharmony_ci        int actualFormat;
966b877906bSopenharmony_ci        unsigned long itemCount, bytesAfter;
967b877906bSopenharmony_ci        XEvent notification, dummy;
968b877906bSopenharmony_ci
969b877906bSopenharmony_ci        XConvertSelection(_glfw.x11.display,
970b877906bSopenharmony_ci                          selection,
971b877906bSopenharmony_ci                          targets[i],
972b877906bSopenharmony_ci                          _glfw.x11.GLFW_SELECTION,
973b877906bSopenharmony_ci                          _glfw.x11.helperWindowHandle,
974b877906bSopenharmony_ci                          CurrentTime);
975b877906bSopenharmony_ci
976b877906bSopenharmony_ci        while (!XCheckTypedWindowEvent(_glfw.x11.display,
977b877906bSopenharmony_ci                                       _glfw.x11.helperWindowHandle,
978b877906bSopenharmony_ci                                       SelectionNotify,
979b877906bSopenharmony_ci                                       &notification))
980b877906bSopenharmony_ci        {
981b877906bSopenharmony_ci            waitForX11Event(NULL);
982b877906bSopenharmony_ci        }
983b877906bSopenharmony_ci
984b877906bSopenharmony_ci        if (notification.xselection.property == None)
985b877906bSopenharmony_ci            continue;
986b877906bSopenharmony_ci
987b877906bSopenharmony_ci        XCheckIfEvent(_glfw.x11.display,
988b877906bSopenharmony_ci                      &dummy,
989b877906bSopenharmony_ci                      isSelPropNewValueNotify,
990b877906bSopenharmony_ci                      (XPointer) &notification);
991b877906bSopenharmony_ci
992b877906bSopenharmony_ci        XGetWindowProperty(_glfw.x11.display,
993b877906bSopenharmony_ci                           notification.xselection.requestor,
994b877906bSopenharmony_ci                           notification.xselection.property,
995b877906bSopenharmony_ci                           0,
996b877906bSopenharmony_ci                           LONG_MAX,
997b877906bSopenharmony_ci                           True,
998b877906bSopenharmony_ci                           AnyPropertyType,
999b877906bSopenharmony_ci                           &actualType,
1000b877906bSopenharmony_ci                           &actualFormat,
1001b877906bSopenharmony_ci                           &itemCount,
1002b877906bSopenharmony_ci                           &bytesAfter,
1003b877906bSopenharmony_ci                           (unsigned char**) &data);
1004b877906bSopenharmony_ci
1005b877906bSopenharmony_ci        if (actualType == _glfw.x11.INCR)
1006b877906bSopenharmony_ci        {
1007b877906bSopenharmony_ci            size_t size = 1;
1008b877906bSopenharmony_ci            char* string = NULL;
1009b877906bSopenharmony_ci
1010b877906bSopenharmony_ci            for (;;)
1011b877906bSopenharmony_ci            {
1012b877906bSopenharmony_ci                while (!XCheckIfEvent(_glfw.x11.display,
1013b877906bSopenharmony_ci                                      &dummy,
1014b877906bSopenharmony_ci                                      isSelPropNewValueNotify,
1015b877906bSopenharmony_ci                                      (XPointer) &notification))
1016b877906bSopenharmony_ci                {
1017b877906bSopenharmony_ci                    waitForX11Event(NULL);
1018b877906bSopenharmony_ci                }
1019b877906bSopenharmony_ci
1020b877906bSopenharmony_ci                XFree(data);
1021b877906bSopenharmony_ci                XGetWindowProperty(_glfw.x11.display,
1022b877906bSopenharmony_ci                                   notification.xselection.requestor,
1023b877906bSopenharmony_ci                                   notification.xselection.property,
1024b877906bSopenharmony_ci                                   0,
1025b877906bSopenharmony_ci                                   LONG_MAX,
1026b877906bSopenharmony_ci                                   True,
1027b877906bSopenharmony_ci                                   AnyPropertyType,
1028b877906bSopenharmony_ci                                   &actualType,
1029b877906bSopenharmony_ci                                   &actualFormat,
1030b877906bSopenharmony_ci                                   &itemCount,
1031b877906bSopenharmony_ci                                   &bytesAfter,
1032b877906bSopenharmony_ci                                   (unsigned char**) &data);
1033b877906bSopenharmony_ci
1034b877906bSopenharmony_ci                if (itemCount)
1035b877906bSopenharmony_ci                {
1036b877906bSopenharmony_ci                    size += itemCount;
1037b877906bSopenharmony_ci                    string = _glfw_realloc(string, size);
1038b877906bSopenharmony_ci                    string[size - itemCount - 1] = '\0';
1039b877906bSopenharmony_ci                    strcat(string, data);
1040b877906bSopenharmony_ci                }
1041b877906bSopenharmony_ci
1042b877906bSopenharmony_ci                if (!itemCount)
1043b877906bSopenharmony_ci                {
1044b877906bSopenharmony_ci                    if (string)
1045b877906bSopenharmony_ci                    {
1046b877906bSopenharmony_ci                        if (targets[i] == XA_STRING)
1047b877906bSopenharmony_ci                        {
1048b877906bSopenharmony_ci                            *selectionString = convertLatin1toUTF8(string);
1049b877906bSopenharmony_ci                            _glfw_free(string);
1050b877906bSopenharmony_ci                        }
1051b877906bSopenharmony_ci                        else
1052b877906bSopenharmony_ci                            *selectionString = string;
1053b877906bSopenharmony_ci                    }
1054b877906bSopenharmony_ci
1055b877906bSopenharmony_ci                    break;
1056b877906bSopenharmony_ci                }
1057b877906bSopenharmony_ci            }
1058b877906bSopenharmony_ci        }
1059b877906bSopenharmony_ci        else if (actualType == targets[i])
1060b877906bSopenharmony_ci        {
1061b877906bSopenharmony_ci            if (targets[i] == XA_STRING)
1062b877906bSopenharmony_ci                *selectionString = convertLatin1toUTF8(data);
1063b877906bSopenharmony_ci            else
1064b877906bSopenharmony_ci                *selectionString = _glfw_strdup(data);
1065b877906bSopenharmony_ci        }
1066b877906bSopenharmony_ci
1067b877906bSopenharmony_ci        XFree(data);
1068b877906bSopenharmony_ci
1069b877906bSopenharmony_ci        if (*selectionString)
1070b877906bSopenharmony_ci            break;
1071b877906bSopenharmony_ci    }
1072b877906bSopenharmony_ci
1073b877906bSopenharmony_ci    if (!*selectionString)
1074b877906bSopenharmony_ci    {
1075b877906bSopenharmony_ci        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
1076b877906bSopenharmony_ci                        "X11: Failed to convert selection to string");
1077b877906bSopenharmony_ci    }
1078b877906bSopenharmony_ci
1079b877906bSopenharmony_ci    return *selectionString;
1080b877906bSopenharmony_ci}
1081b877906bSopenharmony_ci
1082b877906bSopenharmony_ci// Make the specified window and its video mode active on its monitor
1083b877906bSopenharmony_ci//
1084b877906bSopenharmony_cistatic void acquireMonitor(_GLFWwindow* window)
1085b877906bSopenharmony_ci{
1086b877906bSopenharmony_ci    if (_glfw.x11.saver.count == 0)
1087b877906bSopenharmony_ci    {
1088b877906bSopenharmony_ci        // Remember old screen saver settings
1089b877906bSopenharmony_ci        XGetScreenSaver(_glfw.x11.display,
1090b877906bSopenharmony_ci                        &_glfw.x11.saver.timeout,
1091b877906bSopenharmony_ci                        &_glfw.x11.saver.interval,
1092b877906bSopenharmony_ci                        &_glfw.x11.saver.blanking,
1093b877906bSopenharmony_ci                        &_glfw.x11.saver.exposure);
1094b877906bSopenharmony_ci
1095b877906bSopenharmony_ci        // Disable screen saver
1096b877906bSopenharmony_ci        XSetScreenSaver(_glfw.x11.display, 0, 0, DontPreferBlanking,
1097b877906bSopenharmony_ci                        DefaultExposures);
1098b877906bSopenharmony_ci    }
1099b877906bSopenharmony_ci
1100b877906bSopenharmony_ci    if (!window->monitor->window)
1101b877906bSopenharmony_ci        _glfw.x11.saver.count++;
1102b877906bSopenharmony_ci
1103b877906bSopenharmony_ci    _glfwSetVideoModeX11(window->monitor, &window->videoMode);
1104b877906bSopenharmony_ci
1105b877906bSopenharmony_ci    if (window->x11.overrideRedirect)
1106b877906bSopenharmony_ci    {
1107b877906bSopenharmony_ci        int xpos, ypos;
1108b877906bSopenharmony_ci        GLFWvidmode mode;
1109b877906bSopenharmony_ci
1110b877906bSopenharmony_ci        // Manually position the window over its monitor
1111b877906bSopenharmony_ci        _glfwGetMonitorPosX11(window->monitor, &xpos, &ypos);
1112b877906bSopenharmony_ci        _glfwGetVideoModeX11(window->monitor, &mode);
1113b877906bSopenharmony_ci
1114b877906bSopenharmony_ci        XMoveResizeWindow(_glfw.x11.display, window->x11.handle,
1115b877906bSopenharmony_ci                          xpos, ypos, mode.width, mode.height);
1116b877906bSopenharmony_ci    }
1117b877906bSopenharmony_ci
1118b877906bSopenharmony_ci    _glfwInputMonitorWindow(window->monitor, window);
1119b877906bSopenharmony_ci}
1120b877906bSopenharmony_ci
1121b877906bSopenharmony_ci// Remove the window and restore the original video mode
1122b877906bSopenharmony_ci//
1123b877906bSopenharmony_cistatic void releaseMonitor(_GLFWwindow* window)
1124b877906bSopenharmony_ci{
1125b877906bSopenharmony_ci    if (window->monitor->window != window)
1126b877906bSopenharmony_ci        return;
1127b877906bSopenharmony_ci
1128b877906bSopenharmony_ci    _glfwInputMonitorWindow(window->monitor, NULL);
1129b877906bSopenharmony_ci    _glfwRestoreVideoModeX11(window->monitor);
1130b877906bSopenharmony_ci
1131b877906bSopenharmony_ci    _glfw.x11.saver.count--;
1132b877906bSopenharmony_ci
1133b877906bSopenharmony_ci    if (_glfw.x11.saver.count == 0)
1134b877906bSopenharmony_ci    {
1135b877906bSopenharmony_ci        // Restore old screen saver settings
1136b877906bSopenharmony_ci        XSetScreenSaver(_glfw.x11.display,
1137b877906bSopenharmony_ci                        _glfw.x11.saver.timeout,
1138b877906bSopenharmony_ci                        _glfw.x11.saver.interval,
1139b877906bSopenharmony_ci                        _glfw.x11.saver.blanking,
1140b877906bSopenharmony_ci                        _glfw.x11.saver.exposure);
1141b877906bSopenharmony_ci    }
1142b877906bSopenharmony_ci}
1143b877906bSopenharmony_ci
1144b877906bSopenharmony_ci// Process the specified X event
1145b877906bSopenharmony_ci//
1146b877906bSopenharmony_cistatic void processEvent(XEvent *event)
1147b877906bSopenharmony_ci{
1148b877906bSopenharmony_ci    int keycode = 0;
1149b877906bSopenharmony_ci    Bool filtered = False;
1150b877906bSopenharmony_ci
1151b877906bSopenharmony_ci    // HACK: Save scancode as some IMs clear the field in XFilterEvent
1152b877906bSopenharmony_ci    if (event->type == KeyPress || event->type == KeyRelease)
1153b877906bSopenharmony_ci        keycode = event->xkey.keycode;
1154b877906bSopenharmony_ci
1155b877906bSopenharmony_ci    filtered = XFilterEvent(event, None);
1156b877906bSopenharmony_ci
1157b877906bSopenharmony_ci    if (_glfw.x11.randr.available)
1158b877906bSopenharmony_ci    {
1159b877906bSopenharmony_ci        if (event->type == _glfw.x11.randr.eventBase + RRNotify)
1160b877906bSopenharmony_ci        {
1161b877906bSopenharmony_ci            XRRUpdateConfiguration(event);
1162b877906bSopenharmony_ci            _glfwPollMonitorsX11();
1163b877906bSopenharmony_ci            return;
1164b877906bSopenharmony_ci        }
1165b877906bSopenharmony_ci    }
1166b877906bSopenharmony_ci
1167b877906bSopenharmony_ci    if (_glfw.x11.xkb.available)
1168b877906bSopenharmony_ci    {
1169b877906bSopenharmony_ci        if (event->type == _glfw.x11.xkb.eventBase + XkbEventCode)
1170b877906bSopenharmony_ci        {
1171b877906bSopenharmony_ci            if (((XkbEvent*) event)->any.xkb_type == XkbStateNotify &&
1172b877906bSopenharmony_ci                (((XkbEvent*) event)->state.changed & XkbGroupStateMask))
1173b877906bSopenharmony_ci            {
1174b877906bSopenharmony_ci                _glfw.x11.xkb.group = ((XkbEvent*) event)->state.group;
1175b877906bSopenharmony_ci            }
1176b877906bSopenharmony_ci
1177b877906bSopenharmony_ci            return;
1178b877906bSopenharmony_ci        }
1179b877906bSopenharmony_ci    }
1180b877906bSopenharmony_ci
1181b877906bSopenharmony_ci    if (event->type == GenericEvent)
1182b877906bSopenharmony_ci    {
1183b877906bSopenharmony_ci        if (_glfw.x11.xi.available)
1184b877906bSopenharmony_ci        {
1185b877906bSopenharmony_ci            _GLFWwindow* window = _glfw.x11.disabledCursorWindow;
1186b877906bSopenharmony_ci
1187b877906bSopenharmony_ci            if (window &&
1188b877906bSopenharmony_ci                window->rawMouseMotion &&
1189b877906bSopenharmony_ci                event->xcookie.extension == _glfw.x11.xi.majorOpcode &&
1190b877906bSopenharmony_ci                XGetEventData(_glfw.x11.display, &event->xcookie) &&
1191b877906bSopenharmony_ci                event->xcookie.evtype == XI_RawMotion)
1192b877906bSopenharmony_ci            {
1193b877906bSopenharmony_ci                XIRawEvent* re = event->xcookie.data;
1194b877906bSopenharmony_ci                if (re->valuators.mask_len)
1195b877906bSopenharmony_ci                {
1196b877906bSopenharmony_ci                    const double* values = re->raw_values;
1197b877906bSopenharmony_ci                    double xpos = window->virtualCursorPosX;
1198b877906bSopenharmony_ci                    double ypos = window->virtualCursorPosY;
1199b877906bSopenharmony_ci
1200b877906bSopenharmony_ci                    if (XIMaskIsSet(re->valuators.mask, 0))
1201b877906bSopenharmony_ci                    {
1202b877906bSopenharmony_ci                        xpos += *values;
1203b877906bSopenharmony_ci                        values++;
1204b877906bSopenharmony_ci                    }
1205b877906bSopenharmony_ci
1206b877906bSopenharmony_ci                    if (XIMaskIsSet(re->valuators.mask, 1))
1207b877906bSopenharmony_ci                        ypos += *values;
1208b877906bSopenharmony_ci
1209b877906bSopenharmony_ci                    _glfwInputCursorPos(window, xpos, ypos);
1210b877906bSopenharmony_ci                }
1211b877906bSopenharmony_ci            }
1212b877906bSopenharmony_ci
1213b877906bSopenharmony_ci            XFreeEventData(_glfw.x11.display, &event->xcookie);
1214b877906bSopenharmony_ci        }
1215b877906bSopenharmony_ci
1216b877906bSopenharmony_ci        return;
1217b877906bSopenharmony_ci    }
1218b877906bSopenharmony_ci
1219b877906bSopenharmony_ci    if (event->type == SelectionRequest)
1220b877906bSopenharmony_ci    {
1221b877906bSopenharmony_ci        handleSelectionRequest(event);
1222b877906bSopenharmony_ci        return;
1223b877906bSopenharmony_ci    }
1224b877906bSopenharmony_ci
1225b877906bSopenharmony_ci    _GLFWwindow* window = NULL;
1226b877906bSopenharmony_ci    if (XFindContext(_glfw.x11.display,
1227b877906bSopenharmony_ci                     event->xany.window,
1228b877906bSopenharmony_ci                     _glfw.x11.context,
1229b877906bSopenharmony_ci                     (XPointer*) &window) != 0)
1230b877906bSopenharmony_ci    {
1231b877906bSopenharmony_ci        // This is an event for a window that has already been destroyed
1232b877906bSopenharmony_ci        return;
1233b877906bSopenharmony_ci    }
1234b877906bSopenharmony_ci
1235b877906bSopenharmony_ci    switch (event->type)
1236b877906bSopenharmony_ci    {
1237b877906bSopenharmony_ci        case ReparentNotify:
1238b877906bSopenharmony_ci        {
1239b877906bSopenharmony_ci            window->x11.parent = event->xreparent.parent;
1240b877906bSopenharmony_ci            return;
1241b877906bSopenharmony_ci        }
1242b877906bSopenharmony_ci
1243b877906bSopenharmony_ci        case KeyPress:
1244b877906bSopenharmony_ci        {
1245b877906bSopenharmony_ci            const int key = translateKey(keycode);
1246b877906bSopenharmony_ci            const int mods = translateState(event->xkey.state);
1247b877906bSopenharmony_ci            const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
1248b877906bSopenharmony_ci
1249b877906bSopenharmony_ci            if (window->x11.ic)
1250b877906bSopenharmony_ci            {
1251b877906bSopenharmony_ci                // HACK: Do not report the key press events duplicated by XIM
1252b877906bSopenharmony_ci                //       Duplicate key releases are filtered out implicitly by
1253b877906bSopenharmony_ci                //       the GLFW key repeat logic in _glfwInputKey
1254b877906bSopenharmony_ci                //       A timestamp per key is used to handle simultaneous keys
1255b877906bSopenharmony_ci                // NOTE: Always allow the first event for each key through
1256b877906bSopenharmony_ci                //       (the server never sends a timestamp of zero)
1257b877906bSopenharmony_ci                // NOTE: Timestamp difference is compared to handle wrap-around
1258b877906bSopenharmony_ci                Time diff = event->xkey.time - window->x11.keyPressTimes[keycode];
1259b877906bSopenharmony_ci                if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31)))
1260b877906bSopenharmony_ci                {
1261b877906bSopenharmony_ci                    if (keycode)
1262b877906bSopenharmony_ci                        _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
1263b877906bSopenharmony_ci
1264b877906bSopenharmony_ci                    window->x11.keyPressTimes[keycode] = event->xkey.time;
1265b877906bSopenharmony_ci                }
1266b877906bSopenharmony_ci
1267b877906bSopenharmony_ci                if (!filtered)
1268b877906bSopenharmony_ci                {
1269b877906bSopenharmony_ci                    int count;
1270b877906bSopenharmony_ci                    Status status;
1271b877906bSopenharmony_ci                    char buffer[100];
1272b877906bSopenharmony_ci                    char* chars = buffer;
1273b877906bSopenharmony_ci
1274b877906bSopenharmony_ci                    count = Xutf8LookupString(window->x11.ic,
1275b877906bSopenharmony_ci                                              &event->xkey,
1276b877906bSopenharmony_ci                                              buffer, sizeof(buffer) - 1,
1277b877906bSopenharmony_ci                                              NULL, &status);
1278b877906bSopenharmony_ci
1279b877906bSopenharmony_ci                    if (status == XBufferOverflow)
1280b877906bSopenharmony_ci                    {
1281b877906bSopenharmony_ci                        chars = _glfw_calloc(count + 1, 1);
1282b877906bSopenharmony_ci                        count = Xutf8LookupString(window->x11.ic,
1283b877906bSopenharmony_ci                                                  &event->xkey,
1284b877906bSopenharmony_ci                                                  chars, count,
1285b877906bSopenharmony_ci                                                  NULL, &status);
1286b877906bSopenharmony_ci                    }
1287b877906bSopenharmony_ci
1288b877906bSopenharmony_ci                    if (status == XLookupChars || status == XLookupBoth)
1289b877906bSopenharmony_ci                    {
1290b877906bSopenharmony_ci                        const char* c = chars;
1291b877906bSopenharmony_ci                        chars[count] = '\0';
1292b877906bSopenharmony_ci                        while (c - chars < count)
1293b877906bSopenharmony_ci                            _glfwInputChar(window, decodeUTF8(&c), mods, plain);
1294b877906bSopenharmony_ci                    }
1295b877906bSopenharmony_ci
1296b877906bSopenharmony_ci                    if (chars != buffer)
1297b877906bSopenharmony_ci                        _glfw_free(chars);
1298b877906bSopenharmony_ci                }
1299b877906bSopenharmony_ci            }
1300b877906bSopenharmony_ci            else
1301b877906bSopenharmony_ci            {
1302b877906bSopenharmony_ci                KeySym keysym;
1303b877906bSopenharmony_ci                XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
1304b877906bSopenharmony_ci
1305b877906bSopenharmony_ci                _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
1306b877906bSopenharmony_ci
1307b877906bSopenharmony_ci                const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
1308b877906bSopenharmony_ci                if (codepoint != GLFW_INVALID_CODEPOINT)
1309b877906bSopenharmony_ci                    _glfwInputChar(window, codepoint, mods, plain);
1310b877906bSopenharmony_ci            }
1311b877906bSopenharmony_ci
1312b877906bSopenharmony_ci            return;
1313b877906bSopenharmony_ci        }
1314b877906bSopenharmony_ci
1315b877906bSopenharmony_ci        case KeyRelease:
1316b877906bSopenharmony_ci        {
1317b877906bSopenharmony_ci            const int key = translateKey(keycode);
1318b877906bSopenharmony_ci            const int mods = translateState(event->xkey.state);
1319b877906bSopenharmony_ci
1320b877906bSopenharmony_ci            if (!_glfw.x11.xkb.detectable)
1321b877906bSopenharmony_ci            {
1322b877906bSopenharmony_ci                // HACK: Key repeat events will arrive as KeyRelease/KeyPress
1323b877906bSopenharmony_ci                //       pairs with similar or identical time stamps
1324b877906bSopenharmony_ci                //       The key repeat logic in _glfwInputKey expects only key
1325b877906bSopenharmony_ci                //       presses to repeat, so detect and discard release events
1326b877906bSopenharmony_ci                if (XEventsQueued(_glfw.x11.display, QueuedAfterReading))
1327b877906bSopenharmony_ci                {
1328b877906bSopenharmony_ci                    XEvent next;
1329b877906bSopenharmony_ci                    XPeekEvent(_glfw.x11.display, &next);
1330b877906bSopenharmony_ci
1331b877906bSopenharmony_ci                    if (next.type == KeyPress &&
1332b877906bSopenharmony_ci                        next.xkey.window == event->xkey.window &&
1333b877906bSopenharmony_ci                        next.xkey.keycode == keycode)
1334b877906bSopenharmony_ci                    {
1335b877906bSopenharmony_ci                        // HACK: The time of repeat events sometimes doesn't
1336b877906bSopenharmony_ci                        //       match that of the press event, so add an
1337b877906bSopenharmony_ci                        //       epsilon
1338b877906bSopenharmony_ci                        //       Toshiyuki Takahashi can press a button
1339b877906bSopenharmony_ci                        //       16 times per second so it's fairly safe to
1340b877906bSopenharmony_ci                        //       assume that no human is pressing the key 50
1341b877906bSopenharmony_ci                        //       times per second (value is ms)
1342b877906bSopenharmony_ci                        if ((next.xkey.time - event->xkey.time) < 20)
1343b877906bSopenharmony_ci                        {
1344b877906bSopenharmony_ci                            // This is very likely a server-generated key repeat
1345b877906bSopenharmony_ci                            // event, so ignore it
1346b877906bSopenharmony_ci                            return;
1347b877906bSopenharmony_ci                        }
1348b877906bSopenharmony_ci                    }
1349b877906bSopenharmony_ci                }
1350b877906bSopenharmony_ci            }
1351b877906bSopenharmony_ci
1352b877906bSopenharmony_ci            _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods);
1353b877906bSopenharmony_ci            return;
1354b877906bSopenharmony_ci        }
1355b877906bSopenharmony_ci
1356b877906bSopenharmony_ci        case ButtonPress:
1357b877906bSopenharmony_ci        {
1358b877906bSopenharmony_ci            const int mods = translateState(event->xbutton.state);
1359b877906bSopenharmony_ci
1360b877906bSopenharmony_ci            if (event->xbutton.button == Button1)
1361b877906bSopenharmony_ci                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods);
1362b877906bSopenharmony_ci            else if (event->xbutton.button == Button2)
1363b877906bSopenharmony_ci                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods);
1364b877906bSopenharmony_ci            else if (event->xbutton.button == Button3)
1365b877906bSopenharmony_ci                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods);
1366b877906bSopenharmony_ci
1367b877906bSopenharmony_ci            // Modern X provides scroll events as mouse button presses
1368b877906bSopenharmony_ci            else if (event->xbutton.button == Button4)
1369b877906bSopenharmony_ci                _glfwInputScroll(window, 0.0, 1.0);
1370b877906bSopenharmony_ci            else if (event->xbutton.button == Button5)
1371b877906bSopenharmony_ci                _glfwInputScroll(window, 0.0, -1.0);
1372b877906bSopenharmony_ci            else if (event->xbutton.button == Button6)
1373b877906bSopenharmony_ci                _glfwInputScroll(window, 1.0, 0.0);
1374b877906bSopenharmony_ci            else if (event->xbutton.button == Button7)
1375b877906bSopenharmony_ci                _glfwInputScroll(window, -1.0, 0.0);
1376b877906bSopenharmony_ci
1377b877906bSopenharmony_ci            else
1378b877906bSopenharmony_ci            {
1379b877906bSopenharmony_ci                // Additional buttons after 7 are treated as regular buttons
1380b877906bSopenharmony_ci                // We subtract 4 to fill the gap left by scroll input above
1381b877906bSopenharmony_ci                _glfwInputMouseClick(window,
1382b877906bSopenharmony_ci                                     event->xbutton.button - Button1 - 4,
1383b877906bSopenharmony_ci                                     GLFW_PRESS,
1384b877906bSopenharmony_ci                                     mods);
1385b877906bSopenharmony_ci            }
1386b877906bSopenharmony_ci
1387b877906bSopenharmony_ci            return;
1388b877906bSopenharmony_ci        }
1389b877906bSopenharmony_ci
1390b877906bSopenharmony_ci        case ButtonRelease:
1391b877906bSopenharmony_ci        {
1392b877906bSopenharmony_ci            const int mods = translateState(event->xbutton.state);
1393b877906bSopenharmony_ci
1394b877906bSopenharmony_ci            if (event->xbutton.button == Button1)
1395b877906bSopenharmony_ci            {
1396b877906bSopenharmony_ci                _glfwInputMouseClick(window,
1397b877906bSopenharmony_ci                                     GLFW_MOUSE_BUTTON_LEFT,
1398b877906bSopenharmony_ci                                     GLFW_RELEASE,
1399b877906bSopenharmony_ci                                     mods);
1400b877906bSopenharmony_ci            }
1401b877906bSopenharmony_ci            else if (event->xbutton.button == Button2)
1402b877906bSopenharmony_ci            {
1403b877906bSopenharmony_ci                _glfwInputMouseClick(window,
1404b877906bSopenharmony_ci                                     GLFW_MOUSE_BUTTON_MIDDLE,
1405b877906bSopenharmony_ci                                     GLFW_RELEASE,
1406b877906bSopenharmony_ci                                     mods);
1407b877906bSopenharmony_ci            }
1408b877906bSopenharmony_ci            else if (event->xbutton.button == Button3)
1409b877906bSopenharmony_ci            {
1410b877906bSopenharmony_ci                _glfwInputMouseClick(window,
1411b877906bSopenharmony_ci                                     GLFW_MOUSE_BUTTON_RIGHT,
1412b877906bSopenharmony_ci                                     GLFW_RELEASE,
1413b877906bSopenharmony_ci                                     mods);
1414b877906bSopenharmony_ci            }
1415b877906bSopenharmony_ci            else if (event->xbutton.button > Button7)
1416b877906bSopenharmony_ci            {
1417b877906bSopenharmony_ci                // Additional buttons after 7 are treated as regular buttons
1418b877906bSopenharmony_ci                // We subtract 4 to fill the gap left by scroll input above
1419b877906bSopenharmony_ci                _glfwInputMouseClick(window,
1420b877906bSopenharmony_ci                                     event->xbutton.button - Button1 - 4,
1421b877906bSopenharmony_ci                                     GLFW_RELEASE,
1422b877906bSopenharmony_ci                                     mods);
1423b877906bSopenharmony_ci            }
1424b877906bSopenharmony_ci
1425b877906bSopenharmony_ci            return;
1426b877906bSopenharmony_ci        }
1427b877906bSopenharmony_ci
1428b877906bSopenharmony_ci        case EnterNotify:
1429b877906bSopenharmony_ci        {
1430b877906bSopenharmony_ci            // XEnterWindowEvent is XCrossingEvent
1431b877906bSopenharmony_ci            const int x = event->xcrossing.x;
1432b877906bSopenharmony_ci            const int y = event->xcrossing.y;
1433b877906bSopenharmony_ci
1434b877906bSopenharmony_ci            // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise
1435b877906bSopenharmony_ci            //       ignore the defined cursor for hidden cursor mode
1436b877906bSopenharmony_ci            if (window->cursorMode == GLFW_CURSOR_HIDDEN)
1437b877906bSopenharmony_ci                updateCursorImage(window);
1438b877906bSopenharmony_ci
1439b877906bSopenharmony_ci            _glfwInputCursorEnter(window, GLFW_TRUE);
1440b877906bSopenharmony_ci            _glfwInputCursorPos(window, x, y);
1441b877906bSopenharmony_ci
1442b877906bSopenharmony_ci            window->x11.lastCursorPosX = x;
1443b877906bSopenharmony_ci            window->x11.lastCursorPosY = y;
1444b877906bSopenharmony_ci            return;
1445b877906bSopenharmony_ci        }
1446b877906bSopenharmony_ci
1447b877906bSopenharmony_ci        case LeaveNotify:
1448b877906bSopenharmony_ci        {
1449b877906bSopenharmony_ci            _glfwInputCursorEnter(window, GLFW_FALSE);
1450b877906bSopenharmony_ci            return;
1451b877906bSopenharmony_ci        }
1452b877906bSopenharmony_ci
1453b877906bSopenharmony_ci        case MotionNotify:
1454b877906bSopenharmony_ci        {
1455b877906bSopenharmony_ci            const int x = event->xmotion.x;
1456b877906bSopenharmony_ci            const int y = event->xmotion.y;
1457b877906bSopenharmony_ci
1458b877906bSopenharmony_ci            if (x != window->x11.warpCursorPosX ||
1459b877906bSopenharmony_ci                y != window->x11.warpCursorPosY)
1460b877906bSopenharmony_ci            {
1461b877906bSopenharmony_ci                // The cursor was moved by something other than GLFW
1462b877906bSopenharmony_ci
1463b877906bSopenharmony_ci                if (window->cursorMode == GLFW_CURSOR_DISABLED)
1464b877906bSopenharmony_ci                {
1465b877906bSopenharmony_ci                    if (_glfw.x11.disabledCursorWindow != window)
1466b877906bSopenharmony_ci                        return;
1467b877906bSopenharmony_ci                    if (window->rawMouseMotion)
1468b877906bSopenharmony_ci                        return;
1469b877906bSopenharmony_ci
1470b877906bSopenharmony_ci                    const int dx = x - window->x11.lastCursorPosX;
1471b877906bSopenharmony_ci                    const int dy = y - window->x11.lastCursorPosY;
1472b877906bSopenharmony_ci
1473b877906bSopenharmony_ci                    _glfwInputCursorPos(window,
1474b877906bSopenharmony_ci                                        window->virtualCursorPosX + dx,
1475b877906bSopenharmony_ci                                        window->virtualCursorPosY + dy);
1476b877906bSopenharmony_ci                }
1477b877906bSopenharmony_ci                else
1478b877906bSopenharmony_ci                    _glfwInputCursorPos(window, x, y);
1479b877906bSopenharmony_ci            }
1480b877906bSopenharmony_ci
1481b877906bSopenharmony_ci            window->x11.lastCursorPosX = x;
1482b877906bSopenharmony_ci            window->x11.lastCursorPosY = y;
1483b877906bSopenharmony_ci            return;
1484b877906bSopenharmony_ci        }
1485b877906bSopenharmony_ci
1486b877906bSopenharmony_ci        case ConfigureNotify:
1487b877906bSopenharmony_ci        {
1488b877906bSopenharmony_ci            if (event->xconfigure.width != window->x11.width ||
1489b877906bSopenharmony_ci                event->xconfigure.height != window->x11.height)
1490b877906bSopenharmony_ci            {
1491b877906bSopenharmony_ci                window->x11.width = event->xconfigure.width;
1492b877906bSopenharmony_ci                window->x11.height = event->xconfigure.height;
1493b877906bSopenharmony_ci
1494b877906bSopenharmony_ci                _glfwInputFramebufferSize(window,
1495b877906bSopenharmony_ci                                          event->xconfigure.width,
1496b877906bSopenharmony_ci                                          event->xconfigure.height);
1497b877906bSopenharmony_ci
1498b877906bSopenharmony_ci                _glfwInputWindowSize(window,
1499b877906bSopenharmony_ci                                     event->xconfigure.width,
1500b877906bSopenharmony_ci                                     event->xconfigure.height);
1501b877906bSopenharmony_ci            }
1502b877906bSopenharmony_ci
1503b877906bSopenharmony_ci            int xpos = event->xconfigure.x;
1504b877906bSopenharmony_ci            int ypos = event->xconfigure.y;
1505b877906bSopenharmony_ci
1506b877906bSopenharmony_ci            // NOTE: ConfigureNotify events from the server are in local
1507b877906bSopenharmony_ci            //       coordinates, so if we are reparented we need to translate
1508b877906bSopenharmony_ci            //       the position into root (screen) coordinates
1509b877906bSopenharmony_ci            if (!event->xany.send_event && window->x11.parent != _glfw.x11.root)
1510b877906bSopenharmony_ci            {
1511b877906bSopenharmony_ci                _glfwGrabErrorHandlerX11();
1512b877906bSopenharmony_ci
1513b877906bSopenharmony_ci                Window dummy;
1514b877906bSopenharmony_ci                XTranslateCoordinates(_glfw.x11.display,
1515b877906bSopenharmony_ci                                      window->x11.parent,
1516b877906bSopenharmony_ci                                      _glfw.x11.root,
1517b877906bSopenharmony_ci                                      xpos, ypos,
1518b877906bSopenharmony_ci                                      &xpos, &ypos,
1519b877906bSopenharmony_ci                                      &dummy);
1520b877906bSopenharmony_ci
1521b877906bSopenharmony_ci                _glfwReleaseErrorHandlerX11();
1522b877906bSopenharmony_ci                if (_glfw.x11.errorCode == BadWindow)
1523b877906bSopenharmony_ci                    return;
1524b877906bSopenharmony_ci            }
1525b877906bSopenharmony_ci
1526b877906bSopenharmony_ci            if (xpos != window->x11.xpos || ypos != window->x11.ypos)
1527b877906bSopenharmony_ci            {
1528b877906bSopenharmony_ci                window->x11.xpos = xpos;
1529b877906bSopenharmony_ci                window->x11.ypos = ypos;
1530b877906bSopenharmony_ci
1531b877906bSopenharmony_ci                _glfwInputWindowPos(window, xpos, ypos);
1532b877906bSopenharmony_ci            }
1533b877906bSopenharmony_ci
1534b877906bSopenharmony_ci            return;
1535b877906bSopenharmony_ci        }
1536b877906bSopenharmony_ci
1537b877906bSopenharmony_ci        case ClientMessage:
1538b877906bSopenharmony_ci        {
1539b877906bSopenharmony_ci            // Custom client message, probably from the window manager
1540b877906bSopenharmony_ci
1541b877906bSopenharmony_ci            if (filtered)
1542b877906bSopenharmony_ci                return;
1543b877906bSopenharmony_ci
1544b877906bSopenharmony_ci            if (event->xclient.message_type == None)
1545b877906bSopenharmony_ci                return;
1546b877906bSopenharmony_ci
1547b877906bSopenharmony_ci            if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS)
1548b877906bSopenharmony_ci            {
1549b877906bSopenharmony_ci                const Atom protocol = event->xclient.data.l[0];
1550b877906bSopenharmony_ci                if (protocol == None)
1551b877906bSopenharmony_ci                    return;
1552b877906bSopenharmony_ci
1553b877906bSopenharmony_ci                if (protocol == _glfw.x11.WM_DELETE_WINDOW)
1554b877906bSopenharmony_ci                {
1555b877906bSopenharmony_ci                    // The window manager was asked to close the window, for
1556b877906bSopenharmony_ci                    // example by the user pressing a 'close' window decoration
1557b877906bSopenharmony_ci                    // button
1558b877906bSopenharmony_ci                    _glfwInputWindowCloseRequest(window);
1559b877906bSopenharmony_ci                }
1560b877906bSopenharmony_ci                else if (protocol == _glfw.x11.NET_WM_PING)
1561b877906bSopenharmony_ci                {
1562b877906bSopenharmony_ci                    // The window manager is pinging the application to ensure
1563b877906bSopenharmony_ci                    // it's still responding to events
1564b877906bSopenharmony_ci
1565b877906bSopenharmony_ci                    XEvent reply = *event;
1566b877906bSopenharmony_ci                    reply.xclient.window = _glfw.x11.root;
1567b877906bSopenharmony_ci
1568b877906bSopenharmony_ci                    XSendEvent(_glfw.x11.display, _glfw.x11.root,
1569b877906bSopenharmony_ci                               False,
1570b877906bSopenharmony_ci                               SubstructureNotifyMask | SubstructureRedirectMask,
1571b877906bSopenharmony_ci                               &reply);
1572b877906bSopenharmony_ci                }
1573b877906bSopenharmony_ci            }
1574b877906bSopenharmony_ci            else if (event->xclient.message_type == _glfw.x11.XdndEnter)
1575b877906bSopenharmony_ci            {
1576b877906bSopenharmony_ci                // A drag operation has entered the window
1577b877906bSopenharmony_ci                unsigned long count;
1578b877906bSopenharmony_ci                Atom* formats = NULL;
1579b877906bSopenharmony_ci                const GLFWbool list = event->xclient.data.l[1] & 1;
1580b877906bSopenharmony_ci
1581b877906bSopenharmony_ci                _glfw.x11.xdnd.source  = event->xclient.data.l[0];
1582b877906bSopenharmony_ci                _glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24;
1583b877906bSopenharmony_ci                _glfw.x11.xdnd.format  = None;
1584b877906bSopenharmony_ci
1585b877906bSopenharmony_ci                if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
1586b877906bSopenharmony_ci                    return;
1587b877906bSopenharmony_ci
1588b877906bSopenharmony_ci                if (list)
1589b877906bSopenharmony_ci                {
1590b877906bSopenharmony_ci                    count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source,
1591b877906bSopenharmony_ci                                                      _glfw.x11.XdndTypeList,
1592b877906bSopenharmony_ci                                                      XA_ATOM,
1593b877906bSopenharmony_ci                                                      (unsigned char**) &formats);
1594b877906bSopenharmony_ci                }
1595b877906bSopenharmony_ci                else
1596b877906bSopenharmony_ci                {
1597b877906bSopenharmony_ci                    count = 3;
1598b877906bSopenharmony_ci                    formats = (Atom*) event->xclient.data.l + 2;
1599b877906bSopenharmony_ci                }
1600b877906bSopenharmony_ci
1601b877906bSopenharmony_ci                for (unsigned int i = 0;  i < count;  i++)
1602b877906bSopenharmony_ci                {
1603b877906bSopenharmony_ci                    if (formats[i] == _glfw.x11.text_uri_list)
1604b877906bSopenharmony_ci                    {
1605b877906bSopenharmony_ci                        _glfw.x11.xdnd.format = _glfw.x11.text_uri_list;
1606b877906bSopenharmony_ci                        break;
1607b877906bSopenharmony_ci                    }
1608b877906bSopenharmony_ci                }
1609b877906bSopenharmony_ci
1610b877906bSopenharmony_ci                if (list && formats)
1611b877906bSopenharmony_ci                    XFree(formats);
1612b877906bSopenharmony_ci            }
1613b877906bSopenharmony_ci            else if (event->xclient.message_type == _glfw.x11.XdndDrop)
1614b877906bSopenharmony_ci            {
1615b877906bSopenharmony_ci                // The drag operation has finished by dropping on the window
1616b877906bSopenharmony_ci                Time time = CurrentTime;
1617b877906bSopenharmony_ci
1618b877906bSopenharmony_ci                if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
1619b877906bSopenharmony_ci                    return;
1620b877906bSopenharmony_ci
1621b877906bSopenharmony_ci                if (_glfw.x11.xdnd.format)
1622b877906bSopenharmony_ci                {
1623b877906bSopenharmony_ci                    if (_glfw.x11.xdnd.version >= 1)
1624b877906bSopenharmony_ci                        time = event->xclient.data.l[2];
1625b877906bSopenharmony_ci
1626b877906bSopenharmony_ci                    // Request the chosen format from the source window
1627b877906bSopenharmony_ci                    XConvertSelection(_glfw.x11.display,
1628b877906bSopenharmony_ci                                      _glfw.x11.XdndSelection,
1629b877906bSopenharmony_ci                                      _glfw.x11.xdnd.format,
1630b877906bSopenharmony_ci                                      _glfw.x11.XdndSelection,
1631b877906bSopenharmony_ci                                      window->x11.handle,
1632b877906bSopenharmony_ci                                      time);
1633b877906bSopenharmony_ci                }
1634b877906bSopenharmony_ci                else if (_glfw.x11.xdnd.version >= 2)
1635b877906bSopenharmony_ci                {
1636b877906bSopenharmony_ci                    XEvent reply = { ClientMessage };
1637b877906bSopenharmony_ci                    reply.xclient.window = _glfw.x11.xdnd.source;
1638b877906bSopenharmony_ci                    reply.xclient.message_type = _glfw.x11.XdndFinished;
1639b877906bSopenharmony_ci                    reply.xclient.format = 32;
1640b877906bSopenharmony_ci                    reply.xclient.data.l[0] = window->x11.handle;
1641b877906bSopenharmony_ci                    reply.xclient.data.l[1] = 0; // The drag was rejected
1642b877906bSopenharmony_ci                    reply.xclient.data.l[2] = None;
1643b877906bSopenharmony_ci
1644b877906bSopenharmony_ci                    XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
1645b877906bSopenharmony_ci                               False, NoEventMask, &reply);
1646b877906bSopenharmony_ci                    XFlush(_glfw.x11.display);
1647b877906bSopenharmony_ci                }
1648b877906bSopenharmony_ci            }
1649b877906bSopenharmony_ci            else if (event->xclient.message_type == _glfw.x11.XdndPosition)
1650b877906bSopenharmony_ci            {
1651b877906bSopenharmony_ci                // The drag operation has moved over the window
1652b877906bSopenharmony_ci                const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
1653b877906bSopenharmony_ci                const int yabs = (event->xclient.data.l[2]) & 0xffff;
1654b877906bSopenharmony_ci                Window dummy;
1655b877906bSopenharmony_ci                int xpos, ypos;
1656b877906bSopenharmony_ci
1657b877906bSopenharmony_ci                if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
1658b877906bSopenharmony_ci                    return;
1659b877906bSopenharmony_ci
1660b877906bSopenharmony_ci                XTranslateCoordinates(_glfw.x11.display,
1661b877906bSopenharmony_ci                                      _glfw.x11.root,
1662b877906bSopenharmony_ci                                      window->x11.handle,
1663b877906bSopenharmony_ci                                      xabs, yabs,
1664b877906bSopenharmony_ci                                      &xpos, &ypos,
1665b877906bSopenharmony_ci                                      &dummy);
1666b877906bSopenharmony_ci
1667b877906bSopenharmony_ci                _glfwInputCursorPos(window, xpos, ypos);
1668b877906bSopenharmony_ci
1669b877906bSopenharmony_ci                XEvent reply = { ClientMessage };
1670b877906bSopenharmony_ci                reply.xclient.window = _glfw.x11.xdnd.source;
1671b877906bSopenharmony_ci                reply.xclient.message_type = _glfw.x11.XdndStatus;
1672b877906bSopenharmony_ci                reply.xclient.format = 32;
1673b877906bSopenharmony_ci                reply.xclient.data.l[0] = window->x11.handle;
1674b877906bSopenharmony_ci                reply.xclient.data.l[2] = 0; // Specify an empty rectangle
1675b877906bSopenharmony_ci                reply.xclient.data.l[3] = 0;
1676b877906bSopenharmony_ci
1677b877906bSopenharmony_ci                if (_glfw.x11.xdnd.format)
1678b877906bSopenharmony_ci                {
1679b877906bSopenharmony_ci                    // Reply that we are ready to copy the dragged data
1680b877906bSopenharmony_ci                    reply.xclient.data.l[1] = 1; // Accept with no rectangle
1681b877906bSopenharmony_ci                    if (_glfw.x11.xdnd.version >= 2)
1682b877906bSopenharmony_ci                        reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy;
1683b877906bSopenharmony_ci                }
1684b877906bSopenharmony_ci
1685b877906bSopenharmony_ci                XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
1686b877906bSopenharmony_ci                           False, NoEventMask, &reply);
1687b877906bSopenharmony_ci                XFlush(_glfw.x11.display);
1688b877906bSopenharmony_ci            }
1689b877906bSopenharmony_ci
1690b877906bSopenharmony_ci            return;
1691b877906bSopenharmony_ci        }
1692b877906bSopenharmony_ci
1693b877906bSopenharmony_ci        case SelectionNotify:
1694b877906bSopenharmony_ci        {
1695b877906bSopenharmony_ci            if (event->xselection.property == _glfw.x11.XdndSelection)
1696b877906bSopenharmony_ci            {
1697b877906bSopenharmony_ci                // The converted data from the drag operation has arrived
1698b877906bSopenharmony_ci                char* data;
1699b877906bSopenharmony_ci                const unsigned long result =
1700b877906bSopenharmony_ci                    _glfwGetWindowPropertyX11(event->xselection.requestor,
1701b877906bSopenharmony_ci                                              event->xselection.property,
1702b877906bSopenharmony_ci                                              event->xselection.target,
1703b877906bSopenharmony_ci                                              (unsigned char**) &data);
1704b877906bSopenharmony_ci
1705b877906bSopenharmony_ci                if (result)
1706b877906bSopenharmony_ci                {
1707b877906bSopenharmony_ci                    int count;
1708b877906bSopenharmony_ci                    char** paths = _glfwParseUriList(data, &count);
1709b877906bSopenharmony_ci
1710b877906bSopenharmony_ci                    _glfwInputDrop(window, count, (const char**) paths);
1711b877906bSopenharmony_ci
1712b877906bSopenharmony_ci                    for (int i = 0;  i < count;  i++)
1713b877906bSopenharmony_ci                        _glfw_free(paths[i]);
1714b877906bSopenharmony_ci                    _glfw_free(paths);
1715b877906bSopenharmony_ci                }
1716b877906bSopenharmony_ci
1717b877906bSopenharmony_ci                if (data)
1718b877906bSopenharmony_ci                    XFree(data);
1719b877906bSopenharmony_ci
1720b877906bSopenharmony_ci                if (_glfw.x11.xdnd.version >= 2)
1721b877906bSopenharmony_ci                {
1722b877906bSopenharmony_ci                    XEvent reply = { ClientMessage };
1723b877906bSopenharmony_ci                    reply.xclient.window = _glfw.x11.xdnd.source;
1724b877906bSopenharmony_ci                    reply.xclient.message_type = _glfw.x11.XdndFinished;
1725b877906bSopenharmony_ci                    reply.xclient.format = 32;
1726b877906bSopenharmony_ci                    reply.xclient.data.l[0] = window->x11.handle;
1727b877906bSopenharmony_ci                    reply.xclient.data.l[1] = result;
1728b877906bSopenharmony_ci                    reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy;
1729b877906bSopenharmony_ci
1730b877906bSopenharmony_ci                    XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
1731b877906bSopenharmony_ci                               False, NoEventMask, &reply);
1732b877906bSopenharmony_ci                    XFlush(_glfw.x11.display);
1733b877906bSopenharmony_ci                }
1734b877906bSopenharmony_ci            }
1735b877906bSopenharmony_ci
1736b877906bSopenharmony_ci            return;
1737b877906bSopenharmony_ci        }
1738b877906bSopenharmony_ci
1739b877906bSopenharmony_ci        case FocusIn:
1740b877906bSopenharmony_ci        {
1741b877906bSopenharmony_ci            if (event->xfocus.mode == NotifyGrab ||
1742b877906bSopenharmony_ci                event->xfocus.mode == NotifyUngrab)
1743b877906bSopenharmony_ci            {
1744b877906bSopenharmony_ci                // Ignore focus events from popup indicator windows, window menu
1745b877906bSopenharmony_ci                // key chords and window dragging
1746b877906bSopenharmony_ci                return;
1747b877906bSopenharmony_ci            }
1748b877906bSopenharmony_ci
1749b877906bSopenharmony_ci            if (window->cursorMode == GLFW_CURSOR_DISABLED)
1750b877906bSopenharmony_ci                disableCursor(window);
1751b877906bSopenharmony_ci            else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
1752b877906bSopenharmony_ci                captureCursor(window);
1753b877906bSopenharmony_ci
1754b877906bSopenharmony_ci            if (window->x11.ic)
1755b877906bSopenharmony_ci                XSetICFocus(window->x11.ic);
1756b877906bSopenharmony_ci
1757b877906bSopenharmony_ci            _glfwInputWindowFocus(window, GLFW_TRUE);
1758b877906bSopenharmony_ci            return;
1759b877906bSopenharmony_ci        }
1760b877906bSopenharmony_ci
1761b877906bSopenharmony_ci        case FocusOut:
1762b877906bSopenharmony_ci        {
1763b877906bSopenharmony_ci            if (event->xfocus.mode == NotifyGrab ||
1764b877906bSopenharmony_ci                event->xfocus.mode == NotifyUngrab)
1765b877906bSopenharmony_ci            {
1766b877906bSopenharmony_ci                // Ignore focus events from popup indicator windows, window menu
1767b877906bSopenharmony_ci                // key chords and window dragging
1768b877906bSopenharmony_ci                return;
1769b877906bSopenharmony_ci            }
1770b877906bSopenharmony_ci
1771b877906bSopenharmony_ci            if (window->cursorMode == GLFW_CURSOR_DISABLED)
1772b877906bSopenharmony_ci                enableCursor(window);
1773b877906bSopenharmony_ci            else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
1774b877906bSopenharmony_ci                releaseCursor();
1775b877906bSopenharmony_ci
1776b877906bSopenharmony_ci            if (window->x11.ic)
1777b877906bSopenharmony_ci                XUnsetICFocus(window->x11.ic);
1778b877906bSopenharmony_ci
1779b877906bSopenharmony_ci            if (window->monitor && window->autoIconify)
1780b877906bSopenharmony_ci                _glfwIconifyWindowX11(window);
1781b877906bSopenharmony_ci
1782b877906bSopenharmony_ci            _glfwInputWindowFocus(window, GLFW_FALSE);
1783b877906bSopenharmony_ci            return;
1784b877906bSopenharmony_ci        }
1785b877906bSopenharmony_ci
1786b877906bSopenharmony_ci        case Expose:
1787b877906bSopenharmony_ci        {
1788b877906bSopenharmony_ci            _glfwInputWindowDamage(window);
1789b877906bSopenharmony_ci            return;
1790b877906bSopenharmony_ci        }
1791b877906bSopenharmony_ci
1792b877906bSopenharmony_ci        case PropertyNotify:
1793b877906bSopenharmony_ci        {
1794b877906bSopenharmony_ci            if (event->xproperty.state != PropertyNewValue)
1795b877906bSopenharmony_ci                return;
1796b877906bSopenharmony_ci
1797b877906bSopenharmony_ci            if (event->xproperty.atom == _glfw.x11.WM_STATE)
1798b877906bSopenharmony_ci            {
1799b877906bSopenharmony_ci                const int state = getWindowState(window);
1800b877906bSopenharmony_ci                if (state != IconicState && state != NormalState)
1801b877906bSopenharmony_ci                    return;
1802b877906bSopenharmony_ci
1803b877906bSopenharmony_ci                const GLFWbool iconified = (state == IconicState);
1804b877906bSopenharmony_ci                if (window->x11.iconified != iconified)
1805b877906bSopenharmony_ci                {
1806b877906bSopenharmony_ci                    if (window->monitor)
1807b877906bSopenharmony_ci                    {
1808b877906bSopenharmony_ci                        if (iconified)
1809b877906bSopenharmony_ci                            releaseMonitor(window);
1810b877906bSopenharmony_ci                        else
1811b877906bSopenharmony_ci                            acquireMonitor(window);
1812b877906bSopenharmony_ci                    }
1813b877906bSopenharmony_ci
1814b877906bSopenharmony_ci                    window->x11.iconified = iconified;
1815b877906bSopenharmony_ci                    _glfwInputWindowIconify(window, iconified);
1816b877906bSopenharmony_ci                }
1817b877906bSopenharmony_ci            }
1818b877906bSopenharmony_ci            else if (event->xproperty.atom == _glfw.x11.NET_WM_STATE)
1819b877906bSopenharmony_ci            {
1820b877906bSopenharmony_ci                const GLFWbool maximized = _glfwWindowMaximizedX11(window);
1821b877906bSopenharmony_ci                if (window->x11.maximized != maximized)
1822b877906bSopenharmony_ci                {
1823b877906bSopenharmony_ci                    window->x11.maximized = maximized;
1824b877906bSopenharmony_ci                    _glfwInputWindowMaximize(window, maximized);
1825b877906bSopenharmony_ci                }
1826b877906bSopenharmony_ci            }
1827b877906bSopenharmony_ci
1828b877906bSopenharmony_ci            return;
1829b877906bSopenharmony_ci        }
1830b877906bSopenharmony_ci
1831b877906bSopenharmony_ci        case DestroyNotify:
1832b877906bSopenharmony_ci            return;
1833b877906bSopenharmony_ci    }
1834b877906bSopenharmony_ci}
1835b877906bSopenharmony_ci
1836b877906bSopenharmony_ci
1837b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
1838b877906bSopenharmony_ci//////                       GLFW internal API                      //////
1839b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
1840b877906bSopenharmony_ci
1841b877906bSopenharmony_ci// Retrieve a single window property of the specified type
1842b877906bSopenharmony_ci// Inspired by fghGetWindowProperty from freeglut
1843b877906bSopenharmony_ci//
1844b877906bSopenharmony_ciunsigned long _glfwGetWindowPropertyX11(Window window,
1845b877906bSopenharmony_ci                                        Atom property,
1846b877906bSopenharmony_ci                                        Atom type,
1847b877906bSopenharmony_ci                                        unsigned char** value)
1848b877906bSopenharmony_ci{
1849b877906bSopenharmony_ci    Atom actualType;
1850b877906bSopenharmony_ci    int actualFormat;
1851b877906bSopenharmony_ci    unsigned long itemCount, bytesAfter;
1852b877906bSopenharmony_ci
1853b877906bSopenharmony_ci    XGetWindowProperty(_glfw.x11.display,
1854b877906bSopenharmony_ci                       window,
1855b877906bSopenharmony_ci                       property,
1856b877906bSopenharmony_ci                       0,
1857b877906bSopenharmony_ci                       LONG_MAX,
1858b877906bSopenharmony_ci                       False,
1859b877906bSopenharmony_ci                       type,
1860b877906bSopenharmony_ci                       &actualType,
1861b877906bSopenharmony_ci                       &actualFormat,
1862b877906bSopenharmony_ci                       &itemCount,
1863b877906bSopenharmony_ci                       &bytesAfter,
1864b877906bSopenharmony_ci                       value);
1865b877906bSopenharmony_ci
1866b877906bSopenharmony_ci    return itemCount;
1867b877906bSopenharmony_ci}
1868b877906bSopenharmony_ci
1869b877906bSopenharmony_ciGLFWbool _glfwIsVisualTransparentX11(Visual* visual)
1870b877906bSopenharmony_ci{
1871b877906bSopenharmony_ci    if (!_glfw.x11.xrender.available)
1872b877906bSopenharmony_ci        return GLFW_FALSE;
1873b877906bSopenharmony_ci
1874b877906bSopenharmony_ci    XRenderPictFormat* pf = XRenderFindVisualFormat(_glfw.x11.display, visual);
1875b877906bSopenharmony_ci    return pf && pf->direct.alphaMask;
1876b877906bSopenharmony_ci}
1877b877906bSopenharmony_ci
1878b877906bSopenharmony_ci// Push contents of our selection to clipboard manager
1879b877906bSopenharmony_ci//
1880b877906bSopenharmony_civoid _glfwPushSelectionToManagerX11(void)
1881b877906bSopenharmony_ci{
1882b877906bSopenharmony_ci    XConvertSelection(_glfw.x11.display,
1883b877906bSopenharmony_ci                      _glfw.x11.CLIPBOARD_MANAGER,
1884b877906bSopenharmony_ci                      _glfw.x11.SAVE_TARGETS,
1885b877906bSopenharmony_ci                      None,
1886b877906bSopenharmony_ci                      _glfw.x11.helperWindowHandle,
1887b877906bSopenharmony_ci                      CurrentTime);
1888b877906bSopenharmony_ci
1889b877906bSopenharmony_ci    for (;;)
1890b877906bSopenharmony_ci    {
1891b877906bSopenharmony_ci        XEvent event;
1892b877906bSopenharmony_ci
1893b877906bSopenharmony_ci        while (XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL))
1894b877906bSopenharmony_ci        {
1895b877906bSopenharmony_ci            switch (event.type)
1896b877906bSopenharmony_ci            {
1897b877906bSopenharmony_ci                case SelectionRequest:
1898b877906bSopenharmony_ci                    handleSelectionRequest(&event);
1899b877906bSopenharmony_ci                    break;
1900b877906bSopenharmony_ci
1901b877906bSopenharmony_ci                case SelectionNotify:
1902b877906bSopenharmony_ci                {
1903b877906bSopenharmony_ci                    if (event.xselection.target == _glfw.x11.SAVE_TARGETS)
1904b877906bSopenharmony_ci                    {
1905b877906bSopenharmony_ci                        // This means one of two things; either the selection
1906b877906bSopenharmony_ci                        // was not owned, which means there is no clipboard
1907b877906bSopenharmony_ci                        // manager, or the transfer to the clipboard manager has
1908b877906bSopenharmony_ci                        // completed
1909b877906bSopenharmony_ci                        // In either case, it means we are done here
1910b877906bSopenharmony_ci                        return;
1911b877906bSopenharmony_ci                    }
1912b877906bSopenharmony_ci
1913b877906bSopenharmony_ci                    break;
1914b877906bSopenharmony_ci                }
1915b877906bSopenharmony_ci            }
1916b877906bSopenharmony_ci        }
1917b877906bSopenharmony_ci
1918b877906bSopenharmony_ci        waitForX11Event(NULL);
1919b877906bSopenharmony_ci    }
1920b877906bSopenharmony_ci}
1921b877906bSopenharmony_ci
1922b877906bSopenharmony_civoid _glfwCreateInputContextX11(_GLFWwindow* window)
1923b877906bSopenharmony_ci{
1924b877906bSopenharmony_ci    XIMCallback callback;
1925b877906bSopenharmony_ci    callback.callback = (XIMProc) inputContextDestroyCallback;
1926b877906bSopenharmony_ci    callback.client_data = (XPointer) window;
1927b877906bSopenharmony_ci
1928b877906bSopenharmony_ci    window->x11.ic = XCreateIC(_glfw.x11.im,
1929b877906bSopenharmony_ci                               XNInputStyle,
1930b877906bSopenharmony_ci                               XIMPreeditNothing | XIMStatusNothing,
1931b877906bSopenharmony_ci                               XNClientWindow,
1932b877906bSopenharmony_ci                               window->x11.handle,
1933b877906bSopenharmony_ci                               XNFocusWindow,
1934b877906bSopenharmony_ci                               window->x11.handle,
1935b877906bSopenharmony_ci                               XNDestroyCallback,
1936b877906bSopenharmony_ci                               &callback,
1937b877906bSopenharmony_ci                               NULL);
1938b877906bSopenharmony_ci
1939b877906bSopenharmony_ci    if (window->x11.ic)
1940b877906bSopenharmony_ci    {
1941b877906bSopenharmony_ci        XWindowAttributes attribs;
1942b877906bSopenharmony_ci        XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs);
1943b877906bSopenharmony_ci
1944b877906bSopenharmony_ci        unsigned long filter = 0;
1945b877906bSopenharmony_ci        if (XGetICValues(window->x11.ic, XNFilterEvents, &filter, NULL) == NULL)
1946b877906bSopenharmony_ci        {
1947b877906bSopenharmony_ci            XSelectInput(_glfw.x11.display,
1948b877906bSopenharmony_ci                         window->x11.handle,
1949b877906bSopenharmony_ci                         attribs.your_event_mask | filter);
1950b877906bSopenharmony_ci        }
1951b877906bSopenharmony_ci    }
1952b877906bSopenharmony_ci}
1953b877906bSopenharmony_ci
1954b877906bSopenharmony_ci
1955b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
1956b877906bSopenharmony_ci//////                       GLFW platform API                      //////
1957b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
1958b877906bSopenharmony_ci
1959b877906bSopenharmony_ciGLFWbool _glfwCreateWindowX11(_GLFWwindow* window,
1960b877906bSopenharmony_ci                              const _GLFWwndconfig* wndconfig,
1961b877906bSopenharmony_ci                              const _GLFWctxconfig* ctxconfig,
1962b877906bSopenharmony_ci                              const _GLFWfbconfig* fbconfig)
1963b877906bSopenharmony_ci{
1964b877906bSopenharmony_ci    Visual* visual = NULL;
1965b877906bSopenharmony_ci    int depth;
1966b877906bSopenharmony_ci
1967b877906bSopenharmony_ci    if (ctxconfig->client != GLFW_NO_API)
1968b877906bSopenharmony_ci    {
1969b877906bSopenharmony_ci        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
1970b877906bSopenharmony_ci        {
1971b877906bSopenharmony_ci            if (!_glfwInitGLX())
1972b877906bSopenharmony_ci                return GLFW_FALSE;
1973b877906bSopenharmony_ci            if (!_glfwChooseVisualGLX(wndconfig, ctxconfig, fbconfig, &visual, &depth))
1974b877906bSopenharmony_ci                return GLFW_FALSE;
1975b877906bSopenharmony_ci        }
1976b877906bSopenharmony_ci        else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
1977b877906bSopenharmony_ci        {
1978b877906bSopenharmony_ci            if (!_glfwInitEGL())
1979b877906bSopenharmony_ci                return GLFW_FALSE;
1980b877906bSopenharmony_ci            if (!_glfwChooseVisualEGL(wndconfig, ctxconfig, fbconfig, &visual, &depth))
1981b877906bSopenharmony_ci                return GLFW_FALSE;
1982b877906bSopenharmony_ci        }
1983b877906bSopenharmony_ci        else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
1984b877906bSopenharmony_ci        {
1985b877906bSopenharmony_ci            if (!_glfwInitOSMesa())
1986b877906bSopenharmony_ci                return GLFW_FALSE;
1987b877906bSopenharmony_ci        }
1988b877906bSopenharmony_ci    }
1989b877906bSopenharmony_ci
1990b877906bSopenharmony_ci    if (!visual)
1991b877906bSopenharmony_ci    {
1992b877906bSopenharmony_ci        visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen);
1993b877906bSopenharmony_ci        depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);
1994b877906bSopenharmony_ci    }
1995b877906bSopenharmony_ci
1996b877906bSopenharmony_ci    if (!createNativeWindow(window, wndconfig, visual, depth))
1997b877906bSopenharmony_ci        return GLFW_FALSE;
1998b877906bSopenharmony_ci
1999b877906bSopenharmony_ci    if (ctxconfig->client != GLFW_NO_API)
2000b877906bSopenharmony_ci    {
2001b877906bSopenharmony_ci        if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
2002b877906bSopenharmony_ci        {
2003b877906bSopenharmony_ci            if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig))
2004b877906bSopenharmony_ci                return GLFW_FALSE;
2005b877906bSopenharmony_ci        }
2006b877906bSopenharmony_ci        else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
2007b877906bSopenharmony_ci        {
2008b877906bSopenharmony_ci            if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
2009b877906bSopenharmony_ci                return GLFW_FALSE;
2010b877906bSopenharmony_ci        }
2011b877906bSopenharmony_ci        else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
2012b877906bSopenharmony_ci        {
2013b877906bSopenharmony_ci            if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
2014b877906bSopenharmony_ci                return GLFW_FALSE;
2015b877906bSopenharmony_ci        }
2016b877906bSopenharmony_ci
2017b877906bSopenharmony_ci        if (!_glfwRefreshContextAttribs(window, ctxconfig))
2018b877906bSopenharmony_ci            return GLFW_FALSE;
2019b877906bSopenharmony_ci    }
2020b877906bSopenharmony_ci
2021b877906bSopenharmony_ci    if (wndconfig->mousePassthrough)
2022b877906bSopenharmony_ci        _glfwSetWindowMousePassthroughX11(window, GLFW_TRUE);
2023b877906bSopenharmony_ci
2024b877906bSopenharmony_ci    if (window->monitor)
2025b877906bSopenharmony_ci    {
2026b877906bSopenharmony_ci        _glfwShowWindowX11(window);
2027b877906bSopenharmony_ci        updateWindowMode(window);
2028b877906bSopenharmony_ci        acquireMonitor(window);
2029b877906bSopenharmony_ci
2030b877906bSopenharmony_ci        if (wndconfig->centerCursor)
2031b877906bSopenharmony_ci            _glfwCenterCursorInContentArea(window);
2032b877906bSopenharmony_ci    }
2033b877906bSopenharmony_ci    else
2034b877906bSopenharmony_ci    {
2035b877906bSopenharmony_ci        if (wndconfig->visible)
2036b877906bSopenharmony_ci        {
2037b877906bSopenharmony_ci            _glfwShowWindowX11(window);
2038b877906bSopenharmony_ci            if (wndconfig->focused)
2039b877906bSopenharmony_ci                _glfwFocusWindowX11(window);
2040b877906bSopenharmony_ci        }
2041b877906bSopenharmony_ci    }
2042b877906bSopenharmony_ci
2043b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2044b877906bSopenharmony_ci    return GLFW_TRUE;
2045b877906bSopenharmony_ci}
2046b877906bSopenharmony_ci
2047b877906bSopenharmony_civoid _glfwDestroyWindowX11(_GLFWwindow* window)
2048b877906bSopenharmony_ci{
2049b877906bSopenharmony_ci    if (_glfw.x11.disabledCursorWindow == window)
2050b877906bSopenharmony_ci        enableCursor(window);
2051b877906bSopenharmony_ci
2052b877906bSopenharmony_ci    if (window->monitor)
2053b877906bSopenharmony_ci        releaseMonitor(window);
2054b877906bSopenharmony_ci
2055b877906bSopenharmony_ci    if (window->x11.ic)
2056b877906bSopenharmony_ci    {
2057b877906bSopenharmony_ci        XDestroyIC(window->x11.ic);
2058b877906bSopenharmony_ci        window->x11.ic = NULL;
2059b877906bSopenharmony_ci    }
2060b877906bSopenharmony_ci
2061b877906bSopenharmony_ci    if (window->context.destroy)
2062b877906bSopenharmony_ci        window->context.destroy(window);
2063b877906bSopenharmony_ci
2064b877906bSopenharmony_ci    if (window->x11.handle)
2065b877906bSopenharmony_ci    {
2066b877906bSopenharmony_ci        XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context);
2067b877906bSopenharmony_ci        XUnmapWindow(_glfw.x11.display, window->x11.handle);
2068b877906bSopenharmony_ci        XDestroyWindow(_glfw.x11.display, window->x11.handle);
2069b877906bSopenharmony_ci        window->x11.handle = (Window) 0;
2070b877906bSopenharmony_ci    }
2071b877906bSopenharmony_ci
2072b877906bSopenharmony_ci    if (window->x11.colormap)
2073b877906bSopenharmony_ci    {
2074b877906bSopenharmony_ci        XFreeColormap(_glfw.x11.display, window->x11.colormap);
2075b877906bSopenharmony_ci        window->x11.colormap = (Colormap) 0;
2076b877906bSopenharmony_ci    }
2077b877906bSopenharmony_ci
2078b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2079b877906bSopenharmony_ci}
2080b877906bSopenharmony_ci
2081b877906bSopenharmony_civoid _glfwSetWindowTitleX11(_GLFWwindow* window, const char* title)
2082b877906bSopenharmony_ci{
2083b877906bSopenharmony_ci    if (_glfw.x11.xlib.utf8)
2084b877906bSopenharmony_ci    {
2085b877906bSopenharmony_ci        Xutf8SetWMProperties(_glfw.x11.display,
2086b877906bSopenharmony_ci                             window->x11.handle,
2087b877906bSopenharmony_ci                             title, title,
2088b877906bSopenharmony_ci                             NULL, 0,
2089b877906bSopenharmony_ci                             NULL, NULL, NULL);
2090b877906bSopenharmony_ci    }
2091b877906bSopenharmony_ci
2092b877906bSopenharmony_ci    XChangeProperty(_glfw.x11.display,  window->x11.handle,
2093b877906bSopenharmony_ci                    _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8,
2094b877906bSopenharmony_ci                    PropModeReplace,
2095b877906bSopenharmony_ci                    (unsigned char*) title, strlen(title));
2096b877906bSopenharmony_ci
2097b877906bSopenharmony_ci    XChangeProperty(_glfw.x11.display,  window->x11.handle,
2098b877906bSopenharmony_ci                    _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8,
2099b877906bSopenharmony_ci                    PropModeReplace,
2100b877906bSopenharmony_ci                    (unsigned char*) title, strlen(title));
2101b877906bSopenharmony_ci
2102b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2103b877906bSopenharmony_ci}
2104b877906bSopenharmony_ci
2105b877906bSopenharmony_civoid _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* images)
2106b877906bSopenharmony_ci{
2107b877906bSopenharmony_ci    if (count)
2108b877906bSopenharmony_ci    {
2109b877906bSopenharmony_ci        int longCount = 0;
2110b877906bSopenharmony_ci
2111b877906bSopenharmony_ci        for (int i = 0;  i < count;  i++)
2112b877906bSopenharmony_ci            longCount += 2 + images[i].width * images[i].height;
2113b877906bSopenharmony_ci
2114b877906bSopenharmony_ci        unsigned long* icon = _glfw_calloc(longCount, sizeof(unsigned long));
2115b877906bSopenharmony_ci        unsigned long* target = icon;
2116b877906bSopenharmony_ci
2117b877906bSopenharmony_ci        for (int i = 0;  i < count;  i++)
2118b877906bSopenharmony_ci        {
2119b877906bSopenharmony_ci            *target++ = images[i].width;
2120b877906bSopenharmony_ci            *target++ = images[i].height;
2121b877906bSopenharmony_ci
2122b877906bSopenharmony_ci            for (int j = 0;  j < images[i].width * images[i].height;  j++)
2123b877906bSopenharmony_ci            {
2124b877906bSopenharmony_ci                *target++ = (((unsigned long) images[i].pixels[j * 4 + 0]) << 16) |
2125b877906bSopenharmony_ci                            (((unsigned long) images[i].pixels[j * 4 + 1]) <<  8) |
2126b877906bSopenharmony_ci                            (((unsigned long) images[i].pixels[j * 4 + 2]) <<  0) |
2127b877906bSopenharmony_ci                            (((unsigned long) images[i].pixels[j * 4 + 3]) << 24);
2128b877906bSopenharmony_ci            }
2129b877906bSopenharmony_ci        }
2130b877906bSopenharmony_ci
2131b877906bSopenharmony_ci        // NOTE: XChangeProperty expects 32-bit values like the image data above to be
2132b877906bSopenharmony_ci        //       placed in the 32 least significant bits of individual longs.  This is
2133b877906bSopenharmony_ci        //       true even if long is 64-bit and a WM protocol calls for "packed" data.
2134b877906bSopenharmony_ci        //       This is because of a historical mistake that then became part of the Xlib
2135b877906bSopenharmony_ci        //       ABI.  Xlib will pack these values into a regular array of 32-bit values
2136b877906bSopenharmony_ci        //       before sending it over the wire.
2137b877906bSopenharmony_ci        XChangeProperty(_glfw.x11.display, window->x11.handle,
2138b877906bSopenharmony_ci                        _glfw.x11.NET_WM_ICON,
2139b877906bSopenharmony_ci                        XA_CARDINAL, 32,
2140b877906bSopenharmony_ci                        PropModeReplace,
2141b877906bSopenharmony_ci                        (unsigned char*) icon,
2142b877906bSopenharmony_ci                        longCount);
2143b877906bSopenharmony_ci
2144b877906bSopenharmony_ci        _glfw_free(icon);
2145b877906bSopenharmony_ci    }
2146b877906bSopenharmony_ci    else
2147b877906bSopenharmony_ci    {
2148b877906bSopenharmony_ci        XDeleteProperty(_glfw.x11.display, window->x11.handle,
2149b877906bSopenharmony_ci                        _glfw.x11.NET_WM_ICON);
2150b877906bSopenharmony_ci    }
2151b877906bSopenharmony_ci
2152b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2153b877906bSopenharmony_ci}
2154b877906bSopenharmony_ci
2155b877906bSopenharmony_civoid _glfwGetWindowPosX11(_GLFWwindow* window, int* xpos, int* ypos)
2156b877906bSopenharmony_ci{
2157b877906bSopenharmony_ci    Window dummy;
2158b877906bSopenharmony_ci    int x, y;
2159b877906bSopenharmony_ci
2160b877906bSopenharmony_ci    XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
2161b877906bSopenharmony_ci                          0, 0, &x, &y, &dummy);
2162b877906bSopenharmony_ci
2163b877906bSopenharmony_ci    if (xpos)
2164b877906bSopenharmony_ci        *xpos = x;
2165b877906bSopenharmony_ci    if (ypos)
2166b877906bSopenharmony_ci        *ypos = y;
2167b877906bSopenharmony_ci}
2168b877906bSopenharmony_ci
2169b877906bSopenharmony_civoid _glfwSetWindowPosX11(_GLFWwindow* window, int xpos, int ypos)
2170b877906bSopenharmony_ci{
2171b877906bSopenharmony_ci    // HACK: Explicitly setting PPosition to any value causes some WMs, notably
2172b877906bSopenharmony_ci    //       Compiz and Metacity, to honor the position of unmapped windows
2173b877906bSopenharmony_ci    if (!_glfwWindowVisibleX11(window))
2174b877906bSopenharmony_ci    {
2175b877906bSopenharmony_ci        long supplied;
2176b877906bSopenharmony_ci        XSizeHints* hints = XAllocSizeHints();
2177b877906bSopenharmony_ci
2178b877906bSopenharmony_ci        if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied))
2179b877906bSopenharmony_ci        {
2180b877906bSopenharmony_ci            hints->flags |= PPosition;
2181b877906bSopenharmony_ci            hints->x = hints->y = 0;
2182b877906bSopenharmony_ci
2183b877906bSopenharmony_ci            XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
2184b877906bSopenharmony_ci        }
2185b877906bSopenharmony_ci
2186b877906bSopenharmony_ci        XFree(hints);
2187b877906bSopenharmony_ci    }
2188b877906bSopenharmony_ci
2189b877906bSopenharmony_ci    XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos);
2190b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2191b877906bSopenharmony_ci}
2192b877906bSopenharmony_ci
2193b877906bSopenharmony_civoid _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height)
2194b877906bSopenharmony_ci{
2195b877906bSopenharmony_ci    XWindowAttributes attribs;
2196b877906bSopenharmony_ci    XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs);
2197b877906bSopenharmony_ci
2198b877906bSopenharmony_ci    if (width)
2199b877906bSopenharmony_ci        *width = attribs.width;
2200b877906bSopenharmony_ci    if (height)
2201b877906bSopenharmony_ci        *height = attribs.height;
2202b877906bSopenharmony_ci}
2203b877906bSopenharmony_ci
2204b877906bSopenharmony_civoid _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height)
2205b877906bSopenharmony_ci{
2206b877906bSopenharmony_ci    if (window->monitor)
2207b877906bSopenharmony_ci    {
2208b877906bSopenharmony_ci        if (window->monitor->window == window)
2209b877906bSopenharmony_ci            acquireMonitor(window);
2210b877906bSopenharmony_ci    }
2211b877906bSopenharmony_ci    else
2212b877906bSopenharmony_ci    {
2213b877906bSopenharmony_ci        if (!window->resizable)
2214b877906bSopenharmony_ci            updateNormalHints(window, width, height);
2215b877906bSopenharmony_ci
2216b877906bSopenharmony_ci        XResizeWindow(_glfw.x11.display, window->x11.handle, width, height);
2217b877906bSopenharmony_ci    }
2218b877906bSopenharmony_ci
2219b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2220b877906bSopenharmony_ci}
2221b877906bSopenharmony_ci
2222b877906bSopenharmony_civoid _glfwSetWindowSizeLimitsX11(_GLFWwindow* window,
2223b877906bSopenharmony_ci                                 int minwidth, int minheight,
2224b877906bSopenharmony_ci                                 int maxwidth, int maxheight)
2225b877906bSopenharmony_ci{
2226b877906bSopenharmony_ci    int width, height;
2227b877906bSopenharmony_ci    _glfwGetWindowSizeX11(window, &width, &height);
2228b877906bSopenharmony_ci    updateNormalHints(window, width, height);
2229b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2230b877906bSopenharmony_ci}
2231b877906bSopenharmony_ci
2232b877906bSopenharmony_civoid _glfwSetWindowAspectRatioX11(_GLFWwindow* window, int numer, int denom)
2233b877906bSopenharmony_ci{
2234b877906bSopenharmony_ci    int width, height;
2235b877906bSopenharmony_ci    _glfwGetWindowSizeX11(window, &width, &height);
2236b877906bSopenharmony_ci    updateNormalHints(window, width, height);
2237b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2238b877906bSopenharmony_ci}
2239b877906bSopenharmony_ci
2240b877906bSopenharmony_civoid _glfwGetFramebufferSizeX11(_GLFWwindow* window, int* width, int* height)
2241b877906bSopenharmony_ci{
2242b877906bSopenharmony_ci    _glfwGetWindowSizeX11(window, width, height);
2243b877906bSopenharmony_ci}
2244b877906bSopenharmony_ci
2245b877906bSopenharmony_civoid _glfwGetWindowFrameSizeX11(_GLFWwindow* window,
2246b877906bSopenharmony_ci                                int* left, int* top,
2247b877906bSopenharmony_ci                                int* right, int* bottom)
2248b877906bSopenharmony_ci{
2249b877906bSopenharmony_ci    long* extents = NULL;
2250b877906bSopenharmony_ci
2251b877906bSopenharmony_ci    if (window->monitor || !window->decorated)
2252b877906bSopenharmony_ci        return;
2253b877906bSopenharmony_ci
2254b877906bSopenharmony_ci    if (_glfw.x11.NET_FRAME_EXTENTS == None)
2255b877906bSopenharmony_ci        return;
2256b877906bSopenharmony_ci
2257b877906bSopenharmony_ci    if (!_glfwWindowVisibleX11(window) &&
2258b877906bSopenharmony_ci        _glfw.x11.NET_REQUEST_FRAME_EXTENTS)
2259b877906bSopenharmony_ci    {
2260b877906bSopenharmony_ci        XEvent event;
2261b877906bSopenharmony_ci        double timeout = 0.5;
2262b877906bSopenharmony_ci
2263b877906bSopenharmony_ci        // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to
2264b877906bSopenharmony_ci        // function before the window is mapped
2265b877906bSopenharmony_ci        sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS,
2266b877906bSopenharmony_ci                      0, 0, 0, 0, 0);
2267b877906bSopenharmony_ci
2268b877906bSopenharmony_ci        // HACK: Use a timeout because earlier versions of some window managers
2269b877906bSopenharmony_ci        //       (at least Unity, Fluxbox and Xfwm) failed to send the reply
2270b877906bSopenharmony_ci        //       They have been fixed but broken versions are still in the wild
2271b877906bSopenharmony_ci        //       If you are affected by this and your window manager is NOT
2272b877906bSopenharmony_ci        //       listed above, PLEASE report it to their and our issue trackers
2273b877906bSopenharmony_ci        while (!XCheckIfEvent(_glfw.x11.display,
2274b877906bSopenharmony_ci                              &event,
2275b877906bSopenharmony_ci                              isFrameExtentsEvent,
2276b877906bSopenharmony_ci                              (XPointer) window))
2277b877906bSopenharmony_ci        {
2278b877906bSopenharmony_ci            if (!waitForX11Event(&timeout))
2279b877906bSopenharmony_ci            {
2280b877906bSopenharmony_ci                _glfwInputError(GLFW_PLATFORM_ERROR,
2281b877906bSopenharmony_ci                                "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
2282b877906bSopenharmony_ci                return;
2283b877906bSopenharmony_ci            }
2284b877906bSopenharmony_ci        }
2285b877906bSopenharmony_ci    }
2286b877906bSopenharmony_ci
2287b877906bSopenharmony_ci    if (_glfwGetWindowPropertyX11(window->x11.handle,
2288b877906bSopenharmony_ci                                  _glfw.x11.NET_FRAME_EXTENTS,
2289b877906bSopenharmony_ci                                  XA_CARDINAL,
2290b877906bSopenharmony_ci                                  (unsigned char**) &extents) == 4)
2291b877906bSopenharmony_ci    {
2292b877906bSopenharmony_ci        if (left)
2293b877906bSopenharmony_ci            *left = extents[0];
2294b877906bSopenharmony_ci        if (top)
2295b877906bSopenharmony_ci            *top = extents[2];
2296b877906bSopenharmony_ci        if (right)
2297b877906bSopenharmony_ci            *right = extents[1];
2298b877906bSopenharmony_ci        if (bottom)
2299b877906bSopenharmony_ci            *bottom = extents[3];
2300b877906bSopenharmony_ci    }
2301b877906bSopenharmony_ci
2302b877906bSopenharmony_ci    if (extents)
2303b877906bSopenharmony_ci        XFree(extents);
2304b877906bSopenharmony_ci}
2305b877906bSopenharmony_ci
2306b877906bSopenharmony_civoid _glfwGetWindowContentScaleX11(_GLFWwindow* window, float* xscale, float* yscale)
2307b877906bSopenharmony_ci{
2308b877906bSopenharmony_ci    if (xscale)
2309b877906bSopenharmony_ci        *xscale = _glfw.x11.contentScaleX;
2310b877906bSopenharmony_ci    if (yscale)
2311b877906bSopenharmony_ci        *yscale = _glfw.x11.contentScaleY;
2312b877906bSopenharmony_ci}
2313b877906bSopenharmony_ci
2314b877906bSopenharmony_civoid _glfwIconifyWindowX11(_GLFWwindow* window)
2315b877906bSopenharmony_ci{
2316b877906bSopenharmony_ci    if (window->x11.overrideRedirect)
2317b877906bSopenharmony_ci    {
2318b877906bSopenharmony_ci        // Override-redirect windows cannot be iconified or restored, as those
2319b877906bSopenharmony_ci        // tasks are performed by the window manager
2320b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
2321b877906bSopenharmony_ci                        "X11: Iconification of full screen windows requires a WM that supports EWMH full screen");
2322b877906bSopenharmony_ci        return;
2323b877906bSopenharmony_ci    }
2324b877906bSopenharmony_ci
2325b877906bSopenharmony_ci    XIconifyWindow(_glfw.x11.display, window->x11.handle, _glfw.x11.screen);
2326b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2327b877906bSopenharmony_ci}
2328b877906bSopenharmony_ci
2329b877906bSopenharmony_civoid _glfwRestoreWindowX11(_GLFWwindow* window)
2330b877906bSopenharmony_ci{
2331b877906bSopenharmony_ci    if (window->x11.overrideRedirect)
2332b877906bSopenharmony_ci    {
2333b877906bSopenharmony_ci        // Override-redirect windows cannot be iconified or restored, as those
2334b877906bSopenharmony_ci        // tasks are performed by the window manager
2335b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
2336b877906bSopenharmony_ci                        "X11: Iconification of full screen windows requires a WM that supports EWMH full screen");
2337b877906bSopenharmony_ci        return;
2338b877906bSopenharmony_ci    }
2339b877906bSopenharmony_ci
2340b877906bSopenharmony_ci    if (_glfwWindowIconifiedX11(window))
2341b877906bSopenharmony_ci    {
2342b877906bSopenharmony_ci        XMapWindow(_glfw.x11.display, window->x11.handle);
2343b877906bSopenharmony_ci        waitForVisibilityNotify(window);
2344b877906bSopenharmony_ci    }
2345b877906bSopenharmony_ci    else if (_glfwWindowVisibleX11(window))
2346b877906bSopenharmony_ci    {
2347b877906bSopenharmony_ci        if (_glfw.x11.NET_WM_STATE &&
2348b877906bSopenharmony_ci            _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
2349b877906bSopenharmony_ci            _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
2350b877906bSopenharmony_ci        {
2351b877906bSopenharmony_ci            sendEventToWM(window,
2352b877906bSopenharmony_ci                          _glfw.x11.NET_WM_STATE,
2353b877906bSopenharmony_ci                          _NET_WM_STATE_REMOVE,
2354b877906bSopenharmony_ci                          _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
2355b877906bSopenharmony_ci                          _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
2356b877906bSopenharmony_ci                          1, 0);
2357b877906bSopenharmony_ci        }
2358b877906bSopenharmony_ci    }
2359b877906bSopenharmony_ci
2360b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2361b877906bSopenharmony_ci}
2362b877906bSopenharmony_ci
2363b877906bSopenharmony_civoid _glfwMaximizeWindowX11(_GLFWwindow* window)
2364b877906bSopenharmony_ci{
2365b877906bSopenharmony_ci    if (!_glfw.x11.NET_WM_STATE ||
2366b877906bSopenharmony_ci        !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
2367b877906bSopenharmony_ci        !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
2368b877906bSopenharmony_ci    {
2369b877906bSopenharmony_ci        return;
2370b877906bSopenharmony_ci    }
2371b877906bSopenharmony_ci
2372b877906bSopenharmony_ci    if (_glfwWindowVisibleX11(window))
2373b877906bSopenharmony_ci    {
2374b877906bSopenharmony_ci        sendEventToWM(window,
2375b877906bSopenharmony_ci                    _glfw.x11.NET_WM_STATE,
2376b877906bSopenharmony_ci                    _NET_WM_STATE_ADD,
2377b877906bSopenharmony_ci                    _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
2378b877906bSopenharmony_ci                    _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
2379b877906bSopenharmony_ci                    1, 0);
2380b877906bSopenharmony_ci    }
2381b877906bSopenharmony_ci    else
2382b877906bSopenharmony_ci    {
2383b877906bSopenharmony_ci        Atom* states = NULL;
2384b877906bSopenharmony_ci        unsigned long count =
2385b877906bSopenharmony_ci            _glfwGetWindowPropertyX11(window->x11.handle,
2386b877906bSopenharmony_ci                                      _glfw.x11.NET_WM_STATE,
2387b877906bSopenharmony_ci                                      XA_ATOM,
2388b877906bSopenharmony_ci                                      (unsigned char**) &states);
2389b877906bSopenharmony_ci
2390b877906bSopenharmony_ci        // NOTE: We don't check for failure as this property may not exist yet
2391b877906bSopenharmony_ci        //       and that's fine (and we'll create it implicitly with append)
2392b877906bSopenharmony_ci
2393b877906bSopenharmony_ci        Atom missing[2] =
2394b877906bSopenharmony_ci        {
2395b877906bSopenharmony_ci            _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
2396b877906bSopenharmony_ci            _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ
2397b877906bSopenharmony_ci        };
2398b877906bSopenharmony_ci        unsigned long missingCount = 2;
2399b877906bSopenharmony_ci
2400b877906bSopenharmony_ci        for (unsigned long i = 0;  i < count;  i++)
2401b877906bSopenharmony_ci        {
2402b877906bSopenharmony_ci            for (unsigned long j = 0;  j < missingCount;  j++)
2403b877906bSopenharmony_ci            {
2404b877906bSopenharmony_ci                if (states[i] == missing[j])
2405b877906bSopenharmony_ci                {
2406b877906bSopenharmony_ci                    missing[j] = missing[missingCount - 1];
2407b877906bSopenharmony_ci                    missingCount--;
2408b877906bSopenharmony_ci                }
2409b877906bSopenharmony_ci            }
2410b877906bSopenharmony_ci        }
2411b877906bSopenharmony_ci
2412b877906bSopenharmony_ci        if (states)
2413b877906bSopenharmony_ci            XFree(states);
2414b877906bSopenharmony_ci
2415b877906bSopenharmony_ci        if (!missingCount)
2416b877906bSopenharmony_ci            return;
2417b877906bSopenharmony_ci
2418b877906bSopenharmony_ci        XChangeProperty(_glfw.x11.display, window->x11.handle,
2419b877906bSopenharmony_ci                        _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
2420b877906bSopenharmony_ci                        PropModeAppend,
2421b877906bSopenharmony_ci                        (unsigned char*) missing,
2422b877906bSopenharmony_ci                        missingCount);
2423b877906bSopenharmony_ci    }
2424b877906bSopenharmony_ci
2425b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2426b877906bSopenharmony_ci}
2427b877906bSopenharmony_ci
2428b877906bSopenharmony_civoid _glfwShowWindowX11(_GLFWwindow* window)
2429b877906bSopenharmony_ci{
2430b877906bSopenharmony_ci    if (_glfwWindowVisibleX11(window))
2431b877906bSopenharmony_ci        return;
2432b877906bSopenharmony_ci
2433b877906bSopenharmony_ci    XMapWindow(_glfw.x11.display, window->x11.handle);
2434b877906bSopenharmony_ci    waitForVisibilityNotify(window);
2435b877906bSopenharmony_ci}
2436b877906bSopenharmony_ci
2437b877906bSopenharmony_civoid _glfwHideWindowX11(_GLFWwindow* window)
2438b877906bSopenharmony_ci{
2439b877906bSopenharmony_ci    XUnmapWindow(_glfw.x11.display, window->x11.handle);
2440b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2441b877906bSopenharmony_ci}
2442b877906bSopenharmony_ci
2443b877906bSopenharmony_civoid _glfwRequestWindowAttentionX11(_GLFWwindow* window)
2444b877906bSopenharmony_ci{
2445b877906bSopenharmony_ci    if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION)
2446b877906bSopenharmony_ci        return;
2447b877906bSopenharmony_ci
2448b877906bSopenharmony_ci    sendEventToWM(window,
2449b877906bSopenharmony_ci                  _glfw.x11.NET_WM_STATE,
2450b877906bSopenharmony_ci                  _NET_WM_STATE_ADD,
2451b877906bSopenharmony_ci                  _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION,
2452b877906bSopenharmony_ci                  0, 1, 0);
2453b877906bSopenharmony_ci}
2454b877906bSopenharmony_ci
2455b877906bSopenharmony_civoid _glfwFocusWindowX11(_GLFWwindow* window)
2456b877906bSopenharmony_ci{
2457b877906bSopenharmony_ci    if (_glfw.x11.NET_ACTIVE_WINDOW)
2458b877906bSopenharmony_ci        sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0);
2459b877906bSopenharmony_ci    else if (_glfwWindowVisibleX11(window))
2460b877906bSopenharmony_ci    {
2461b877906bSopenharmony_ci        XRaiseWindow(_glfw.x11.display, window->x11.handle);
2462b877906bSopenharmony_ci        XSetInputFocus(_glfw.x11.display, window->x11.handle,
2463b877906bSopenharmony_ci                       RevertToParent, CurrentTime);
2464b877906bSopenharmony_ci    }
2465b877906bSopenharmony_ci
2466b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2467b877906bSopenharmony_ci}
2468b877906bSopenharmony_ci
2469b877906bSopenharmony_civoid _glfwSetWindowMonitorX11(_GLFWwindow* window,
2470b877906bSopenharmony_ci                              _GLFWmonitor* monitor,
2471b877906bSopenharmony_ci                              int xpos, int ypos,
2472b877906bSopenharmony_ci                              int width, int height,
2473b877906bSopenharmony_ci                              int refreshRate)
2474b877906bSopenharmony_ci{
2475b877906bSopenharmony_ci    if (window->monitor == monitor)
2476b877906bSopenharmony_ci    {
2477b877906bSopenharmony_ci        if (monitor)
2478b877906bSopenharmony_ci        {
2479b877906bSopenharmony_ci            if (monitor->window == window)
2480b877906bSopenharmony_ci                acquireMonitor(window);
2481b877906bSopenharmony_ci        }
2482b877906bSopenharmony_ci        else
2483b877906bSopenharmony_ci        {
2484b877906bSopenharmony_ci            if (!window->resizable)
2485b877906bSopenharmony_ci                updateNormalHints(window, width, height);
2486b877906bSopenharmony_ci
2487b877906bSopenharmony_ci            XMoveResizeWindow(_glfw.x11.display, window->x11.handle,
2488b877906bSopenharmony_ci                              xpos, ypos, width, height);
2489b877906bSopenharmony_ci        }
2490b877906bSopenharmony_ci
2491b877906bSopenharmony_ci        XFlush(_glfw.x11.display);
2492b877906bSopenharmony_ci        return;
2493b877906bSopenharmony_ci    }
2494b877906bSopenharmony_ci
2495b877906bSopenharmony_ci    if (window->monitor)
2496b877906bSopenharmony_ci    {
2497b877906bSopenharmony_ci        _glfwSetWindowDecoratedX11(window, window->decorated);
2498b877906bSopenharmony_ci        _glfwSetWindowFloatingX11(window, window->floating);
2499b877906bSopenharmony_ci        releaseMonitor(window);
2500b877906bSopenharmony_ci    }
2501b877906bSopenharmony_ci
2502b877906bSopenharmony_ci    _glfwInputWindowMonitor(window, monitor);
2503b877906bSopenharmony_ci    updateNormalHints(window, width, height);
2504b877906bSopenharmony_ci
2505b877906bSopenharmony_ci    if (window->monitor)
2506b877906bSopenharmony_ci    {
2507b877906bSopenharmony_ci        if (!_glfwWindowVisibleX11(window))
2508b877906bSopenharmony_ci        {
2509b877906bSopenharmony_ci            XMapRaised(_glfw.x11.display, window->x11.handle);
2510b877906bSopenharmony_ci            waitForVisibilityNotify(window);
2511b877906bSopenharmony_ci        }
2512b877906bSopenharmony_ci
2513b877906bSopenharmony_ci        updateWindowMode(window);
2514b877906bSopenharmony_ci        acquireMonitor(window);
2515b877906bSopenharmony_ci    }
2516b877906bSopenharmony_ci    else
2517b877906bSopenharmony_ci    {
2518b877906bSopenharmony_ci        updateWindowMode(window);
2519b877906bSopenharmony_ci        XMoveResizeWindow(_glfw.x11.display, window->x11.handle,
2520b877906bSopenharmony_ci                          xpos, ypos, width, height);
2521b877906bSopenharmony_ci    }
2522b877906bSopenharmony_ci
2523b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2524b877906bSopenharmony_ci}
2525b877906bSopenharmony_ci
2526b877906bSopenharmony_ciGLFWbool _glfwWindowFocusedX11(_GLFWwindow* window)
2527b877906bSopenharmony_ci{
2528b877906bSopenharmony_ci    Window focused;
2529b877906bSopenharmony_ci    int state;
2530b877906bSopenharmony_ci
2531b877906bSopenharmony_ci    XGetInputFocus(_glfw.x11.display, &focused, &state);
2532b877906bSopenharmony_ci    return window->x11.handle == focused;
2533b877906bSopenharmony_ci}
2534b877906bSopenharmony_ci
2535b877906bSopenharmony_ciGLFWbool _glfwWindowIconifiedX11(_GLFWwindow* window)
2536b877906bSopenharmony_ci{
2537b877906bSopenharmony_ci    return getWindowState(window) == IconicState;
2538b877906bSopenharmony_ci}
2539b877906bSopenharmony_ci
2540b877906bSopenharmony_ciGLFWbool _glfwWindowVisibleX11(_GLFWwindow* window)
2541b877906bSopenharmony_ci{
2542b877906bSopenharmony_ci    XWindowAttributes wa;
2543b877906bSopenharmony_ci    XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa);
2544b877906bSopenharmony_ci    return wa.map_state == IsViewable;
2545b877906bSopenharmony_ci}
2546b877906bSopenharmony_ci
2547b877906bSopenharmony_ciGLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window)
2548b877906bSopenharmony_ci{
2549b877906bSopenharmony_ci    Atom* states;
2550b877906bSopenharmony_ci    GLFWbool maximized = GLFW_FALSE;
2551b877906bSopenharmony_ci
2552b877906bSopenharmony_ci    if (!_glfw.x11.NET_WM_STATE ||
2553b877906bSopenharmony_ci        !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
2554b877906bSopenharmony_ci        !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
2555b877906bSopenharmony_ci    {
2556b877906bSopenharmony_ci        return maximized;
2557b877906bSopenharmony_ci    }
2558b877906bSopenharmony_ci
2559b877906bSopenharmony_ci    const unsigned long count =
2560b877906bSopenharmony_ci        _glfwGetWindowPropertyX11(window->x11.handle,
2561b877906bSopenharmony_ci                                  _glfw.x11.NET_WM_STATE,
2562b877906bSopenharmony_ci                                  XA_ATOM,
2563b877906bSopenharmony_ci                                  (unsigned char**) &states);
2564b877906bSopenharmony_ci
2565b877906bSopenharmony_ci    for (unsigned long i = 0;  i < count;  i++)
2566b877906bSopenharmony_ci    {
2567b877906bSopenharmony_ci        if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
2568b877906bSopenharmony_ci            states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
2569b877906bSopenharmony_ci        {
2570b877906bSopenharmony_ci            maximized = GLFW_TRUE;
2571b877906bSopenharmony_ci            break;
2572b877906bSopenharmony_ci        }
2573b877906bSopenharmony_ci    }
2574b877906bSopenharmony_ci
2575b877906bSopenharmony_ci    if (states)
2576b877906bSopenharmony_ci        XFree(states);
2577b877906bSopenharmony_ci
2578b877906bSopenharmony_ci    return maximized;
2579b877906bSopenharmony_ci}
2580b877906bSopenharmony_ci
2581b877906bSopenharmony_ciGLFWbool _glfwWindowHoveredX11(_GLFWwindow* window)
2582b877906bSopenharmony_ci{
2583b877906bSopenharmony_ci    Window w = _glfw.x11.root;
2584b877906bSopenharmony_ci    while (w)
2585b877906bSopenharmony_ci    {
2586b877906bSopenharmony_ci        Window root;
2587b877906bSopenharmony_ci        int rootX, rootY, childX, childY;
2588b877906bSopenharmony_ci        unsigned int mask;
2589b877906bSopenharmony_ci
2590b877906bSopenharmony_ci        _glfwGrabErrorHandlerX11();
2591b877906bSopenharmony_ci
2592b877906bSopenharmony_ci        const Bool result = XQueryPointer(_glfw.x11.display, w,
2593b877906bSopenharmony_ci                                          &root, &w, &rootX, &rootY,
2594b877906bSopenharmony_ci                                          &childX, &childY, &mask);
2595b877906bSopenharmony_ci
2596b877906bSopenharmony_ci        _glfwReleaseErrorHandlerX11();
2597b877906bSopenharmony_ci
2598b877906bSopenharmony_ci        if (_glfw.x11.errorCode == BadWindow)
2599b877906bSopenharmony_ci            w = _glfw.x11.root;
2600b877906bSopenharmony_ci        else if (!result)
2601b877906bSopenharmony_ci            return GLFW_FALSE;
2602b877906bSopenharmony_ci        else if (w == window->x11.handle)
2603b877906bSopenharmony_ci            return GLFW_TRUE;
2604b877906bSopenharmony_ci    }
2605b877906bSopenharmony_ci
2606b877906bSopenharmony_ci    return GLFW_FALSE;
2607b877906bSopenharmony_ci}
2608b877906bSopenharmony_ci
2609b877906bSopenharmony_ciGLFWbool _glfwFramebufferTransparentX11(_GLFWwindow* window)
2610b877906bSopenharmony_ci{
2611b877906bSopenharmony_ci    if (!window->x11.transparent)
2612b877906bSopenharmony_ci        return GLFW_FALSE;
2613b877906bSopenharmony_ci
2614b877906bSopenharmony_ci    return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None;
2615b877906bSopenharmony_ci}
2616b877906bSopenharmony_ci
2617b877906bSopenharmony_civoid _glfwSetWindowResizableX11(_GLFWwindow* window, GLFWbool enabled)
2618b877906bSopenharmony_ci{
2619b877906bSopenharmony_ci    int width, height;
2620b877906bSopenharmony_ci    _glfwGetWindowSizeX11(window, &width, &height);
2621b877906bSopenharmony_ci    updateNormalHints(window, width, height);
2622b877906bSopenharmony_ci}
2623b877906bSopenharmony_ci
2624b877906bSopenharmony_civoid _glfwSetWindowDecoratedX11(_GLFWwindow* window, GLFWbool enabled)
2625b877906bSopenharmony_ci{
2626b877906bSopenharmony_ci    struct
2627b877906bSopenharmony_ci    {
2628b877906bSopenharmony_ci        unsigned long flags;
2629b877906bSopenharmony_ci        unsigned long functions;
2630b877906bSopenharmony_ci        unsigned long decorations;
2631b877906bSopenharmony_ci        long input_mode;
2632b877906bSopenharmony_ci        unsigned long status;
2633b877906bSopenharmony_ci    } hints = {0};
2634b877906bSopenharmony_ci
2635b877906bSopenharmony_ci    hints.flags = MWM_HINTS_DECORATIONS;
2636b877906bSopenharmony_ci    hints.decorations = enabled ? MWM_DECOR_ALL : 0;
2637b877906bSopenharmony_ci
2638b877906bSopenharmony_ci    XChangeProperty(_glfw.x11.display, window->x11.handle,
2639b877906bSopenharmony_ci                    _glfw.x11.MOTIF_WM_HINTS,
2640b877906bSopenharmony_ci                    _glfw.x11.MOTIF_WM_HINTS, 32,
2641b877906bSopenharmony_ci                    PropModeReplace,
2642b877906bSopenharmony_ci                    (unsigned char*) &hints,
2643b877906bSopenharmony_ci                    sizeof(hints) / sizeof(long));
2644b877906bSopenharmony_ci}
2645b877906bSopenharmony_ci
2646b877906bSopenharmony_civoid _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled)
2647b877906bSopenharmony_ci{
2648b877906bSopenharmony_ci    if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_ABOVE)
2649b877906bSopenharmony_ci        return;
2650b877906bSopenharmony_ci
2651b877906bSopenharmony_ci    if (_glfwWindowVisibleX11(window))
2652b877906bSopenharmony_ci    {
2653b877906bSopenharmony_ci        const long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
2654b877906bSopenharmony_ci        sendEventToWM(window,
2655b877906bSopenharmony_ci                      _glfw.x11.NET_WM_STATE,
2656b877906bSopenharmony_ci                      action,
2657b877906bSopenharmony_ci                      _glfw.x11.NET_WM_STATE_ABOVE,
2658b877906bSopenharmony_ci                      0, 1, 0);
2659b877906bSopenharmony_ci    }
2660b877906bSopenharmony_ci    else
2661b877906bSopenharmony_ci    {
2662b877906bSopenharmony_ci        Atom* states = NULL;
2663b877906bSopenharmony_ci        const unsigned long count =
2664b877906bSopenharmony_ci            _glfwGetWindowPropertyX11(window->x11.handle,
2665b877906bSopenharmony_ci                                      _glfw.x11.NET_WM_STATE,
2666b877906bSopenharmony_ci                                      XA_ATOM,
2667b877906bSopenharmony_ci                                      (unsigned char**) &states);
2668b877906bSopenharmony_ci
2669b877906bSopenharmony_ci        // NOTE: We don't check for failure as this property may not exist yet
2670b877906bSopenharmony_ci        //       and that's fine (and we'll create it implicitly with append)
2671b877906bSopenharmony_ci
2672b877906bSopenharmony_ci        if (enabled)
2673b877906bSopenharmony_ci        {
2674b877906bSopenharmony_ci            unsigned long i;
2675b877906bSopenharmony_ci
2676b877906bSopenharmony_ci            for (i = 0;  i < count;  i++)
2677b877906bSopenharmony_ci            {
2678b877906bSopenharmony_ci                if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
2679b877906bSopenharmony_ci                    break;
2680b877906bSopenharmony_ci            }
2681b877906bSopenharmony_ci
2682b877906bSopenharmony_ci            if (i == count)
2683b877906bSopenharmony_ci            {
2684b877906bSopenharmony_ci                XChangeProperty(_glfw.x11.display, window->x11.handle,
2685b877906bSopenharmony_ci                                _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
2686b877906bSopenharmony_ci                                PropModeAppend,
2687b877906bSopenharmony_ci                                (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
2688b877906bSopenharmony_ci                                1);
2689b877906bSopenharmony_ci            }
2690b877906bSopenharmony_ci        }
2691b877906bSopenharmony_ci        else if (states)
2692b877906bSopenharmony_ci        {
2693b877906bSopenharmony_ci            for (unsigned long i = 0;  i < count;  i++)
2694b877906bSopenharmony_ci            {
2695b877906bSopenharmony_ci                if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
2696b877906bSopenharmony_ci                {
2697b877906bSopenharmony_ci                    states[i] = states[count - 1];
2698b877906bSopenharmony_ci                    XChangeProperty(_glfw.x11.display, window->x11.handle,
2699b877906bSopenharmony_ci                                    _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
2700b877906bSopenharmony_ci                                    PropModeReplace, (unsigned char*) states, count - 1);
2701b877906bSopenharmony_ci                    break;
2702b877906bSopenharmony_ci                }
2703b877906bSopenharmony_ci            }
2704b877906bSopenharmony_ci        }
2705b877906bSopenharmony_ci
2706b877906bSopenharmony_ci        if (states)
2707b877906bSopenharmony_ci            XFree(states);
2708b877906bSopenharmony_ci    }
2709b877906bSopenharmony_ci
2710b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2711b877906bSopenharmony_ci}
2712b877906bSopenharmony_ci
2713b877906bSopenharmony_civoid _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled)
2714b877906bSopenharmony_ci{
2715b877906bSopenharmony_ci    if (!_glfw.x11.xshape.available)
2716b877906bSopenharmony_ci        return;
2717b877906bSopenharmony_ci
2718b877906bSopenharmony_ci    if (enabled)
2719b877906bSopenharmony_ci    {
2720b877906bSopenharmony_ci        Region region = XCreateRegion();
2721b877906bSopenharmony_ci        XShapeCombineRegion(_glfw.x11.display, window->x11.handle,
2722b877906bSopenharmony_ci                            ShapeInput, 0, 0, region, ShapeSet);
2723b877906bSopenharmony_ci        XDestroyRegion(region);
2724b877906bSopenharmony_ci    }
2725b877906bSopenharmony_ci    else
2726b877906bSopenharmony_ci    {
2727b877906bSopenharmony_ci        XShapeCombineMask(_glfw.x11.display, window->x11.handle,
2728b877906bSopenharmony_ci                          ShapeInput, 0, 0, None, ShapeSet);
2729b877906bSopenharmony_ci    }
2730b877906bSopenharmony_ci}
2731b877906bSopenharmony_ci
2732b877906bSopenharmony_cifloat _glfwGetWindowOpacityX11(_GLFWwindow* window)
2733b877906bSopenharmony_ci{
2734b877906bSopenharmony_ci    float opacity = 1.f;
2735b877906bSopenharmony_ci
2736b877906bSopenharmony_ci    if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx))
2737b877906bSopenharmony_ci    {
2738b877906bSopenharmony_ci        CARD32* value = NULL;
2739b877906bSopenharmony_ci
2740b877906bSopenharmony_ci        if (_glfwGetWindowPropertyX11(window->x11.handle,
2741b877906bSopenharmony_ci                                      _glfw.x11.NET_WM_WINDOW_OPACITY,
2742b877906bSopenharmony_ci                                      XA_CARDINAL,
2743b877906bSopenharmony_ci                                      (unsigned char**) &value))
2744b877906bSopenharmony_ci        {
2745b877906bSopenharmony_ci            opacity = (float) (*value / (double) 0xffffffffu);
2746b877906bSopenharmony_ci        }
2747b877906bSopenharmony_ci
2748b877906bSopenharmony_ci        if (value)
2749b877906bSopenharmony_ci            XFree(value);
2750b877906bSopenharmony_ci    }
2751b877906bSopenharmony_ci
2752b877906bSopenharmony_ci    return opacity;
2753b877906bSopenharmony_ci}
2754b877906bSopenharmony_ci
2755b877906bSopenharmony_civoid _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity)
2756b877906bSopenharmony_ci{
2757b877906bSopenharmony_ci    const CARD32 value = (CARD32) (0xffffffffu * (double) opacity);
2758b877906bSopenharmony_ci    XChangeProperty(_glfw.x11.display, window->x11.handle,
2759b877906bSopenharmony_ci                    _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32,
2760b877906bSopenharmony_ci                    PropModeReplace, (unsigned char*) &value, 1);
2761b877906bSopenharmony_ci}
2762b877906bSopenharmony_ci
2763b877906bSopenharmony_civoid _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled)
2764b877906bSopenharmony_ci{
2765b877906bSopenharmony_ci    if (!_glfw.x11.xi.available)
2766b877906bSopenharmony_ci        return;
2767b877906bSopenharmony_ci
2768b877906bSopenharmony_ci    if (_glfw.x11.disabledCursorWindow != window)
2769b877906bSopenharmony_ci        return;
2770b877906bSopenharmony_ci
2771b877906bSopenharmony_ci    if (enabled)
2772b877906bSopenharmony_ci        enableRawMouseMotion(window);
2773b877906bSopenharmony_ci    else
2774b877906bSopenharmony_ci        disableRawMouseMotion(window);
2775b877906bSopenharmony_ci}
2776b877906bSopenharmony_ci
2777b877906bSopenharmony_ciGLFWbool _glfwRawMouseMotionSupportedX11(void)
2778b877906bSopenharmony_ci{
2779b877906bSopenharmony_ci    return _glfw.x11.xi.available;
2780b877906bSopenharmony_ci}
2781b877906bSopenharmony_ci
2782b877906bSopenharmony_civoid _glfwPollEventsX11(void)
2783b877906bSopenharmony_ci{
2784b877906bSopenharmony_ci    drainEmptyEvents();
2785b877906bSopenharmony_ci
2786b877906bSopenharmony_ci#if defined(GLFW_BUILD_LINUX_JOYSTICK)
2787b877906bSopenharmony_ci    if (_glfw.joysticksInitialized)
2788b877906bSopenharmony_ci        _glfwDetectJoystickConnectionLinux();
2789b877906bSopenharmony_ci#endif
2790b877906bSopenharmony_ci    XPending(_glfw.x11.display);
2791b877906bSopenharmony_ci
2792b877906bSopenharmony_ci    while (QLength(_glfw.x11.display))
2793b877906bSopenharmony_ci    {
2794b877906bSopenharmony_ci        XEvent event;
2795b877906bSopenharmony_ci        XNextEvent(_glfw.x11.display, &event);
2796b877906bSopenharmony_ci        processEvent(&event);
2797b877906bSopenharmony_ci    }
2798b877906bSopenharmony_ci
2799b877906bSopenharmony_ci    _GLFWwindow* window = _glfw.x11.disabledCursorWindow;
2800b877906bSopenharmony_ci    if (window)
2801b877906bSopenharmony_ci    {
2802b877906bSopenharmony_ci        int width, height;
2803b877906bSopenharmony_ci        _glfwGetWindowSizeX11(window, &width, &height);
2804b877906bSopenharmony_ci
2805b877906bSopenharmony_ci        // NOTE: Re-center the cursor only if it has moved since the last call,
2806b877906bSopenharmony_ci        //       to avoid breaking glfwWaitEvents with MotionNotify
2807b877906bSopenharmony_ci        if (window->x11.lastCursorPosX != width / 2 ||
2808b877906bSopenharmony_ci            window->x11.lastCursorPosY != height / 2)
2809b877906bSopenharmony_ci        {
2810b877906bSopenharmony_ci            _glfwSetCursorPosX11(window, width / 2, height / 2);
2811b877906bSopenharmony_ci        }
2812b877906bSopenharmony_ci    }
2813b877906bSopenharmony_ci
2814b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2815b877906bSopenharmony_ci}
2816b877906bSopenharmony_ci
2817b877906bSopenharmony_civoid _glfwWaitEventsX11(void)
2818b877906bSopenharmony_ci{
2819b877906bSopenharmony_ci    waitForAnyEvent(NULL);
2820b877906bSopenharmony_ci    _glfwPollEventsX11();
2821b877906bSopenharmony_ci}
2822b877906bSopenharmony_ci
2823b877906bSopenharmony_civoid _glfwWaitEventsTimeoutX11(double timeout)
2824b877906bSopenharmony_ci{
2825b877906bSopenharmony_ci    waitForAnyEvent(&timeout);
2826b877906bSopenharmony_ci    _glfwPollEventsX11();
2827b877906bSopenharmony_ci}
2828b877906bSopenharmony_ci
2829b877906bSopenharmony_civoid _glfwPostEmptyEventX11(void)
2830b877906bSopenharmony_ci{
2831b877906bSopenharmony_ci    writeEmptyEvent();
2832b877906bSopenharmony_ci}
2833b877906bSopenharmony_ci
2834b877906bSopenharmony_civoid _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos)
2835b877906bSopenharmony_ci{
2836b877906bSopenharmony_ci    Window root, child;
2837b877906bSopenharmony_ci    int rootX, rootY, childX, childY;
2838b877906bSopenharmony_ci    unsigned int mask;
2839b877906bSopenharmony_ci
2840b877906bSopenharmony_ci    XQueryPointer(_glfw.x11.display, window->x11.handle,
2841b877906bSopenharmony_ci                  &root, &child,
2842b877906bSopenharmony_ci                  &rootX, &rootY, &childX, &childY,
2843b877906bSopenharmony_ci                  &mask);
2844b877906bSopenharmony_ci
2845b877906bSopenharmony_ci    if (xpos)
2846b877906bSopenharmony_ci        *xpos = childX;
2847b877906bSopenharmony_ci    if (ypos)
2848b877906bSopenharmony_ci        *ypos = childY;
2849b877906bSopenharmony_ci}
2850b877906bSopenharmony_ci
2851b877906bSopenharmony_civoid _glfwSetCursorPosX11(_GLFWwindow* window, double x, double y)
2852b877906bSopenharmony_ci{
2853b877906bSopenharmony_ci    // Store the new position so it can be recognized later
2854b877906bSopenharmony_ci    window->x11.warpCursorPosX = (int) x;
2855b877906bSopenharmony_ci    window->x11.warpCursorPosY = (int) y;
2856b877906bSopenharmony_ci
2857b877906bSopenharmony_ci    XWarpPointer(_glfw.x11.display, None, window->x11.handle,
2858b877906bSopenharmony_ci                 0,0,0,0, (int) x, (int) y);
2859b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2860b877906bSopenharmony_ci}
2861b877906bSopenharmony_ci
2862b877906bSopenharmony_civoid _glfwSetCursorModeX11(_GLFWwindow* window, int mode)
2863b877906bSopenharmony_ci{
2864b877906bSopenharmony_ci    if (_glfwWindowFocusedX11(window))
2865b877906bSopenharmony_ci    {
2866b877906bSopenharmony_ci        if (mode == GLFW_CURSOR_DISABLED)
2867b877906bSopenharmony_ci        {
2868b877906bSopenharmony_ci            _glfwGetCursorPosX11(window,
2869b877906bSopenharmony_ci                                 &_glfw.x11.restoreCursorPosX,
2870b877906bSopenharmony_ci                                 &_glfw.x11.restoreCursorPosY);
2871b877906bSopenharmony_ci            _glfwCenterCursorInContentArea(window);
2872b877906bSopenharmony_ci            if (window->rawMouseMotion)
2873b877906bSopenharmony_ci                enableRawMouseMotion(window);
2874b877906bSopenharmony_ci        }
2875b877906bSopenharmony_ci        else if (_glfw.x11.disabledCursorWindow == window)
2876b877906bSopenharmony_ci        {
2877b877906bSopenharmony_ci            if (window->rawMouseMotion)
2878b877906bSopenharmony_ci                disableRawMouseMotion(window);
2879b877906bSopenharmony_ci        }
2880b877906bSopenharmony_ci
2881b877906bSopenharmony_ci        if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED)
2882b877906bSopenharmony_ci            captureCursor(window);
2883b877906bSopenharmony_ci        else
2884b877906bSopenharmony_ci            releaseCursor();
2885b877906bSopenharmony_ci
2886b877906bSopenharmony_ci        if (mode == GLFW_CURSOR_DISABLED)
2887b877906bSopenharmony_ci            _glfw.x11.disabledCursorWindow = window;
2888b877906bSopenharmony_ci        else if (_glfw.x11.disabledCursorWindow == window)
2889b877906bSopenharmony_ci        {
2890b877906bSopenharmony_ci            _glfw.x11.disabledCursorWindow = NULL;
2891b877906bSopenharmony_ci            _glfwSetCursorPosX11(window,
2892b877906bSopenharmony_ci                                 _glfw.x11.restoreCursorPosX,
2893b877906bSopenharmony_ci                                 _glfw.x11.restoreCursorPosY);
2894b877906bSopenharmony_ci        }
2895b877906bSopenharmony_ci    }
2896b877906bSopenharmony_ci
2897b877906bSopenharmony_ci    updateCursorImage(window);
2898b877906bSopenharmony_ci    XFlush(_glfw.x11.display);
2899b877906bSopenharmony_ci}
2900b877906bSopenharmony_ci
2901b877906bSopenharmony_ciconst char* _glfwGetScancodeNameX11(int scancode)
2902b877906bSopenharmony_ci{
2903b877906bSopenharmony_ci    if (!_glfw.x11.xkb.available)
2904b877906bSopenharmony_ci        return NULL;
2905b877906bSopenharmony_ci
2906b877906bSopenharmony_ci    if (scancode < 0 || scancode > 0xff)
2907b877906bSopenharmony_ci    {
2908b877906bSopenharmony_ci        _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
2909b877906bSopenharmony_ci        return NULL;
2910b877906bSopenharmony_ci    }
2911b877906bSopenharmony_ci
2912b877906bSopenharmony_ci    const int key = _glfw.x11.keycodes[scancode];
2913b877906bSopenharmony_ci    if (key == GLFW_KEY_UNKNOWN)
2914b877906bSopenharmony_ci        return NULL;
2915b877906bSopenharmony_ci
2916b877906bSopenharmony_ci    const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display,
2917b877906bSopenharmony_ci                                             scancode, _glfw.x11.xkb.group, 0);
2918b877906bSopenharmony_ci    if (keysym == NoSymbol)
2919b877906bSopenharmony_ci        return NULL;
2920b877906bSopenharmony_ci
2921b877906bSopenharmony_ci    const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
2922b877906bSopenharmony_ci    if (codepoint == GLFW_INVALID_CODEPOINT)
2923b877906bSopenharmony_ci        return NULL;
2924b877906bSopenharmony_ci
2925b877906bSopenharmony_ci    const size_t count = _glfwEncodeUTF8(_glfw.x11.keynames[key], codepoint);
2926b877906bSopenharmony_ci    if (count == 0)
2927b877906bSopenharmony_ci        return NULL;
2928b877906bSopenharmony_ci
2929b877906bSopenharmony_ci    _glfw.x11.keynames[key][count] = '\0';
2930b877906bSopenharmony_ci    return _glfw.x11.keynames[key];
2931b877906bSopenharmony_ci}
2932b877906bSopenharmony_ci
2933b877906bSopenharmony_ciint _glfwGetKeyScancodeX11(int key)
2934b877906bSopenharmony_ci{
2935b877906bSopenharmony_ci    return _glfw.x11.scancodes[key];
2936b877906bSopenharmony_ci}
2937b877906bSopenharmony_ci
2938b877906bSopenharmony_ciGLFWbool _glfwCreateCursorX11(_GLFWcursor* cursor,
2939b877906bSopenharmony_ci                              const GLFWimage* image,
2940b877906bSopenharmony_ci                              int xhot, int yhot)
2941b877906bSopenharmony_ci{
2942b877906bSopenharmony_ci    cursor->x11.handle = _glfwCreateNativeCursorX11(image, xhot, yhot);
2943b877906bSopenharmony_ci    if (!cursor->x11.handle)
2944b877906bSopenharmony_ci        return GLFW_FALSE;
2945b877906bSopenharmony_ci
2946b877906bSopenharmony_ci    return GLFW_TRUE;
2947b877906bSopenharmony_ci}
2948b877906bSopenharmony_ci
2949b877906bSopenharmony_ciGLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape)
2950b877906bSopenharmony_ci{
2951b877906bSopenharmony_ci    if (_glfw.x11.xcursor.handle)
2952b877906bSopenharmony_ci    {
2953b877906bSopenharmony_ci        char* theme = XcursorGetTheme(_glfw.x11.display);
2954b877906bSopenharmony_ci        if (theme)
2955b877906bSopenharmony_ci        {
2956b877906bSopenharmony_ci            const int size = XcursorGetDefaultSize(_glfw.x11.display);
2957b877906bSopenharmony_ci            const char* name = NULL;
2958b877906bSopenharmony_ci
2959b877906bSopenharmony_ci            switch (shape)
2960b877906bSopenharmony_ci            {
2961b877906bSopenharmony_ci                case GLFW_ARROW_CURSOR:
2962b877906bSopenharmony_ci                    name = "default";
2963b877906bSopenharmony_ci                    break;
2964b877906bSopenharmony_ci                case GLFW_IBEAM_CURSOR:
2965b877906bSopenharmony_ci                    name = "text";
2966b877906bSopenharmony_ci                    break;
2967b877906bSopenharmony_ci                case GLFW_CROSSHAIR_CURSOR:
2968b877906bSopenharmony_ci                    name = "crosshair";
2969b877906bSopenharmony_ci                    break;
2970b877906bSopenharmony_ci                case GLFW_POINTING_HAND_CURSOR:
2971b877906bSopenharmony_ci                    name = "pointer";
2972b877906bSopenharmony_ci                    break;
2973b877906bSopenharmony_ci                case GLFW_RESIZE_EW_CURSOR:
2974b877906bSopenharmony_ci                    name = "ew-resize";
2975b877906bSopenharmony_ci                    break;
2976b877906bSopenharmony_ci                case GLFW_RESIZE_NS_CURSOR:
2977b877906bSopenharmony_ci                    name = "ns-resize";
2978b877906bSopenharmony_ci                    break;
2979b877906bSopenharmony_ci                case GLFW_RESIZE_NWSE_CURSOR:
2980b877906bSopenharmony_ci                    name = "nwse-resize";
2981b877906bSopenharmony_ci                    break;
2982b877906bSopenharmony_ci                case GLFW_RESIZE_NESW_CURSOR:
2983b877906bSopenharmony_ci                    name = "nesw-resize";
2984b877906bSopenharmony_ci                    break;
2985b877906bSopenharmony_ci                case GLFW_RESIZE_ALL_CURSOR:
2986b877906bSopenharmony_ci                    name = "all-scroll";
2987b877906bSopenharmony_ci                    break;
2988b877906bSopenharmony_ci                case GLFW_NOT_ALLOWED_CURSOR:
2989b877906bSopenharmony_ci                    name = "not-allowed";
2990b877906bSopenharmony_ci                    break;
2991b877906bSopenharmony_ci            }
2992b877906bSopenharmony_ci
2993b877906bSopenharmony_ci            XcursorImage* image = XcursorLibraryLoadImage(name, theme, size);
2994b877906bSopenharmony_ci            if (image)
2995b877906bSopenharmony_ci            {
2996b877906bSopenharmony_ci                cursor->x11.handle = XcursorImageLoadCursor(_glfw.x11.display, image);
2997b877906bSopenharmony_ci                XcursorImageDestroy(image);
2998b877906bSopenharmony_ci            }
2999b877906bSopenharmony_ci        }
3000b877906bSopenharmony_ci    }
3001b877906bSopenharmony_ci
3002b877906bSopenharmony_ci    if (!cursor->x11.handle)
3003b877906bSopenharmony_ci    {
3004b877906bSopenharmony_ci        unsigned int native = 0;
3005b877906bSopenharmony_ci
3006b877906bSopenharmony_ci        switch (shape)
3007b877906bSopenharmony_ci        {
3008b877906bSopenharmony_ci            case GLFW_ARROW_CURSOR:
3009b877906bSopenharmony_ci                native = XC_left_ptr;
3010b877906bSopenharmony_ci                break;
3011b877906bSopenharmony_ci            case GLFW_IBEAM_CURSOR:
3012b877906bSopenharmony_ci                native = XC_xterm;
3013b877906bSopenharmony_ci                break;
3014b877906bSopenharmony_ci            case GLFW_CROSSHAIR_CURSOR:
3015b877906bSopenharmony_ci                native = XC_crosshair;
3016b877906bSopenharmony_ci                break;
3017b877906bSopenharmony_ci            case GLFW_POINTING_HAND_CURSOR:
3018b877906bSopenharmony_ci                native = XC_hand2;
3019b877906bSopenharmony_ci                break;
3020b877906bSopenharmony_ci            case GLFW_RESIZE_EW_CURSOR:
3021b877906bSopenharmony_ci                native = XC_sb_h_double_arrow;
3022b877906bSopenharmony_ci                break;
3023b877906bSopenharmony_ci            case GLFW_RESIZE_NS_CURSOR:
3024b877906bSopenharmony_ci                native = XC_sb_v_double_arrow;
3025b877906bSopenharmony_ci                break;
3026b877906bSopenharmony_ci            case GLFW_RESIZE_ALL_CURSOR:
3027b877906bSopenharmony_ci                native = XC_fleur;
3028b877906bSopenharmony_ci                break;
3029b877906bSopenharmony_ci            default:
3030b877906bSopenharmony_ci                _glfwInputError(GLFW_CURSOR_UNAVAILABLE,
3031b877906bSopenharmony_ci                                "X11: Standard cursor shape unavailable");
3032b877906bSopenharmony_ci                return GLFW_FALSE;
3033b877906bSopenharmony_ci        }
3034b877906bSopenharmony_ci
3035b877906bSopenharmony_ci        cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
3036b877906bSopenharmony_ci        if (!cursor->x11.handle)
3037b877906bSopenharmony_ci        {
3038b877906bSopenharmony_ci            _glfwInputError(GLFW_PLATFORM_ERROR,
3039b877906bSopenharmony_ci                            "X11: Failed to create standard cursor");
3040b877906bSopenharmony_ci            return GLFW_FALSE;
3041b877906bSopenharmony_ci        }
3042b877906bSopenharmony_ci    }
3043b877906bSopenharmony_ci
3044b877906bSopenharmony_ci    return GLFW_TRUE;
3045b877906bSopenharmony_ci}
3046b877906bSopenharmony_ci
3047b877906bSopenharmony_civoid _glfwDestroyCursorX11(_GLFWcursor* cursor)
3048b877906bSopenharmony_ci{
3049b877906bSopenharmony_ci    if (cursor->x11.handle)
3050b877906bSopenharmony_ci        XFreeCursor(_glfw.x11.display, cursor->x11.handle);
3051b877906bSopenharmony_ci}
3052b877906bSopenharmony_ci
3053b877906bSopenharmony_civoid _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor)
3054b877906bSopenharmony_ci{
3055b877906bSopenharmony_ci    if (window->cursorMode == GLFW_CURSOR_NORMAL ||
3056b877906bSopenharmony_ci        window->cursorMode == GLFW_CURSOR_CAPTURED)
3057b877906bSopenharmony_ci    {
3058b877906bSopenharmony_ci        updateCursorImage(window);
3059b877906bSopenharmony_ci        XFlush(_glfw.x11.display);
3060b877906bSopenharmony_ci    }
3061b877906bSopenharmony_ci}
3062b877906bSopenharmony_ci
3063b877906bSopenharmony_civoid _glfwSetClipboardStringX11(const char* string)
3064b877906bSopenharmony_ci{
3065b877906bSopenharmony_ci    char* copy = _glfw_strdup(string);
3066b877906bSopenharmony_ci    _glfw_free(_glfw.x11.clipboardString);
3067b877906bSopenharmony_ci    _glfw.x11.clipboardString = copy;
3068b877906bSopenharmony_ci
3069b877906bSopenharmony_ci    XSetSelectionOwner(_glfw.x11.display,
3070b877906bSopenharmony_ci                       _glfw.x11.CLIPBOARD,
3071b877906bSopenharmony_ci                       _glfw.x11.helperWindowHandle,
3072b877906bSopenharmony_ci                       CurrentTime);
3073b877906bSopenharmony_ci
3074b877906bSopenharmony_ci    if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) !=
3075b877906bSopenharmony_ci        _glfw.x11.helperWindowHandle)
3076b877906bSopenharmony_ci    {
3077b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
3078b877906bSopenharmony_ci                        "X11: Failed to become owner of clipboard selection");
3079b877906bSopenharmony_ci    }
3080b877906bSopenharmony_ci}
3081b877906bSopenharmony_ci
3082b877906bSopenharmony_ciconst char* _glfwGetClipboardStringX11(void)
3083b877906bSopenharmony_ci{
3084b877906bSopenharmony_ci    return getSelectionString(_glfw.x11.CLIPBOARD);
3085b877906bSopenharmony_ci}
3086b877906bSopenharmony_ci
3087b877906bSopenharmony_ciEGLenum _glfwGetEGLPlatformX11(EGLint** attribs)
3088b877906bSopenharmony_ci{
3089b877906bSopenharmony_ci    if (_glfw.egl.ANGLE_platform_angle)
3090b877906bSopenharmony_ci    {
3091b877906bSopenharmony_ci        int type = 0;
3092b877906bSopenharmony_ci
3093b877906bSopenharmony_ci        if (_glfw.egl.ANGLE_platform_angle_opengl)
3094b877906bSopenharmony_ci        {
3095b877906bSopenharmony_ci            if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL)
3096b877906bSopenharmony_ci                type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
3097b877906bSopenharmony_ci        }
3098b877906bSopenharmony_ci
3099b877906bSopenharmony_ci        if (_glfw.egl.ANGLE_platform_angle_vulkan)
3100b877906bSopenharmony_ci        {
3101b877906bSopenharmony_ci            if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN)
3102b877906bSopenharmony_ci                type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
3103b877906bSopenharmony_ci        }
3104b877906bSopenharmony_ci
3105b877906bSopenharmony_ci        if (type)
3106b877906bSopenharmony_ci        {
3107b877906bSopenharmony_ci            *attribs = _glfw_calloc(5, sizeof(EGLint));
3108b877906bSopenharmony_ci            (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE;
3109b877906bSopenharmony_ci            (*attribs)[1] = type;
3110b877906bSopenharmony_ci            (*attribs)[2] = EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE;
3111b877906bSopenharmony_ci            (*attribs)[3] = EGL_PLATFORM_X11_EXT;
3112b877906bSopenharmony_ci            (*attribs)[4] = EGL_NONE;
3113b877906bSopenharmony_ci            return EGL_PLATFORM_ANGLE_ANGLE;
3114b877906bSopenharmony_ci        }
3115b877906bSopenharmony_ci    }
3116b877906bSopenharmony_ci
3117b877906bSopenharmony_ci    if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_x11)
3118b877906bSopenharmony_ci        return EGL_PLATFORM_X11_EXT;
3119b877906bSopenharmony_ci
3120b877906bSopenharmony_ci    return 0;
3121b877906bSopenharmony_ci}
3122b877906bSopenharmony_ci
3123b877906bSopenharmony_ciEGLNativeDisplayType _glfwGetEGLNativeDisplayX11(void)
3124b877906bSopenharmony_ci{
3125b877906bSopenharmony_ci    return _glfw.x11.display;
3126b877906bSopenharmony_ci}
3127b877906bSopenharmony_ci
3128b877906bSopenharmony_ciEGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow* window)
3129b877906bSopenharmony_ci{
3130b877906bSopenharmony_ci    if (_glfw.egl.platform)
3131b877906bSopenharmony_ci        return &window->x11.handle;
3132b877906bSopenharmony_ci    else
3133b877906bSopenharmony_ci        return (EGLNativeWindowType) window->x11.handle;
3134b877906bSopenharmony_ci}
3135b877906bSopenharmony_ci
3136b877906bSopenharmony_civoid _glfwGetRequiredInstanceExtensionsX11(char** extensions)
3137b877906bSopenharmony_ci{
3138b877906bSopenharmony_ci    if (!_glfw.vk.KHR_surface)
3139b877906bSopenharmony_ci        return;
3140b877906bSopenharmony_ci
3141b877906bSopenharmony_ci    if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle)
3142b877906bSopenharmony_ci    {
3143b877906bSopenharmony_ci        if (!_glfw.vk.KHR_xlib_surface)
3144b877906bSopenharmony_ci            return;
3145b877906bSopenharmony_ci    }
3146b877906bSopenharmony_ci
3147b877906bSopenharmony_ci    extensions[0] = "VK_KHR_surface";
3148b877906bSopenharmony_ci
3149b877906bSopenharmony_ci    // NOTE: VK_KHR_xcb_surface is preferred due to some early ICDs exposing but
3150b877906bSopenharmony_ci    //       not correctly implementing VK_KHR_xlib_surface
3151b877906bSopenharmony_ci    if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle)
3152b877906bSopenharmony_ci        extensions[1] = "VK_KHR_xcb_surface";
3153b877906bSopenharmony_ci    else
3154b877906bSopenharmony_ci        extensions[1] = "VK_KHR_xlib_surface";
3155b877906bSopenharmony_ci}
3156b877906bSopenharmony_ci
3157b877906bSopenharmony_ciGLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance,
3158b877906bSopenharmony_ci                                                      VkPhysicalDevice device,
3159b877906bSopenharmony_ci                                                      uint32_t queuefamily)
3160b877906bSopenharmony_ci{
3161b877906bSopenharmony_ci    VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display,
3162b877906bSopenharmony_ci                                                          _glfw.x11.screen));
3163b877906bSopenharmony_ci
3164b877906bSopenharmony_ci    if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle)
3165b877906bSopenharmony_ci    {
3166b877906bSopenharmony_ci        PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR
3167b877906bSopenharmony_ci            vkGetPhysicalDeviceXcbPresentationSupportKHR =
3168b877906bSopenharmony_ci            (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)
3169b877906bSopenharmony_ci            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR");
3170b877906bSopenharmony_ci        if (!vkGetPhysicalDeviceXcbPresentationSupportKHR)
3171b877906bSopenharmony_ci        {
3172b877906bSopenharmony_ci            _glfwInputError(GLFW_API_UNAVAILABLE,
3173b877906bSopenharmony_ci                            "X11: Vulkan instance missing VK_KHR_xcb_surface extension");
3174b877906bSopenharmony_ci            return GLFW_FALSE;
3175b877906bSopenharmony_ci        }
3176b877906bSopenharmony_ci
3177b877906bSopenharmony_ci        xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display);
3178b877906bSopenharmony_ci        if (!connection)
3179b877906bSopenharmony_ci        {
3180b877906bSopenharmony_ci            _glfwInputError(GLFW_PLATFORM_ERROR,
3181b877906bSopenharmony_ci                            "X11: Failed to retrieve XCB connection");
3182b877906bSopenharmony_ci            return GLFW_FALSE;
3183b877906bSopenharmony_ci        }
3184b877906bSopenharmony_ci
3185b877906bSopenharmony_ci        return vkGetPhysicalDeviceXcbPresentationSupportKHR(device,
3186b877906bSopenharmony_ci                                                            queuefamily,
3187b877906bSopenharmony_ci                                                            connection,
3188b877906bSopenharmony_ci                                                            visualID);
3189b877906bSopenharmony_ci    }
3190b877906bSopenharmony_ci    else
3191b877906bSopenharmony_ci    {
3192b877906bSopenharmony_ci        PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR
3193b877906bSopenharmony_ci            vkGetPhysicalDeviceXlibPresentationSupportKHR =
3194b877906bSopenharmony_ci            (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)
3195b877906bSopenharmony_ci            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR");
3196b877906bSopenharmony_ci        if (!vkGetPhysicalDeviceXlibPresentationSupportKHR)
3197b877906bSopenharmony_ci        {
3198b877906bSopenharmony_ci            _glfwInputError(GLFW_API_UNAVAILABLE,
3199b877906bSopenharmony_ci                            "X11: Vulkan instance missing VK_KHR_xlib_surface extension");
3200b877906bSopenharmony_ci            return GLFW_FALSE;
3201b877906bSopenharmony_ci        }
3202b877906bSopenharmony_ci
3203b877906bSopenharmony_ci        return vkGetPhysicalDeviceXlibPresentationSupportKHR(device,
3204b877906bSopenharmony_ci                                                             queuefamily,
3205b877906bSopenharmony_ci                                                             _glfw.x11.display,
3206b877906bSopenharmony_ci                                                             visualID);
3207b877906bSopenharmony_ci    }
3208b877906bSopenharmony_ci}
3209b877906bSopenharmony_ci
3210b877906bSopenharmony_ciVkResult _glfwCreateWindowSurfaceX11(VkInstance instance,
3211b877906bSopenharmony_ci                                     _GLFWwindow* window,
3212b877906bSopenharmony_ci                                     const VkAllocationCallbacks* allocator,
3213b877906bSopenharmony_ci                                     VkSurfaceKHR* surface)
3214b877906bSopenharmony_ci{
3215b877906bSopenharmony_ci    if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle)
3216b877906bSopenharmony_ci    {
3217b877906bSopenharmony_ci        VkResult err;
3218b877906bSopenharmony_ci        VkXcbSurfaceCreateInfoKHR sci;
3219b877906bSopenharmony_ci        PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR;
3220b877906bSopenharmony_ci
3221b877906bSopenharmony_ci        xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display);
3222b877906bSopenharmony_ci        if (!connection)
3223b877906bSopenharmony_ci        {
3224b877906bSopenharmony_ci            _glfwInputError(GLFW_PLATFORM_ERROR,
3225b877906bSopenharmony_ci                            "X11: Failed to retrieve XCB connection");
3226b877906bSopenharmony_ci            return VK_ERROR_EXTENSION_NOT_PRESENT;
3227b877906bSopenharmony_ci        }
3228b877906bSopenharmony_ci
3229b877906bSopenharmony_ci        vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)
3230b877906bSopenharmony_ci            vkGetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR");
3231b877906bSopenharmony_ci        if (!vkCreateXcbSurfaceKHR)
3232b877906bSopenharmony_ci        {
3233b877906bSopenharmony_ci            _glfwInputError(GLFW_API_UNAVAILABLE,
3234b877906bSopenharmony_ci                            "X11: Vulkan instance missing VK_KHR_xcb_surface extension");
3235b877906bSopenharmony_ci            return VK_ERROR_EXTENSION_NOT_PRESENT;
3236b877906bSopenharmony_ci        }
3237b877906bSopenharmony_ci
3238b877906bSopenharmony_ci        memset(&sci, 0, sizeof(sci));
3239b877906bSopenharmony_ci        sci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
3240b877906bSopenharmony_ci        sci.connection = connection;
3241b877906bSopenharmony_ci        sci.window = window->x11.handle;
3242b877906bSopenharmony_ci
3243b877906bSopenharmony_ci        err = vkCreateXcbSurfaceKHR(instance, &sci, allocator, surface);
3244b877906bSopenharmony_ci        if (err)
3245b877906bSopenharmony_ci        {
3246b877906bSopenharmony_ci            _glfwInputError(GLFW_PLATFORM_ERROR,
3247b877906bSopenharmony_ci                            "X11: Failed to create Vulkan XCB surface: %s",
3248b877906bSopenharmony_ci                            _glfwGetVulkanResultString(err));
3249b877906bSopenharmony_ci        }
3250b877906bSopenharmony_ci
3251b877906bSopenharmony_ci        return err;
3252b877906bSopenharmony_ci    }
3253b877906bSopenharmony_ci    else
3254b877906bSopenharmony_ci    {
3255b877906bSopenharmony_ci        VkResult err;
3256b877906bSopenharmony_ci        VkXlibSurfaceCreateInfoKHR sci;
3257b877906bSopenharmony_ci        PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
3258b877906bSopenharmony_ci
3259b877906bSopenharmony_ci        vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)
3260b877906bSopenharmony_ci            vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR");
3261b877906bSopenharmony_ci        if (!vkCreateXlibSurfaceKHR)
3262b877906bSopenharmony_ci        {
3263b877906bSopenharmony_ci            _glfwInputError(GLFW_API_UNAVAILABLE,
3264b877906bSopenharmony_ci                            "X11: Vulkan instance missing VK_KHR_xlib_surface extension");
3265b877906bSopenharmony_ci            return VK_ERROR_EXTENSION_NOT_PRESENT;
3266b877906bSopenharmony_ci        }
3267b877906bSopenharmony_ci
3268b877906bSopenharmony_ci        memset(&sci, 0, sizeof(sci));
3269b877906bSopenharmony_ci        sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
3270b877906bSopenharmony_ci        sci.dpy = _glfw.x11.display;
3271b877906bSopenharmony_ci        sci.window = window->x11.handle;
3272b877906bSopenharmony_ci
3273b877906bSopenharmony_ci        err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface);
3274b877906bSopenharmony_ci        if (err)
3275b877906bSopenharmony_ci        {
3276b877906bSopenharmony_ci            _glfwInputError(GLFW_PLATFORM_ERROR,
3277b877906bSopenharmony_ci                            "X11: Failed to create Vulkan X11 surface: %s",
3278b877906bSopenharmony_ci                            _glfwGetVulkanResultString(err));
3279b877906bSopenharmony_ci        }
3280b877906bSopenharmony_ci
3281b877906bSopenharmony_ci        return err;
3282b877906bSopenharmony_ci    }
3283b877906bSopenharmony_ci}
3284b877906bSopenharmony_ci
3285b877906bSopenharmony_ci
3286b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
3287b877906bSopenharmony_ci//////                        GLFW native API                       //////
3288b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
3289b877906bSopenharmony_ci
3290b877906bSopenharmony_ciGLFWAPI Display* glfwGetX11Display(void)
3291b877906bSopenharmony_ci{
3292b877906bSopenharmony_ci    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
3293b877906bSopenharmony_ci
3294b877906bSopenharmony_ci    if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
3295b877906bSopenharmony_ci    {
3296b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized");
3297b877906bSopenharmony_ci        return NULL;
3298b877906bSopenharmony_ci    }
3299b877906bSopenharmony_ci
3300b877906bSopenharmony_ci    return _glfw.x11.display;
3301b877906bSopenharmony_ci}
3302b877906bSopenharmony_ci
3303b877906bSopenharmony_ciGLFWAPI Window glfwGetX11Window(GLFWwindow* handle)
3304b877906bSopenharmony_ci{
3305b877906bSopenharmony_ci    _GLFW_REQUIRE_INIT_OR_RETURN(None);
3306b877906bSopenharmony_ci
3307b877906bSopenharmony_ci    if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
3308b877906bSopenharmony_ci    {
3309b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized");
3310b877906bSopenharmony_ci        return None;
3311b877906bSopenharmony_ci    }
3312b877906bSopenharmony_ci
3313b877906bSopenharmony_ci    _GLFWwindow* window = (_GLFWwindow*) handle;
3314b877906bSopenharmony_ci    assert(window != NULL);
3315b877906bSopenharmony_ci
3316b877906bSopenharmony_ci    return window->x11.handle;
3317b877906bSopenharmony_ci}
3318b877906bSopenharmony_ci
3319b877906bSopenharmony_ciGLFWAPI void glfwSetX11SelectionString(const char* string)
3320b877906bSopenharmony_ci{
3321b877906bSopenharmony_ci    assert(string != NULL);
3322b877906bSopenharmony_ci
3323b877906bSopenharmony_ci    _GLFW_REQUIRE_INIT();
3324b877906bSopenharmony_ci
3325b877906bSopenharmony_ci    if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
3326b877906bSopenharmony_ci    {
3327b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized");
3328b877906bSopenharmony_ci        return;
3329b877906bSopenharmony_ci    }
3330b877906bSopenharmony_ci
3331b877906bSopenharmony_ci    _glfw_free(_glfw.x11.primarySelectionString);
3332b877906bSopenharmony_ci    _glfw.x11.primarySelectionString = _glfw_strdup(string);
3333b877906bSopenharmony_ci
3334b877906bSopenharmony_ci    XSetSelectionOwner(_glfw.x11.display,
3335b877906bSopenharmony_ci                       _glfw.x11.PRIMARY,
3336b877906bSopenharmony_ci                       _glfw.x11.helperWindowHandle,
3337b877906bSopenharmony_ci                       CurrentTime);
3338b877906bSopenharmony_ci
3339b877906bSopenharmony_ci    if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.PRIMARY) !=
3340b877906bSopenharmony_ci        _glfw.x11.helperWindowHandle)
3341b877906bSopenharmony_ci    {
3342b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
3343b877906bSopenharmony_ci                        "X11: Failed to become owner of primary selection");
3344b877906bSopenharmony_ci    }
3345b877906bSopenharmony_ci}
3346b877906bSopenharmony_ci
3347b877906bSopenharmony_ciGLFWAPI const char* glfwGetX11SelectionString(void)
3348b877906bSopenharmony_ci{
3349b877906bSopenharmony_ci    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
3350b877906bSopenharmony_ci
3351b877906bSopenharmony_ci    if (_glfw.platform.platformID != GLFW_PLATFORM_X11)
3352b877906bSopenharmony_ci    {
3353b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized");
3354b877906bSopenharmony_ci        return NULL;
3355b877906bSopenharmony_ci    }
3356b877906bSopenharmony_ci
3357b877906bSopenharmony_ci    return getSelectionString(_glfw.x11.PRIMARY);
3358b877906bSopenharmony_ci}
3359b877906bSopenharmony_ci
3360b877906bSopenharmony_ci#endif // _GLFW_X11
3361b877906bSopenharmony_ci
3362