123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899 |
- //========================================================================
- // GLFW 3.4 Wayland - www.glfw.org
- //------------------------------------------------------------------------
- // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
- //
- // This software is provided 'as-is', without any express or implied
- // warranty. In no event will the authors be held liable for any damages
- // arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it
- // freely, subject to the following restrictions:
- //
- // 1. The origin of this software must not be misrepresented; you must not
- // claim that you wrote the original software. If you use this software
- // in a product, an acknowledgment in the product documentation would
- // be appreciated but is not required.
- //
- // 2. Altered source versions must be plainly marked as such, and must not
- // be misrepresented as being the original software.
- //
- // 3. This notice may not be removed or altered from any source
- // distribution.
- //
- //========================================================================
- // It is fine to use C99 in this file because it will not be built with VS
- //========================================================================
- #define _GNU_SOURCE
- #include "internal.h"
- #include "backend_utils.h"
- #include "wl_client_side_decorations.h"
- #include "linux_desktop_settings.h"
- #include "../kitty/monotonic.h"
- #include "wl_text_input.h"
- #include "wayland-text-input-unstable-v3-client-protocol.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/socket.h>
- #include <wayland-client.h>
- #include <stdio.h>
- // errno.h needed for BSD code paths
- #include <errno.h>
- // Needed for the BTN_* defines
- #ifdef __has_include
- #if __has_include(<linux/input.h>)
- #include <linux/input.h>
- #elif __has_include(<dev/evdev/input.h>)
- #include <dev/evdev/input.h>
- #endif
- #else
- #include <linux/input.h>
- #endif
- #define debug debug_rendering
- #define x window->wl.allCursorPosX
- #define y window->wl.allCursorPosY
- static _GLFWwindow*
- get_window_from_surface(struct wl_surface* surface) {
- if (!surface) return NULL;
- _GLFWwindow *ans = wl_surface_get_user_data(surface);
- if (ans) {
- const _GLFWwindow *w = _glfw.windowListHead;
- while (w) {
- if (w == ans) return ans;
- w = w->next;
- }
- }
- return NULL;
- }
- static void
- pointerHandleEnter(
- void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t serial, struct wl_surface* surface,
- wl_fixed_t sx, wl_fixed_t sy
- ) {
- _GLFWwindow* window = get_window_from_surface(surface);
- if (!window) return;
- _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.pointer_serial = serial; _glfw.wl.pointer_enter_serial = serial;
- _glfw.wl.pointerFocus = window;
- window->wl.allCursorPosX = wl_fixed_to_double(sx);
- window->wl.allCursorPosY = wl_fixed_to_double(sy);
- if (surface != window->wl.surface) {
- csd_handle_pointer_event(window, -2, -2, surface);
- } else {
- window->wl.decorations.focus = CENTRAL_WINDOW;
- window->wl.hovered = true;
- window->wl.cursorPosX = x;
- window->wl.cursorPosY = y;
- _glfwPlatformSetCursor(window, window->wl.currentCursor);
- _glfwInputCursorEnter(window, true);
- }
- }
- static void
- pointerHandleLeave(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t serial, struct wl_surface* surface) {
- _GLFWwindow* window = _glfw.wl.pointerFocus;
- if (!window) return;
- _glfw.wl.serial = serial;
- _glfw.wl.pointerFocus = NULL;
- if (window->wl.surface == surface) {
- window->wl.hovered = false;
- _glfwInputCursorEnter(window, false);
- _glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
- } else csd_handle_pointer_event(window, -3, -3, surface);
- }
- static void
- pointerHandleMotion(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t time UNUSED, wl_fixed_t sx, wl_fixed_t sy) {
- _GLFWwindow* window = _glfw.wl.pointerFocus;
- if (!window || window->cursorMode == GLFW_CURSOR_DISABLED) return;
- window->wl.allCursorPosX = wl_fixed_to_double(sx);
- window->wl.allCursorPosY = wl_fixed_to_double(sy);
- if (window->wl.decorations.focus != CENTRAL_WINDOW) {
- csd_handle_pointer_event(window, -1, -1, NULL);
- } else {
- window->wl.cursorPosX = x;
- window->wl.cursorPosY = y;
- _glfwInputCursorPos(window, x, y);
- _glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
- }
- }
- static void pointerHandleButton(void* data UNUSED,
- struct wl_pointer* pointer UNUSED,
- uint32_t serial,
- uint32_t time UNUSED,
- uint32_t button,
- uint32_t state)
- {
- _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.pointer_serial = serial;
- _GLFWwindow* window = _glfw.wl.pointerFocus;
- if (!window) return;
- if (window->wl.decorations.focus != CENTRAL_WINDOW) {
- csd_handle_pointer_event(window, button, state, NULL);
- return;
- }
- /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
- * codes. */
- int glfwButton = button - BTN_LEFT;
- _glfwInputMouseClick(
- window, glfwButton, state == WL_POINTER_BUTTON_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE, _glfw.wl.xkb.states.modifiers);
- }
- #undef x
- #undef y
- #define info (window->wl.pointer_curr_axis_info)
- static void
- pointer_handle_axis_common(enum _GLFWWaylandAxisEvent type, uint32_t axis, wl_fixed_t value) {
- _GLFWwindow* window = _glfw.wl.pointerFocus;
- if (!window || window->wl.decorations.focus != CENTRAL_WINDOW) return;
- float fval = (float) wl_fixed_to_double(value);
- #define CASE(type, type_const, axis, fval) \
- case type_const: \
- if (info.type.axis##_axis_type == AXIS_EVENT_UNKNOWN) { \
- info.type.axis##_axis_type = type_const; info.type.axis = 0.f; } \
- info.type.axis += fval; break;
- if (window) {
- switch ((enum wl_pointer_axis)axis) {
- case WL_POINTER_AXIS_VERTICAL_SCROLL:
- switch (type) {
- case AXIS_EVENT_UNKNOWN: break;
- CASE(discrete, AXIS_EVENT_DISCRETE, y, -fval); // wheel event
- CASE(discrete, AXIS_EVENT_VALUE120, y, -fval); // wheel event higher res than plain discrete
- CASE(continuous, AXIS_EVENT_CONTINUOUS, y, -fval); // touchpad, etc. high res
- }
- break;
- case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
- switch (type) {
- case AXIS_EVENT_UNKNOWN: break;
- CASE(discrete, AXIS_EVENT_DISCRETE, x, fval); // wheel event
- CASE(discrete, AXIS_EVENT_VALUE120, x, fval); // wheel event higher res than plain discrete
- CASE(continuous, AXIS_EVENT_CONTINUOUS, x, fval); // touchpad, etc. high res
- }
- break;
- }
- }
- #undef CASE
- }
- static void
- pointer_handle_axis(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t time, uint32_t axis, wl_fixed_t value) {
- _GLFWwindow* window = _glfw.wl.pointerFocus;
- if (!window) return;
- if (!info.timestamp_ns) info.timestamp_ns = ms_to_monotonic_t(time);
- pointer_handle_axis_common(AXIS_EVENT_CONTINUOUS, axis, value);
- }
- static void
- pointer_handle_frame(void *data UNUSED, struct wl_pointer *pointer UNUSED) {
- _GLFWwindow* window = _glfw.wl.pointerFocus;
- if (!window) return;
- float x = 0, y = 0;
- int highres = 0;
- if (info.discrete.y_axis_type != AXIS_EVENT_UNKNOWN) {
- y = info.discrete.y;
- if (info.discrete.y_axis_type == AXIS_EVENT_VALUE120) y /= 120.f;
- } else if (info.continuous.y_axis_type != AXIS_EVENT_UNKNOWN) {
- highres = 1;
- y = info.continuous.y;
- }
- if (info.discrete.x_axis_type != AXIS_EVENT_UNKNOWN) {
- x = info.discrete.x;
- if (info.discrete.x_axis_type == AXIS_EVENT_VALUE120) x /= 120.f;
- } else if (info.continuous.x_axis_type != AXIS_EVENT_UNKNOWN) {
- highres = 1;
- x = info.continuous.x;
- }
- /* clear pointer_curr_axis_info for next frame */
- memset(&info, 0, sizeof(info));
- if (x != 0.0f || y != 0.0f) {
- float scale = (float)_glfwWaylandWindowScale(window);
- y *= scale; x *= scale;
- _glfwInputScroll(window, -x, y, highres, _glfw.wl.xkb.states.modifiers);
- }
- }
- static void
- pointer_handle_axis_source(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t source UNUSED) { }
- static void
- pointer_handle_axis_stop(void *data UNUSED, struct wl_pointer *wl_pointer UNUSED, uint32_t time UNUSED, uint32_t axis UNUSED) { }
- static void
- pointer_handle_axis_discrete(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis, int32_t discrete) {
- pointer_handle_axis_common(AXIS_EVENT_DISCRETE, axis, wl_fixed_from_int(discrete));
- }
- static void
- pointer_handle_axis_value120(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis, int32_t value120) {
- pointer_handle_axis_common(AXIS_EVENT_VALUE120, axis, wl_fixed_from_int(value120));
- }
- static void
- pointer_handle_axis_relative_direction(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis UNUSED, uint32_t axis_relative_direction UNUSED) { }
- #undef info
- static const struct wl_pointer_listener pointerListener = {
- .enter = pointerHandleEnter,
- .leave = pointerHandleLeave,
- .motion = pointerHandleMotion,
- .button = pointerHandleButton,
- .axis = pointer_handle_axis,
- .frame = pointer_handle_frame,
- .axis_source = pointer_handle_axis_source,
- .axis_stop = pointer_handle_axis_stop,
- .axis_discrete = pointer_handle_axis_discrete,
- #ifdef WL_POINTER_AXIS_VALUE120_SINCE_VERSION
- .axis_value120 = pointer_handle_axis_value120,
- #endif
- #ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
- .axis_relative_direction = pointer_handle_axis_relative_direction,
- #endif
- };
- static void keyboardHandleKeymap(void* data UNUSED,
- struct wl_keyboard* keyboard UNUSED,
- uint32_t format,
- int fd,
- uint32_t size)
- {
- char* mapStr;
- if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
- {
- _glfwInputError(GLFW_PLATFORM_ERROR, "Unknown keymap format: %u", format);
- close(fd);
- return;
- }
- mapStr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (mapStr == MAP_FAILED) {
- close(fd);
- _glfwInputError(GLFW_PLATFORM_ERROR, "Mapping of keymap file descriptor failed: %u", format);
- return;
- }
- glfw_xkb_compile_keymap(&_glfw.wl.xkb, mapStr);
- munmap(mapStr, size);
- close(fd);
- }
- static void keyboardHandleEnter(void* data UNUSED,
- struct wl_keyboard* keyboard UNUSED,
- uint32_t serial,
- struct wl_surface* surface,
- struct wl_array* keys)
- {
- _GLFWwindow* window = get_window_from_surface(surface);
- if (!window) return;
- _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.keyboard_enter_serial = serial;
- _glfw.wl.keyboardFocusId = window->id;
- _glfwInputWindowFocus(window, true);
- uint32_t* key;
- if (keys && _glfw.wl.keyRepeatInfo.key) {
- wl_array_for_each(key, keys) {
- if (*key == _glfw.wl.keyRepeatInfo.key) {
- toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
- break;
- }
- }
- }
- }
- static void keyboardHandleLeave(void* data UNUSED,
- struct wl_keyboard* keyboard UNUSED,
- uint32_t serial,
- struct wl_surface* surface UNUSED)
- {
- _GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
- if (!window)
- return;
- _glfw.wl.serial = serial;
- _glfw.wl.keyboardFocusId = 0;
- _glfwInputWindowFocus(window, false);
- toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
- }
- static void
- dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) {
- if (_glfw.wl.keyRepeatInfo.keyboardFocusId != _glfw.wl.keyboardFocusId || _glfw.wl.keyboardRepeatRate == 0) return;
- _GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
- if (!window) return;
- glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT);
- changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (s_to_monotonic_t(1ll) / (monotonic_t)_glfw.wl.keyboardRepeatRate));
- toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
- }
- static void keyboardHandleKey(void* data UNUSED,
- struct wl_keyboard* keyboard UNUSED,
- uint32_t serial,
- uint32_t time UNUSED,
- uint32_t key,
- uint32_t state)
- {
- _GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
- if (!window)
- return;
- int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
- _glfw.wl.serial = serial; _glfw.wl.input_serial = serial;
- glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
- if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
- {
- _glfw.wl.keyRepeatInfo.key = key;
- _glfw.wl.keyRepeatInfo.keyboardFocusId = window->id;
- changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, _glfw.wl.keyboardRepeatDelay);
- toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
- } else if (action == GLFW_RELEASE && key == _glfw.wl.keyRepeatInfo.key) {
- _glfw.wl.keyRepeatInfo.key = 0;
- toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
- }
- }
- static void keyboardHandleModifiers(void* data UNUSED,
- struct wl_keyboard* keyboard UNUSED,
- uint32_t serial,
- uint32_t modsDepressed,
- uint32_t modsLatched,
- uint32_t modsLocked,
- uint32_t group)
- {
- _glfw.wl.serial = serial; _glfw.wl.input_serial = serial;
- glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, 0, 0, group);
- }
- static void keyboardHandleRepeatInfo(void* data UNUSED,
- struct wl_keyboard* keyboard,
- int32_t rate,
- int32_t delay)
- {
- if (keyboard != _glfw.wl.keyboard)
- return;
- _glfw.wl.keyboardRepeatRate = rate;
- _glfw.wl.keyboardRepeatDelay = ms_to_monotonic_t(delay);
- }
- static const struct wl_keyboard_listener keyboardListener = {
- keyboardHandleKeymap,
- keyboardHandleEnter,
- keyboardHandleLeave,
- keyboardHandleKey,
- keyboardHandleModifiers,
- keyboardHandleRepeatInfo,
- };
- static void seatHandleCapabilities(void* data UNUSED,
- struct wl_seat* seat,
- enum wl_seat_capability caps)
- {
- if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)
- {
- _glfw.wl.pointer = wl_seat_get_pointer(seat);
- wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);
- if (_glfw.wl.wp_cursor_shape_manager_v1) {
- if (_glfw.wl.wp_cursor_shape_device_v1) wp_cursor_shape_device_v1_destroy(_glfw.wl.wp_cursor_shape_device_v1);
- _glfw.wl.wp_cursor_shape_device_v1 = NULL;
- _glfw.wl.wp_cursor_shape_device_v1 = wp_cursor_shape_manager_v1_get_pointer(_glfw.wl.wp_cursor_shape_manager_v1, _glfw.wl.pointer);
- }
- }
- else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
- {
- if (_glfw.wl.wp_cursor_shape_device_v1) wp_cursor_shape_device_v1_destroy(_glfw.wl.wp_cursor_shape_device_v1);
- _glfw.wl.wp_cursor_shape_device_v1 = NULL;
- wl_pointer_destroy(_glfw.wl.pointer);
- _glfw.wl.pointer = NULL;
- if (_glfw.wl.cursorAnimationTimer) toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
- }
- if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)
- {
- _glfw.wl.keyboard = wl_seat_get_keyboard(seat);
- wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
- }
- else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
- {
- wl_keyboard_destroy(_glfw.wl.keyboard);
- _glfw.wl.keyboard = NULL;
- _glfw.wl.keyboardFocusId = 0;
- if (_glfw.wl.keyRepeatInfo.keyRepeatTimer) toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
- }
- }
- static void seatHandleName(void* data UNUSED,
- struct wl_seat* seat UNUSED,
- const char* name UNUSED)
- {
- }
- static const struct wl_seat_listener seatListener = {
- seatHandleCapabilities,
- seatHandleName,
- };
- static void wmBaseHandlePing(void* data UNUSED,
- struct xdg_wm_base* wmBase,
- uint32_t serial)
- {
- xdg_wm_base_pong(wmBase, serial);
- }
- static const struct xdg_wm_base_listener wmBaseListener = {
- wmBaseHandlePing
- };
- static void registryHandleGlobal(void* data UNUSED,
- struct wl_registry* registry,
- uint32_t name,
- const char* interface,
- uint32_t version)
- {
- #define is(x) strcmp(interface, x##_interface.name) == 0
- if (is(wl_compositor))
- {
- #ifdef WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION
- _glfw.wl.compositorVersion = MIN(WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION, (int)version);
- _glfw.wl.has_preferred_buffer_scale = _glfw.wl.compositorVersion >= WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION;
- #else
- _glfw.wl.compositorVersion = MIN(3, (int)version);
- #endif
- _glfw.wl.compositor = wl_registry_bind(registry, name, &wl_compositor_interface, _glfw.wl.compositorVersion);
- }
- else if (is(wl_subcompositor))
- {
- _glfw.wl.subcompositor =
- wl_registry_bind(registry, name, &wl_subcompositor_interface, 1);
- }
- else if (is(wl_shm))
- {
- _glfw.wl.shm =
- wl_registry_bind(registry, name, &wl_shm_interface, 1);
- }
- else if (is(wl_output))
- {
- _glfwAddOutputWayland(name, version);
- }
- else if (is(wl_seat))
- {
- if (!_glfw.wl.seat)
- {
- #ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
- _glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION, (int)version);
- #elif defined(WL_POINTER_AXIS_VALUE120_SINCE_VERSION)
- _glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_VALUE120_SINCE_VERSION, (int)version);
- #else
- _glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_DISCRETE_SINCE_VERSION, version);
- #endif
- _glfw.wl.seat =
- wl_registry_bind(registry, name, &wl_seat_interface,
- _glfw.wl.seatVersion);
- wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
- }
- if (_glfw.wl.seat) {
- if (_glfw.wl.dataDeviceManager && !_glfw.wl.dataDevice) _glfwSetupWaylandDataDevice();
- if (_glfw.wl.primarySelectionDeviceManager && !_glfw.wl.primarySelectionDevice) {
- _glfwSetupWaylandPrimarySelectionDevice();
- }
- }
- }
- else if (is(xdg_wm_base))
- {
- _glfw.wl.xdg_wm_base_version = 1;
- #ifdef XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION
- _glfw.wl.xdg_wm_base_version = MIN(XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION, (int)version);
- #elif defined(XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)
- _glfw.wl.xdg_wm_base_version = MIN(XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION, (int)version);
- #endif
- _glfw.wl.wmBase = wl_registry_bind(registry, name, &xdg_wm_base_interface, _glfw.wl.xdg_wm_base_version);
- xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
- }
- else if (is(zxdg_decoration_manager_v1))
- {
- _glfw.wl.decorationManager =
- wl_registry_bind(registry, name,
- &zxdg_decoration_manager_v1_interface, 1);
- }
- else if (is(zwp_relative_pointer_manager_v1))
- {
- _glfw.wl.relativePointerManager =
- wl_registry_bind(registry, name,
- &zwp_relative_pointer_manager_v1_interface,
- 1);
- }
- else if (is(zwp_pointer_constraints_v1))
- {
- _glfw.wl.pointerConstraints =
- wl_registry_bind(registry, name,
- &zwp_pointer_constraints_v1_interface,
- 1);
- }
- else if (is(zwp_text_input_manager_v3))
- {
- _glfwWaylandBindTextInput(registry, name);
- }
- else if (is(wl_data_device_manager))
- {
- _glfw.wl.dataDeviceManager =
- wl_registry_bind(registry, name,
- &wl_data_device_manager_interface,
- 1);
- if (_glfw.wl.seat && _glfw.wl.dataDeviceManager && !_glfw.wl.dataDevice) {
- _glfwSetupWaylandDataDevice();
- }
- }
- else if (is(zwp_primary_selection_device_manager_v1))
- {
- _glfw.wl.primarySelectionDeviceManager =
- wl_registry_bind(registry, name,
- &zwp_primary_selection_device_manager_v1_interface,
- 1);
- if (_glfw.wl.seat && _glfw.wl.primarySelectionDeviceManager && !_glfw.wl.primarySelectionDevice) {
- _glfwSetupWaylandPrimarySelectionDevice();
- }
- }
- else if (is(wp_single_pixel_buffer_manager_v1)) {
- _glfw.wl.wp_single_pixel_buffer_manager_v1 = wl_registry_bind(registry, name, &wp_single_pixel_buffer_manager_v1_interface, 1);
- }
- else if (is(xdg_activation_v1)) {
- _glfw.wl.xdg_activation_v1 = wl_registry_bind(registry, name, &xdg_activation_v1_interface, 1);
- }
- else if (is(wp_cursor_shape_manager_v1)) {
- _glfw.wl.wp_cursor_shape_manager_v1 = wl_registry_bind(registry, name, &wp_cursor_shape_manager_v1_interface, 1);
- }
- else if (is(wp_fractional_scale_manager_v1)) {
- _glfw.wl.wp_fractional_scale_manager_v1 = wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, 1);
- }
- else if (is(wp_viewporter)) {
- _glfw.wl.wp_viewporter = wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
- }
- else if (is(org_kde_kwin_blur_manager)) {
- _glfw.wl.org_kde_kwin_blur_manager = wl_registry_bind(registry, name, &org_kde_kwin_blur_manager_interface, 1);
- }
- else if (is(zwlr_layer_shell_v1)) {
- if (version >= 4) {
- _glfw.wl.zwlr_layer_shell_v1_version = version;
- _glfw.wl.zwlr_layer_shell_v1 = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version);
- }
- }
- else if (is(zwp_idle_inhibit_manager_v1)) {
- _glfw.wl.idle_inhibit_manager = wl_registry_bind(registry, name, &zwp_idle_inhibit_manager_v1_interface, 1);
- }
- #undef is
- }
- static void registryHandleGlobalRemove(void *data UNUSED,
- struct wl_registry *registry UNUSED,
- uint32_t name)
- {
- _GLFWmonitor* monitor;
- for (int i = 0; i < _glfw.monitorCount; ++i)
- {
- monitor = _glfw.monitors[i];
- if (monitor->wl.name == name)
- {
- for (_GLFWwindow *window = _glfw.windowListHead; window; window = window->next) {
- for (int m = window->wl.monitorsCount - 1; m >= 0; m--) {
- if (window->wl.monitors[m] == monitor) {
- remove_i_from_array(window->wl.monitors, m, window->wl.monitorsCount);
- }
- }
- }
- _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0);
- return;
- }
- }
- }
- static const struct wl_registry_listener registryListener = {
- registryHandleGlobal,
- registryHandleGlobalRemove
- };
- GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialized) {
- return glfw_current_system_color_theme(query_if_unintialized);
- }
- static pid_t
- get_socket_peer_pid(int fd) {
- (void)fd;
- #ifdef __linux__
- struct ucred ucred;
- socklen_t len = sizeof(struct ucred);
- return (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) ? -1 : ucred.pid;
- #elif defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
- struct xucred peercred;
- socklen_t peercredlen = sizeof(peercred);
- return (getsockopt(c->fd, LOCAL_PEERCRED, 1, (void *)&peercred, &peercredlen) == 0 && peercred.cr_version == XUCRED_VERSION) ? peercred.cr_pid : -1;
- #elif defined(LOCAL_PEERPID)
- pid_t pid;
- socklen_t pid_size = sizeof(pid);
- return getsockopt(client, SOL_LOCAL, LOCAL_PEERPID, &pid, &pid_size) == -1 ? -1 : pid;
- #else
- errno = ENOSYS;
- return -1;
- #endif
- }
- GLFWAPI pid_t glfwWaylandCompositorPID(void) {
- if (!_glfw.wl.display) return -1;
- int fd = wl_display_get_fd(_glfw.wl.display);
- if (fd < 0) return -1;
- return get_socket_peer_pid(fd);
- }
- //////////////////////////////////////////////////////////////////////////
- ////// GLFW platform API //////
- //////////////////////////////////////////////////////////////////////////
- static const char*
- get_compositor_missing_capabilities(void) {
- #define C(title, x) if (!_glfw.wl.x) p += snprintf(buf, sizeof(buf) - (p - buf), "%s", #title);
- static char buf[256];
- char *p = buf;
- *p = 0;
- C(viewporter, wp_viewporter); C(fractional_scale, wp_fractional_scale_manager_v1);
- C(blur, org_kde_kwin_blur_manager); C(server_side_decorations, decorationManager);
- C(cursor_shape, wp_cursor_shape_manager_v1); C(layer_shell, zwlr_layer_shell_v1);
- C(single_pixel_buffer, wp_single_pixel_buffer_manager_v1); C(preferred_scale, has_preferred_buffer_scale);
- C(idle_inhibit, idle_inhibit_manager);
- #undef C
- return buf;
- }
- GLFWAPI const char* glfwWaylandMissingCapabilities(void) { return get_compositor_missing_capabilities(); }
- int _glfwPlatformInit(void)
- {
- int i;
- _GLFWmonitor* monitor;
- _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
- if (!_glfw.wl.cursor.handle)
- {
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "Wayland: Failed to open libwayland-cursor");
- return false;
- }
- glfw_dlsym(_glfw.wl.cursor.theme_load, _glfw.wl.cursor.handle, "wl_cursor_theme_load");
- glfw_dlsym(_glfw.wl.cursor.theme_destroy, _glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
- glfw_dlsym(_glfw.wl.cursor.theme_get_cursor, _glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
- glfw_dlsym(_glfw.wl.cursor.image_get_buffer, _glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");
- _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
- if (!_glfw.wl.egl.handle)
- {
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "Wayland: Failed to open libwayland-egl");
- return false;
- }
- glfw_dlsym(_glfw.wl.egl.window_create, _glfw.wl.egl.handle, "wl_egl_window_create");
- glfw_dlsym(_glfw.wl.egl.window_destroy, _glfw.wl.egl.handle, "wl_egl_window_destroy");
- glfw_dlsym(_glfw.wl.egl.window_resize, _glfw.wl.egl.handle, "wl_egl_window_resize");
- _glfw.wl.display = wl_display_connect(NULL);
- if (!_glfw.wl.display)
- {
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "Wayland: Failed to connect to display");
- return false;
- }
- if (!initPollData(&_glfw.wl.eventLoopData, wl_display_get_fd(_glfw.wl.display))) {
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "Wayland: Failed to initialize event loop data");
- }
- glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
- glfw_initialize_desktop_settings();
- _glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", ms_to_monotonic_t(500ll), 0, true, dispatchPendingKeyRepeats, NULL, NULL);
- _glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", ms_to_monotonic_t(500ll), 0, true, animateCursorImage, NULL, NULL);
- _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
- wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
- if (!glfw_xkb_create_context(&_glfw.wl.xkb)) return false;
- // Sync so we got all registry objects
- wl_display_roundtrip(_glfw.wl.display);
- _glfwWaylandInitTextInput();
- // Sync so we got all initial output events
- wl_display_roundtrip(_glfw.wl.display);
- for (i = 0; i < _glfw.monitorCount; ++i)
- {
- monitor = _glfw.monitors[i];
- if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
- {
- // If Wayland does not provide a physical size, assume the default 96 DPI
- monitor->widthMM = (int) (monitor->modes[monitor->wl.currentMode].width * 25.4f / 96.f);
- monitor->heightMM = (int) (monitor->modes[monitor->wl.currentMode].height * 25.4f / 96.f);
- }
- }
- if (!_glfw.wl.wmBase)
- {
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "Wayland: Failed to find xdg-shell in your compositor");
- return false;
- }
- if (_glfw.wl.shm)
- {
- _glfw.wl.cursorSurface =
- wl_compositor_create_surface(_glfw.wl.compositor);
- }
- else
- {
- _glfwInputError(GLFW_PLATFORM_ERROR,
- "Wayland: Failed to find Wayland SHM");
- return false;
- }
- if (_glfw.hints.init.debugRendering) {
- const char *mc = get_compositor_missing_capabilities();
- if (mc && mc[0]) debug("Compositor missing capabilities: %s\n", mc);
- }
- return true;
- }
- void _glfwPlatformTerminate(void)
- {
- if (_glfw.wl.activation_requests.array) {
- for (size_t i=0; i < _glfw.wl.activation_requests.sz; i++) {
- glfw_wl_xdg_activation_request *r = _glfw.wl.activation_requests.array + i;
- if (r->callback) r->callback(NULL, NULL, r->callback_data);
- xdg_activation_token_v1_destroy(r->token);
- }
- free(_glfw.wl.activation_requests.array);
- }
- _glfwTerminateEGL();
- if (_glfw.wl.egl.handle)
- {
- _glfw_dlclose(_glfw.wl.egl.handle);
- _glfw.wl.egl.handle = NULL;
- }
- glfw_xkb_release(&_glfw.wl.xkb);
- glfw_dbus_terminate(&_glfw.wl.dbus);
- glfw_wlc_destroy();
- if (_glfw.wl.cursor.handle)
- {
- _glfw_dlclose(_glfw.wl.cursor.handle);
- _glfw.wl.cursor.handle = NULL;
- }
- if (_glfw.wl.cursorSurface)
- wl_surface_destroy(_glfw.wl.cursorSurface);
- if (_glfw.wl.subcompositor)
- wl_subcompositor_destroy(_glfw.wl.subcompositor);
- if (_glfw.wl.compositor)
- wl_compositor_destroy(_glfw.wl.compositor);
- if (_glfw.wl.shm)
- wl_shm_destroy(_glfw.wl.shm);
- if (_glfw.wl.decorationManager)
- zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
- if (_glfw.wl.wmBase)
- xdg_wm_base_destroy(_glfw.wl.wmBase);
- if (_glfw.wl.pointer)
- wl_pointer_destroy(_glfw.wl.pointer);
- if (_glfw.wl.keyboard)
- wl_keyboard_destroy(_glfw.wl.keyboard);
- if (_glfw.wl.seat)
- wl_seat_destroy(_glfw.wl.seat);
- if (_glfw.wl.relativePointerManager)
- zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);
- if (_glfw.wl.pointerConstraints)
- zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);
- _glfwWaylandDestroyTextInput();
- if (_glfw.wl.dataSourceForClipboard)
- wl_data_source_destroy(_glfw.wl.dataSourceForClipboard);
- if (_glfw.wl.dataSourceForPrimarySelection)
- zwp_primary_selection_source_v1_destroy(_glfw.wl.dataSourceForPrimarySelection);
- for (size_t doi=0; doi < arraysz(_glfw.wl.dataOffers); doi++) {
- if (_glfw.wl.dataOffers[doi].id) {
- destroy_data_offer(&_glfw.wl.dataOffers[doi]);
- }
- }
- if (_glfw.wl.dataDevice)
- wl_data_device_destroy(_glfw.wl.dataDevice);
- if (_glfw.wl.dataDeviceManager)
- wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
- if (_glfw.wl.primarySelectionDevice)
- zwp_primary_selection_device_v1_destroy(_glfw.wl.primarySelectionDevice);
- if (_glfw.wl.primarySelectionDeviceManager)
- zwp_primary_selection_device_manager_v1_destroy(_glfw.wl.primarySelectionDeviceManager);
- if (_glfw.wl.xdg_activation_v1)
- xdg_activation_v1_destroy(_glfw.wl.xdg_activation_v1);
- if (_glfw.wl.wp_single_pixel_buffer_manager_v1)
- wp_single_pixel_buffer_manager_v1_destroy(_glfw.wl.wp_single_pixel_buffer_manager_v1);
- if (_glfw.wl.wp_cursor_shape_manager_v1)
- wp_cursor_shape_manager_v1_destroy(_glfw.wl.wp_cursor_shape_manager_v1);
- if (_glfw.wl.wp_viewporter)
- wp_viewporter_destroy(_glfw.wl.wp_viewporter);
- if (_glfw.wl.wp_fractional_scale_manager_v1)
- wp_fractional_scale_manager_v1_destroy(_glfw.wl.wp_fractional_scale_manager_v1);
- if (_glfw.wl.org_kde_kwin_blur_manager)
- org_kde_kwin_blur_manager_destroy(_glfw.wl.org_kde_kwin_blur_manager);
- if (_glfw.wl.zwlr_layer_shell_v1)
- zwlr_layer_shell_v1_destroy(_glfw.wl.zwlr_layer_shell_v1);
- if (_glfw.wl.idle_inhibit_manager)
- zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idle_inhibit_manager);
- if (_glfw.wl.registry)
- wl_registry_destroy(_glfw.wl.registry);
- if (_glfw.wl.display)
- {
- wl_display_flush(_glfw.wl.display);
- wl_display_disconnect(_glfw.wl.display);
- }
- finalizePollData(&_glfw.wl.eventLoopData);
- }
- #define GLFW_LOOP_BACKEND wl
- #include "main_loop.h"
- const char* _glfwPlatformGetVersionString(void)
- {
- (void)keep_going;
- return _GLFW_VERSION_NUMBER " Wayland EGL OSMesa"
- #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
- " clock_gettime"
- #else
- " gettimeofday"
- #endif
- " evdev"
- #if defined(_GLFW_BUILD_DLL)
- " shared"
- #endif
- ;
- }
|