From 47bd4dbe2e4a576a1f02507e9a87502d99df4f52 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Mon, 12 Oct 2026 22:49:52 +0300 Subject: feat(x11): implement interactive resize, window menu, IME caret/preedit, and advertise YASL_CAP_CSD --- src/x11/window.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) (limited to 'src/x11') diff --git a/src/x11/window.c b/src/x11/window.c index f7d036f..c00a449 100644 --- a/src/x11/window.c +++ b/src/x11/window.c @@ -62,6 +62,10 @@ struct x11_surface { struct x11_surface *parent; bool is_popup; struct yasl_vector2i content_offset; + char *ime_preedit; + int ime_cursor_begin; + int ime_cursor_end; + struct yasl_rect2i ime_caret; }; struct paste_request { @@ -593,6 +597,8 @@ static void surface_destroy(struct yasl_surface *base) if (*p == s) { *p = s->next; break; } } cancel_pastes(d, s); + free(s->ime_preedit); + s->ime_preedit = NULL; if (s->ic) XDestroyIC(s->ic); if (s->shm_active) { XShmDetach(d->native, &s->shm_info); @@ -1682,7 +1688,7 @@ static void display_close(struct yasl_display *base) static uint32_t caps(const struct yasl_display *d) { return YASL_CAP_POPUPS | YASL_CAP_DRAG | YASL_CAP_DRAG_CARRY | YASL_CAP_PLACE_WINDOW | - YASL_CAP_PRIMARY_SELECTION | + YASL_CAP_PRIMARY_SELECTION | YASL_CAP_CSD | (((const struct x11_display *)d)->xi2 ? YASL_CAP_TABLET : 0); } @@ -1948,6 +1954,75 @@ static bool interactive_move(struct yasl_surface *base) return true; } +static bool interactive_resize(struct yasl_surface *base, enum yasl_resize_edge edge) +{ + struct x11_surface *s = (struct x11_surface *)base; + struct x11_display *d = display_of(base); + Window root, child; + int rx, ry, x, y; + unsigned mask; + if (s->destroyed || !d->native || !XQueryPointer(d->native, s->window, + &root, &child, &rx, &ry, &x, &y, &mask)) return false; + + int dir; + switch (edge) { + case YASL_EDGE_TOP_LEFT: dir = 0; break; + case YASL_EDGE_TOP: dir = 1; break; + case YASL_EDGE_TOP_RIGHT: dir = 2; break; + case YASL_EDGE_RIGHT: dir = 3; break; + case YASL_EDGE_BOTTOM_RIGHT: dir = 4; break; + case YASL_EDGE_BOTTOM: dir = 5; break; + case YASL_EDGE_BOTTOM_LEFT: dir = 6; break; + case YASL_EDGE_LEFT: dir = 7; break; + default: return false; + } + + XUngrabPointer(d->native, CurrentTime); + net_message(s, XInternAtom(d->native, "_NET_WM_MOVERESIZE", False), rx, ry, dir, 1, 1); + return true; +} + +static bool show_window_menu(struct yasl_surface *base, struct yasl_vector2i pos) +{ + struct x11_surface *s = (struct x11_surface *)base; + struct x11_display *d = display_of(base); + if (s->destroyed || !d->native) return false; + Atom atom = XInternAtom(d->native, "_GTK_SHOW_WINDOW_MENU", False); + net_message(s, atom, s->window, pos.x, pos.y, 0, 0); + return true; +} + +static void set_ime_caret(struct yasl_surface *base, struct yasl_rect2i caret) +{ + struct x11_surface *s = (struct x11_surface *)base; + if (!s) return; + s->ime_caret = caret; + if (s->ic) { + XPoint spot = { (short)caret.x, (short)(caret.y + caret.height) }; + XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); + if (preedit_attr) { + XSetICValues(s->ic, XNPreeditAttributes, preedit_attr, NULL); + XFree(preedit_attr); + } + } +} + +static const char *ime_preedit(const struct yasl_surface *base) +{ + const struct x11_surface *s = (const struct x11_surface *)base; + return s ? s->ime_preedit : NULL; +} + +static bool ime_preedit_cursor(const struct yasl_surface *base, int *begin, int *end) +{ + const struct x11_surface *s = (const struct x11_surface *)base; + if (!s || !s->ime_preedit || s->ime_cursor_begin < 0) + return false; + if (begin) *begin = s->ime_cursor_begin; + if (end) *end = s->ime_cursor_end; + return true; +} + const struct yasl_backend_ops yasl_x11_backend = { .type = YASL_BACKEND_X11, .display_open = display_open, @@ -1978,6 +2053,11 @@ const struct yasl_backend_ops yasl_x11_backend = { .surface_drag_carry = drag_carry, .surface_place_under_pointer = place, .surface_start_interactive_move = interactive_move, + .surface_start_interactive_resize = interactive_resize, + .surface_show_window_menu = show_window_menu, + .surface_set_ime_caret = set_ime_caret, + .surface_ime_preedit = ime_preedit, + .surface_ime_preedit_cursor = ime_preedit_cursor, .display_get_native_handle = native_display, .surface_get_native_handle = native_surface, }; -- cgit v1.2.3