|
@@ -28,7 +28,6 @@
|
|
|
|
|
|
#include "internal.h"
|
|
#include "internal.h"
|
|
|
|
|
|
-#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <limits.h>
|
|
#include <linux/input.h>
|
|
#include <linux/input.h>
|
|
@@ -56,765 +55,6 @@
|
|
#include "wayland-pointer-constraints-unstable-v1-client-protocol-code.h"
|
|
#include "wayland-pointer-constraints-unstable-v1-client-protocol-code.h"
|
|
#include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h"
|
|
#include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h"
|
|
|
|
|
|
-
|
|
|
|
-static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
|
|
|
|
- int* which)
|
|
|
|
-{
|
|
|
|
- int focus;
|
|
|
|
- _GLFWwindow* window = _glfw.windowListHead;
|
|
|
|
- if (!which)
|
|
|
|
- which = &focus;
|
|
|
|
- while (window)
|
|
|
|
- {
|
|
|
|
- if (surface == window->wl.decorations.top.surface)
|
|
|
|
- {
|
|
|
|
- *which = topDecoration;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (surface == window->wl.decorations.left.surface)
|
|
|
|
- {
|
|
|
|
- *which = leftDecoration;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (surface == window->wl.decorations.right.surface)
|
|
|
|
- {
|
|
|
|
- *which = rightDecoration;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (surface == window->wl.decorations.bottom.surface)
|
|
|
|
- {
|
|
|
|
- *which = bottomDecoration;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- window = window->next;
|
|
|
|
- }
|
|
|
|
- return window;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void pointerHandleEnter(void* userData,
|
|
|
|
- struct wl_pointer* pointer,
|
|
|
|
- uint32_t serial,
|
|
|
|
- struct wl_surface* surface,
|
|
|
|
- wl_fixed_t sx,
|
|
|
|
- wl_fixed_t sy)
|
|
|
|
-{
|
|
|
|
- // Happens in the case we just destroyed the surface.
|
|
|
|
- if (!surface)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- int focus = 0;
|
|
|
|
- _GLFWwindow* window = wl_surface_get_user_data(surface);
|
|
|
|
- if (!window)
|
|
|
|
- {
|
|
|
|
- window = findWindowFromDecorationSurface(surface, &focus);
|
|
|
|
- if (!window)
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- window->wl.decorations.focus = focus;
|
|
|
|
- _glfw.wl.serial = serial;
|
|
|
|
- _glfw.wl.pointerEnterSerial = serial;
|
|
|
|
- _glfw.wl.pointerFocus = window;
|
|
|
|
-
|
|
|
|
- window->wl.hovered = GLFW_TRUE;
|
|
|
|
-
|
|
|
|
- _glfwSetCursorWayland(window, window->wl.currentCursor);
|
|
|
|
- _glfwInputCursorEnter(window, GLFW_TRUE);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void pointerHandleLeave(void* userData,
|
|
|
|
- struct wl_pointer* pointer,
|
|
|
|
- uint32_t serial,
|
|
|
|
- struct wl_surface* surface)
|
|
|
|
-{
|
|
|
|
- _GLFWwindow* window = _glfw.wl.pointerFocus;
|
|
|
|
-
|
|
|
|
- if (!window)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- window->wl.hovered = GLFW_FALSE;
|
|
|
|
-
|
|
|
|
- _glfw.wl.serial = serial;
|
|
|
|
- _glfw.wl.pointerFocus = NULL;
|
|
|
|
- _glfwInputCursorEnter(window, GLFW_FALSE);
|
|
|
|
- _glfw.wl.cursorPreviousName = NULL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void setCursor(_GLFWwindow* window, const char* name)
|
|
|
|
-{
|
|
|
|
- struct wl_buffer* buffer;
|
|
|
|
- struct wl_cursor* cursor;
|
|
|
|
- struct wl_cursor_image* image;
|
|
|
|
- struct wl_surface* surface = _glfw.wl.cursorSurface;
|
|
|
|
- struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
|
|
|
|
- int scale = 1;
|
|
|
|
-
|
|
|
|
- if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI)
|
|
|
|
- {
|
|
|
|
- // We only support up to scale=2 for now, since libwayland-cursor
|
|
|
|
- // requires us to load a different theme for each size.
|
|
|
|
- scale = 2;
|
|
|
|
- theme = _glfw.wl.cursorThemeHiDPI;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- cursor = wl_cursor_theme_get_cursor(theme, name);
|
|
|
|
- if (!cursor)
|
|
|
|
- {
|
|
|
|
- _glfwInputError(GLFW_CURSOR_UNAVAILABLE,
|
|
|
|
- "Wayland: Standard cursor shape unavailable");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- // TODO: handle animated cursors too.
|
|
|
|
- image = cursor->images[0];
|
|
|
|
-
|
|
|
|
- if (!image)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- buffer = wl_cursor_image_get_buffer(image);
|
|
|
|
- if (!buffer)
|
|
|
|
- return;
|
|
|
|
- wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
|
|
|
|
- surface,
|
|
|
|
- image->hotspot_x / scale,
|
|
|
|
- image->hotspot_y / scale);
|
|
|
|
- wl_surface_set_buffer_scale(surface, scale);
|
|
|
|
- wl_surface_attach(surface, buffer, 0, 0);
|
|
|
|
- wl_surface_damage(surface, 0, 0,
|
|
|
|
- image->width, image->height);
|
|
|
|
- wl_surface_commit(surface);
|
|
|
|
- _glfw.wl.cursorPreviousName = name;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void pointerHandleMotion(void* userData,
|
|
|
|
- struct wl_pointer* pointer,
|
|
|
|
- uint32_t time,
|
|
|
|
- wl_fixed_t sx,
|
|
|
|
- wl_fixed_t sy)
|
|
|
|
-{
|
|
|
|
- _GLFWwindow* window = _glfw.wl.pointerFocus;
|
|
|
|
- const char* cursorName = NULL;
|
|
|
|
- double x, y;
|
|
|
|
-
|
|
|
|
- if (!window)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
|
|
|
- return;
|
|
|
|
- x = wl_fixed_to_double(sx);
|
|
|
|
- y = wl_fixed_to_double(sy);
|
|
|
|
- window->wl.cursorPosX = x;
|
|
|
|
- window->wl.cursorPosY = y;
|
|
|
|
-
|
|
|
|
- switch (window->wl.decorations.focus)
|
|
|
|
- {
|
|
|
|
- case mainWindow:
|
|
|
|
- _glfwInputCursorPos(window, x, y);
|
|
|
|
- _glfw.wl.cursorPreviousName = NULL;
|
|
|
|
- return;
|
|
|
|
- case topDecoration:
|
|
|
|
- if (y < _GLFW_DECORATION_WIDTH)
|
|
|
|
- cursorName = "n-resize";
|
|
|
|
- else
|
|
|
|
- cursorName = "left_ptr";
|
|
|
|
- break;
|
|
|
|
- case leftDecoration:
|
|
|
|
- if (y < _GLFW_DECORATION_WIDTH)
|
|
|
|
- cursorName = "nw-resize";
|
|
|
|
- else
|
|
|
|
- cursorName = "w-resize";
|
|
|
|
- break;
|
|
|
|
- case rightDecoration:
|
|
|
|
- if (y < _GLFW_DECORATION_WIDTH)
|
|
|
|
- cursorName = "ne-resize";
|
|
|
|
- else
|
|
|
|
- cursorName = "e-resize";
|
|
|
|
- break;
|
|
|
|
- case bottomDecoration:
|
|
|
|
- if (x < _GLFW_DECORATION_WIDTH)
|
|
|
|
- cursorName = "sw-resize";
|
|
|
|
- else if (x > window->wl.width + _GLFW_DECORATION_WIDTH)
|
|
|
|
- cursorName = "se-resize";
|
|
|
|
- else
|
|
|
|
- cursorName = "s-resize";
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- assert(0);
|
|
|
|
- }
|
|
|
|
- if (_glfw.wl.cursorPreviousName != cursorName)
|
|
|
|
- setCursor(window, cursorName);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void pointerHandleButton(void* userData,
|
|
|
|
- struct wl_pointer* pointer,
|
|
|
|
- uint32_t serial,
|
|
|
|
- uint32_t time,
|
|
|
|
- uint32_t button,
|
|
|
|
- uint32_t state)
|
|
|
|
-{
|
|
|
|
- _GLFWwindow* window = _glfw.wl.pointerFocus;
|
|
|
|
- int glfwButton;
|
|
|
|
- uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
|
|
|
-
|
|
|
|
- if (!window)
|
|
|
|
- return;
|
|
|
|
- if (button == BTN_LEFT)
|
|
|
|
- {
|
|
|
|
- switch (window->wl.decorations.focus)
|
|
|
|
- {
|
|
|
|
- case mainWindow:
|
|
|
|
- break;
|
|
|
|
- case topDecoration:
|
|
|
|
- if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
|
|
|
- edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
|
|
|
|
- else
|
|
|
|
- xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
|
|
|
|
- break;
|
|
|
|
- case leftDecoration:
|
|
|
|
- if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
|
|
|
- edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
|
|
|
|
- else
|
|
|
|
- edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
|
|
|
|
- break;
|
|
|
|
- case rightDecoration:
|
|
|
|
- if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
|
|
|
- edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
|
|
|
|
- else
|
|
|
|
- edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
|
|
|
|
- break;
|
|
|
|
- case bottomDecoration:
|
|
|
|
- if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
|
|
|
|
- edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
|
|
|
|
- else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
|
|
|
|
- edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
|
|
|
|
- else
|
|
|
|
- edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- assert(0);
|
|
|
|
- }
|
|
|
|
- if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
|
|
|
|
- {
|
|
|
|
- xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
|
|
|
|
- serial, edges);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else if (button == BTN_RIGHT)
|
|
|
|
- {
|
|
|
|
- if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel)
|
|
|
|
- {
|
|
|
|
- xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
|
|
|
|
- _glfw.wl.seat, serial,
|
|
|
|
- window->wl.cursorPosX,
|
|
|
|
- window->wl.cursorPosY);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Don’t pass the button to the user if it was related to a decoration.
|
|
|
|
- if (window->wl.decorations.focus != mainWindow)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- _glfw.wl.serial = serial;
|
|
|
|
-
|
|
|
|
- /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
|
|
|
|
- * codes. */
|
|
|
|
- glfwButton = button - BTN_LEFT;
|
|
|
|
-
|
|
|
|
- _glfwInputMouseClick(window,
|
|
|
|
- glfwButton,
|
|
|
|
- state == WL_POINTER_BUTTON_STATE_PRESSED
|
|
|
|
- ? GLFW_PRESS
|
|
|
|
- : GLFW_RELEASE,
|
|
|
|
- _glfw.wl.xkb.modifiers);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void pointerHandleAxis(void* userData,
|
|
|
|
- struct wl_pointer* pointer,
|
|
|
|
- uint32_t time,
|
|
|
|
- uint32_t axis,
|
|
|
|
- wl_fixed_t value)
|
|
|
|
-{
|
|
|
|
- _GLFWwindow* window = _glfw.wl.pointerFocus;
|
|
|
|
- double x = 0.0, y = 0.0;
|
|
|
|
- // Wayland scroll events are in pointer motion coordinate space (think two
|
|
|
|
- // finger scroll). The factor 10 is commonly used to convert to "scroll
|
|
|
|
- // step means 1.0.
|
|
|
|
- const double scrollFactor = 1.0 / 10.0;
|
|
|
|
-
|
|
|
|
- if (!window)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||
|
|
|
|
- axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
|
|
|
|
-
|
|
|
|
- if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
|
|
|
|
- x = -wl_fixed_to_double(value) * scrollFactor;
|
|
|
|
- else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
|
|
|
- y = -wl_fixed_to_double(value) * scrollFactor;
|
|
|
|
-
|
|
|
|
- _glfwInputScroll(window, x, y);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static const struct wl_pointer_listener pointerListener = {
|
|
|
|
- pointerHandleEnter,
|
|
|
|
- pointerHandleLeave,
|
|
|
|
- pointerHandleMotion,
|
|
|
|
- pointerHandleButton,
|
|
|
|
- pointerHandleAxis,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static void keyboardHandleKeymap(void* userData,
|
|
|
|
- struct wl_keyboard* keyboard,
|
|
|
|
- uint32_t format,
|
|
|
|
- int fd,
|
|
|
|
- uint32_t size)
|
|
|
|
-{
|
|
|
|
- struct xkb_keymap* keymap;
|
|
|
|
- struct xkb_state* state;
|
|
|
|
- struct xkb_compose_table* composeTable;
|
|
|
|
- struct xkb_compose_state* composeState;
|
|
|
|
-
|
|
|
|
- char* mapStr;
|
|
|
|
- const char* locale;
|
|
|
|
-
|
|
|
|
- if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
|
|
|
|
- {
|
|
|
|
- close(fd);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
|
|
|
- if (mapStr == MAP_FAILED) {
|
|
|
|
- close(fd);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
|
|
|
|
- mapStr,
|
|
|
|
- XKB_KEYMAP_FORMAT_TEXT_V1,
|
|
|
|
- 0);
|
|
|
|
- munmap(mapStr, size);
|
|
|
|
- close(fd);
|
|
|
|
-
|
|
|
|
- if (!keymap)
|
|
|
|
- {
|
|
|
|
- _glfwInputError(GLFW_PLATFORM_ERROR,
|
|
|
|
- "Wayland: Failed to compile keymap");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- state = xkb_state_new(keymap);
|
|
|
|
- if (!state)
|
|
|
|
- {
|
|
|
|
- _glfwInputError(GLFW_PLATFORM_ERROR,
|
|
|
|
- "Wayland: Failed to create XKB state");
|
|
|
|
- xkb_keymap_unref(keymap);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Look up the preferred locale, falling back to "C" as default.
|
|
|
|
- locale = getenv("LC_ALL");
|
|
|
|
- if (!locale)
|
|
|
|
- locale = getenv("LC_CTYPE");
|
|
|
|
- if (!locale)
|
|
|
|
- locale = getenv("LANG");
|
|
|
|
- if (!locale)
|
|
|
|
- locale = "C";
|
|
|
|
-
|
|
|
|
- composeTable =
|
|
|
|
- xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,
|
|
|
|
- XKB_COMPOSE_COMPILE_NO_FLAGS);
|
|
|
|
- if (composeTable)
|
|
|
|
- {
|
|
|
|
- composeState =
|
|
|
|
- xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
|
|
|
|
- xkb_compose_table_unref(composeTable);
|
|
|
|
- if (composeState)
|
|
|
|
- _glfw.wl.xkb.composeState = composeState;
|
|
|
|
- else
|
|
|
|
- _glfwInputError(GLFW_PLATFORM_ERROR,
|
|
|
|
- "Wayland: Failed to create XKB compose state");
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- _glfwInputError(GLFW_PLATFORM_ERROR,
|
|
|
|
- "Wayland: Failed to create XKB compose table");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- xkb_keymap_unref(_glfw.wl.xkb.keymap);
|
|
|
|
- xkb_state_unref(_glfw.wl.xkb.state);
|
|
|
|
- _glfw.wl.xkb.keymap = keymap;
|
|
|
|
- _glfw.wl.xkb.state = state;
|
|
|
|
-
|
|
|
|
- _glfw.wl.xkb.controlMask =
|
|
|
|
- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");
|
|
|
|
- _glfw.wl.xkb.altMask =
|
|
|
|
- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
|
|
|
|
- _glfw.wl.xkb.shiftMask =
|
|
|
|
- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
|
|
|
|
- _glfw.wl.xkb.superMask =
|
|
|
|
- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
|
|
|
|
- _glfw.wl.xkb.capsLockMask =
|
|
|
|
- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
|
|
|
|
- _glfw.wl.xkb.numLockMask =
|
|
|
|
- 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void keyboardHandleEnter(void* userData,
|
|
|
|
- struct wl_keyboard* keyboard,
|
|
|
|
- uint32_t serial,
|
|
|
|
- struct wl_surface* surface,
|
|
|
|
- struct wl_array* keys)
|
|
|
|
-{
|
|
|
|
- // Happens in the case we just destroyed the surface.
|
|
|
|
- if (!surface)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- _GLFWwindow* window = wl_surface_get_user_data(surface);
|
|
|
|
- if (!window)
|
|
|
|
- {
|
|
|
|
- window = findWindowFromDecorationSurface(surface, NULL);
|
|
|
|
- if (!window)
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _glfw.wl.serial = serial;
|
|
|
|
- _glfw.wl.keyboardFocus = window;
|
|
|
|
- _glfwInputWindowFocus(window, GLFW_TRUE);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void keyboardHandleLeave(void* userData,
|
|
|
|
- struct wl_keyboard* keyboard,
|
|
|
|
- uint32_t serial,
|
|
|
|
- struct wl_surface* surface)
|
|
|
|
-{
|
|
|
|
- _GLFWwindow* window = _glfw.wl.keyboardFocus;
|
|
|
|
-
|
|
|
|
- if (!window)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- struct itimerspec timer = {};
|
|
|
|
- timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);
|
|
|
|
-
|
|
|
|
- _glfw.wl.serial = serial;
|
|
|
|
- _glfw.wl.keyboardFocus = NULL;
|
|
|
|
- _glfwInputWindowFocus(window, GLFW_FALSE);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int translateKey(uint32_t scancode)
|
|
|
|
-{
|
|
|
|
- if (scancode < sizeof(_glfw.wl.keycodes) / sizeof(_glfw.wl.keycodes[0]))
|
|
|
|
- return _glfw.wl.keycodes[scancode];
|
|
|
|
-
|
|
|
|
- return GLFW_KEY_UNKNOWN;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
|
|
|
|
-{
|
|
|
|
- if (sym == XKB_KEY_NoSymbol || !_glfw.wl.xkb.composeState)
|
|
|
|
- return sym;
|
|
|
|
- if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)
|
|
|
|
- != XKB_COMPOSE_FEED_ACCEPTED)
|
|
|
|
- return sym;
|
|
|
|
- switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))
|
|
|
|
- {
|
|
|
|
- case XKB_COMPOSE_COMPOSED:
|
|
|
|
- return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);
|
|
|
|
- case XKB_COMPOSE_COMPOSING:
|
|
|
|
- case XKB_COMPOSE_CANCELLED:
|
|
|
|
- return XKB_KEY_NoSymbol;
|
|
|
|
- case XKB_COMPOSE_NOTHING:
|
|
|
|
- default:
|
|
|
|
- return sym;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode)
|
|
|
|
-{
|
|
|
|
- const xkb_keysym_t* keysyms;
|
|
|
|
- const xkb_keycode_t keycode = scancode + 8;
|
|
|
|
-
|
|
|
|
- if (xkb_state_key_get_syms(_glfw.wl.xkb.state, keycode, &keysyms) == 1)
|
|
|
|
- {
|
|
|
|
- const xkb_keysym_t keysym = composeSymbol(keysyms[0]);
|
|
|
|
- const uint32_t codepoint = _glfwKeySym2Unicode(keysym);
|
|
|
|
- if (codepoint != GLFW_INVALID_CODEPOINT)
|
|
|
|
- {
|
|
|
|
- const int mods = _glfw.wl.xkb.modifiers;
|
|
|
|
- const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
|
|
|
- _glfwInputChar(window, codepoint, mods, plain);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, keycode);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void keyboardHandleKey(void* userData,
|
|
|
|
- struct wl_keyboard* keyboard,
|
|
|
|
- uint32_t serial,
|
|
|
|
- uint32_t time,
|
|
|
|
- uint32_t scancode,
|
|
|
|
- uint32_t state)
|
|
|
|
-{
|
|
|
|
- _GLFWwindow* window = _glfw.wl.keyboardFocus;
|
|
|
|
- if (!window)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- const int key = translateKey(scancode);
|
|
|
|
- const int action =
|
|
|
|
- state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
|
|
|
|
-
|
|
|
|
- _glfw.wl.serial = serial;
|
|
|
|
- _glfwInputKey(window, key, scancode, action, _glfw.wl.xkb.modifiers);
|
|
|
|
-
|
|
|
|
- struct itimerspec timer = {};
|
|
|
|
-
|
|
|
|
- if (action == GLFW_PRESS)
|
|
|
|
- {
|
|
|
|
- const GLFWbool shouldRepeat = _glfwInputTextWayland(window, scancode);
|
|
|
|
-
|
|
|
|
- if (shouldRepeat && _glfw.wl.keyboardRepeatRate > 0)
|
|
|
|
- {
|
|
|
|
- _glfw.wl.keyboardLastKey = key;
|
|
|
|
- _glfw.wl.keyboardLastScancode = scancode;
|
|
|
|
- if (_glfw.wl.keyboardRepeatRate > 1)
|
|
|
|
- timer.it_interval.tv_nsec = 1000000000 / _glfw.wl.keyboardRepeatRate;
|
|
|
|
- else
|
|
|
|
- timer.it_interval.tv_sec = 1;
|
|
|
|
-
|
|
|
|
- timer.it_value.tv_sec = _glfw.wl.keyboardRepeatDelay / 1000;
|
|
|
|
- timer.it_value.tv_nsec = (_glfw.wl.keyboardRepeatDelay % 1000) * 1000000;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- timerfd_settime(_glfw.wl.timerfd, 0, &timer, NULL);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void keyboardHandleModifiers(void* userData,
|
|
|
|
- struct wl_keyboard* keyboard,
|
|
|
|
- uint32_t serial,
|
|
|
|
- uint32_t modsDepressed,
|
|
|
|
- uint32_t modsLatched,
|
|
|
|
- uint32_t modsLocked,
|
|
|
|
- uint32_t group)
|
|
|
|
-{
|
|
|
|
- _glfw.wl.serial = serial;
|
|
|
|
-
|
|
|
|
- if (!_glfw.wl.xkb.keymap)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- xkb_state_update_mask(_glfw.wl.xkb.state,
|
|
|
|
- modsDepressed,
|
|
|
|
- modsLatched,
|
|
|
|
- modsLocked,
|
|
|
|
- 0,
|
|
|
|
- 0,
|
|
|
|
- group);
|
|
|
|
-
|
|
|
|
- const xkb_mod_mask_t mask =
|
|
|
|
- xkb_state_serialize_mods(_glfw.wl.xkb.state,
|
|
|
|
- XKB_STATE_MODS_DEPRESSED |
|
|
|
|
- XKB_STATE_LAYOUT_DEPRESSED |
|
|
|
|
- XKB_STATE_MODS_LATCHED |
|
|
|
|
- XKB_STATE_LAYOUT_LATCHED);
|
|
|
|
-
|
|
|
|
- unsigned int mods = 0;
|
|
|
|
-
|
|
|
|
- if (mask & _glfw.wl.xkb.controlMask)
|
|
|
|
- mods |= GLFW_MOD_CONTROL;
|
|
|
|
- if (mask & _glfw.wl.xkb.altMask)
|
|
|
|
- mods |= GLFW_MOD_ALT;
|
|
|
|
- if (mask & _glfw.wl.xkb.shiftMask)
|
|
|
|
- mods |= GLFW_MOD_SHIFT;
|
|
|
|
- if (mask & _glfw.wl.xkb.superMask)
|
|
|
|
- mods |= GLFW_MOD_SUPER;
|
|
|
|
- if (mask & _glfw.wl.xkb.capsLockMask)
|
|
|
|
- mods |= GLFW_MOD_CAPS_LOCK;
|
|
|
|
- if (mask & _glfw.wl.xkb.numLockMask)
|
|
|
|
- mods |= GLFW_MOD_NUM_LOCK;
|
|
|
|
-
|
|
|
|
- _glfw.wl.xkb.modifiers = mods;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
|
|
|
|
-static void keyboardHandleRepeatInfo(void* userData,
|
|
|
|
- struct wl_keyboard* keyboard,
|
|
|
|
- int32_t rate,
|
|
|
|
- int32_t delay)
|
|
|
|
-{
|
|
|
|
- if (keyboard != _glfw.wl.keyboard)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- _glfw.wl.keyboardRepeatRate = rate;
|
|
|
|
- _glfw.wl.keyboardRepeatDelay = delay;
|
|
|
|
-}
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-static const struct wl_keyboard_listener keyboardListener = {
|
|
|
|
- keyboardHandleKeymap,
|
|
|
|
- keyboardHandleEnter,
|
|
|
|
- keyboardHandleLeave,
|
|
|
|
- keyboardHandleKey,
|
|
|
|
- keyboardHandleModifiers,
|
|
|
|
-#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
|
|
|
|
- keyboardHandleRepeatInfo,
|
|
|
|
-#endif
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static void seatHandleCapabilities(void* userData,
|
|
|
|
- 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);
|
|
|
|
- }
|
|
|
|
- else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
|
|
|
|
- {
|
|
|
|
- wl_pointer_destroy(_glfw.wl.pointer);
|
|
|
|
- _glfw.wl.pointer = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- 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;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void seatHandleName(void* userData,
|
|
|
|
- struct wl_seat* seat,
|
|
|
|
- const char* name)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static const struct wl_seat_listener seatListener = {
|
|
|
|
- seatHandleCapabilities,
|
|
|
|
- seatHandleName,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static void dataOfferHandleOffer(void* userData,
|
|
|
|
- struct wl_data_offer* offer,
|
|
|
|
- const char* mimeType)
|
|
|
|
-{
|
|
|
|
- for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
|
|
|
- {
|
|
|
|
- if (_glfw.wl.offers[i].offer == offer)
|
|
|
|
- {
|
|
|
|
- if (strcmp(mimeType, "text/plain;charset=utf-8") == 0)
|
|
|
|
- _glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE;
|
|
|
|
-
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static const struct wl_data_offer_listener dataOfferListener = {
|
|
|
|
- dataOfferHandleOffer,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static void dataDeviceHandleDataOffer(void* userData,
|
|
|
|
- struct wl_data_device* device,
|
|
|
|
- struct wl_data_offer* offer)
|
|
|
|
-{
|
|
|
|
- _GLFWofferWayland* offers =
|
|
|
|
- _glfw_realloc(_glfw.wl.offers, _glfw.wl.offerCount + 1);
|
|
|
|
- if (!offers)
|
|
|
|
- {
|
|
|
|
- _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _glfw.wl.offers = offers;
|
|
|
|
- _glfw.wl.offerCount++;
|
|
|
|
-
|
|
|
|
- _glfw.wl.offers[_glfw.wl.offerCount - 1] = (_GLFWofferWayland) { offer };
|
|
|
|
- wl_data_offer_add_listener(offer, &dataOfferListener, NULL);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void dataDeviceHandleEnter(void* userData,
|
|
|
|
- struct wl_data_device* device,
|
|
|
|
- uint32_t serial,
|
|
|
|
- struct wl_surface* surface,
|
|
|
|
- wl_fixed_t x,
|
|
|
|
- wl_fixed_t y,
|
|
|
|
- struct wl_data_offer* offer)
|
|
|
|
-{
|
|
|
|
- for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
|
|
|
- {
|
|
|
|
- if (_glfw.wl.offers[i].offer == offer)
|
|
|
|
- {
|
|
|
|
- _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
|
|
|
|
- _glfw.wl.offerCount--;
|
|
|
|
-
|
|
|
|
- // We don't yet handle drag and drop
|
|
|
|
- wl_data_offer_accept(offer, serial, NULL);
|
|
|
|
- wl_data_offer_destroy(offer);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void dataDeviceHandleLeave(void* userData,
|
|
|
|
- struct wl_data_device* device)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void dataDeviceHandleMotion(void* userData,
|
|
|
|
- struct wl_data_device* device,
|
|
|
|
- uint32_t time,
|
|
|
|
- wl_fixed_t x,
|
|
|
|
- wl_fixed_t y)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void dataDeviceHandleDrop(void* userData,
|
|
|
|
- struct wl_data_device* device)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void dataDeviceHandleSelection(void* userData,
|
|
|
|
- struct wl_data_device* device,
|
|
|
|
- struct wl_data_offer* offer)
|
|
|
|
-{
|
|
|
|
- if (_glfw.wl.selectionOffer)
|
|
|
|
- {
|
|
|
|
- wl_data_offer_destroy(_glfw.wl.selectionOffer);
|
|
|
|
- _glfw.wl.selectionOffer = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
|
|
|
- {
|
|
|
|
- if (_glfw.wl.offers[i].offer == offer)
|
|
|
|
- {
|
|
|
|
- if (_glfw.wl.offers[i].text_plain_utf8)
|
|
|
|
- _glfw.wl.selectionOffer = offer;
|
|
|
|
- else
|
|
|
|
- wl_data_offer_destroy(offer);
|
|
|
|
-
|
|
|
|
- _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
|
|
|
|
- _glfw.wl.offerCount--;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static const struct wl_data_device_listener dataDeviceListener = {
|
|
|
|
- dataDeviceHandleDataOffer,
|
|
|
|
- dataDeviceHandleEnter,
|
|
|
|
- dataDeviceHandleLeave,
|
|
|
|
- dataDeviceHandleMotion,
|
|
|
|
- dataDeviceHandleDrop,
|
|
|
|
- dataDeviceHandleSelection,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
static void wmBaseHandlePing(void* userData,
|
|
static void wmBaseHandlePing(void* userData,
|
|
struct xdg_wm_base* wmBase,
|
|
struct xdg_wm_base* wmBase,
|
|
uint32_t serial)
|
|
uint32_t serial)
|
|
@@ -861,7 +101,7 @@ static void registryHandleGlobal(void* userData,
|
|
_glfw.wl.seat =
|
|
_glfw.wl.seat =
|
|
wl_registry_bind(registry, name, &wl_seat_interface,
|
|
wl_registry_bind(registry, name, &wl_seat_interface,
|
|
_glfw.wl.seatVersion);
|
|
_glfw.wl.seatVersion);
|
|
- wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
|
|
|
|
|
|
+ _glfwAddSeatListenerWayland(_glfw.wl.seat);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp(interface, "wl_data_device_manager") == 0)
|
|
else if (strcmp(interface, "wl_data_device_manager") == 0)
|
|
@@ -1412,7 +652,7 @@ int _glfwInitWayland(void)
|
|
_glfw.wl.dataDevice =
|
|
_glfw.wl.dataDevice =
|
|
wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
|
|
wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
|
|
_glfw.wl.seat);
|
|
_glfw.wl.seat);
|
|
- wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
|
|
|
|
|
|
+ _glfwAddDataDeviceListenerWayland(_glfw.wl.dataDevice);
|
|
}
|
|
}
|
|
|
|
|
|
return GLFW_TRUE;
|
|
return GLFW_TRUE;
|