mirror of
https://github.com/glfw/glfw.git
synced 2024-11-15 10:44:34 +00:00
Merge branch 'master' into multi-context-windows-merge-master
This commit is contained in:
commit
41bb2515ef
@ -162,6 +162,7 @@ video tutorials.
|
|||||||
- Orson Peters
|
- Orson Peters
|
||||||
- Emmanuel Gil Peyrot
|
- Emmanuel Gil Peyrot
|
||||||
- Cyril Pichard
|
- Cyril Pichard
|
||||||
|
- Pilzschaf
|
||||||
- Keith Pitt
|
- Keith Pitt
|
||||||
- Stanislav Podgorskiy
|
- Stanislav Podgorskiy
|
||||||
- Konstantin Podsvirov
|
- Konstantin Podsvirov
|
||||||
|
@ -291,6 +291,7 @@ information on what to include when reporting a bug.
|
|||||||
- [X11] Bugfix: Left shift of int constant relied on undefined behavior (#1951)
|
- [X11] Bugfix: Left shift of int constant relied on undefined behavior (#1951)
|
||||||
- [Wayland] Added dynamic loading of all Wayland libraries
|
- [Wayland] Added dynamic loading of all Wayland libraries
|
||||||
- [Wayland] Added support for key names via xkbcommon
|
- [Wayland] Added support for key names via xkbcommon
|
||||||
|
- [Wayland] Added support for file path drop events (#2040)
|
||||||
- [Wayland] Removed support for `wl_shell` (#1443)
|
- [Wayland] Removed support for `wl_shell` (#1443)
|
||||||
- [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432)
|
- [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432)
|
||||||
- [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
|
- [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
|
||||||
@ -314,6 +315,13 @@ information on what to include when reporting a bug.
|
|||||||
- [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN`
|
- [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN`
|
||||||
- [Wayland] Bugfix: Text input did not repeat along with key repeat
|
- [Wayland] Bugfix: Text input did not repeat along with key repeat
|
||||||
- [Wayland] Bugfix: `glfwPostEmptyEvent` sometimes had no effect (#1520,#1521)
|
- [Wayland] Bugfix: `glfwPostEmptyEvent` sometimes had no effect (#1520,#1521)
|
||||||
|
- [Wayland] Bugfix: `glfwSetClipboardString` would fail if set to result of
|
||||||
|
`glfwGetClipboardString`
|
||||||
|
- [Wayland] Bugfix: Data source creation error would cause double free at termination
|
||||||
|
- [Wayland] Bugfix: Partial writes of clipboard string would cause beginning to repeat
|
||||||
|
- [Wayland] Bugfix: Some errors would cause clipboard string transfer to hang
|
||||||
|
- [Wayland] Bugfix: Drag and drop data was misinterpreted as clipboard string
|
||||||
|
- [Wayland] Bugfix: MIME type matching was not performed for clipboard string
|
||||||
- [POSIX] Removed use of deprecated function `gettimeofday`
|
- [POSIX] Removed use of deprecated function `gettimeofday`
|
||||||
- [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled
|
- [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled
|
||||||
- [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072)
|
- [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072)
|
||||||
|
53
src/init.c
53
src/init.c
@ -172,6 +172,59 @@ size_t _glfwEncodeUTF8(char* s, uint32_t codepoint)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Splits and translates a text/uri-list into separate file paths
|
||||||
|
// NOTE: This function destroys the provided string
|
||||||
|
//
|
||||||
|
char** _glfwParseUriList(char* text, int* count)
|
||||||
|
{
|
||||||
|
const char* prefix = "file://";
|
||||||
|
char** paths = NULL;
|
||||||
|
char* line;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
while ((line = strtok(text, "\r\n")))
|
||||||
|
{
|
||||||
|
char* path;
|
||||||
|
|
||||||
|
text = NULL;
|
||||||
|
|
||||||
|
if (line[0] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
||||||
|
{
|
||||||
|
line += strlen(prefix);
|
||||||
|
// TODO: Validate hostname
|
||||||
|
while (*line != '/')
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*count)++;
|
||||||
|
|
||||||
|
path = _glfw_calloc(strlen(line) + 1, 1);
|
||||||
|
paths = _glfw_realloc(paths, *count * sizeof(char*));
|
||||||
|
paths[*count - 1] = path;
|
||||||
|
|
||||||
|
while (*line)
|
||||||
|
{
|
||||||
|
if (line[0] == '%' && line[1] && line[2])
|
||||||
|
{
|
||||||
|
const char digits[3] = { line[1], line[2], '\0' };
|
||||||
|
*path = (char) strtol(digits, NULL, 16);
|
||||||
|
line += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*path = *line;
|
||||||
|
|
||||||
|
path++;
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
char* _glfw_strdup(const char* source)
|
char* _glfw_strdup(const char* source)
|
||||||
{
|
{
|
||||||
const size_t length = strlen(source);
|
const size_t length = strlen(source);
|
||||||
|
@ -1428,3 +1428,4 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void)
|
|||||||
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
return _glfwPlatformGetTimerFrequency();
|
return _glfwPlatformGetTimerFrequency();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1033,6 +1033,7 @@ void _glfwTerminateVulkan(void);
|
|||||||
const char* _glfwGetVulkanResultString(VkResult result);
|
const char* _glfwGetVulkanResultString(VkResult result);
|
||||||
|
|
||||||
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);
|
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);
|
||||||
|
char** _glfwParseUriList(char* text, int* count);
|
||||||
|
|
||||||
char* _glfw_strdup(const char* source);
|
char* _glfw_strdup(const char* source);
|
||||||
int _glfw_min(int a, int b);
|
int _glfw_min(int a, int b);
|
||||||
|
768
src/wl_init.c
768
src/wl_init.c
@ -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,726 +55,19 @@
|
|||||||
#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 void wmBaseHandlePing(void* userData,
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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_PLATFORM_ERROR,
|
|
||||||
"Wayland: Standard cursor not found");
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
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* data,
|
|
||||||
struct wl_seat* seat,
|
|
||||||
const char* name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct wl_seat_listener seatListener = {
|
|
||||||
seatHandleCapabilities,
|
|
||||||
seatHandleName,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void dataOfferHandleOffer(void* data,
|
|
||||||
struct wl_data_offer* dataOffer,
|
|
||||||
const char* mimeType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct wl_data_offer_listener dataOfferListener = {
|
|
||||||
dataOfferHandleOffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void dataDeviceHandleDataOffer(void* data,
|
|
||||||
struct wl_data_device* dataDevice,
|
|
||||||
struct wl_data_offer* id)
|
|
||||||
{
|
|
||||||
if (_glfw.wl.dataOffer)
|
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffer);
|
|
||||||
|
|
||||||
_glfw.wl.dataOffer = id;
|
|
||||||
wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dataDeviceHandleEnter(void* data,
|
|
||||||
struct wl_data_device* dataDevice,
|
|
||||||
uint32_t serial,
|
|
||||||
struct wl_surface *surface,
|
|
||||||
wl_fixed_t x,
|
|
||||||
wl_fixed_t y,
|
|
||||||
struct wl_data_offer *id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dataDeviceHandleLeave(void* data,
|
|
||||||
struct wl_data_device* dataDevice)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dataDeviceHandleMotion(void* data,
|
|
||||||
struct wl_data_device* dataDevice,
|
|
||||||
uint32_t time,
|
|
||||||
wl_fixed_t x,
|
|
||||||
wl_fixed_t y)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dataDeviceHandleDrop(void* data,
|
|
||||||
struct wl_data_device* dataDevice)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dataDeviceHandleSelection(void* data,
|
|
||||||
struct wl_data_device* dataDevice,
|
|
||||||
struct wl_data_offer* id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct wl_data_device_listener dataDeviceListener = {
|
|
||||||
dataDeviceHandleDataOffer,
|
|
||||||
dataDeviceHandleEnter,
|
|
||||||
dataDeviceHandleLeave,
|
|
||||||
dataDeviceHandleMotion,
|
|
||||||
dataDeviceHandleDrop,
|
|
||||||
dataDeviceHandleSelection,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void wmBaseHandlePing(void* data,
|
|
||||||
struct xdg_wm_base* wmBase,
|
struct xdg_wm_base* wmBase,
|
||||||
uint32_t serial)
|
uint32_t serial)
|
||||||
{
|
{
|
||||||
xdg_wm_base_pong(wmBase, serial);
|
xdg_wm_base_pong(wmBase, serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct xdg_wm_base_listener wmBaseListener = {
|
static const struct xdg_wm_base_listener wmBaseListener =
|
||||||
|
{
|
||||||
wmBaseHandlePing
|
wmBaseHandlePing
|
||||||
};
|
};
|
||||||
|
|
||||||
static void registryHandleGlobal(void* data,
|
static void registryHandleGlobal(void* userData,
|
||||||
struct wl_registry* registry,
|
struct wl_registry* registry,
|
||||||
uint32_t name,
|
uint32_t name,
|
||||||
const char* interface,
|
const char* interface,
|
||||||
@ -810,7 +102,7 @@ static void registryHandleGlobal(void* data,
|
|||||||
_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)
|
||||||
@ -863,8 +155,8 @@ static void registryHandleGlobal(void* data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registryHandleGlobalRemove(void *data,
|
static void registryHandleGlobalRemove(void* userData,
|
||||||
struct wl_registry *registry,
|
struct wl_registry* registry,
|
||||||
uint32_t name)
|
uint32_t name)
|
||||||
{
|
{
|
||||||
_GLFWmonitor* monitor;
|
_GLFWmonitor* monitor;
|
||||||
@ -881,7 +173,8 @@ static void registryHandleGlobalRemove(void *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct wl_registry_listener registryListener = {
|
static const struct wl_registry_listener registryListener =
|
||||||
|
{
|
||||||
registryHandleGlobal,
|
registryHandleGlobal,
|
||||||
registryHandleGlobalRemove
|
registryHandleGlobalRemove
|
||||||
};
|
};
|
||||||
@ -1117,7 +410,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
|
|||||||
if (platformID == GLFW_PLATFORM_WAYLAND)
|
if (platformID == GLFW_PLATFORM_WAYLAND)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Failed to open libwayland-client");
|
"Wayland: Failed to load libwayland-client");
|
||||||
}
|
}
|
||||||
|
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
@ -1156,9 +449,9 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
|
|||||||
|
|
||||||
int _glfwInitWayland(void)
|
int _glfwInitWayland(void)
|
||||||
{
|
{
|
||||||
const char *cursorTheme;
|
const char* cursorTheme;
|
||||||
const char *cursorSizeStr;
|
const char* cursorSizeStr;
|
||||||
char *cursorSizeEnd;
|
char* cursorSizeEnd;
|
||||||
long cursorSizeLong;
|
long cursorSizeLong;
|
||||||
int cursorSize;
|
int cursorSize;
|
||||||
|
|
||||||
@ -1222,7 +515,7 @@ int _glfwInitWayland(void)
|
|||||||
if (!_glfw.wl.cursor.handle)
|
if (!_glfw.wl.cursor.handle)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Failed to open libwayland-cursor");
|
"Wayland: Failed to load libwayland-cursor");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1239,7 +532,7 @@ int _glfwInitWayland(void)
|
|||||||
if (!_glfw.wl.egl.handle)
|
if (!_glfw.wl.egl.handle)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Failed to open libwayland-egl");
|
"Wayland: Failed to load libwayland-egl");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1254,7 +547,7 @@ int _glfwInitWayland(void)
|
|||||||
if (!_glfw.wl.xkb.handle)
|
if (!_glfw.wl.xkb.handle)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Failed to open libxkbcommon");
|
"Wayland: Failed to load libxkbcommon");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1346,7 +639,7 @@ int _glfwInitWayland(void)
|
|||||||
if (!_glfw.wl.cursorTheme)
|
if (!_glfw.wl.cursorTheme)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Unable to load default cursor theme");
|
"Wayland: Failed to load default cursor theme");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
// If this happens to be NULL, we just fallback to the scale=1 version.
|
// If this happens to be NULL, we just fallback to the scale=1 version.
|
||||||
@ -1362,16 +655,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);
|
||||||
|
|
||||||
_glfw.wl.clipboardSize = 4096;
|
|
||||||
_glfw.wl.clipboardString = _glfw_calloc(_glfw.wl.clipboardSize, 1);
|
|
||||||
if (!_glfw.wl.clipboardString)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_OUT_OF_MEMORY,
|
|
||||||
"Wayland: Unable to allocate clipboard memory");
|
|
||||||
return GLFW_FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
@ -1410,6 +694,11 @@ void _glfwTerminateWayland(void)
|
|||||||
_glfw.wl.cursor.handle = NULL;
|
_glfw.wl.cursor.handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
||||||
|
wl_data_offer_destroy(_glfw.wl.offers[i].offer);
|
||||||
|
|
||||||
|
_glfw_free(_glfw.wl.offers);
|
||||||
|
|
||||||
if (_glfw.wl.cursorSurface)
|
if (_glfw.wl.cursorSurface)
|
||||||
wl_surface_destroy(_glfw.wl.cursorSurface);
|
wl_surface_destroy(_glfw.wl.cursorSurface);
|
||||||
if (_glfw.wl.subcompositor)
|
if (_glfw.wl.subcompositor)
|
||||||
@ -1424,12 +713,14 @@ void _glfwTerminateWayland(void)
|
|||||||
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
|
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
|
||||||
if (_glfw.wl.wmBase)
|
if (_glfw.wl.wmBase)
|
||||||
xdg_wm_base_destroy(_glfw.wl.wmBase);
|
xdg_wm_base_destroy(_glfw.wl.wmBase);
|
||||||
if (_glfw.wl.dataSource)
|
if (_glfw.wl.selectionOffer)
|
||||||
wl_data_source_destroy(_glfw.wl.dataSource);
|
wl_data_offer_destroy(_glfw.wl.selectionOffer);
|
||||||
|
if (_glfw.wl.dragOffer)
|
||||||
|
wl_data_offer_destroy(_glfw.wl.dragOffer);
|
||||||
|
if (_glfw.wl.selectionSource)
|
||||||
|
wl_data_source_destroy(_glfw.wl.selectionSource);
|
||||||
if (_glfw.wl.dataDevice)
|
if (_glfw.wl.dataDevice)
|
||||||
wl_data_device_destroy(_glfw.wl.dataDevice);
|
wl_data_device_destroy(_glfw.wl.dataDevice);
|
||||||
if (_glfw.wl.dataOffer)
|
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffer);
|
|
||||||
if (_glfw.wl.dataDeviceManager)
|
if (_glfw.wl.dataDeviceManager)
|
||||||
wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
|
wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
|
||||||
if (_glfw.wl.pointer)
|
if (_glfw.wl.pointer)
|
||||||
@ -1458,6 +749,5 @@ void _glfwTerminateWayland(void)
|
|||||||
close(_glfw.wl.cursorTimerfd);
|
close(_glfw.wl.cursorTimerfd);
|
||||||
|
|
||||||
_glfw_free(_glfw.wl.clipboardString);
|
_glfw_free(_glfw.wl.clipboardString);
|
||||||
_glfw_free(_glfw.wl.clipboardSendString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#include "wayland-client-protocol.h"
|
#include "wayland-client-protocol.h"
|
||||||
|
|
||||||
|
|
||||||
static void outputHandleGeometry(void* data,
|
static void outputHandleGeometry(void* userData,
|
||||||
struct wl_output* output,
|
struct wl_output* output,
|
||||||
int32_t x,
|
int32_t x,
|
||||||
int32_t y,
|
int32_t y,
|
||||||
@ -48,7 +48,7 @@ static void outputHandleGeometry(void* data,
|
|||||||
const char* model,
|
const char* model,
|
||||||
int32_t transform)
|
int32_t transform)
|
||||||
{
|
{
|
||||||
struct _GLFWmonitor *monitor = data;
|
struct _GLFWmonitor* monitor = userData;
|
||||||
|
|
||||||
monitor->wl.x = x;
|
monitor->wl.x = x;
|
||||||
monitor->wl.y = y;
|
monitor->wl.y = y;
|
||||||
@ -58,14 +58,14 @@ static void outputHandleGeometry(void* data,
|
|||||||
snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model);
|
snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outputHandleMode(void* data,
|
static void outputHandleMode(void* userData,
|
||||||
struct wl_output* output,
|
struct wl_output* output,
|
||||||
uint32_t flags,
|
uint32_t flags,
|
||||||
int32_t width,
|
int32_t width,
|
||||||
int32_t height,
|
int32_t height,
|
||||||
int32_t refresh)
|
int32_t refresh)
|
||||||
{
|
{
|
||||||
struct _GLFWmonitor *monitor = data;
|
struct _GLFWmonitor* monitor = userData;
|
||||||
GLFWvidmode mode;
|
GLFWvidmode mode;
|
||||||
|
|
||||||
mode.width = width;
|
mode.width = width;
|
||||||
@ -84,9 +84,9 @@ static void outputHandleMode(void* data,
|
|||||||
monitor->wl.currentMode = monitor->modeCount - 1;
|
monitor->wl.currentMode = monitor->modeCount - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outputHandleDone(void* data, struct wl_output* output)
|
static void outputHandleDone(void* userData, struct wl_output* output)
|
||||||
{
|
{
|
||||||
struct _GLFWmonitor *monitor = data;
|
struct _GLFWmonitor* monitor = userData;
|
||||||
|
|
||||||
if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
|
if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
|
||||||
{
|
{
|
||||||
@ -99,16 +99,17 @@ static void outputHandleDone(void* data, struct wl_output* output)
|
|||||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outputHandleScale(void* data,
|
static void outputHandleScale(void* userData,
|
||||||
struct wl_output* output,
|
struct wl_output* output,
|
||||||
int32_t factor)
|
int32_t factor)
|
||||||
{
|
{
|
||||||
struct _GLFWmonitor *monitor = data;
|
struct _GLFWmonitor* monitor = userData;
|
||||||
|
|
||||||
monitor->wl.scale = factor;
|
monitor->wl.scale = factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_output_listener outputListener = {
|
static const struct wl_output_listener outputListener =
|
||||||
|
{
|
||||||
outputHandleGeometry,
|
outputHandleGeometry,
|
||||||
outputHandleMode,
|
outputHandleMode,
|
||||||
outputHandleDone,
|
outputHandleDone,
|
||||||
@ -122,8 +123,8 @@ static const struct wl_output_listener outputListener = {
|
|||||||
|
|
||||||
void _glfwAddOutputWayland(uint32_t name, uint32_t version)
|
void _glfwAddOutputWayland(uint32_t name, uint32_t version)
|
||||||
{
|
{
|
||||||
_GLFWmonitor *monitor;
|
_GLFWmonitor* monitor;
|
||||||
struct wl_output *output;
|
struct wl_output* output;
|
||||||
|
|
||||||
if (version < 2)
|
if (version < 2)
|
||||||
{
|
{
|
||||||
|
@ -45,10 +45,10 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
|||||||
#include "xkb_unicode.h"
|
#include "xkb_unicode.h"
|
||||||
#include "posix_poll.h"
|
#include "posix_poll.h"
|
||||||
|
|
||||||
typedef int (* PFN_wl_display_flush)(struct wl_display *display);
|
typedef int (* PFN_wl_display_flush)(struct wl_display* display);
|
||||||
typedef void (* PFN_wl_display_cancel_read)(struct wl_display *display);
|
typedef void (* PFN_wl_display_cancel_read)(struct wl_display* display);
|
||||||
typedef int (* PFN_wl_display_dispatch_pending)(struct wl_display *display);
|
typedef int (* PFN_wl_display_dispatch_pending)(struct wl_display* display);
|
||||||
typedef int (* PFN_wl_display_read_events)(struct wl_display *display);
|
typedef int (* PFN_wl_display_read_events)(struct wl_display* display);
|
||||||
typedef struct wl_display* (* PFN_wl_display_connect)(const char*);
|
typedef struct wl_display* (* PFN_wl_display_connect)(const char*);
|
||||||
typedef void (* PFN_wl_display_disconnect)(struct wl_display*);
|
typedef void (* PFN_wl_display_disconnect)(struct wl_display*);
|
||||||
typedef int (* PFN_wl_display_roundtrip)(struct wl_display*);
|
typedef int (* PFN_wl_display_roundtrip)(struct wl_display*);
|
||||||
@ -219,6 +219,13 @@ typedef struct _GLFWdecorationWayland
|
|||||||
struct wp_viewport* viewport;
|
struct wp_viewport* viewport;
|
||||||
} _GLFWdecorationWayland;
|
} _GLFWdecorationWayland;
|
||||||
|
|
||||||
|
typedef struct _GLFWofferWayland
|
||||||
|
{
|
||||||
|
struct wl_data_offer* offer;
|
||||||
|
GLFWbool text_plain_utf8;
|
||||||
|
GLFWbool text_uri_list;
|
||||||
|
} _GLFWofferWayland;
|
||||||
|
|
||||||
// Wayland-specific per-window data
|
// Wayland-specific per-window data
|
||||||
//
|
//
|
||||||
typedef struct _GLFWwindowWayland
|
typedef struct _GLFWwindowWayland
|
||||||
@ -281,8 +288,6 @@ typedef struct _GLFWlibraryWayland
|
|||||||
struct wl_keyboard* keyboard;
|
struct wl_keyboard* keyboard;
|
||||||
struct wl_data_device_manager* dataDeviceManager;
|
struct wl_data_device_manager* dataDeviceManager;
|
||||||
struct wl_data_device* dataDevice;
|
struct wl_data_device* dataDevice;
|
||||||
struct wl_data_offer* dataOffer;
|
|
||||||
struct wl_data_source* dataSource;
|
|
||||||
struct xdg_wm_base* wmBase;
|
struct xdg_wm_base* wmBase;
|
||||||
struct zxdg_decoration_manager_v1* decorationManager;
|
struct zxdg_decoration_manager_v1* decorationManager;
|
||||||
struct wp_viewporter* viewporter;
|
struct wp_viewporter* viewporter;
|
||||||
@ -290,6 +295,16 @@ typedef struct _GLFWlibraryWayland
|
|||||||
struct zwp_pointer_constraints_v1* pointerConstraints;
|
struct zwp_pointer_constraints_v1* pointerConstraints;
|
||||||
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
|
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
|
||||||
|
|
||||||
|
_GLFWofferWayland* offers;
|
||||||
|
unsigned int offerCount;
|
||||||
|
|
||||||
|
struct wl_data_offer* selectionOffer;
|
||||||
|
struct wl_data_source* selectionSource;
|
||||||
|
|
||||||
|
struct wl_data_offer* dragOffer;
|
||||||
|
_GLFWwindow* dragFocus;
|
||||||
|
uint32_t dragSerial;
|
||||||
|
|
||||||
int compositorVersion;
|
int compositorVersion;
|
||||||
int seatVersion;
|
int seatVersion;
|
||||||
|
|
||||||
@ -306,9 +321,6 @@ typedef struct _GLFWlibraryWayland
|
|||||||
int keyboardLastKey;
|
int keyboardLastKey;
|
||||||
int keyboardLastScancode;
|
int keyboardLastScancode;
|
||||||
char* clipboardString;
|
char* clipboardString;
|
||||||
size_t clipboardSize;
|
|
||||||
char* clipboardSendString;
|
|
||||||
size_t clipboardSendSize;
|
|
||||||
int timerfd;
|
int timerfd;
|
||||||
short int keycodes[256];
|
short int keycodes[256];
|
||||||
short int scancodes[GLFW_KEY_LAST + 1];
|
short int scancodes[GLFW_KEY_LAST + 1];
|
||||||
@ -458,7 +470,7 @@ float _glfwGetWindowOpacityWayland(_GLFWwindow* window);
|
|||||||
void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity);
|
void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity);
|
||||||
void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled);
|
void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled);
|
||||||
|
|
||||||
void _glfwSetRawMouseMotionWayland(_GLFWwindow *window, GLFWbool enabled);
|
void _glfwSetRawMouseMotionWayland(_GLFWwindow* window, GLFWbool enabled);
|
||||||
GLFWbool _glfwRawMouseMotionSupportedWayland(void);
|
GLFWbool _glfwRawMouseMotionSupportedWayland(void);
|
||||||
|
|
||||||
void _glfwPollEventsWayland(void);
|
void _glfwPollEventsWayland(void);
|
||||||
@ -499,3 +511,7 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version);
|
|||||||
GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode);
|
GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode);
|
||||||
|
|
||||||
_GLFWusercontext* _glfwCreateUserContextWayland(_GLFWwindow* window);
|
_GLFWusercontext* _glfwCreateUserContextWayland(_GLFWwindow* window);
|
||||||
|
|
||||||
|
void _glfwAddSeatListenerWayland(struct wl_seat* seat);
|
||||||
|
void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);
|
||||||
|
|
||||||
|
1145
src/wl_window.c
1145
src/wl_window.c
File diff suppressed because it is too large
Load Diff
@ -113,7 +113,7 @@ static void writeEmptyEvent(void)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
const char byte = 0;
|
const char byte = 0;
|
||||||
const int result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);
|
const ssize_t result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);
|
||||||
if (result == 1 || (result == -1 && errno != EINTR))
|
if (result == 1 || (result == -1 && errno != EINTR))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ static void drainEmptyEvents(void)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
char dummy[64];
|
char dummy[64];
|
||||||
const int result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));
|
const ssize_t result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));
|
||||||
if (result == -1 && errno != EINTR)
|
if (result == -1 && errno != EINTR)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -407,57 +407,6 @@ static void updateWindowMode(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splits and translates a text/uri-list into separate file paths
|
|
||||||
// NOTE: This function destroys the provided string
|
|
||||||
//
|
|
||||||
static char** parseUriList(char* text, int* count)
|
|
||||||
{
|
|
||||||
const char* prefix = "file://";
|
|
||||||
char** paths = NULL;
|
|
||||||
char* line;
|
|
||||||
|
|
||||||
*count = 0;
|
|
||||||
|
|
||||||
while ((line = strtok(text, "\r\n")))
|
|
||||||
{
|
|
||||||
text = NULL;
|
|
||||||
|
|
||||||
if (line[0] == '#')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
|
||||||
{
|
|
||||||
line += strlen(prefix);
|
|
||||||
// TODO: Validate hostname
|
|
||||||
while (*line != '/')
|
|
||||||
line++;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*count)++;
|
|
||||||
|
|
||||||
char* path = _glfw_calloc(strlen(line) + 1, 1);
|
|
||||||
paths = _glfw_realloc(paths, *count * sizeof(char*));
|
|
||||||
paths[*count - 1] = path;
|
|
||||||
|
|
||||||
while (*line)
|
|
||||||
{
|
|
||||||
if (line[0] == '%' && line[1] && line[2])
|
|
||||||
{
|
|
||||||
const char digits[3] = { line[1], line[2], '\0' };
|
|
||||||
*path = strtol(digits, NULL, 16);
|
|
||||||
line += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*path = *line;
|
|
||||||
|
|
||||||
path++;
|
|
||||||
line++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode a Unicode code point from a UTF-8 stream
|
// Decode a Unicode code point from a UTF-8 stream
|
||||||
// Based on cutef8 by Jeff Bezanson (Public Domain)
|
// Based on cutef8 by Jeff Bezanson (Public Domain)
|
||||||
//
|
//
|
||||||
@ -1715,7 +1664,7 @@ static void processEvent(XEvent *event)
|
|||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
char** paths = parseUriList(data, &count);
|
char** paths = _glfwParseUriList(data, &count);
|
||||||
|
|
||||||
_glfwInputDrop(window, count, (const char**) paths);
|
_glfwInputDrop(window, count, (const char**) paths);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user