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 ¬ification)) 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) ¬ification); 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) ¬ification)) 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