diff options
Diffstat (limited to 'src/platform/x11/window.c')
| -rw-r--r-- | src/platform/x11/window.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/platform/x11/window.c b/src/platform/x11/window.c index be1ff32..724987f 100644 --- a/src/platform/x11/window.c +++ b/src/platform/x11/window.c @@ -6,6 +6,7 @@ #include "keymap.h" #include "common/utf8.h" #include "common/timing.h" +#include "platform/freedesktop/dbus.h" #include <X11/Xatom.h> #include <X11/XKBlib.h> @@ -27,6 +28,7 @@ #include <limits.h> #include <math.h> #include <poll.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> @@ -1804,6 +1806,83 @@ static bool place(struct yasl_surface *base, struct yasl_vector2i at) return true; } +static uint32_t xsettings_card(const unsigned char *p, int size, bool msb) +{ + uint32_t v = 0; + for (int i = 0; i < size; i++) + v |= (uint32_t)p[i] << (8 * (msb ? size - 1 - i : i)); + return v; +} + +/* Find an integer in an _XSETTINGS_SETTINGS blob: a byte-order byte, three + * pad bytes, a serial, a count, then entries of type, pad, name length, name + * padded to four bytes, serial, and a typed value. */ +static bool xsettings_int(const unsigned char *p, size_t len, const char *name, int32_t *out) +{ + if (len < 12) return false; + bool msb = p[0] == MSBFirst; + uint32_t n = xsettings_card(p + 8, 4, msb); + size_t want = strlen(name); + size_t off = 12; + for (uint32_t i = 0; i < n; i++) { + if (len - off < 4) return false; + unsigned type = p[off]; + size_t name_len = xsettings_card(p + off + 2, 2, msb); + size_t padded = (name_len + 3) & ~(size_t)3; + const unsigned char *entry_name = p + off + 4; + off += 4; + if (len - off < padded + 4) return false; + off += padded + 4; + size_t value_len; + if (type == 0) { + value_len = 4; + } else if (type == 1) { + if (len - off < 4) return false; + size_t str_len = xsettings_card(p + off, 4, msb); + if (str_len > len) return false; + value_len = 4 + ((str_len + 3) & ~(size_t)3); + } else if (type == 2) { + value_len = 8; + } else { + return false; + } + if (len - off < value_len) return false; + if (type == 0 && name_len == want && memcmp(entry_name, name, want) == 0) { + *out = (int32_t)xsettings_card(p + off, 4, msb); + return true; + } + off += value_len; + } + return false; +} + +static int double_click_ms(const struct yasl_display *base) +{ + const struct x11_display *d = (const struct x11_display *)base; + if (d->native) { + char name[32]; + snprintf(name, sizeof(name), "_XSETTINGS_S%d", d->screen); + Atom selection = XInternAtom(d->native, name, True); + Atom property = XInternAtom(d->native, "_XSETTINGS_SETTINGS", True); + Window owner = selection ? XGetSelectionOwner(d->native, selection) : None; + Atom actual; + int format; + unsigned long count, left; + unsigned char *data = NULL; + int32_t ms; + if (owner && property && + XGetWindowProperty(d->native, owner, property, 0, 0x10000, False, property, + &actual, &format, &count, &left, &data) == Success && + data && actual == property && format == 8 && + xsettings_int(data, count, "Net/DoubleClickTime", &ms)) { + XFree(data); + return ms; + } + if (data) XFree(data); + } + return portal_double_click_ms(); +} + static bool bell(struct yasl_surface *base) { struct x11_surface *s = (struct x11_surface *)base; @@ -2059,6 +2138,7 @@ const struct yasl_backend_ops yasl_x11_backend = { .surface_drag_carry = drag_carry, .surface_place_under_pointer = place, .surface_bell = bell, + .display_double_click_ms = double_click_ms, .surface_start_interactive_move = interactive_move, .surface_start_interactive_resize = interactive_resize, .surface_show_window_menu = show_window_menu, |
