diff options
Diffstat (limited to 'src/platform/wayland')
| -rw-r--r-- | src/platform/wayland/api.h | 50 | ||||
| -rw-r--r-- | src/platform/wayland/backend.c | 236 | ||||
| -rw-r--r-- | src/platform/wayland/buffer.c | 93 | ||||
| -rw-r--r-- | src/platform/wayland/clipboard.c | 60 | ||||
| -rw-r--r-- | src/platform/wayland/clipboard.h | 16 | ||||
| -rw-r--r-- | src/platform/wayland/drag.c | 54 | ||||
| -rw-r--r-- | src/platform/wayland/ime.c | 147 | ||||
| -rw-r--r-- | src/platform/wayland/internal.h | 70 | ||||
| -rw-r--r-- | src/platform/wayland/keyboard.c | 60 | ||||
| -rw-r--r-- | src/platform/wayland/keymap.c | 2 | ||||
| -rw-r--r-- | src/platform/wayland/keymap.h | 6 | ||||
| -rw-r--r-- | src/platform/wayland/native.c | 14 | ||||
| -rw-r--r-- | src/platform/wayland/pointer.c | 398 | ||||
| -rw-r--r-- | src/platform/wayland/popup.c | 79 | ||||
| -rw-r--r-- | src/platform/wayland/shell.c | 50 | ||||
| -rw-r--r-- | src/platform/wayland/surface.c | 119 |
16 files changed, 1007 insertions, 447 deletions
diff --git a/src/platform/wayland/api.h b/src/platform/wayland/api.h index 0f935b2..9670af1 100644 --- a/src/platform/wayland/api.h +++ b/src/platform/wayland/api.h @@ -1,48 +1,48 @@ -#ifndef YASL_WAYLAND_API_H -#define YASL_WAYLAND_API_H +#ifndef YASL_PRIVATE_WAYLAND_API_H +#define YASL_PRIVATE_WAYLAND_API_H -#include "yasl/yasl.h" +#include "common/types.h" struct wayland_display; struct wayland_surface; -struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec); +struct wayland_display *wayland_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec); void wayland_display_close(struct wayland_display *d); uint32_t wayland_display_caps(const struct wayland_display *d); int wayland_display_dispatch_timeout(struct wayland_display *d, int timeout_ms); void wayland_display_flush(struct wayland_display *d); int wayland_display_modifiers(const struct wayland_display *d); -void wayland_display_copy(struct wayland_display *d, enum yasl_selection sel, const char *text); -void wayland_display_paste(struct wayland_display *d, enum yasl_selection sel, struct wayland_surface *target); -bool wayland_display_copy_text(struct wayland_display *d, enum yasl_selection sel, const char *text); -bool wayland_display_request_paste(struct wayland_display *d, enum yasl_selection sel, +void wayland_display_copy(struct wayland_display *d, enum yasl_private_selection sel, const char *text); +void wayland_display_paste(struct wayland_display *d, enum yasl_private_selection sel, struct wayland_surface *target); +bool wayland_display_copy_text(struct wayland_display *d, enum yasl_private_selection sel, const char *text); +bool wayland_display_request_paste(struct wayland_display *d, enum yasl_private_selection sel, struct wayland_surface *target, uint64_t request_id); -bool wayland_display_drag_start(struct wayland_display *d, struct wayland_surface *origin, const struct yasl_drag_image *image, const struct yasl_drag_listener *l, void *ud); +bool wayland_display_drag_start(struct wayland_display *d, struct wayland_surface *origin, const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *l, void *ud); void wayland_display_drag_cancel(struct wayland_display *d); struct wayland_surface *wayland_surface_create_toplevel(struct wayland_display *d, - const struct yasl_window_spec *spec, void *graphics_device); -struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *parent, const struct yasl_popup_spec *spec); -bool wayland_surface_popup_reposition(struct wayland_surface *popup, const struct yasl_popup_spec *spec); + const struct yasl_private_window_spec *spec, void *graphics_device); +struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *parent, const struct yasl_private_popup_spec *spec); +bool wayland_surface_popup_reposition(struct wayland_surface *popup, const struct yasl_private_popup_spec *spec); void wayland_surface_destroy(struct wayland_surface *s); -void wayland_surface_set_callbacks(struct wayland_surface *s, const struct yasl_window_cbs *cbs, void *ud); +void wayland_surface_set_callbacks(struct wayland_surface *s, const struct yasl_private_window_cbs *cbs, void *ud); void wayland_surface_set_title(struct wayland_surface *s, const char *title); void wayland_surface_schedule_redraw(struct wayland_surface *s); -bool wayland_surface_present(struct wayland_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage); -bool wayland_surface_poll_event(struct wayland_surface *s, struct yasl_event *ev); -struct yasl_geometry wayland_surface_geometry(const struct wayland_surface *s); -struct yasl_timing wayland_surface_timing(const struct wayland_surface *s); -void wayland_surface_set_cursor(struct wayland_surface *s, enum yasl_cursor cursor); -bool wayland_surface_set_pointer_mode(struct wayland_surface *s, enum yasl_pointer_mode mode); +bool wayland_surface_present(struct wayland_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage); +bool wayland_surface_poll_event(struct wayland_surface *s, struct yasl_private_event *ev); +struct yasl_private_geometry wayland_surface_geometry(const struct wayland_surface *s); +struct yasl_private_timing wayland_surface_timing(const struct wayland_surface *s); +void wayland_surface_set_cursor(struct wayland_surface *s, enum yasl_private_cursor cursor); +bool wayland_surface_set_pointer_mode(struct wayland_surface *s, enum yasl_private_pointer_mode mode); void wayland_surface_set_background_color(struct wayland_surface *s, uint32_t bg); bool wayland_surface_ime_preedit_cursor(const struct wayland_surface *s, int *begin, int *end); -void wayland_surface_set_ime_caret(struct wayland_surface *s, struct yasl_rect2i caret); +void wayland_surface_set_ime_caret(struct wayland_surface *s, struct yasl_private_rect2i caret); bool wayland_surface_start_interactive_move(struct wayland_surface *s); -bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_resize_edge edge); -bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_vector2i pos); -bool wayland_surface_drag_carry(struct wayland_surface *s, struct yasl_vector2i offset); -bool wayland_surface_place_under_pointer(struct wayland_surface *s, struct yasl_vector2i at); +bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_private_resize_edge edge); +bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_private_vector2i pos); +bool wayland_surface_drag_carry(struct wayland_surface *s, struct yasl_private_vector2i offset); +bool wayland_surface_place_under_pointer(struct wayland_surface *s, struct yasl_private_vector2i at); bool wayland_surface_bell(struct wayland_surface *s); bool wayland_surface_read_pixels(struct wayland_surface *s, uint32_t *out, size_t cap, - struct yasl_vector2i *size); + struct yasl_private_vector2i *size); #endif diff --git a/src/platform/wayland/backend.c b/src/platform/wayland/backend.c index 7026a8c..02aae59 100644 --- a/src/platform/wayland/backend.c +++ b/src/platform/wayland/backend.c @@ -2,50 +2,50 @@ #include "platform/freedesktop/dbus.h" #include <errno.h> -static struct yasl_display *impl_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec) +static struct yasl_private_display *impl_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec) { struct wayland_display *result = wayland_display_open(loop, spec); return result ? &result->base : NULL; } -static void impl_display_close(struct yasl_display *d) +static void impl_display_close(struct yasl_private_display *d) { wayland_display_close((struct wayland_display *)d); } -static uint32_t impl_display_caps(const struct yasl_display *d) +static uint32_t impl_display_caps(const struct yasl_private_display *d) { return wayland_display_caps((const struct wayland_display *)d); } -static int impl_display_dispatch_timeout(struct yasl_display *d, int timeout_ms) +static int impl_display_dispatch_timeout(struct yasl_private_display *d, int timeout_ms) { return wayland_display_dispatch_timeout((struct wayland_display *)d, timeout_ms); } -static void impl_display_flush(struct yasl_display *d) +static void impl_display_flush(struct yasl_private_display *d) { wayland_display_flush((struct wayland_display *)d); } -static int impl_display_modifiers(const struct yasl_display *d) +static int impl_display_modifiers(const struct yasl_private_display *d) { return wayland_display_modifiers((const struct wayland_display *)d); } -static int impl_display_double_click_ms(const struct yasl_display *d) +static int impl_display_double_click_ms(const struct yasl_private_display *d) { /* Wayland has no protocol for it; desktops publish it as a setting. */ (void)d; return portal_double_click_ms(); } -static void impl_display_copy(struct yasl_display *d, enum yasl_selection sel, const char *text) +static void impl_display_copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text) { wayland_display_copy((struct wayland_display *)d, sel, text); } -static bool impl_display_copy_text(struct yasl_display *d, enum yasl_selection sel, +static bool impl_display_copy_text(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text) { bool ok = wayland_display_copy_text((struct wayland_display *)d, sel, text); @@ -53,12 +53,12 @@ static bool impl_display_copy_text(struct yasl_display *d, enum yasl_selection s return ok; } -static void impl_display_paste(struct yasl_display *d, enum yasl_selection sel, struct yasl_surface *target) +static void impl_display_paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target) { wayland_display_paste((struct wayland_display *)d, sel, (struct wayland_surface *)target); } -static bool impl_display_request_paste(struct yasl_display *d, enum yasl_selection sel, +static bool impl_display_request_paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target, uint64_t request_id) { bool ok = wayland_display_request_paste((struct wayland_display *)d, sel, @@ -67,30 +67,171 @@ static bool impl_display_request_paste(struct yasl_display *d, enum yasl_selecti return ok; } -static bool impl_display_drag_start(struct yasl_display *d, struct yasl_surface *origin, const struct yasl_drag_image *image, const struct yasl_drag_listener *l, void *ud) +static bool impl_display_drag_start(struct yasl_private_display *d, struct yasl_surface *origin, const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *l, void *ud) { return wayland_display_drag_start((struct wayland_display *)d, (struct wayland_surface *)origin, image, l, ud); } -static void impl_display_drag_cancel(struct yasl_display *d) +static void impl_display_drag_cancel(struct yasl_private_display *d) { wayland_display_drag_cancel((struct wayland_display *)d); } -static struct yasl_surface *impl_surface_create_toplevel(struct yasl_display *d, - const struct yasl_window_spec *spec, void *graphics_device) +static struct yasl_surface *impl_surface_create_toplevel(struct yasl_private_display *d, + const struct yasl_private_window_spec *spec, void *graphics_device) { struct wayland_surface *result = wayland_surface_create_toplevel((struct wayland_display *)d, spec, graphics_device); return result ? &result->base : NULL; } -static struct yasl_surface *impl_surface_create_popup(struct yasl_surface *parent, const struct yasl_popup_spec *spec) +static bool impl_surface_update_text_input(struct yasl_surface *s) +{ + return wayland_surface_update_text_input((struct wayland_surface *)s); +} + +#if YASL_HAS_EGL +static bool egl_configure(struct wayland_display *d, const struct yasl_private_gl_options *o, EGLConfig *config) +{ + if (!d->egl_initialized) return false; + EGLint renderable = o->api == YASL_PRIVATE_GL_OPENGL_ES + ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT; +#ifdef EGL_OPENGL_ES_BIT + if (o->api == YASL_PRIVATE_GL_OPENGL_ES && o->major < 2) + renderable = EGL_OPENGL_ES_BIT; +#endif +#ifdef EGL_OPENGL_ES3_BIT_KHR + if (o->api == YASL_PRIVATE_GL_OPENGL_ES && o->major >= 3) + renderable = EGL_OPENGL_ES3_BIT_KHR; +#endif + EGLint attrs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, renderable, + EGL_RED_SIZE, o->red_bits, + EGL_GREEN_SIZE, o->green_bits, + EGL_BLUE_SIZE, o->blue_bits, + EGL_ALPHA_SIZE, o->alpha_bits, + EGL_DEPTH_SIZE, o->depth_bits, + EGL_STENCIL_SIZE, o->stencil_bits, + EGL_SAMPLE_BUFFERS, o->samples > 0 ? 1 : 0, + EGL_SAMPLES, o->samples, + EGL_NONE, + }; + EGLint api = o->api == YASL_PRIVATE_GL_OPENGL_ES ? EGL_OPENGL_ES_API : EGL_OPENGL_API; + if (d->egl_api && d->egl_api != api) return false; + EGLint count = 0; + if (!eglChooseConfig(d->egl_display, attrs, config, 1, &count) || count < 1) + return false; + d->egl_api = api; + return eglBindAPI(api) == EGL_TRUE; +} + +static struct yasl_surface *impl_surface_create_gl(struct yasl_private_display *display, + const struct yasl_private_window_spec *spec, const int *attributes, struct yasl_surface *share) +{ + struct wayland_display *d = (struct wayland_display *)display; + struct yasl_private_gl_options o; + if (!spec || !yasl_private_gl_parse_options(attributes, &o) || !d || !d->egl_initialized) + return NULL; + struct yasl_private_window_spec gl_spec = *spec; + gl_spec.external_gpu = true; + gl_spec.flags &= ~YASL_PRIVATE_SURFACE_CPU; + struct wayland_surface *w = wayland_surface_create_toplevel(d, &gl_spec, NULL); + if (!w) return NULL; + if (!egl_configure(d, &o, &w->egl_config)) goto fail; + EGLContext share_context = share && share->display == display + ? ((struct wayland_surface *)share)->egl_context : EGL_NO_CONTEXT; + if (share && share_context == EGL_NO_CONTEXT) goto fail; + w->egl_window = wl_egl_window_create(w->surface, w->width, w->height); + if (!w->egl_window) goto fail; + EGLint context_attrs[12]; + int n = 0; + if (o.api == YASL_PRIVATE_GL_OPENGL_ES) { + context_attrs[n++] = EGL_CONTEXT_CLIENT_VERSION; + context_attrs[n++] = o.major; + } else { + context_attrs[n++] = EGL_CONTEXT_MAJOR_VERSION_KHR; + context_attrs[n++] = o.major; + context_attrs[n++] = EGL_CONTEXT_MINOR_VERSION_KHR; + context_attrs[n++] = o.minor; + if (o.profile != YASL_PRIVATE_GL_ANY) { + context_attrs[n++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; + context_attrs[n++] = o.profile == YASL_PRIVATE_GL_CORE + ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR + : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; + } + EGLint flags = (o.debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0) | + (o.forward_compat ? EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR : 0); + if (flags) { + context_attrs[n++] = EGL_CONTEXT_FLAGS_KHR; + context_attrs[n++] = flags; + } + } + context_attrs[n] = EGL_NONE; + w->egl_context = eglCreateContext(d->egl_display, w->egl_config, share_context, context_attrs); + if (w->egl_context == EGL_NO_CONTEXT) goto fail; + EGLint surface_attrs[] = { +#ifdef EGL_GL_COLORSPACE_KHR + EGL_GL_COLORSPACE_KHR, o.srgb ? EGL_GL_COLORSPACE_SRGB_KHR : EGL_GL_COLORSPACE_LINEAR_KHR, +#endif + EGL_NONE, + }; + w->egl_surface = eglCreateWindowSurface(d->egl_display, w->egl_config, + (EGLNativeWindowType)w->egl_window, surface_attrs); + if (w->egl_surface == EGL_NO_SURFACE) { w->egl_surface = 0; goto fail; } + w->base.presenter = YASL_PRIVATE_PRESENTER_GL; + return &w->base; +fail: + wayland_surface_destroy(w); + return NULL; +} + +static bool impl_gl_make_current(struct yasl_private_display *display, struct yasl_surface *surface) +{ + struct wayland_display *d = (struct wayland_display *)display; + struct wayland_surface *w = (struct wayland_surface *)surface; + if (!d) return false; + if (!w) + return eglMakeCurrent(d->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_TRUE; + return w->conn == d && w->base.presenter == YASL_PRIVATE_PRESENTER_GL && + eglMakeCurrent(d->egl_display, w->egl_surface, w->egl_surface, w->egl_context) == EGL_TRUE; +} + +static yasl_private_gl_proc impl_gl_get_proc_address(struct yasl_private_display *display, const char *name) +{ + (void)display; + return name ? (yasl_private_gl_proc)eglGetProcAddress(name) : NULL; +} + +static bool impl_gl_swap_interval(struct yasl_private_display *display, struct yasl_surface *surface, int interval) +{ + struct wayland_display *d = (struct wayland_display *)display; + struct wayland_surface *w = (struct wayland_surface *)surface; + return d && w && w->conn == d && w->base.presenter == YASL_PRIVATE_PRESENTER_GL && + impl_gl_make_current(display, surface) && eglSwapInterval(d->egl_display, interval) == EGL_TRUE; +} + +static bool impl_gl_swap_buffers(struct yasl_private_display *display, struct yasl_surface *surface) +{ + struct wayland_display *d = (struct wayland_display *)display; + struct wayland_surface *w = (struct wayland_surface *)surface; + if (!d || !w || w->conn != d || w->closed || !w->configured || + w->base.presenter != YASL_PRIVATE_PRESENTER_GL) + return false; + if (!impl_gl_make_current(display, surface)) return false; + wayland_surface_arm_frame(w); + surface_request_presentation_feedback(w); + if (!eglSwapBuffers(d->egl_display, w->egl_surface)) return false; + return true; +} +#endif + +static struct yasl_surface *impl_surface_create_popup(struct yasl_surface *parent, const struct yasl_private_popup_spec *spec) { struct wayland_surface *result = wayland_surface_create_popup((struct wayland_surface *)parent, spec); return result ? &result->base : NULL; } -static bool impl_surface_popup_reposition(struct yasl_surface *popup, const struct yasl_popup_spec *spec) +static bool impl_surface_popup_reposition(struct yasl_surface *popup, const struct yasl_private_popup_spec *spec) { return wayland_surface_popup_reposition((struct wayland_surface *)popup, spec); } @@ -106,7 +247,7 @@ static struct input_queue *impl_surface_input_queue(struct yasl_surface *s) return w ? &w->input : NULL; } -static bool impl_surface_set_size(struct yasl_surface *s, struct yasl_vector2i size) +static bool impl_surface_set_size(struct yasl_surface *s, struct yasl_private_vector2i size) { struct wayland_surface *w = (struct wayland_surface *)s; if (!w || w->closed || w->destroyed || !w->toplevel || @@ -114,8 +255,19 @@ static bool impl_surface_set_size(struct yasl_surface *s, struct yasl_vector2i s errno = EINVAL; return false; } - errno = ENOTSUP; - return false; + /* Floating windows choose their own size; constrained states keep it for later. */ + w->floating_width = size.x; + w->floating_height = size.y; + if (w->base.state & (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_TILED)) + return true; + w->req_width = w->req_height = 0; + w->size_pending = true; + if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU && w->configured && apply_pending_geometry(w) < 0) { + errno = EIO; + return false; + } + wayland_surface_schedule_redraw(w); + return true; } static bool impl_surface_set_fullscreen(struct yasl_surface *s, bool enabled) @@ -153,14 +305,14 @@ static bool impl_surface_minimize(struct yasl_surface *s) return true; } -static struct yasl_display *impl_surface_display(const struct yasl_surface *s) +static struct yasl_private_display *impl_surface_display(const struct yasl_surface *s) { const struct wayland_surface *w = (const struct wayland_surface *)s; struct wayland_display *result = w ? w->conn : NULL; return result ? &result->base : NULL; } -static void impl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_window_cbs *cbs, void *ud) +static void impl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_private_window_cbs *cbs, void *ud) { wayland_surface_set_callbacks((struct wayland_surface *)s, cbs, ud); } @@ -175,37 +327,37 @@ static void impl_surface_schedule_redraw(struct yasl_surface *s) wayland_surface_schedule_redraw((struct wayland_surface *)s); } -static bool impl_surface_present(struct yasl_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage) +static bool impl_surface_present(struct yasl_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage) { return wayland_surface_present((struct wayland_surface *)s, fb, damage); } -static bool impl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev) +static bool impl_surface_poll_event(struct yasl_surface *s, struct yasl_private_event *ev) { return wayland_surface_poll_event((struct wayland_surface *)s, ev); } -static struct yasl_geometry impl_surface_geometry(const struct yasl_surface *s) +static struct yasl_private_geometry impl_surface_geometry(const struct yasl_surface *s) { return wayland_surface_geometry((const struct wayland_surface *)s); } -static struct yasl_timing impl_surface_timing(const struct yasl_surface *s) +static struct yasl_private_timing impl_surface_timing(const struct yasl_surface *s) { return wayland_surface_timing((const struct wayland_surface *)s); } static uint64_t impl_surface_frame_time_ns(struct yasl_surface *s, uint64_t now) { - return yasl_clock_frame_timestamp_ns(&((struct wayland_surface *)s)->clock, now); + return yasl_private_clock_frame_timestamp_ns(&((struct wayland_surface *)s)->clock, now); } -static void impl_surface_set_cursor(struct yasl_surface *s, enum yasl_cursor cursor) +static void impl_surface_set_cursor(struct yasl_surface *s, enum yasl_private_cursor cursor) { wayland_surface_set_cursor((struct wayland_surface *)s, cursor); } -static bool impl_surface_set_pointer_mode(struct yasl_surface *s, enum yasl_pointer_mode mode) +static bool impl_surface_set_pointer_mode(struct yasl_surface *s, enum yasl_private_pointer_mode mode) { return wayland_surface_set_pointer_mode((struct wayland_surface *)s, mode); } @@ -226,7 +378,7 @@ static bool impl_surface_ime_preedit_cursor(const struct yasl_surface *s, int *b return wayland_surface_ime_preedit_cursor((const struct wayland_surface *)s, begin, end); } -static void impl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_rect2i caret) +static void impl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_private_rect2i caret) { wayland_surface_set_ime_caret((struct wayland_surface *)s, caret); } @@ -236,28 +388,28 @@ static bool impl_surface_start_interactive_move(struct yasl_surface *s) return wayland_surface_start_interactive_move((struct wayland_surface *)s); } -static bool impl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_resize_edge edge) +static bool impl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_private_resize_edge edge) { return wayland_surface_start_interactive_resize((struct wayland_surface *)s, edge); } -static bool impl_surface_show_window_menu(struct yasl_surface *s, struct yasl_vector2i pos) +static bool impl_surface_show_window_menu(struct yasl_surface *s, struct yasl_private_vector2i pos) { return wayland_surface_show_window_menu((struct wayland_surface *)s, pos); } -static bool impl_surface_drag_carry(struct yasl_surface *s, struct yasl_vector2i offset) +static bool impl_surface_drag_carry(struct yasl_surface *s, struct yasl_private_vector2i offset) { return wayland_surface_drag_carry((struct wayland_surface *)s, offset); } -static bool impl_surface_place_under_pointer(struct yasl_surface *s, struct yasl_vector2i at) +static bool impl_surface_place_under_pointer(struct yasl_surface *s, struct yasl_private_vector2i at) { return wayland_surface_place_under_pointer((struct wayland_surface *)s, at); } static bool impl_surface_read_pixels(struct yasl_surface *s, uint32_t *out, size_t cap, - struct yasl_vector2i *size) + struct yasl_private_vector2i *size) { return wayland_surface_read_pixels((struct wayland_surface *)s, out, cap, size); } @@ -267,7 +419,7 @@ static bool impl_surface_bell(struct yasl_surface *s) return wayland_surface_bell((struct wayland_surface *)s); } -static void *impl_display_get_native_handle(struct yasl_display *d) +static void *impl_display_get_native_handle(struct yasl_private_display *d) { struct wayland_display *w = (struct wayland_display *)d; return w ? w->wl : NULL; @@ -279,8 +431,16 @@ static void *impl_surface_get_native_handle(struct yasl_surface *s) return w ? w->surface : NULL; } -const struct yasl_backend_ops yasl_wayland_backend = { - .type = YASL_BACKEND_WAYLAND, +const struct yasl_private_backend_ops yasl_private_wayland_backend = { +#if YASL_HAS_EGL + .surface_create_gl = impl_surface_create_gl, + .gl_make_current = impl_gl_make_current, + .gl_get_proc_address = impl_gl_get_proc_address, + .gl_swap_interval = impl_gl_swap_interval, + .gl_swap_buffers = impl_gl_swap_buffers, +#endif + .surface_update_text_input = impl_surface_update_text_input, + .type = YASL_PRIVATE_BACKEND_WAYLAND, .display_open = impl_display_open, .display_close = impl_display_close, .display_caps = impl_display_caps, diff --git a/src/platform/wayland/buffer.c b/src/platform/wayland/buffer.c index 874cc76..bbc055d 100644 --- a/src/platform/wayland/buffer.c +++ b/src/platform/wayland/buffer.c @@ -24,7 +24,7 @@ static const struct wl_buffer_listener buffer_listener; int device_px(int logical, uint32_t scale_120) { - int64_t px = ((int64_t)logical * scale_120 + YASL_SCALE_UNIT / 2) / YASL_SCALE_UNIT; + int64_t px = ((int64_t)logical * scale_120 + YASL_PRIVATE_SCALE_UNIT / 2) / YASL_PRIVATE_SCALE_UNIT; return px > 0 && px <= INT_MAX ? (int)px : -1; } @@ -58,7 +58,7 @@ int buffer_reserve(struct wayland_surface *w, struct buffer *b, size_t needed) if (b->busy || needed > INT32_MAX) return -1; size_t capacity = b->capacity <= INT32_MAX / 2 ? b->capacity * 2 : INT32_MAX; if (capacity < needed) capacity = needed; - int fd = memfd_create("yasl_surface_buffer", MFD_CLOEXEC | MFD_ALLOW_SEALING); + int fd = memfd_create("yasl_private_surface_buffer", MFD_CLOEXEC | MFD_ALLOW_SEALING); if (fd < 0) return -1; if (!fd_truncate(fd, capacity) || fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL) < 0) { @@ -89,7 +89,7 @@ int buffer_prepare(struct wayland_surface *w, struct buffer *b, int width, int h { if (b->proxy && !b->busy && b->width == width && b->height == height) return 0; long faults_before = minor_faults(); - uint64_t t0 = yasl_loop_now_ns(); + uint64_t t0 = yasl_private_loop_now_ns(); size_t bytes; if (!buffer_size(width, height, &bytes) || buffer_reserve(w, b, bytes) < 0) return -1; @@ -104,7 +104,7 @@ int buffer_prepare(struct wayland_surface *w, struct buffer *b, int width, int h b->busy = false; b->presented = false; wl_buffer_add_listener(proxy, listener, b); - yasl_clock_note_resize(&w->clock, yasl_loop_now_ns() - t0); + yasl_private_clock_note_resize(&w->clock, yasl_private_loop_now_ns() - t0); long faults = minor_faults() - faults_before; if (faults > 0) w->clock.resize_minflt += faults; return 0; @@ -114,10 +114,10 @@ static void publish_surface_scale(struct wayland_surface *w) { if (w->viewport) { wp_viewport_set_destination(w->viewport, w->logical_width, w->logical_height); - } else if (w->scale_120 % YASL_SCALE_UNIT == 0 && + } else if (w->scale_120 % YASL_PRIVATE_SCALE_UNIT == 0 && wl_proxy_get_version((struct wl_proxy *)w->surface) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) { - wl_surface_set_buffer_scale(w->surface, (int32_t)(w->scale_120 / YASL_SCALE_UNIT)); + wl_surface_set_buffer_scale(w->surface, (int32_t)(w->scale_120 / YASL_PRIVATE_SCALE_UNIT)); } } @@ -137,16 +137,16 @@ int apply_pending_geometry(struct wayland_surface *w) return 0; } bool floating = !w->parent && !(w->base.state & - (YASL_STATE_MAXIMIZED | YASL_STATE_FULLSCREEN | YASL_STATE_TILED)); + (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_TILED)); int free_w = floating && w->floating_width > 0 ? w->floating_width : w->logical_width; int free_h = floating && w->floating_height > 0 ? w->floating_height : w->logical_height; int logical_w = !w->parent && w->req_width > 0 ? w->req_width : free_w; int logical_h = !w->parent && w->req_height > 0 ? w->req_height : free_h; if (!w->parent) { - if (logical_w < YASL_MIN_LOGICAL_PX) logical_w = YASL_MIN_LOGICAL_PX; - if (logical_h < YASL_MIN_LOGICAL_PX) logical_h = YASL_MIN_LOGICAL_PX; + if (logical_w < YASL_PRIVATE_MIN_LOGICAL_PX) logical_w = YASL_PRIVATE_MIN_LOGICAL_PX; + if (logical_h < YASL_PRIVATE_MIN_LOGICAL_PX) logical_h = YASL_PRIVATE_MIN_LOGICAL_PX; } - if (!(w->base.state & YASL_STATE_FULLSCREEN)) { + if (!(w->base.state & YASL_PRIVATE_STATE_FULLSCREEN)) { if (w->bound_width > 0 && logical_w > w->bound_width) logical_w = w->bound_width; if (w->bound_height > 0 && logical_h > w->bound_height) @@ -155,7 +155,9 @@ int apply_pending_geometry(struct wayland_surface *w) int width = device_px(logical_w, w->pending_scale_120); int height = device_px(logical_h, w->pending_scale_120); size_t bytes; - if (!buffer_size(width, height, &bytes)) { + if (width <= 0 || height <= 0 || + (w->base.presenter == YASL_PRIVATE_PRESENTER_CPU && + !buffer_size(width, height, &bytes))) { return -1; } bool rescaled = w->scale_120 != w->pending_scale_120; @@ -169,13 +171,17 @@ int apply_pending_geometry(struct wayland_surface *w) return 0; w->scale_120 = w->pending_scale_120; - w->scale_factor = (double)w->scale_120 / YASL_SCALE_UNIT; + w->scale_factor = (double)w->scale_120 / YASL_PRIVATE_SCALE_UNIT; w->width = width; w->height = height; - w->base.size = (struct yasl_vector2i){width, height}; + w->base.size = (struct yasl_private_vector2i){width, height}; w->base.scale_120 = w->scale_120; w->logical_width = logical_w; w->logical_height = logical_h; +#if YASL_HAS_EGL + if (w->egl_window && (resized || rescaled)) + wl_egl_window_resize(w->egl_window, width, height, 0, 0); +#endif surface_update_opaque_region(w); if (resized || rescaled) { for (int i = 0; i < NBUF; i++) @@ -183,7 +189,7 @@ int apply_pending_geometry(struct wayland_surface *w) } publish_surface_scale(w); if (resized || rescaled) { - yasl_surface_notify_configure(&w->base, (struct yasl_geometry){ + yasl_private_surface_notify_configure(&w->base, (struct yasl_private_geometry){ .size = { .x = width, .y = height }, .scale_120 = w->scale_120, }); if (w->closed || w->destroyed) @@ -225,7 +231,7 @@ void surface_follow_outputs(struct wayland_surface *w) w->clock.refresh_ns = refresh; if (need_scale) - surface_request_scale(w, (uint32_t)max_scale * YASL_SCALE_UNIT); + surface_request_scale(w, (uint32_t)max_scale * YASL_PRIVATE_SCALE_UNIT); } static void surface_enter(void *data, struct wl_surface *surface, struct wl_output *output) @@ -250,7 +256,7 @@ static void surface_preferred_scale(void *data, struct wl_surface *surface, int3 struct wayland_surface *w = data; if (w->frac_scale || w->parent || factor <= 0) return; - surface_request_scale(w, (uint32_t)factor * YASL_SCALE_UNIT); + surface_request_scale(w, (uint32_t)factor * YASL_PRIVATE_SCALE_UNIT); } static void surface_preferred_transform(void *data, struct wl_surface *surface, @@ -285,13 +291,15 @@ static void frame_done(void *data, struct wl_callback *cb, uint32_t ms) wl_callback_destroy(cb); w->frame_cb = NULL; - uint64_t now = yasl_loop_now_ns(); + uint64_t now = yasl_private_loop_now_ns(); if (!w->conn->pres_clock_known) { - yasl_clock_presented(&w->clock, yasl_clock_extend_ms(ms, now), w->sample_refresh); - w->clock.source = YASL_TIMING_FRAME_CALLBACK; + yasl_private_clock_presented(&w->clock, yasl_private_clock_extend_ms(ms, now), w->sample_refresh); + w->clock.source = YASL_PRIVATE_TIMING_FRAME_CALLBACK; } - if (w->want_draw) + if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU) + yasl_private_surface_notify_refresh(&w->base); + else if (w->want_draw) wayland_surface_schedule_redraw(w); } @@ -299,14 +307,14 @@ static const struct wl_callback_listener frame_listener = { .done = frame_done, }; -static void arm_frame(struct wayland_surface *w) +void wayland_surface_arm_frame(struct wayland_surface *w) { if (!w->configured || w->closed || w->frame_cb) return; w->frame_cb = wl_surface_frame(w->surface); if (!w->frame_cb) { surface_fail(w); return; } w->sample_refresh = w->clock.last_present_ns && - yasl_loop_now_ns() - w->clock.last_present_ns < + yasl_private_loop_now_ns() - w->clock.last_present_ns < (uint64_t)(w->clock.refresh_ns / 2); if (wl_callback_add_listener(w->frame_cb, &frame_listener, w) < 0) { wl_callback_destroy(w->frame_cb); @@ -365,7 +373,7 @@ static void presented(void *data, struct wp_presentation_feedback *fb, (((uint64_t)tv_sec_hi << 32) | tv_sec_lo) * 1000000000ull + tv_nsec); if (refresh) w->clock.refresh_ns = refresh; w->clock.last_present_ns = ns; - w->clock.source = YASL_TIMING_PRESENTATION; + w->clock.source = YASL_PRIVATE_TIMING_PRESENTATION; } (void)fb; feedback_destroy(feedback); @@ -419,7 +427,7 @@ static void commit_buffer(struct wayland_surface *w, int idx) { wl_surface_attach(w->surface, w->buffers[idx].proxy, 0, 0); - const struct yasl_damage_list *d = &w->damage; + const struct yasl_private_damage_list *d = &w->damage; if (d->n < 0 || !w->buffers[idx].presented) wl_surface_damage_buffer(w->surface, 0, 0, w->width, w->height); else @@ -438,8 +446,8 @@ static void commit_buffer(struct wayland_surface *w, int idx) wp_fifo_v1_set_barrier(w->fifo); } if (w->commit_timer && w->conn->pres_clock_known) { - uint64_t now = yasl_loop_now_ns(); - uint64_t next = yasl_clock_next_present_ns(&w->clock); + uint64_t now = yasl_private_loop_now_ns(); + uint64_t next = yasl_private_clock_next_present_ns(&w->clock); bool soon = next > now && next - now < (uint64_t)(w->clock.refresh_ns * 1.5); next = conn_mono_to_pres(w->conn, next); if (soon) @@ -458,10 +466,11 @@ static void commit_buffer(struct wayland_surface *w, int idx) w->buffers[idx].presented = true; } -bool wayland_surface_present(struct wayland_surface *w, const struct yasl_framebuffer *fb, - const struct yasl_damage_list *damage) +bool wayland_surface_present(struct wayland_surface *w, const struct yasl_private_framebuffer *fb, + const struct yasl_private_damage_list *damage) { - if (!w || w->closed || !w->frame_active || w->frame_presented || !fb || + if (!w || w->base.presenter != YASL_PRIVATE_PRESENTER_CPU || + w->closed || !w->frame_active || w->frame_presented || !fb || !damage || fb->pixels != w->frame.target.pixels || fb->size.x != w->width || fb->size.y != w->height) return false; @@ -470,7 +479,7 @@ bool wayland_surface_present(struct wayland_surface *w, const struct yasl_frameb w->damage.bounds = damage->bounds; if (damage->n > 0) memcpy(w->damage.rects, damage->rects, (size_t)damage->n * sizeof(damage->rects[0])); - arm_frame(w); + wayland_surface_arm_frame(w); if (w->closed) return false; commit_buffer(w, w->cur); @@ -481,17 +490,17 @@ bool wayland_surface_present(struct wayland_surface *w, const struct yasl_frameb } bool wayland_surface_read_pixels(struct wayland_surface *w, uint32_t *out, size_t cap, - struct yasl_vector2i *size) + struct yasl_private_vector2i *size) { if (!w || w->closed || w->frame_active || !w->has_shown) return false; const struct buffer *b = &w->buffers[w->shown]; if (!b->pixels) return false; - return yasl_copy_frame(b->pixels, (struct yasl_vector2i){b->width, b->height}, out, cap, size); + return yasl_private_copy_frame(b->pixels, (struct yasl_private_vector2i){b->width, b->height}, out, cap, size); } void surface_draw_frame(struct wayland_surface *w) { - if (w->closed || !w->configured) + if (w->closed || !w->configured || w->base.presenter != YASL_PRIVATE_PRESENTER_CPU) return; if (apply_pending_geometry(w) < 0) { surface_fail(w); @@ -517,18 +526,18 @@ void surface_draw_frame(struct wayland_surface *w) if (w->parent) memset(w->buffers[idx].pixels, 0, (size_t)w->width * (size_t)w->height * sizeof(uint32_t)); - w->damage = (struct yasl_damage_list){0}; - w->frame = (struct yasl_frame){ + w->damage = (struct yasl_private_damage_list){0}; + w->frame = (struct yasl_private_frame){ .surface = &w->base, .target = { - .generation = yasl_frame_begin(&w->base), + .generation = yasl_private_frame_begin(&w->base), .pixels = w->buffers[idx].pixels, .size = { .x = w->width, .y = w->height }, }, }; w->frame_active = true; w->frame_presented = false; - yasl_surface_draw(&w->base, &w->frame); + yasl_private_surface_draw(&w->base, &w->frame); if (w->closed || w->destroyed) return; w->frame_active = false; @@ -555,21 +564,21 @@ int surface_init_scaling(struct wayland_surface *w) void wayland_surface_set_title(struct wayland_surface *w, const char *title) { if (!w || !w->toplevel || !title) return; - char *copy = yasl_utf8_sanitize_dup(title); + char *copy = yasl_private_utf8_sanitize_dup(title); if (!copy) return; xdg_toplevel_set_title(w->toplevel, copy); free(copy); } -struct yasl_timing wayland_surface_timing(const struct wayland_surface *w) +struct yasl_private_timing wayland_surface_timing(const struct wayland_surface *w) { - struct yasl_timing t = { + struct yasl_private_timing t = { .refresh_ns = w->clock.refresh_ns, .last_present_ns = w->clock.last_present_ns, - .next_present_ns = yasl_clock_next_present_ns(&w->clock), + .next_present_ns = yasl_private_clock_next_present_ns(&w->clock), .frames_skipped = w->frames_skipped, .source = w->clock.source, }; - yasl_clock_resize_stats(&w->clock, &t.resize); + yasl_private_clock_resize_stats(&w->clock, &t.resize); return t; } diff --git a/src/platform/wayland/clipboard.c b/src/platform/wayland/clipboard.c index 8ca9b93..cf39b6c 100644 --- a/src/platform/wayland/clipboard.c +++ b/src/platform/wayland/clipboard.c @@ -25,7 +25,7 @@ struct transfer { struct offer *drop; struct wl_surface *drop_surface; int fd, id; - yasl_timer_id timeout; + yasl_private_timer_id timeout; char *text; size_t len, offset, capacity; uint64_t request_id; @@ -48,7 +48,7 @@ struct clipboard { struct offer *drag_offer; struct primary_offer *primary_selection; struct primary_offer *primary_pending_offers; - struct yasl_loop *loop; + struct yasl_private_loop *loop; struct transfer *transfers; char *text; char *primary_text; @@ -70,7 +70,7 @@ const char *clipboard_drag_mime(void) return mime; } -static void drag_event(struct clipboard *c, enum yasl_drag_event ev, +static void drag_event(struct clipboard *c, enum yasl_private_drag_event ev, wl_fixed_t x, wl_fixed_t y) { if (c->drag) @@ -78,7 +78,7 @@ static void drag_event(struct clipboard *c, enum yasl_drag_event ev, c->drag_ud); } -static void drop_event(struct clipboard *c, enum yasl_drop_event ev) +static void drop_event(struct clipboard *c, enum yasl_private_drop_event ev) { if (c->drop && c->drag_surface) c->drop(ev, c->drag_surface, wl_fixed_to_double(c->drag_x), @@ -89,7 +89,7 @@ static void free_offer(struct offer *o); static void transfer_end(struct transfer *t, bool complete); -static uint64_t transfer_timeout(void *ud, yasl_timer_id id, uint64_t interval) +static uint64_t transfer_timeout(void *ud, yasl_private_timer_id id, uint64_t interval) { (void)interval; struct transfer *t = ud; @@ -106,9 +106,9 @@ static void transfer_end(struct transfer *t, bool complete) struct transfer **p = &owner->transfers; while (*p && *p != t) p = &(*p)->next; if (*p) *p = t->next; - yasl_loop_del_fd(owner->loop, t->id); + yasl_private_loop_del_fd(owner->loop, t->id); if (t->timeout) - yasl_loop_del_timer(owner->loop, t->timeout); + yasl_private_loop_del_timer(owner->loop, t->timeout); close(t->fd); if (t->drop) { if (complete && wl_data_offer_get_version(t->drop->proxy) >= @@ -124,7 +124,7 @@ static void transfer_end(struct transfer *t, bool complete) struct wl_surface *surface = t->drop_surface; uint64_t request_id = t->request_id; bool uri_list = t->uri_list; - enum yasl_transfer_status status = complete ? YASL_TRANSFER_OK : YASL_TRANSFER_FAILED; + enum yasl_private_transfer_status status = complete ? YASL_PRIVATE_TRANSFER_OK : YASL_PRIVATE_TRANSFER_FAILED; const char *text = complete ? (t->text ? t->text : "") : NULL; size_t len = complete ? t->len : 0; if (notify) @@ -156,7 +156,7 @@ static int transfer_io(int fd, short events, void *ud) if (n > 0) { t->len += (size_t)n; } else if (n == 0) { - bool valid = yasl_utf8_validate(t->text, t->len); + bool valid = yasl_private_utf8_validate(t->text, t->len); transfer_end(t, valid); } else if (errno != EAGAIN && errno != EINTR) transfer_end(t, false); } @@ -176,12 +176,12 @@ static struct transfer *start_transfer_text(struct clipboard *c, int fd, bool se if (!t->text) { close(fd); free(t); return NULL; } t->len = strlen(t->text); } - t->id = yasl_loop_add_fd(c->loop, fd, sending ? POLLOUT : POLLIN, transfer_io, t); + t->id = yasl_private_loop_add_fd(c->loop, fd, sending ? POLLOUT : POLLIN, transfer_io, t); if (t->id < 0) { close(fd); free(t->text); free(t); return NULL; } - t->timeout = yasl_loop_add_timer(c->loop, CLIPBOARD_TRANSFER_TIMEOUT_NS, + t->timeout = yasl_private_loop_add_timer(c->loop, CLIPBOARD_TRANSFER_TIMEOUT_NS, transfer_timeout, t); if (!t->timeout) { - yasl_loop_del_fd(c->loop, t->id); + yasl_private_loop_del_fd(c->loop, t->id); close(fd); free(t->text); free(t); @@ -311,9 +311,9 @@ static void drag_offer_enter(void *ud, struct wl_data_device *device, uint32_t s c->drag_y = y; c->drag_surface = surface; if (o && o->tab) - drag_event(c, YASL_DRAG_OVER, x, y); + drag_event(c, YASL_PRIVATE_DRAG_OVER, x, y); else if (o && !o->tab && (o->uri_list || o->mime)) - drop_event(c, YASL_DROP_OVER); + drop_event(c, YASL_PRIVATE_DROP_OVER); } } static void drag_offer_clear(void *ud, struct wl_data_device *device) @@ -321,10 +321,10 @@ static void drag_offer_clear(void *ud, struct wl_data_device *device) (void)device; struct clipboard *c = ud; if (c->drag_offer && c->drag_offer->tab) - drag_event(c, YASL_DRAG_LEAVE, c->drag_x, c->drag_y); + drag_event(c, YASL_PRIVATE_DRAG_LEAVE, c->drag_x, c->drag_y); else if (c->drag_offer && !c->drag_offer->tab && (c->drag_offer->uri_list || c->drag_offer->mime)) - drop_event(c, YASL_DROP_LEAVE); + drop_event(c, YASL_PRIVATE_DROP_LEAVE); free_offer(c->drag_offer); c->drag_offer = NULL; c->drag_surface = NULL; @@ -336,10 +336,10 @@ static void drag_motion(void *ud, struct wl_data_device *device, uint32_t time, c->drag_x = x; c->drag_y = y; if (c->drag_offer && c->drag_offer->tab) - drag_event(c, YASL_DRAG_OVER, x, y); + drag_event(c, YASL_PRIVATE_DRAG_OVER, x, y); else if (c->drag_offer && !c->drag_offer->tab && (c->drag_offer->uri_list || c->drag_offer->mime)) - drop_event(c, YASL_DROP_OVER); + drop_event(c, YASL_PRIVATE_DROP_OVER); } static void drag_drop(void *ud, struct wl_data_device *device) { @@ -350,11 +350,11 @@ static void drag_drop(void *ud, struct wl_data_device *device) c->drag_offer = NULL; bool v3 = wl_data_offer_get_version(o->proxy) >= 3; if (o->tab) { - drag_event(c, YASL_DRAG_DROP, c->drag_x, c->drag_y); + drag_event(c, YASL_PRIVATE_DRAG_DROP, c->drag_x, c->drag_y); if (v3) wl_data_offer_finish(o->proxy); } else if (o && !o->tab && (o->uri_list || o->mime)) { - drop_event(c, YASL_DROP_LEAVE); + drop_event(c, YASL_PRIVATE_DROP_LEAVE); int fds[2]; if (pipe2(fds, O_CLOEXEC) == 0) { wl_data_offer_receive(o->proxy, o->uri_list ? "text/uri-list" : o->mime, fds[1]); @@ -522,7 +522,7 @@ struct wl_data_device *clipboard_data_device(const struct clipboard *c) } struct clipboard *clipboard_create(struct wl_display *display, struct wl_data_device_manager *manager, - struct wl_seat *seat, struct yasl_loop *loop, + struct wl_seat *seat, struct yasl_private_loop *loop, clipboard_receive_fn receive, void *ud) { if (!manager || !seat) return NULL; @@ -603,7 +603,7 @@ bool clipboard_copy(struct clipboard *c, const char *text, uint32_t serial) void clipboard_paste(struct clipboard *c, struct wl_surface *target) { if (c && target) - (void)clipboard_request_paste(c, YASL_CLIPBOARD, target, 0); + (void)clipboard_request_paste(c, YASL_PRIVATE_CLIPBOARD, target, 0); } bool clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t serial) @@ -630,24 +630,24 @@ bool clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t seri void clipboard_paste_primary(struct clipboard *c, struct wl_surface *target) { if (c && target) - (void)clipboard_request_paste(c, YASL_PRIMARY, target, 0); + (void)clipboard_request_paste(c, YASL_PRIVATE_PRIMARY, target, 0); } -bool clipboard_request_paste(struct clipboard *c, enum yasl_selection selection, +bool clipboard_request_paste(struct clipboard *c, enum yasl_private_selection selection, struct wl_surface *target, uint64_t request_id) { if (!c || !target || !c->receive) return false; int fds[2]; - if (selection == YASL_PRIMARY) { + if (selection == YASL_PRIVATE_PRIMARY) { if (!c->primary_device || !c->primary_selection || !c->primary_selection->mime) { c->receive(NULL, 0, false, target, request_id, - YASL_TRANSFER_UNAVAILABLE, c->ud); + YASL_PRIVATE_TRANSFER_UNAVAILABLE, c->ud); return true; } if (pipe2(fds, O_CLOEXEC) < 0) { c->receive(NULL, 0, false, target, request_id, - YASL_TRANSFER_FAILED, c->ud); + YASL_PRIVATE_TRANSFER_FAILED, c->ud); return true; } zwp_primary_selection_offer_v1_receive(c->primary_selection->proxy, @@ -656,12 +656,12 @@ bool clipboard_request_paste(struct clipboard *c, enum yasl_selection selection, } else { if (!c->device || !c->selection || !c->selection->mime) { c->receive(NULL, 0, false, target, request_id, - YASL_TRANSFER_UNAVAILABLE, c->ud); + YASL_PRIVATE_TRANSFER_UNAVAILABLE, c->ud); return true; } if (pipe2(fds, O_CLOEXEC) < 0) { c->receive(NULL, 0, false, target, request_id, - YASL_TRANSFER_FAILED, c->ud); + YASL_PRIVATE_TRANSFER_FAILED, c->ud); return true; } wl_data_offer_receive(c->selection->proxy, c->selection->mime, fds[1]); @@ -670,7 +670,7 @@ bool clipboard_request_paste(struct clipboard *c, enum yasl_selection selection, struct transfer *transfer = start_transfer_paste(c, fds[0], target, request_id); if (!transfer) { c->receive(NULL, 0, false, target, request_id, - YASL_TRANSFER_FAILED, c->ud); + YASL_PRIVATE_TRANSFER_FAILED, c->ud); return true; } if (wl_display_flush(c->display) < 0 && errno != EAGAIN) diff --git a/src/platform/wayland/clipboard.h b/src/platform/wayland/clipboard.h index 133cc14..d03df17 100644 --- a/src/platform/wayland/clipboard.h +++ b/src/platform/wayland/clipboard.h @@ -1,10 +1,10 @@ -#ifndef YASL_WAYLAND_CLIPBOARD_H -#define YASL_WAYLAND_CLIPBOARD_H +#ifndef YASL_PRIVATE_WAYLAND_CLIPBOARD_H +#define YASL_PRIVATE_WAYLAND_CLIPBOARD_H #include <stdint.h> #include <stddef.h> #include <stdbool.h> -#include "yasl/yasl.h" +#include "common/types.h" struct wl_display; struct wl_data_device_manager; @@ -16,27 +16,27 @@ struct zwp_primary_selection_device_manager_v1; typedef void (*clipboard_receive_fn)(const char *, size_t, bool uri_list, struct wl_surface *on, uint64_t request_id, - enum yasl_transfer_status, void *); + enum yasl_private_transfer_status, void *); struct clipboard *clipboard_create(struct wl_display *, struct wl_data_device_manager *, - struct wl_seat *, struct yasl_loop *, + struct wl_seat *, struct yasl_private_loop *, clipboard_receive_fn, void *); void clipboard_destroy(struct clipboard *); bool clipboard_set_seat(struct clipboard *, struct wl_seat *); void clipboard_set_primary_manager(struct clipboard *, struct zwp_primary_selection_device_manager_v1 *); bool clipboard_copy(struct clipboard *, const char *, uint32_t); void clipboard_paste(struct clipboard *, struct wl_surface *target); -bool clipboard_request_paste(struct clipboard *, enum yasl_selection, +bool clipboard_request_paste(struct clipboard *, enum yasl_private_selection, struct wl_surface *target, uint64_t request_id); void clipboard_forget_surface(struct clipboard *, struct wl_surface *); bool clipboard_copy_primary(struct clipboard *, const char *, uint32_t); void clipboard_paste_primary(struct clipboard *, struct wl_surface *target); -typedef void (*clipboard_drag_fn)(enum yasl_drag_event, struct wl_surface *on, +typedef void (*clipboard_drag_fn)(enum yasl_private_drag_event, struct wl_surface *on, double x, double y, void *); void clipboard_set_drag_handler(struct clipboard *, clipboard_drag_fn, void *); -typedef void (*clipboard_drop_fn)(enum yasl_drop_event, struct wl_surface *on, +typedef void (*clipboard_drop_fn)(enum yasl_private_drop_event, struct wl_surface *on, double x, double y, void *); void clipboard_set_drop_handler(struct clipboard *, clipboard_drop_fn, void *); const char *clipboard_drag_mime(void); diff --git a/src/platform/wayland/drag.c b/src/platform/wayland/drag.c index 1f4a78b..07e31b5 100644 --- a/src/platform/wayland/drag.c +++ b/src/platform/wayland/drag.c @@ -11,13 +11,13 @@ static void icon_clear(struct drag_icon *icon) *icon = (struct drag_icon){0}; } -static bool icon_create(struct wayland_display *c, const struct yasl_drag_image *image) +static bool icon_create(struct wayland_display *c, const struct yasl_private_drag_image *image) { struct drag_icon *icon = &c->drag.icon; size_t bytes; if (!image->pixels || !buffer_size(image->size.x, image->size.y, &bytes)) return false; - int fd = memfd_create("yasl_drag_icon", MFD_CLOEXEC | MFD_ALLOW_SEALING); + int fd = memfd_create("yasl_private_drag_icon", MFD_CLOEXEC | MFD_ALLOW_SEALING); if (fd < 0) return false; void *mapping = MAP_FAILED; @@ -48,7 +48,7 @@ static bool icon_create(struct wayland_display *c, const struct yasl_drag_image return true; } -static void icon_show(struct wayland_display *c, const struct yasl_drag_image *image) +static void icon_show(struct wayland_display *c, const struct yasl_private_drag_image *image) { struct drag_icon *icon = &c->drag.icon; uint32_t scale = c->drag.scale_120; @@ -56,18 +56,18 @@ static void icon_show(struct wayland_display *c, const struct yasl_drag_image *i icon->viewport = wp_viewporter_get_viewport(c->viewporter, icon->surface); if (icon->viewport) wp_viewport_set_destination(icon->viewport, - yasl_scale_to_logical(image->size.x, scale), - yasl_scale_to_logical(image->size.y, scale)); - } else if (scale % YASL_SCALE_UNIT == 0 && + yasl_private_scale_to_logical(image->size.x, scale), + yasl_private_scale_to_logical(image->size.y, scale)); + } else if (scale % YASL_PRIVATE_SCALE_UNIT == 0 && wl_proxy_get_version((struct wl_proxy *)icon->surface) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) { - wl_surface_set_buffer_scale(icon->surface, (int32_t)(scale / YASL_SCALE_UNIT)); + wl_surface_set_buffer_scale(icon->surface, (int32_t)(scale / YASL_PRIVATE_SCALE_UNIT)); } if (wl_proxy_get_version((struct wl_proxy *)icon->surface) >= WL_SURFACE_OFFSET_SINCE_VERSION) wl_surface_offset(icon->surface, - -yasl_scale_to_logical(image->hotspot.x, scale), - -yasl_scale_to_logical(image->hotspot.y, scale)); + -yasl_private_scale_to_logical(image->hotspot.x, scale), + -yasl_private_scale_to_logical(image->hotspot.y, scale)); wl_surface_attach(icon->surface, icon->buffer, 0, 0); wl_surface_damage_buffer(icon->surface, 0, 0, image->size.x, image->size.y); wl_surface_commit(icon->surface); @@ -88,9 +88,9 @@ static void drag_clear(struct wayland_display *c, bool ended) *d = (struct conn_drag){0}; } -static void drag_finish(struct wayland_display *c, enum yasl_drag_end how, bool ended) +static void drag_finish(struct wayland_display *c, enum yasl_private_drag_end how, bool ended) { - struct yasl_drag_listener l = c->drag.listener; + struct yasl_private_drag_listener l = c->drag.listener; void *ud = c->drag.ud; drag_clear(c, ended); if (l.end) @@ -100,7 +100,7 @@ static void drag_finish(struct wayland_display *c, enum yasl_drag_end how, bool void conn_drag_end(struct wayland_display *c) { if (c && c->drag.source) - drag_finish(c, YASL_DRAG_CANCELLED, false); + drag_finish(c, YASL_PRIVATE_DRAG_CANCELLED, false); } static void source_target(void *ud, struct wl_data_source *s, const char *mime) { (void)ud; (void)s; (void)mime; } @@ -112,7 +112,7 @@ static void source_cancelled(void *ud, struct wl_data_source *s) (void)s; struct wayland_display *c = ud; bool released = c->drag.dropped; - drag_finish(c, released ? YASL_DRAG_DROPPED : YASL_DRAG_CANCELLED, true); + drag_finish(c, released ? YASL_PRIVATE_DRAG_DROPPED : YASL_PRIVATE_DRAG_CANCELLED, true); } static void source_dropped(void *ud, struct wl_data_source *s) @@ -124,7 +124,7 @@ static void source_dropped(void *ud, struct wl_data_source *s) static void source_finished(void *ud, struct wl_data_source *s) { (void)s; - drag_finish(ud, YASL_DRAG_DROPPED, true); + drag_finish(ud, YASL_PRIVATE_DRAG_DROPPED, true); } static const struct wl_data_source_listener source_listener = { @@ -150,8 +150,8 @@ static struct seat *drag_seat(struct wayland_display *c, struct wayland_surface } bool wayland_display_drag_start(struct wayland_display *c, struct wayland_surface *origin, - const struct yasl_drag_image *image, - const struct yasl_drag_listener *l, void *ud) + const struct yasl_private_drag_image *image, + const struct yasl_private_drag_listener *l, void *ud) { if (!c || !origin || origin->conn != c || !l || c->drag.source) return false; @@ -190,39 +190,39 @@ bool wayland_display_drag_start(struct wayland_display *c, struct wayland_surfac void wayland_display_drag_cancel(struct wayland_display *c) { if (c && c->drag.source) - drag_finish(c, YASL_DRAG_CANCELLED, false); + drag_finish(c, YASL_PRIVATE_DRAG_CANCELLED, false); } -bool wayland_surface_drag_carry(struct wayland_surface *w, struct yasl_vector2i offset) +bool wayland_surface_drag_carry(struct wayland_surface *w, struct yasl_private_vector2i offset) { struct wayland_display *c = w ? w->conn : NULL; if (!c || !c->drag.source || !c->drag.toplevel || !w->toplevel) return false; uint32_t scale = c->drag.scale_120; xdg_toplevel_drag_v1_attach(c->drag.toplevel, w->toplevel, - yasl_scale_to_logical(offset.x, scale), - yasl_scale_to_logical(offset.y, scale)); + yasl_private_scale_to_logical(offset.x, scale), + yasl_private_scale_to_logical(offset.y, scale)); c->drag.carrying = true; return true; } -bool wayland_surface_place_under_pointer(struct wayland_surface *w, struct yasl_vector2i at) +bool wayland_surface_place_under_pointer(struct wayland_surface *w, struct yasl_private_vector2i at) { (void)w; (void)at; return false; } -static struct yasl_vector2i drag_device_pos(const struct wayland_surface *w, double x, double y) +static struct yasl_private_vector2i drag_device_pos(const struct wayland_surface *w, double x, double y) { double dx = x * w->scale_factor, dy = y * w->scale_factor; - return (struct yasl_vector2i){ + return (struct yasl_private_vector2i){ .x = (int)(dx < 0 ? dx - 0.5 : dx + 0.5), .y = (int)(dy < 0 ? dy - 0.5 : dy + 0.5), }; } -void conn_drop_target(struct wayland_display *c, enum yasl_drop_event ev, +void conn_drop_target(struct wayland_display *c, enum yasl_private_drop_event ev, struct wl_surface *on, double x, double y) { (void)c; @@ -230,10 +230,10 @@ void conn_drop_target(struct wayland_display *c, enum yasl_drop_event ev, (struct wayland_surface *)wl_surface_get_user_data(on) : NULL; if (!w || w->parent || w->closed) return; - yasl_surface_notify_drop(&w->base, ev, drag_device_pos(w, x, y)); + yasl_private_surface_notify_drop(&w->base, ev, drag_device_pos(w, x, y)); } -void conn_drag_target(struct wayland_display *c, enum yasl_drag_event ev, +void conn_drag_target(struct wayland_display *c, enum yasl_private_drag_event ev, struct wl_surface *on, double x, double y) { (void)c; @@ -241,5 +241,5 @@ void conn_drag_target(struct wayland_display *c, enum yasl_drag_event ev, (struct wayland_surface *)wl_surface_get_user_data(on) : NULL; if (!w || w->parent || w->closed) return; - yasl_surface_notify_drag(&w->base, ev, drag_device_pos(w, x, y)); + yasl_private_surface_notify_drag(&w->base, ev, drag_device_pos(w, x, y)); } diff --git a/src/platform/wayland/ime.c b/src/platform/wayland/ime.c index 4a091d8..62e5936 100644 --- a/src/platform/wayland/ime.c +++ b/src/platform/wayland/ime.c @@ -1,5 +1,7 @@ #include "internal.h" +#include <errno.h> + #define IME_TEXT_MAX (256u * 1024) static void show_preedit(struct wayland_surface *w, char *text, int begin, int end) @@ -12,7 +14,7 @@ static void show_preedit(struct wayland_surface *w, char *text, int begin, int e w->ime_shown_begin = begin; w->ime_shown_end = end; if (changed) { - yasl_surface_notify_composition(&w->base, w->ime_shown, + yasl_private_surface_notify_composition(&w->base, w->ime_shown, w->ime_shown_begin, w->ime_shown_end); wayland_surface_schedule_redraw(w); } @@ -24,21 +26,63 @@ void ime_reset(struct wayland_surface *w) w->ime_preedit = NULL; free(w->ime_commit); w->ime_commit = NULL; + w->ime_delete_pending = false; show_preedit(w, NULL, -1, -1); } void ime_send_caret(struct wayland_surface *w) { + wayland_surface_update_text_input(w); +} + +bool wayland_surface_update_text_input(struct wayland_surface *w) +{ + if (!w || !w->conn) { + errno = EINVAL; + return false; + } + if (!w->conn->text_input_mgr) { + errno = ENOTSUP; + return false; + } struct seat *seat = w->ime_seat; - if (!seat || !seat->text_input) - return; - uint32_t scale = w->scale_120 ? w->scale_120 : YASL_SCALE_UNIT; + if (!seat || !seat->text_input || seat->ime_focus != w) + return true; + if (!w->base.text_input_active) { + if (seat->ime_enabled) { + zwp_text_input_v3_disable(seat->text_input); + zwp_text_input_v3_commit(seat->text_input); + seat->ime_enabled = false; + } + ime_reset(w); + return true; + } + if (!seat->ime_enabled) { + zwp_text_input_v3_enable(seat->text_input); + seat->ime_enabled = true; + } + unsigned purpose = w->base.text_purpose; + if (purpose > ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL) + purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL; + zwp_text_input_v3_set_content_type(seat->text_input, + ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, purpose); + const char *surrounding = w->base.text_surrounding ? w->base.text_surrounding : ""; + size_t length = w->base.text_surrounding ? w->base.text_length : 0; + size_t cursor = w->base.text_surrounding ? w->base.text_end : 0; + size_t anchor = w->base.text_surrounding ? w->base.text_begin : 0; + if (cursor > length) cursor = length; + if (anchor > length) anchor = length; + if (length <= INT32_MAX && cursor <= INT32_MAX && anchor <= INT32_MAX) + zwp_text_input_v3_set_surrounding_text(seat->text_input, surrounding, + (int32_t)cursor, (int32_t)anchor); + uint32_t scale = w->scale_120 ? w->scale_120 : YASL_PRIVATE_SCALE_UNIT; zwp_text_input_v3_set_cursor_rectangle(seat->text_input, - yasl_scale_to_logical(w->ime_caret.x, scale), - yasl_scale_to_logical(w->ime_caret.y, scale), - yasl_scale_to_logical(w->ime_caret.width, scale), - yasl_scale_to_logical(w->ime_caret.height, scale)); + yasl_private_scale_to_logical(w->ime_caret.x, scale), + yasl_private_scale_to_logical(w->ime_caret.y, scale), + yasl_private_scale_to_logical(w->ime_caret.width, scale), + yasl_private_scale_to_logical(w->ime_caret.height, scale)); zwp_text_input_v3_commit(seat->text_input); + return true; } bool wayland_surface_ime_preedit_cursor(const struct wayland_surface *w, int *begin, int *end) @@ -50,7 +94,7 @@ bool wayland_surface_ime_preedit_cursor(const struct wayland_surface *w, int *be return true; } -void wayland_surface_set_ime_caret(struct wayland_surface *w, struct yasl_rect2i caret) +void wayland_surface_set_ime_caret(struct wayland_surface *w, struct yasl_private_rect2i caret) { if (!w || (w->ime_caret.x == caret.x && w->ime_caret.y == caret.y && w->ime_caret.width == caret.width && w->ime_caret.height == caret.height)) @@ -62,17 +106,14 @@ void wayland_surface_set_ime_caret(struct wayland_surface *w, struct yasl_rect2i static void text_input_enter(void *data, struct zwp_text_input_v3 *text_input, struct wl_surface *surface) { + (void)text_input; struct seat *s = data; struct wayland_surface *w = surface_root(surface ? (struct wayland_surface *)wl_surface_get_user_data(surface) : NULL); s->ime_focus = w; if (!w) return; - zwp_text_input_v3_enable(text_input); - zwp_text_input_v3_set_content_type(text_input, - ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, - ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL); w->ime_seat = s; - ime_send_caret(w); + wayland_surface_update_text_input(w); } static void text_input_leave(void *data, struct zwp_text_input_v3 *text_input, @@ -83,8 +124,11 @@ static void text_input_leave(void *data, struct zwp_text_input_v3 *text_input, struct wayland_surface *w = s->ime_focus; s->ime_focus = NULL; if (!w) return; - zwp_text_input_v3_disable(text_input); - zwp_text_input_v3_commit(text_input); + if (s->ime_enabled) { + zwp_text_input_v3_disable(text_input); + zwp_text_input_v3_commit(text_input); + s->ime_enabled = false; + } if (w->ime_seat == s) w->ime_seat = NULL; ime_reset(w); @@ -110,7 +154,7 @@ static void text_input_preedit_string(void *data, { (void)text_input; struct wayland_surface *w = ((struct seat *)data)->ime_focus; - if (!w) return; + if (!w || !w->base.text_input_active) return; keyboard_text_reset((struct seat *)data); free(w->ime_preedit); w->ime_preedit = text ? copy_text(text) : NULL; @@ -126,7 +170,7 @@ static void text_input_commit_string(void *data, { (void)text_input; struct wayland_surface *w = ((struct seat *)data)->ime_focus; - if (!w) return; + if (!w || !w->base.text_input_active) return; keyboard_text_reset((struct seat *)data); free(w->ime_commit); w->ime_commit = (text && text[0]) ? copy_text(text) : NULL; @@ -136,7 +180,31 @@ static void text_input_delete_surrounding_text(void *data, struct zwp_text_input_v3 *text_input, uint32_t before_length, uint32_t after_length) { - (void)data; (void)text_input; (void)before_length; (void)after_length; + (void)text_input; + struct seat *seat = data; + struct wayland_surface *w = seat->ime_focus; + if (!w || !w->base.text_input_active || !w->base.text_surrounding) + return; + size_t length = w->base.text_length; + size_t cursor = w->base.text_end <= length ? w->base.text_end : length; + while (cursor && cursor < length && + (((unsigned char)w->base.text_surrounding[cursor] & 0xc0) == 0x80)) + cursor--; + size_t begin = before_length > cursor ? 0 : cursor - before_length; + size_t end = after_length > length - cursor ? length : cursor + after_length; + while (begin && begin < length && + (((unsigned char)w->base.text_surrounding[begin] & 0xc0) == 0x80)) + begin--; + while (end < length && (((unsigned char)w->base.text_surrounding[end] & 0xc0) == 0x80)) + end++; + /* text_input_v3 batches deletion and commit into one `done` group. Keep + * the replacement range paired with that group's committed text and + * enqueue both together below, preserving snapshot metadata. */ + w->ime_delete_pending = true; + w->ime_delete_begin = begin; + w->ime_delete_end = end; + w->ime_delete_revision = w->base.text_revision; + w->ime_delete_generation = w->base.text_generation; } static void text_input_done(void *data, struct zwp_text_input_v3 *text_input, @@ -144,17 +212,46 @@ static void text_input_done(void *data, struct zwp_text_input_v3 *text_input, { (void)text_input; (void)serial; struct wayland_surface *w = ((struct seat *)data)->ime_focus; - if (!w) return; - if (w->ime_commit) { - struct yasl_event ev = { - .type = YASL_EVENT_TEXT, + if (!w || !w->base.text_input_active) return; + bool has_snapshot = w->base.text_surrounding != NULL && + w->base.text_length <= INT32_MAX; + bool has_commit = w->ime_commit && w->ime_commit[0]; + bool edit = w->ime_delete_pending || (has_commit && has_snapshot); + if (edit) { + size_t begin = w->ime_delete_pending ? w->ime_delete_begin : w->base.text_begin; + size_t end = w->ime_delete_pending ? w->ime_delete_end : w->base.text_end; + if (begin > w->base.text_length) begin = w->base.text_length; + if (end > w->base.text_length) end = w->base.text_length; + if (end < begin) end = begin; + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_TEXT_EDIT, + .surface = &w->base, + .text_edit = { + .data = has_commit ? w->ime_commit : "", + .len = has_commit ? strlen(w->ime_commit) : 0, + .revision = w->ime_delete_revision, + .generation = w->ime_delete_generation, + .begin = begin, + .end = end, + }, + }; + if (!w->ime_delete_pending) { + ev.text_edit.revision = w->base.text_revision; + ev.text_edit.generation = w->base.text_generation; + } + input_queue_push(&w->input, &ev); + w->ime_delete_pending = false; + } + if (w->ime_commit && !edit) { + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_TEXT, .surface = &w->base, .text = { .data = w->ime_commit, .len = strlen(w->ime_commit) }, }; input_queue_push(&w->input, &ev); - free(w->ime_commit); - w->ime_commit = NULL; } + free(w->ime_commit); + w->ime_commit = NULL; char *preedit = w->ime_preedit && w->ime_preedit[0] ? w->ime_preedit : NULL; if (!preedit) free(w->ime_preedit); diff --git a/src/platform/wayland/internal.h b/src/platform/wayland/internal.h index 34d4133..a479e2b 100644 --- a/src/platform/wayland/internal.h +++ b/src/platform/wayland/internal.h @@ -1,5 +1,5 @@ -#ifndef YASL_WAYLAND_INTERNAL_H -#define YASL_WAYLAND_INTERNAL_H +#ifndef YASL_PRIVATE_WAYLAND_INTERNAL_H +#define YASL_PRIVATE_WAYLAND_INTERNAL_H #define _GNU_SOURCE @@ -10,6 +10,11 @@ #include <wayland-client.h> #include <wayland-cursor.h> +#if YASL_HAS_EGL +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <wayland-egl.h> +#endif #include "protocols/xdg-shell-client-protocol.h" #include "protocols/xdg-decoration-client-protocol.h" #include "protocols/cursor-shape-v1-client-protocol.h" @@ -73,7 +78,7 @@ struct wl_conn_output { struct pending_press { struct wayland_surface *surface; - struct yasl_vector2i pos; + struct yasl_private_vector2i pos; int button; bool release; }; @@ -105,7 +110,7 @@ struct conn_drag { struct wl_data_source *source; struct xdg_toplevel_drag_v1 *toplevel; struct drag_icon icon; - struct yasl_drag_listener listener; + struct yasl_private_drag_listener listener; void *ud; struct seat *seat; uint32_t scale_120; @@ -160,15 +165,20 @@ struct seat { uint64_t pointer_buttons; uint64_t tool_buttons; double axis[2], axis_value120[2]; + double axis_pixels[2]; int64_t axis_discrete[2]; + uint32_t axis_source; + bool scroll_gesture, axis_stop_pending; + unsigned axis_phase; + bool ime_enabled; bool axis_has_value120[2], axis_has_discrete[2]; double touch_scroll_y; /* Embedded structs */ xkb_mod_mask_t input_mod_masks[8]; - struct yasl_vector2i pointer_pos; - struct yasl_vector2i ptr_left_pos; - struct yasl_vector2i tool_pos; + struct yasl_private_vector2i pointer_pos; + struct yasl_private_vector2i ptr_left_pos; + struct yasl_private_vector2i tool_pos; struct touch_point touch_points[SEAT_TOUCH_POINTS]; struct press_queue ptr_presses; struct press_queue tool_presses; @@ -183,7 +193,7 @@ struct seat { uint32_t press_serial; uint32_t pointer_serial; int cursor_shape; - struct yasl_pointer_pen pen; + struct yasl_private_pointer_pen pen; int tool_wheel; /* 1-byte booleans grouped tightly */ @@ -199,9 +209,14 @@ struct seat { #include "common/input.h" struct wayland_display { - struct yasl_display base; + struct yasl_private_display base; /* 8-byte pointers & 64-bit masks */ struct wl_display *wl; +#if YASL_HAS_EGL + EGLDisplay egl_display; + EGLint egl_api; + bool egl_initialized; +#endif struct wl_registry *registry; struct wl_compositor *compositor; struct wl_shm *shm; @@ -228,8 +243,8 @@ struct wayland_display { struct wp_fifo_manager_v1 *fifo_mgr; struct wp_commit_timing_manager_v1 *commit_timing_mgr; struct xkb_context *xkb_ctx; - struct yasl_loop *loop; - const struct yasl_display_cbs *cbs; + struct yasl_private_loop *loop; + const struct yasl_private_display_cbs *cbs; void *ud; char *app_id; struct xdg_toplevel_drag_manager_v1 *toplevel_drag_mgr; @@ -243,6 +258,7 @@ struct wayland_display { clockid_t pres_clock; int watch; int depth; + uint64_t next_tool_id; /* 1-byte booleans */ bool owns_loop; @@ -266,6 +282,12 @@ struct wayland_surface { struct wayland_surface *dead_next; struct wayland_surface *parent; struct wl_surface *surface; +#if YASL_HAS_EGL + struct wl_egl_window *egl_window; + EGLSurface egl_surface; + EGLContext egl_context; + EGLConfig egl_config; +#endif struct xdg_surface *xdg_surface; struct xdg_toplevel *toplevel; struct xdg_popup *popup; @@ -276,6 +298,8 @@ struct wayland_surface { char *ime_commit; char *ime_shown; struct seat *ime_seat; + size_t ime_delete_begin, ime_delete_end; + uint64_t ime_delete_revision, ime_delete_generation; struct wp_tearing_control_v1 *tearing_control; struct latency_feedback *latency_feedbacks; struct latency_feedback latency_pool[8]; @@ -285,24 +309,24 @@ struct wayland_surface { /* Persistent lock held while relative; lock_seat owns the locked wl_pointer. */ struct zwp_locked_pointer_v1 *pointer_lock; struct seat *lock_seat; - const struct yasl_window_cbs *cbs; + const struct yasl_private_window_cbs *cbs; void *ud; uint64_t frames_skipped; uint64_t outputs; double scale_factor; /* Sub-structures */ - struct yasl_rect2i ime_caret; - struct yasl_rect2i content; - struct yasl_frame_clock clock; + struct yasl_private_rect2i ime_caret; + struct yasl_private_rect2i content; + struct yasl_private_frame_clock clock; struct buffer buffers[NBUF]; - struct yasl_frame frame; - struct yasl_damage_list damage; + struct yasl_private_frame frame; + struct yasl_private_damage_list damage; int ime_cursor_begin; struct input_queue input; /* 4-byte integers */ - enum yasl_cursor cursor; + enum yasl_private_cursor cursor; int ime_cursor_end; int ime_shown_begin, ime_shown_end; int floating_width, floating_height; @@ -331,6 +355,7 @@ struct wayland_surface { bool want_draw; bool relative; bool pointer_locked; + bool ime_delete_pending; }; @@ -343,7 +368,7 @@ int buffer_prepare(struct wayland_surface *w, struct buffer *b, int width, int const struct wl_buffer_listener *listener); int apply_pending_geometry(struct wayland_surface *w); -static inline void wl_damage_list(struct wl_surface *s, const struct yasl_damage_list *d) +static inline void wl_damage_list(struct wl_surface *s, const struct yasl_private_damage_list *d) { if (d->n < 0) { wl_surface_damage_buffer(s, d->bounds.x, d->bounds.y, @@ -365,6 +390,7 @@ void surface_follow_outputs(struct wayland_surface *w); uint64_t conn_pres_to_mono(const struct wayland_display *c, uint64_t ns); uint64_t conn_mono_to_pres(const struct wayland_display *c, uint64_t ns); void surface_draw_frame(struct wayland_surface *w); +void wayland_surface_arm_frame(struct wayland_surface *w); void surface_fail(struct wayland_surface *w); void display_leave(struct wayland_display *c); @@ -376,9 +402,9 @@ static inline struct wayland_surface *surface_root(struct wayland_surface *w) } void conn_drag_end(struct wayland_display *c); -void conn_drop_target(struct wayland_display *c, enum yasl_drop_event ev, +void conn_drop_target(struct wayland_display *c, enum yasl_private_drop_event ev, struct wl_surface *on, double x, double y); -void conn_drag_target(struct wayland_display *c, enum yasl_drag_event ev, +void conn_drag_target(struct wayland_display *c, enum yasl_private_drag_event ev, struct wl_surface *on, double x, double y); void seat_bind(struct wayland_display *c, struct wl_registry *registry, @@ -386,6 +412,7 @@ void seat_bind(struct wayland_display *c, struct wl_registry *registry, bool seat_remove(struct wayland_display *c, uint32_t name); void seat_destroy(struct seat *s); void seat_note_input(struct seat *s, uint32_t serial); +void seat_ensure_text_input(struct seat *s); void seat_forget_surface(struct seat *s, struct wayland_surface *w); void seat_clipboard_ensure(struct seat *s); int display_input_init(struct wayland_display *c); @@ -409,6 +436,7 @@ extern const struct zwp_text_input_v3_listener text_input_listener; void ime_reset(struct wayland_surface *w); void keyboard_text_reset(struct seat *s); void ime_send_caret(struct wayland_surface *w); +bool wayland_surface_update_text_input(struct wayland_surface *w); int surface_init_shell(struct wayland_surface *w, const char *title); extern const struct xdg_surface_listener shell_surface_listener; diff --git a/src/platform/wayland/keyboard.c b/src/platform/wayland/keyboard.c index 7f8274d..6f9dec9 100644 --- a/src/platform/wayland/keyboard.c +++ b/src/platform/wayland/keyboard.c @@ -133,8 +133,8 @@ bool conn_keyboard_on(const struct wayland_display *c, const struct wayland_surf static void push_focus(struct wayland_surface *w, bool focused) { - struct yasl_event ev = { - .type = YASL_EVENT_FOCUS, + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_FOCUS, .surface = &w->base, .focus = { .focused = focused }, }; @@ -218,18 +218,18 @@ static uint32_t key_codepoint_at_level(struct seat *s, uint32_t key, xkb_layout_ return n == 1 ? xkb_keysym_to_utf32(syms[0]) : 0; } -static struct yasl_key_event xkb_key_event(struct seat *s, uint32_t key, +static struct yasl_private_key_event xkb_key_event(struct seat *s, uint32_t key, enum yasl_key_action action) { uint32_t code = key + XKB_EVDEV_OFFSET; xkb_layout_index_t layout = xkb_state_key_get_layout(s->xkb_state, code); - struct yasl_key_event k = { - .key = yasl_key_from_evdev(key), + struct yasl_private_key_event k = { + .key = yasl_private_key_from_evdev(key), .action = action, .mods = input_modifiers(s), - .codepoint = yasl_key_label(key_codepoint_at_level(s, key, layout, 0)), - .shifted = yasl_key_label(key_codepoint_at_level(s, key, layout, 1)), + .codepoint = yasl_private_key_label(key_codepoint_at_level(s, key, layout, 0)), + .shifted = yasl_private_key_label(key_codepoint_at_level(s, key, layout, 1)), .native_code = key, }; return k; @@ -239,8 +239,8 @@ static void keyboard_text(struct seat *s, struct wayland_surface *w, uint32_t ke { uint32_t code = key + XKB_EVDEV_OFFSET; unsigned mods = input_modifiers(s); - if ((mods & (YASL_MOD_CTRL | YASL_MOD_SUPER)) || - ((mods & YASL_MOD_ALT) && + if ((mods & (YASL_PRIVATE_MOD_CTRL | YASL_PRIVATE_MOD_SUPER)) || + ((mods & YASL_PRIVATE_MOD_ALT) && !xkb_state_mod_index_is_consumed(s->xkb_state, code, s->mod_alt))) { keyboard_text_reset(s); return; @@ -278,13 +278,13 @@ static void keyboard_text(struct seat *s, struct wayland_surface *w, uint32_t ke else xkb_state_key_get_utf8(s->xkb_state, code, text, (size_t)len + 1); /* Editing commands belong to key events, not text insertion. */ if ((unsigned char)text[0] >= 0x20 && text[0] != 0x7f) { - struct yasl_event ev = {.type = YASL_EVENT_TEXT, + struct yasl_private_event ev = {.type = YASL_PRIVATE_EVENT_TEXT, .surface = &w->base, .text = {.data = text, .len = (size_t)len}}; input_queue_push(&w->input, &ev); } if (text != local) free(text); } else { - struct yasl_event ev = {.type = YASL_EVENT_INPUT_RESET, .surface = &w->base}; + struct yasl_private_event ev = {.type = YASL_PRIVATE_EVENT_INPUT_RESET, .surface = &w->base}; input_queue_push(&w->input, &ev); } } @@ -296,9 +296,9 @@ static bool keyboard_dispatch_key(struct seat *s, struct wayland_surface *w, uin { if (!s->xkb_state || !w->cbs) return false; - struct yasl_key_event k = xkb_key_event(s, key, action); - struct yasl_event ev = { - .type = YASL_EVENT_KEY, + struct yasl_private_key_event k = xkb_key_event(s, key, action); + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_KEY, .surface = &w->base, .key = k, }; @@ -329,7 +329,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard, if (keyboard_dispatch_key(s, w, key, YASL_KEY_PRESS) && repeatable) { s->repeat_key = key; s->repeat_held = true; - s->repeat_started_ns = yasl_loop_now_ns(); + s->repeat_started_ns = yasl_private_loop_now_ns(); keyboard_repeat_sync(s); } } @@ -389,7 +389,7 @@ int keyboard_repeat_init(struct seat *s) if (s->repeat_fd >= 0) return 0; s->repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); if (s->repeat_fd < 0) return -1; - s->repeat_watch = yasl_loop_add_fd(s->conn->loop, s->repeat_fd, POLLIN, + s->repeat_watch = yasl_private_loop_add_fd(s->conn->loop, s->repeat_fd, POLLIN, keyboard_repeat_ready, s); if (s->repeat_watch <= 0) { s->repeat_watch = 0; @@ -406,18 +406,18 @@ int seat_modifiers(const struct seat *s) if (unlikely(!s || !s->xkb_state)) return 0; return ((s->mod_shift != XKB_MOD_INVALID && xkb_state_mod_index_is_active(s->xkb_state, s->mod_shift, - XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_SHIFT) | + XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_SHIFT) | ((s->mod_alt != XKB_MOD_INVALID && xkb_state_mod_index_is_active(s->xkb_state, s->mod_alt, - XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_ALT) | + XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_ALT) | ((s->mod_ctrl != XKB_MOD_INVALID && xkb_state_mod_index_is_active(s->xkb_state, s->mod_ctrl, - XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_CTRL) | + XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_CTRL) | ((s->mod_super != XKB_MOD_INVALID && xkb_state_mod_index_is_active(s->xkb_state, s->mod_super, - XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_SUPER) | + XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_SUPER) | ((xkb_state_mod_name_is_active(s->xkb_state, XKB_MOD_NAME_CAPS, - XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_CAPS); + XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_CAPS); } int wayland_display_modifiers(const struct wayland_display *c) @@ -425,12 +425,12 @@ int wayland_display_modifiers(const struct wayland_display *c) return c ? seat_modifiers(c->active_seat ? c->active_seat : c->seats) : 0; } -void wayland_display_copy(struct wayland_display *c, enum yasl_selection sel, const char *text) +void wayland_display_copy(struct wayland_display *c, enum yasl_private_selection sel, const char *text) { (void)wayland_display_copy_text(c, sel, text); } -bool wayland_display_copy_text(struct wayland_display *c, enum yasl_selection sel, +bool wayland_display_copy_text(struct wayland_display *c, enum yasl_private_selection sel, const char *text) { struct seat *s = c ? (c->active_seat ? c->active_seat : c->seats) : NULL; @@ -447,28 +447,28 @@ bool wayland_display_copy_text(struct wayland_display *c, enum yasl_selection se return false; } errno = 0; - bool ok = sel == YASL_PRIMARY ? + bool ok = sel == YASL_PRIVATE_PRIMARY ? clipboard_copy_primary(s->clipboard, text, s->input_serial) : clipboard_copy(s->clipboard, text, s->input_serial); return ok; } -void wayland_display_paste(struct wayland_display *c, enum yasl_selection sel, struct wayland_surface *target) +void wayland_display_paste(struct wayland_display *c, enum yasl_private_selection sel, struct wayland_surface *target) { struct seat *s = c ? (c->active_seat ? c->active_seat : c->seats) : NULL; if (!target || target->closed || target->destroyed) return; if (!s || !s->clipboard) { - yasl_surface_complete_paste(&target->base, 0, - YASL_TRANSFER_UNAVAILABLE, NULL, 0); + yasl_private_surface_complete_paste(&target->base, 0, + YASL_PRIVATE_TRANSFER_UNAVAILABLE, NULL, 0); return; } - if (sel == YASL_PRIMARY) + if (sel == YASL_PRIVATE_PRIMARY) clipboard_paste_primary(s->clipboard, target->surface); else clipboard_paste(s->clipboard, target->surface); } -bool wayland_display_request_paste(struct wayland_display *c, enum yasl_selection sel, +bool wayland_display_request_paste(struct wayland_display *c, enum yasl_private_selection sel, struct wayland_surface *target, uint64_t request_id) { struct seat *s = c ? (c->active_seat ? c->active_seat : c->seats) : NULL; @@ -486,7 +486,7 @@ bool wayland_display_request_paste(struct wayland_display *c, enum yasl_selectio return ok; } -bool wayland_surface_poll_event(struct wayland_surface *w, struct yasl_event *ev) +bool wayland_surface_poll_event(struct wayland_surface *w, struct yasl_private_event *ev) { return w && ev && input_queue_pop(&w->input, ev); } diff --git a/src/platform/wayland/keymap.c b/src/platform/wayland/keymap.c index d626f30..6c3b4dd 100644 --- a/src/platform/wayland/keymap.c +++ b/src/platform/wayland/keymap.c @@ -1,7 +1,7 @@ #include "keymap.h" /* Numeric Linux evdev codes; no platform headers are needed by this table. */ -enum yasl_key yasl_key_from_evdev(uint32_t code) +enum yasl_key yasl_private_key_from_evdev(uint32_t code) { switch (code) { case 1: return YASL_KEY_ESCAPE; /* KEY_ESC */ diff --git a/src/platform/wayland/keymap.h b/src/platform/wayland/keymap.h index c0ff81e..26b6ed4 100644 --- a/src/platform/wayland/keymap.h +++ b/src/platform/wayland/keymap.h @@ -1,8 +1,8 @@ -#ifndef YASL_WAYLAND_KEYMAP_H -#define YASL_WAYLAND_KEYMAP_H +#ifndef YASL_PRIVATE_WAYLAND_KEYMAP_H +#define YASL_PRIVATE_WAYLAND_KEYMAP_H #include "yasl/keycodes.h" -enum yasl_key yasl_key_from_evdev(uint32_t code); +enum yasl_key yasl_private_key_from_evdev(uint32_t code); #endif diff --git a/src/platform/wayland/native.c b/src/platform/wayland/native.c index 55ce445..54ca184 100644 --- a/src/platform/wayland/native.c +++ b/src/platform/wayland/native.c @@ -1,14 +1,14 @@ #include "common/backend.h" -#include "yasl/native/wayland.h" +#include "common/private_native_wayland.h" -struct wl_display *yasl_wayland_display_get_wl_display(struct yasl_display *d) +struct wl_display *yasl_private_wayland_display_get_wl_display(struct yasl_private_display *d) { - return (d && yasl_display_backend(d) == YASL_BACKEND_WAYLAND) ? - (struct wl_display *)yasl_display_get_native_handle(d) : NULL; + return (d && yasl_private_display_backend(d) == YASL_PRIVATE_BACKEND_WAYLAND) ? + (struct wl_display *)yasl_private_display_get_native_handle(d) : NULL; } -struct wl_surface *yasl_wayland_surface_get_wl_surface(struct yasl_surface *s) +struct wl_surface *yasl_private_wayland_surface_get_wl_surface(struct yasl_surface *s) { - return (s && s->display && yasl_display_backend(s->display) == YASL_BACKEND_WAYLAND) ? - (struct wl_surface *)yasl_surface_get_native_handle(s) : NULL; + return (s && s->display && yasl_private_display_backend(s->display) == YASL_PRIVATE_BACKEND_WAYLAND) ? + (struct wl_surface *)yasl_private_surface_get_native_handle(s) : NULL; } diff --git a/src/platform/wayland/pointer.c b/src/platform/wayland/pointer.c index da666da..5f486ae 100644 --- a/src/platform/wayland/pointer.c +++ b/src/platform/wayland/pointer.c @@ -12,12 +12,22 @@ struct tablet_tool { struct zwp_tablet_tool_v2 *proxy; struct wp_cursor_shape_device_v1 *shape_dev; uint32_t proximity_serial; + uint64_t device_id, tool_id; + uint32_t axes_valid, axes_changed, capability_mask; + double x, y; + double pressure, tilt_x, tilt_y, rotation, distance, tangential, wheel_degrees; + unsigned changed_button; + unsigned pending_actions[8], pending_buttons[8], pending_action_count; + bool pending_contacts[8]; + unsigned kind; + bool in_contact, pen_in_proximity; bool eraser; }; struct tablet_device { struct tablet_device *next; struct zwp_tablet_v2 *proxy; + uint64_t id; }; struct tablet_pad { @@ -25,10 +35,10 @@ struct tablet_pad { struct zwp_tablet_pad_v2 *proxy; }; -static struct yasl_vector2i device_from_fixed(const struct wayland_surface *w, +static struct yasl_private_vector2i device_from_fixed(const struct wayland_surface *w, wl_fixed_t x, wl_fixed_t y) { - return (struct yasl_vector2i){ + return (struct yasl_private_vector2i){ .x = (int)lrint(wl_fixed_to_double(x) * w->scale_factor), .y = (int)lrint(wl_fixed_to_double(y) * w->scale_factor), }; @@ -41,10 +51,10 @@ void seat_note_input(struct seat *s, uint32_t serial) } static void push_pointer(struct seat *s, struct wayland_surface *w, - enum yasl_event_type type, struct yasl_pointer_event ev) + enum yasl_private_event_type type, struct yasl_private_pointer_event ev) { ev.mods = (uint32_t)seat_modifiers(s); - struct yasl_event input_ev = { + struct yasl_private_event input_ev = { .type = type, .surface = &w->base, .pointer = ev, @@ -52,13 +62,15 @@ static void push_pointer(struct seat *s, struct wayland_surface *w, input_queue_push(&surface_root(w)->input, &input_ev); } -static void report_wheel(struct seat *s, struct wayland_surface *w, - struct yasl_vector2i pos, double x, double y) +static unsigned scroll_source_of(uint32_t source) { - if ((x == 0 && y == 0) || !isfinite(x) || !isfinite(y)) return; - push_pointer(s, w, YASL_EVENT_POINTER_SCROLL, (struct yasl_pointer_event){ - .pos = pos, .scroll = {x, y}, - }); + switch (source) { + case WL_POINTER_AXIS_SOURCE_WHEEL: return 1; + case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: return 1; + case WL_POINTER_AXIS_SOURCE_FINGER: return 2; + case WL_POINTER_AXIS_SOURCE_CONTINUOUS: return 3; + default: return 0; + } } static bool cursor_theme_for(struct wayland_display *c, int scale) @@ -90,10 +102,10 @@ static bool seat_cursor_surface(struct seat *s) } static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w, - enum yasl_cursor shape) + enum yasl_private_cursor shape) { struct wayland_display *c = s->conn; - int scale = (int)((w->scale_120 + YASL_SCALE_UNIT - 1) / YASL_SCALE_UNIT); + int scale = (int)((w->scale_120 + YASL_PRIVATE_SCALE_UNIT - 1) / YASL_PRIVATE_SCALE_UNIT); if (scale < 1) scale = 1; if (!seat_cursor_surface(s) || !cursor_theme_for(c, scale)) return; static const char *names[][2] = { @@ -107,7 +119,7 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w, {"ew-resize", "ew-resize"}, {"ns-resize", "ns-resize"}, }; - int idx = (unsigned)shape < YASL_CURSOR_HIDDEN ? (int)shape : 0; + int idx = (unsigned)shape < YASL_PRIVATE_CURSOR_HIDDEN ? (int)shape : 0; struct wl_cursor *cursor = wl_cursor_theme_get_cursor(c->cursor_theme, names[idx][0]); if (!cursor) cursor = wl_cursor_theme_get_cursor(c->cursor_theme, names[idx][1]); if (!cursor || !cursor->image_count) return; @@ -117,11 +129,11 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w, int theme_scale = c->cursor_theme_scale; if (s->cursor_viewport) { - uint32_t scale_120 = (uint32_t)theme_scale * YASL_SCALE_UNIT; + uint32_t scale_120 = (uint32_t)theme_scale * YASL_PRIVATE_SCALE_UNIT; wp_viewport_set_destination(s->cursor_viewport, - (int)(((int64_t)(int)img->width * YASL_SCALE_UNIT + scale_120 - 1) / + (int)(((int64_t)(int)img->width * YASL_PRIVATE_SCALE_UNIT + scale_120 - 1) / scale_120), - (int)(((int64_t)(int)img->height * YASL_SCALE_UNIT + scale_120 - 1) / + (int)(((int64_t)(int)img->height * YASL_PRIVATE_SCALE_UNIT + scale_120 - 1) / scale_120)); } else { if (img->width % (uint32_t)theme_scale || img->height % (uint32_t)theme_scale) @@ -137,17 +149,17 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w, wl_surface_commit(s->cursor_surface); } -static uint32_t cursor_shape_of(enum yasl_cursor shape) +static uint32_t cursor_shape_of(enum yasl_private_cursor shape) { switch (shape) { - case YASL_CURSOR_TEXT: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT; - case YASL_CURSOR_LINK: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER; - case YASL_CURSOR_CROSSHAIR: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR; - case YASL_CURSOR_MOVE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE; - case YASL_CURSOR_RESIZE_EW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE; - case YASL_CURSOR_RESIZE_NS: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE; - case YASL_CURSOR_RESIZE_NWSE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE; - case YASL_CURSOR_RESIZE_NESW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE; + case YASL_PRIVATE_CURSOR_TEXT: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT; + case YASL_PRIVATE_CURSOR_LINK: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER; + case YASL_PRIVATE_CURSOR_CROSSHAIR: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR; + case YASL_PRIVATE_CURSOR_MOVE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE; + case YASL_PRIVATE_CURSOR_RESIZE_EW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE; + case YASL_PRIVATE_CURSOR_RESIZE_NS: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE; + case YASL_PRIVATE_CURSOR_RESIZE_NWSE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE; + case YASL_PRIVATE_CURSOR_RESIZE_NESW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE; default: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT; } } @@ -155,11 +167,11 @@ static uint32_t cursor_shape_of(enum yasl_cursor shape) /* Relative mode hides the pointer but keeps w->cursor for the return to NORMAL. */ static void seat_set_cursor(struct seat *s, struct wayland_surface *w) { - enum yasl_cursor shape = w->relative ? YASL_CURSOR_HIDDEN : w->cursor; + enum yasl_private_cursor shape = w->relative ? YASL_PRIVATE_CURSOR_HIDDEN : w->cursor; if (!s->pointer || !s->pointer_serial || s->pointer_focus != w || s->cursor_shape == (int)shape) return; - if (shape == YASL_CURSOR_HIDDEN) + if (shape == YASL_PRIVATE_CURSOR_HIDDEN) wl_pointer_set_cursor(s->pointer, s->pointer_serial, NULL, 0, 0); else if (s->cursor_shape_dev) wp_cursor_shape_device_v1_set_shape(s->cursor_shape_dev, @@ -169,20 +181,20 @@ static void seat_set_cursor(struct seat *s, struct wayland_surface *w) s->cursor_shape = shape; } -static void tool_set_cursor(struct tablet_tool *t, enum yasl_cursor shape) +static void tool_set_cursor(struct tablet_tool *t, enum yasl_private_cursor shape) { if (!t->proximity_serial) return; - if (shape == YASL_CURSOR_HIDDEN) + if (shape == YASL_PRIVATE_CURSOR_HIDDEN) zwp_tablet_tool_v2_set_cursor(t->proxy, t->proximity_serial, NULL, 0, 0); else if (t->shape_dev) wp_cursor_shape_device_v1_set_shape(t->shape_dev, t->proximity_serial, cursor_shape_of(shape)); } -void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_cursor shape) +void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_private_cursor shape) { - if (!w || !w->conn || w->destroyed || (unsigned)shape > YASL_CURSOR_HIDDEN) return; + if (!w || !w->conn || w->destroyed || (unsigned)shape > YASL_PRIVATE_CURSOR_HIDDEN) return; w->cursor = shape; for (struct seat *s = w->conn->seats; s; s = s->next) { seat_set_cursor(s, w); @@ -193,7 +205,7 @@ void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_cursor shap static void press_queue_flush(struct seat *s, struct press_queue *q, struct wayland_surface *only, uint64_t *buttons, - struct yasl_pointer_event like) + struct yasl_private_pointer_event like) { int kept = 0; int count = q->n; @@ -206,10 +218,10 @@ static void press_queue_flush(struct seat *s, struct press_queue *q, if (!p.surface) continue; uint64_t mask = 1ull << p.button; *buttons = (*buttons & ~mask) | ((uint64_t)(!p.release) << p.button); - struct yasl_pointer_event ev = like; + struct yasl_private_pointer_event ev = like; ev.pos = p.pos; - ev.button = (enum yasl_pointer_button)p.button; - enum yasl_event_type type = p.release ? YASL_EVENT_POINTER_UP : YASL_EVENT_POINTER_DOWN; + ev.button = (enum yasl_private_pointer_button)p.button; + enum yasl_private_event_type type = p.release ? YASL_PRIVATE_EVENT_POINTER_UP : YASL_PRIVATE_EVENT_POINTER_DOWN; push_pointer(s, p.surface, type, ev); } q->head = 0; @@ -217,7 +229,7 @@ static void press_queue_flush(struct seat *s, struct press_queue *q, } static void press_queue_push(struct press_queue *q, struct wayland_surface *w, - struct yasl_vector2i pos, int button, bool release) + struct yasl_private_vector2i pos, int button, bool release) { if (q->n == 8) { q->head = (q->head + 1) & 7; @@ -244,10 +256,15 @@ void seat_pointer_reset(struct seat *s) s->pointer_serial = 0; s->motion_pending = false; memset(s->axis, 0, sizeof(s->axis)); + memset(s->axis_pixels, 0, sizeof(s->axis_pixels)); memset(s->axis_value120, 0, sizeof(s->axis_value120)); memset(s->axis_discrete, 0, sizeof(s->axis_discrete)); memset(s->axis_has_value120, 0, sizeof(s->axis_has_value120)); memset(s->axis_has_discrete, 0, sizeof(s->axis_has_discrete)); + s->axis_stop_pending = false; + s->scroll_gesture = false; + s->axis_phase = 0; + s->axis_source = WL_POINTER_AXIS_SOURCE_WHEEL; s->cursor_shape = -1; } @@ -263,7 +280,7 @@ static void flush_pending_motion(struct seat *s, struct wayland_surface *w) { if (!s->motion_pending) return; s->motion_pending = false; - push_pointer(s, w, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){ + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){ .pos = s->pointer_pos, }); } @@ -356,6 +373,13 @@ static void pointer_axis(void *data, struct wl_pointer *pointer, double v = wl_fixed_to_double(value); if (likely(axis < 2)) { s->axis[axis] += v; + s->axis_pixels[axis] += v; + if (s->axis_source == WL_POINTER_AXIS_SOURCE_FINGER || + s->axis_source == WL_POINTER_AXIS_SOURCE_CONTINUOUS) { + if (!s->scroll_gesture) s->axis_phase = 1u; + else if (s->axis_phase != 1u) s->axis_phase = 2u; + s->scroll_gesture = true; + } } pointer_event_done(s); } @@ -363,13 +387,14 @@ static void pointer_axis(void *data, struct wl_pointer *pointer, static void pointer_axis_source(void *data, struct wl_pointer *pointer, uint32_t axis_source) { (void)pointer; - (void)data; (void)axis_source; + ((struct seat *)data)->axis_source = axis_source; } static void pointer_axis_stop(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis) { /* A stop ends a gesture, not the offsets already received in this frame. */ - (void)data; (void)pointer; (void)time; (void)axis; + (void)pointer; (void)time; (void)axis; + ((struct seat *)data)->axis_stop_pending = true; } static void pointer_axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t discrete) @@ -405,7 +430,28 @@ static void pointer_frame_scroll(struct seat *s, struct wayland_surface *w) s->axis_discrete[axis] = 0; s->axis_has_value120[axis] = s->axis_has_discrete[axis] = false; } - report_wheel(s, w, s->pointer_pos, lines[1], lines[0]); + bool stopped = s->axis_stop_pending; + unsigned source = scroll_source_of(s->axis_source); + unsigned phase = source == 2 || source == 3 + ? (stopped ? 3u : s->axis_phase) : 0u; + bool has_pixels = (source == 2 || source == 3) && + (s->axis_pixels[0] != 0 || s->axis_pixels[1] != 0); + if (lines[0] != 0 || lines[1] != 0 || stopped) { + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_SCROLL, + (struct yasl_private_pointer_event){ + .pos = s->pointer_pos, + .scroll = {lines[1], lines[0]}, + .pixel_scroll = {s->axis_pixels[1] * w->scale_factor, + s->axis_pixels[0] * w->scale_factor}, + .scroll_valid = 1u | (has_pixels ? 2u : 0u), + .scroll_source = source, + .scroll_phase = phase, + }); + } + memset(s->axis_pixels, 0, sizeof(s->axis_pixels)); + s->axis_stop_pending = false; + if (stopped) s->scroll_gesture = false; + s->axis_phase = 0; } static void pointer_frame(void *data, struct wl_pointer *pointer) @@ -416,14 +462,14 @@ static void pointer_frame(void *data, struct wl_pointer *pointer) if (left) { s->ptr_left = NULL; if (s->ptr_left_motion) - push_pointer(s, left, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){ + push_pointer(s, left, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){ .pos = s->ptr_left_pos, }); - press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_pointer_event){0}); - push_pointer(s, left, YASL_EVENT_POINTER_LEAVE, (struct yasl_pointer_event){ + press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_private_pointer_event){0}); + push_pointer(s, left, YASL_PRIVATE_EVENT_POINTER_LEAVE, (struct yasl_private_pointer_event){ .pos = s->ptr_left_pos, }); - struct yasl_vector2i pos = s->pointer_pos; + struct yasl_private_vector2i pos = s->pointer_pos; bool motion = s->motion_pending; uint32_t serial = s->pointer_focus ? s->pointer_serial : 0; int shape = s->pointer_focus ? s->cursor_shape : -1; @@ -440,7 +486,7 @@ static void pointer_frame(void *data, struct wl_pointer *pointer) } flush_pending_motion(s, w); - press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_pointer_event){0}); + press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_private_pointer_event){0}); pointer_frame_scroll(s, w); } @@ -460,7 +506,7 @@ static void relative_motion(void *data, struct zwp_relative_pointer_v1 *pointer, /* Unlocked movement arrives as wl_pointer.motion; the queue derives its delta. */ if (!w || !w->pointer_locked || w->lock_seat != s) return; flush_pending_motion(s, w); - push_pointer(s, w, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){ + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){ .pos = s->pointer_pos, .delta = {wl_fixed_to_double(dx) * w->scale_factor, wl_fixed_to_double(dy) * w->scale_factor}, @@ -525,12 +571,12 @@ static void seat_lock_surfaces(struct seat *s) surface_lock_pointer(w, s); } -bool wayland_surface_set_pointer_mode(struct wayland_surface *w, enum yasl_pointer_mode mode) +bool wayland_surface_set_pointer_mode(struct wayland_surface *w, enum yasl_private_pointer_mode mode) { if (!w || !w->conn || w->destroyed) return false; struct wayland_display *c = w->conn; - bool relative = mode == YASL_POINTER_RELATIVE; + bool relative = mode == YASL_PRIVATE_POINTER_RELATIVE; if (relative && (!c->relative_pointer_mgr || !c->pointer_constraints)) return false; w->relative = relative; @@ -572,10 +618,10 @@ static struct touch_point *touch_find(struct seat *s, int32_t id) return NULL; } -static struct yasl_vector2i touch_pos(const struct touch_point *p) +static struct yasl_private_vector2i touch_pos(const struct touch_point *p) { double scale = p->surface->scale_factor; - return (struct yasl_vector2i){ + return (struct yasl_private_vector2i){ .x = (int)lrint(p->x * scale), .y = (int)lrint(p->y * scale), }; } @@ -583,11 +629,11 @@ static struct yasl_vector2i touch_pos(const struct touch_point *p) static void touch_report(struct seat *s, struct touch_point *p, int button, - enum yasl_event_type type) + enum yasl_private_event_type type) { - push_pointer(s, p->surface, type, (struct yasl_pointer_event){ - .pos = touch_pos(p), .button = (enum yasl_pointer_button)button, - .device = YASL_PTR_DEV_TOUCH, + push_pointer(s, p->surface, type, (struct yasl_private_pointer_event){ + .pos = touch_pos(p), .button = (enum yasl_private_pointer_button)button, + .device = YASL_PRIVATE_PTR_DEV_TOUCH, }); } @@ -644,7 +690,7 @@ static void touch_frame(void *data, struct wl_touch *touch) if (p->down && !s->touch_primary && !s->touch_scrolling) { s->touch_primary = p; s->touch_pressed = true; - touch_report(s, p, 0, YASL_EVENT_POINTER_DOWN); + touch_report(s, p, 0, YASL_PRIVATE_EVENT_POINTER_DOWN); } if (!p->up) { active_n++; @@ -657,7 +703,7 @@ static void touch_frame(void *data, struct wl_touch *touch) struct touch_point *primary = s->touch_primary; if (primary && !s->touch_scrolling && active_n >= 2) { if (s->touch_pressed) - touch_report(s, primary, 0, YASL_EVENT_POINTER_UP); + touch_report(s, primary, 0, YASL_PRIVATE_EVENT_POINTER_UP); s->touch_pressed = false; s->touch_scrolling = true; s->touch_scroll_y = centroid_n ? centroid_sum / centroid_n : 0; @@ -667,14 +713,14 @@ static void touch_frame(void *data, struct wl_touch *touch) s->touch_scroll_y = y; if (dy != 0.0) { double lines = dy / SCROLL_PX_PER_LINE; - push_pointer(s, primary->surface, YASL_EVENT_POINTER_SCROLL, (struct yasl_pointer_event){ + push_pointer(s, primary->surface, YASL_PRIVATE_EVENT_POINTER_SCROLL, (struct yasl_private_pointer_event){ .pos = touch_pos(primary), .scroll = {0, -lines}, - .device = YASL_PTR_DEV_TOUCH, + .device = YASL_PRIVATE_PTR_DEV_TOUCH, }); } } else if (primary && primary->moved && s->touch_pressed) { - touch_report(s, primary, 0, YASL_EVENT_POINTER_MOTION); + touch_report(s, primary, 0, YASL_PRIVATE_EVENT_POINTER_MOTION); } for (int i = 0; i < SEAT_TOUCH_POINTS; i++) { struct touch_point *p = &s->touch_points[i]; @@ -683,7 +729,7 @@ static void touch_frame(void *data, struct wl_touch *touch) active_n--; if (p == s->touch_primary) { if (s->touch_pressed) - touch_report(s, p, 0, YASL_EVENT_POINTER_UP); + touch_report(s, p, 0, YASL_PRIVATE_EVENT_POINTER_UP); s->touch_pressed = false; s->touch_primary = NULL; } @@ -701,7 +747,7 @@ static void touch_cancel(void *data, struct wl_touch *touch) (void)touch; struct seat *s = data; if (s->touch_primary && s->touch_pressed) - touch_report(s, s->touch_primary, 0, YASL_EVENT_POINTER_UP); + touch_report(s, s->touch_primary, 0, YASL_PRIVATE_EVENT_POINTER_UP); memset(s->touch_points, 0, sizeof(s->touch_points)); s->touch_primary = NULL; s->touch_pressed = false; @@ -719,29 +765,100 @@ static const struct wl_touch_listener touch_listener = { .frame = touch_frame, .cancel = touch_cancel, }; -static struct yasl_pointer_event tool_event(const struct seat *s) +static struct yasl_private_pointer_event tool_event(const struct seat *s) { - return (struct yasl_pointer_event){ - .device = s->tool && s->tool->eraser ? YASL_PTR_DEV_ERASER : YASL_PTR_DEV_PEN, + return (struct yasl_private_pointer_event){ + .device = s->tool && s->tool->eraser ? YASL_PRIVATE_PTR_DEV_ERASER : YASL_PRIVATE_PTR_DEV_PEN, .pen = s->pen, }; } +static void push_pen_sample(struct tablet_tool *tool, struct wayland_surface *w, + unsigned action, uint32_t changed) +{ + struct seat *s = tool->seat; + if (!w) return; + uint64_t buttons = s->tool_buttons; + for (int i = 0; i < s->tool_presses.n; i++) { + const struct pending_press *press = &s->tool_presses.ev[(s->tool_presses.head + i) & 7]; + if (press->surface && press->button >= 0 && press->button < 32) { + uint64_t bit = 1ull << press->button; + buttons = (buttons & ~bit) | ((uint64_t)!press->release << press->button); + } + } + if (action == YASL_PRIVATE_PEN_LEAVE || action == YASL_PRIVATE_PEN_CANCEL) + buttons = 0; + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_PEN, + .surface = &w->base, + .pen = { + .device_id = tool->device_id, + .tool_id = tool->tool_id, + .x = tool->x, + .y = tool->y, + .pressure = tool->pressure, + .tilt_x = tool->tilt_x, + .tilt_y = tool->tilt_y, + .rotation = tool->rotation, + .distance = tool->distance, + .tangential = tool->tangential, + .wheel_degrees = tool->wheel_degrees, + .axes_valid = tool->axes_valid, + .axes_changed = changed, + .buttons = (uint32_t)buttons, + .changed_button = tool->changed_button, + .in_contact = tool->in_contact, + .tool = tool->kind, + .action = action, + }, + }; + input_queue_push(&surface_root(w)->input, &ev); +} + +static void pen_action_push(struct tablet_tool *tool, unsigned action, unsigned button) +{ + if (tool->pending_action_count == 8) { + memmove(tool->pending_actions, tool->pending_actions + 1, + 7 * sizeof(tool->pending_actions[0])); + memmove(tool->pending_buttons, tool->pending_buttons + 1, + 7 * sizeof(tool->pending_buttons[0])); + memmove(tool->pending_contacts, tool->pending_contacts + 1, + 7 * sizeof(tool->pending_contacts[0])); + tool->pending_action_count--; + } + unsigned i = tool->pending_action_count++; + tool->pending_actions[i] = action; + tool->pending_buttons[i] = button; + tool->pending_contacts[i] = tool->in_contact; +} + static void tablet_tool_proximity_in(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) { - (void)tool; (void)tablet; + (void)tool; struct tablet_tool *t = data; struct seat *s = t->seat; struct wayland_surface *w = surface ? (struct wayland_surface *)wl_surface_get_user_data(surface) : NULL; s->tablet_focus = w; s->tool = t; + t->device_id = 0; + for (struct tablet_device *device = s->tablet_devices; device; device = device->next) + if (device->proxy == tablet) { t->device_id = device->id; break; } + t->pen_in_proximity = true; + t->in_contact = false; + t->pending_action_count = 0; + pen_action_push(t, YASL_PRIVATE_PEN_ENTER, 0); + t->axes_changed = 0; + t->pressure = t->tilt_x = t->tilt_y = t->rotation = t->distance = 0; + t->tangential = t->wheel_degrees = 0; s->tool_buttons = 0; - s->pen = (struct yasl_pointer_pen){0}; + s->pen = (struct yasl_private_pointer_pen){0}; t->proximity_serial = serial; if (!w) return; + t->x = s->tool_pos.x; + t->y = s->tool_pos.y; if (s->conn->cursor_shape_mgr && !t->shape_dev) t->shape_dev = wp_cursor_shape_manager_v1_get_tablet_tool_v2( s->conn->cursor_shape_mgr, t->proxy); @@ -756,11 +873,14 @@ static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *too struct seat *s = t->seat; struct wayland_surface *w = s->tablet_focus; if (w) { + t->in_contact = false; + t->pressure = 0; + push_pen_sample(t, w, YASL_PRIVATE_PEN_LEAVE, 0); press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, tool_event(s)); s->pen.pressure = 0; - struct yasl_pointer_event ev = tool_event(s); + struct yasl_private_pointer_event ev = tool_event(s); ev.pos = s->tool_pos; - push_pointer(s, w, YASL_EVENT_POINTER_LEAVE, ev); + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_LEAVE, ev); } s->tool_presses.n = 0; s->tablet_focus = NULL; @@ -769,28 +889,38 @@ static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *too s->tool_wheel = 0; s->tool_buttons = 0; t->proximity_serial = 0; + t->pen_in_proximity = false; + t->in_contact = false; } static void tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial) { (void)tool; - struct seat *s = ((struct tablet_tool *)data)->seat; + struct tablet_tool *t = data; + struct seat *s = t->seat; struct wayland_surface *w = s->tablet_focus; if (!w) return; seat_note_input(s, serial); s->press_serial = serial; s->press_surface = w; press_queue_push(&s->tool_presses, w, s->tool_pos, 0, false); + t->in_contact = true; + pen_action_push(t, YASL_PRIVATE_PEN_DOWN, 0); } static void tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *tool) { (void)tool; struct seat *s = ((struct tablet_tool *)data)->seat; + struct tablet_tool *t = data; struct wayland_surface *w = s->tablet_focus; if (!w) return; s->pen.pressure = 0; press_queue_push(&s->tool_presses, w, s->tool_pos, 0, true); + t->pressure = 0; + t->in_contact = false; + pen_action_push(t, YASL_PRIVATE_PEN_UP, 0); + t->axes_changed |= YASL_PRIVATE_PEN_PRESSURE; } static void tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, wl_fixed_t x, wl_fixed_t y) @@ -800,6 +930,9 @@ static void tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, wl_f struct wayland_surface *w = s->tablet_focus; if (!w) return; s->tool_pos = device_from_fixed(w, x, y); + struct tablet_tool *owned = data; + owned->x = wl_fixed_to_double(x) * w->scale_factor; + owned->y = wl_fixed_to_double(y) * w->scale_factor; s->tool_motion = true; } @@ -807,7 +940,8 @@ static void tablet_tool_button(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial, uint32_t button, uint32_t state) { (void)tool; - struct seat *s = ((struct tablet_tool *)data)->seat; + struct tablet_tool *t = data; + struct seat *s = t->seat; struct wayland_surface *w = s->tablet_focus; if (!w) return; seat_note_input(s, serial); @@ -820,13 +954,18 @@ static void tablet_tool_button(void *data, struct zwp_tablet_tool_v2 *tool, } bool release = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED; press_queue_push(&s->tool_presses, w, s->tool_pos, b, release); + pen_action_push(t, YASL_PRIVATE_PEN_BUTTON, (unsigned)b); } static void tool_pressure(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v) { (void)t; struct seat *s = ((struct tablet_tool *)d)->seat; + struct tablet_tool *owned = d; s->pen.pressure = v > 65535 ? 65535 : (uint16_t)v; + owned->pressure = (double)(v > 65535 ? 65535 : v) / 65535.0; + owned->axes_valid |= YASL_PRIVATE_PEN_PRESSURE; + owned->axes_changed |= YASL_PRIVATE_PEN_PRESSURE; s->tool_motion = true; } @@ -840,40 +979,68 @@ static void tool_tilt(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t x, wl_fi { (void)t; struct seat *s = ((struct tablet_tool *)d)->seat; + struct tablet_tool *owned = d; s->pen.tilt_x = tilt_degrees(x); s->pen.tilt_y = tilt_degrees(y); + owned->tilt_x = wl_fixed_to_double(x); + owned->tilt_y = wl_fixed_to_double(y); + owned->axes_valid |= YASL_PRIVATE_PEN_TILT; + owned->axes_changed |= YASL_PRIVATE_PEN_TILT; s->tool_motion = true; } static void tool_wheel(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg, int32_t clicks) { - (void)t; (void)deg; - ((struct tablet_tool *)d)->seat->tool_wheel += clicks; + (void)t; + struct tablet_tool *owned = d; + owned->seat->tool_wheel += clicks; + owned->wheel_degrees += wl_fixed_to_double(deg); + owned->axes_valid |= YASL_PRIVATE_PEN_WHEEL; + owned->axes_changed |= YASL_PRIVATE_PEN_WHEEL; } static void tool_frame(void *d, struct zwp_tablet_tool_v2 *t, uint32_t time) { (void)t; (void)time; struct seat *s = ((struct tablet_tool *)d)->seat; + struct tablet_tool *owned = d; struct wayland_surface *w = s->tablet_focus; if (!w) { s->tool_presses.n = 0; s->tool_wheel = 0; return; } - struct yasl_pointer_event like = tool_event(s); + struct yasl_private_pointer_event like = tool_event(s); + if (owned->pending_action_count) { + unsigned actions = owned->pending_action_count; + bool contact = owned->in_contact; + for (unsigned i = 0; i < actions; i++) { + owned->changed_button = owned->pending_buttons[i]; + owned->in_contact = owned->pending_contacts[i]; + push_pen_sample(owned, w, owned->pending_actions[i], + i + 1 == actions ? owned->axes_changed : 0); + } + owned->in_contact = contact; + owned->pending_action_count = 0; + owned->axes_changed = 0; + owned->changed_button = 0; + } else if (s->tool_motion || owned->axes_changed) { + push_pen_sample(owned, w, YASL_PRIVATE_PEN_MOVE, owned->axes_changed); + owned->axes_changed = 0; + owned->changed_button = 0; + } if (s->tool_motion) { - struct yasl_pointer_event ev = like; + struct yasl_private_pointer_event ev = like; ev.pos = s->tool_pos; - push_pointer(s, w, YASL_EVENT_POINTER_MOTION, ev); + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, ev); s->tool_motion = false; } press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, like); if (s->tool_wheel) { - struct yasl_pointer_event ev = like; + struct yasl_private_pointer_event ev = like; ev.pos = s->tool_pos; ev.scroll.y = s->tool_wheel; - push_pointer(s, w, YASL_EVENT_POINTER_SCROLL, ev); + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_SCROLL, ev); s->tool_wheel = 0; } } @@ -899,16 +1066,43 @@ static void tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *tool) static void tool_type(void *d, struct zwp_tablet_tool_v2 *t, uint32_t type) { (void)t; - ((struct tablet_tool *)d)->eraser = type == ZWP_TABLET_TOOL_V2_TYPE_ERASER; + struct tablet_tool *tool = d; + tool->eraser = type == ZWP_TABLET_TOOL_V2_TYPE_ERASER; + switch (type) { + case ZWP_TABLET_TOOL_V2_TYPE_PEN: tool->kind = 1; break; + case ZWP_TABLET_TOOL_V2_TYPE_ERASER: tool->kind = 2; break; + case ZWP_TABLET_TOOL_V2_TYPE_BRUSH: tool->kind = 3; break; + case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH: tool->kind = 4; break; + case ZWP_TABLET_TOOL_V2_TYPE_PENCIL: tool->kind = 5; break; + default: tool->kind = 0; break; + } } -static void tool_hardware_serial(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) { (void)d; (void)t; (void)hi; (void)lo; } +static void tool_hardware_serial(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) +{ (void)t; struct tablet_tool *tool = d; uint64_t id = ((uint64_t)hi << 32) | lo; if (id) tool->tool_id = id; } static void tool_hardware_id_wacom(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) { (void)d; (void)t; (void)hi; (void)lo; } -static void tool_capability(void *d, struct zwp_tablet_tool_v2 *t, uint32_t cap) { (void)d; (void)t; (void)cap; } +static void tool_capability(void *d, struct zwp_tablet_tool_v2 *t, uint32_t cap) +{ + (void)t; + struct tablet_tool *tool = d; + tool->capability_mask |= 1u << cap; + switch (cap) { + case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE: tool->axes_valid |= YASL_PRIVATE_PEN_PRESSURE; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT: tool->axes_valid |= YASL_PRIVATE_PEN_TILT; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION: tool->axes_valid |= YASL_PRIVATE_PEN_ROTATION; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE: tool->axes_valid |= YASL_PRIVATE_PEN_DISTANCE; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER: tool->axes_valid |= YASL_PRIVATE_PEN_TANGENTIAL; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL: tool->axes_valid |= YASL_PRIVATE_PEN_WHEEL; break; + default: break; + } +} static void tool_done(void *d, struct zwp_tablet_tool_v2 *t) { (void)d; (void)t; } -static void tool_distance(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v) { (void)d; (void)t; (void)v; } -static void tool_rotation(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg) { (void)d; (void)t; (void)deg; } -static void tool_slider(void *d, struct zwp_tablet_tool_v2 *t, int32_t pos) { (void)d; (void)t; (void)pos; } +static void tool_distance(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v) +{ (void)t; struct tablet_tool *tool = d; tool->distance = (double)(v > 65535 ? 65535 : v) / 65535.0; tool->axes_valid |= YASL_PRIVATE_PEN_DISTANCE; tool->axes_changed |= YASL_PRIVATE_PEN_DISTANCE; } +static void tool_rotation(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg) +{ (void)t; struct tablet_tool *tool = d; tool->rotation = wl_fixed_to_double(deg); tool->axes_valid |= YASL_PRIVATE_PEN_ROTATION; tool->axes_changed |= YASL_PRIVATE_PEN_ROTATION; } +static void tool_slider(void *d, struct zwp_tablet_tool_v2 *t, int32_t pos) +{ (void)t; struct tablet_tool *tool = d; tool->tangential = pos / 65535.0; if (tool->tangential < -1) tool->tangential = -1; if (tool->tangential > 1) tool->tangential = 1; tool->axes_valid |= YASL_PRIVATE_PEN_TANGENTIAL; tool->axes_changed |= YASL_PRIVATE_PEN_TANGENTIAL; } static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { .type = tool_type, .hardware_serial = tool_hardware_serial, @@ -997,6 +1191,7 @@ static void tablet_seat_tablet_added(void *data, struct zwp_tablet_seat_v2 *tabl struct tablet_device *owned = calloc(1, sizeof(*owned)); if (!owned) { zwp_tablet_v2_destroy(tablet); return; } owned->proxy = tablet; + owned->id = ++s->conn->next_tool_id; owned->next = s->tablet_devices; s->tablet_devices = owned; zwp_tablet_v2_add_listener(tablet, &tablet_listener, s); @@ -1010,6 +1205,7 @@ static void tablet_seat_tool_added(void *data, struct zwp_tablet_seat_v2 *tablet if (!owned) { zwp_tablet_tool_v2_destroy(tool); return; } owned->proxy = tool; owned->seat = s; + owned->tool_id = ++s->conn->next_tool_id; owned->next = s->tablet_tools; s->tablet_tools = owned; zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, owned); @@ -1035,7 +1231,7 @@ static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { static void clipboard_received(const char *text, size_t len, bool uri_list, struct wl_surface *on, uint64_t request_id, - enum yasl_transfer_status status, void *ud) + enum yasl_private_transfer_status status, void *ud) { (void)ud; struct wayland_surface *w = on ? @@ -1043,13 +1239,13 @@ static void clipboard_received(const char *text, size_t len, bool uri_list, if (uri_list) w = surface_root(w); if (!w || w->closed || w->destroyed) return; if (!uri_list) { - yasl_surface_complete_paste(&w->base, request_id, status, text, len); + yasl_private_surface_complete_paste(&w->base, request_id, status, text, len); return; } - if (status != YASL_TRANSFER_OK) return; - struct yasl_event ev = { + if (status != YASL_PRIVATE_TRANSFER_OK) return; + struct yasl_private_event ev = { .surface = &w->base, - .type = uri_list ? YASL_EVENT_DROP : YASL_EVENT_PASTE, + .type = uri_list ? YASL_PRIVATE_EVENT_DROP : YASL_PRIVATE_EVENT_PASTE, .text = { .data = text, .len = len, @@ -1058,14 +1254,14 @@ static void clipboard_received(const char *text, size_t len, bool uri_list, input_queue_push(&w->input, &ev); } -static void clipboard_drag(enum yasl_drag_event ev, struct wl_surface *on, +static void clipboard_drag(enum yasl_private_drag_event ev, struct wl_surface *on, double x, double y, void *ud) { struct seat *s = ud; conn_drag_target(s->conn, ev, on, x, y); } -static void clipboard_drop_hover(enum yasl_drop_event ev, struct wl_surface *on, +static void clipboard_drop_hover(enum yasl_private_drop_event ev, struct wl_surface *on, double x, double y, void *ud) { struct seat *s = ud; @@ -1152,6 +1348,16 @@ static void seat_drop_touch(struct seat *s) } } +void seat_ensure_text_input(struct seat *s) +{ + if (!s || !s->conn->text_input_mgr || s->text_input || !s->proxy) + return; + s->text_input = zwp_text_input_manager_v3_get_text_input( + s->conn->text_input_mgr, s->proxy); + if (s->text_input) + zwp_text_input_v3_add_listener(s->text_input, &text_input_listener, s); +} + static void seat_capabilities(void *data, struct wl_seat *proxy, uint32_t caps) { struct seat *s = data; @@ -1209,11 +1415,7 @@ static void seat_capabilities(void *data, struct wl_seat *proxy, uint32_t caps) zwp_tablet_seat_v2_add_listener(s->tablet_seat, &tablet_seat_listener, s); } - if (c->text_input_mgr && !s->text_input) { - s->text_input = zwp_text_input_manager_v3_get_text_input(c->text_input_mgr, proxy); - if (s->text_input) - zwp_text_input_v3_add_listener(s->text_input, &text_input_listener, s); - } + seat_ensure_text_input(s); seat_clipboard_ensure(s); } @@ -1297,8 +1499,8 @@ void seat_destroy(struct seat *s) seat_drop_keyboard(s); struct wayland_surface *left = s->focus_leaving; if (left && !conn_keyboard_on(c, left, NULL)) { - struct yasl_event ev = { - .type = YASL_EVENT_FOCUS, + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_FOCUS, .surface = &left->base, .focus = { .focused = false }, }; @@ -1306,7 +1508,7 @@ void seat_destroy(struct seat *s) } seat_drop_touch(s); clipboard_destroy(s->clipboard); - if (s->repeat_watch > 0) yasl_loop_del_fd(c->loop, s->repeat_watch); + if (s->repeat_watch > 0) yasl_private_loop_del_fd(c->loop, s->repeat_watch); if (s->repeat_fd >= 0) close(s->repeat_fd); if (s->cursor_viewport) wp_viewport_destroy(s->cursor_viewport); if (s->cursor_surface) wl_surface_destroy(s->cursor_surface); diff --git a/src/platform/wayland/popup.c b/src/platform/wayland/popup.c index 44c7206..c563eb4 100644 --- a/src/platform/wayland/popup.c +++ b/src/platform/wayland/popup.c @@ -24,9 +24,19 @@ static const struct xdg_popup_listener popup_listener = { }; static bool popup_spec_valid(const struct wayland_surface *parent, - const struct yasl_popup_spec *spec) + const struct yasl_private_popup_spec *spec) { if (!parent || !spec) return false; + if (spec->positioner_explicit && + (spec->anchor_edges > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT || + spec->gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT || + (spec->constraints & ~(unsigned)(XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)))) + return false; int64_t x = (int64_t)spec->anchor.x - parent->content.x; int64_t y = (int64_t)spec->anchor.y - parent->content.y; return x >= INT_MIN && x <= INT_MAX && y >= INT_MIN && y <= INT_MAX && @@ -37,29 +47,29 @@ static bool popup_spec_valid(const struct wayland_surface *parent, (int64_t)spec->content_offset.y + spec->content_size.y <= spec->size.y; } -static bool popup_apply_spec(struct wayland_surface *w, const struct yasl_popup_spec *spec) +static bool popup_apply_spec(struct wayland_surface *w, const struct yasl_private_popup_spec *spec) { uint32_t scale = w->parent->scale_120; - struct yasl_vector2i logical = { - .x = (int)(((int64_t)spec->size.x * YASL_SCALE_UNIT + scale - 1) / scale), - .y = (int)(((int64_t)spec->size.y * YASL_SCALE_UNIT + scale - 1) / scale), + struct yasl_private_vector2i logical = { + .x = (int)(((int64_t)spec->size.x * YASL_PRIVATE_SCALE_UNIT + scale - 1) / scale), + .y = (int)(((int64_t)spec->size.y * YASL_PRIVATE_SCALE_UNIT + scale - 1) / scale), }; int width = device_px(logical.x, scale); int height = device_px(logical.y, scale); size_t bytes; if (logical.x <= 0 || logical.y <= 0 || !buffer_size(width, height, &bytes)) return false; - struct yasl_vector2i content = spec->content_size; + struct yasl_private_vector2i content = spec->content_size; if (!content.x) content.x = spec->size.x - spec->content_offset.x; if (!content.y) content.y = spec->size.y - spec->content_offset.y; bool rescaled = scale != w->scale_120; w->scale_120 = w->pending_scale_120 = scale; - w->scale_factor = (double)scale / YASL_SCALE_UNIT; + w->scale_factor = (double)scale / YASL_PRIVATE_SCALE_UNIT; w->width = width; w->height = height; w->logical_width = logical.x; w->logical_height = logical.y; - w->content = (struct yasl_rect2i){ + w->content = (struct yasl_private_rect2i){ .x = spec->content_offset.x, .y = spec->content_offset.y, .width = content.x, .height = content.y }; @@ -67,20 +77,20 @@ static bool popup_apply_spec(struct wayland_surface *w, const struct yasl_popup_ w->buffers[i].presented = false; if (w->viewport) wp_viewport_set_destination(w->viewport, logical.x, logical.y); - else if ((rescaled || !w->configured) && scale % YASL_SCALE_UNIT == 0 && + else if ((rescaled || !w->configured) && scale % YASL_PRIVATE_SCALE_UNIT == 0 && wl_proxy_get_version((struct wl_proxy *)w->surface) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) - wl_surface_set_buffer_scale(w->surface, (int32_t)(scale / YASL_SCALE_UNIT)); + wl_surface_set_buffer_scale(w->surface, (int32_t)(scale / YASL_PRIVATE_SCALE_UNIT)); return true; } static void popup_set_geometry(struct wayland_surface *w) { uint32_t scale = w->scale_120; - int gx = yasl_scale_to_logical(w->content.x, scale); - int gy = yasl_scale_to_logical(w->content.y, scale); - int gw = yasl_scale_to_logical(w->content.width, scale); - int gh = yasl_scale_to_logical(w->content.height, scale); + int gx = yasl_private_scale_to_logical(w->content.x, scale); + int gy = yasl_private_scale_to_logical(w->content.y, scale); + int gw = yasl_private_scale_to_logical(w->content.width, scale); + int gh = yasl_private_scale_to_logical(w->content.height, scale); if (gw < 1) gw = 1; if (gh < 1) gh = 1; if (gx + gw > w->logical_width) @@ -91,41 +101,45 @@ static void popup_set_geometry(struct wayland_surface *w) } static struct xdg_positioner *popup_positioner(struct wayland_surface *w, - const struct yasl_popup_spec *spec) + const struct yasl_private_popup_spec *spec) { struct wayland_surface *parent = w->parent; struct xdg_positioner *pos = xdg_wm_base_create_positioner(w->conn->wm_base); if (!pos) return NULL; uint32_t scale = parent->scale_120; - int gw = yasl_scale_to_logical(w->content.width, scale); - int gh = yasl_scale_to_logical(w->content.height, scale); + int gw = yasl_private_scale_to_logical(w->content.width, scale); + int gh = yasl_private_scale_to_logical(w->content.height, scale); xdg_positioner_set_size(pos, gw > 0 ? gw : 1, gh > 0 ? gh : 1); - struct yasl_vector2i at = { + struct yasl_private_vector2i at = { .x = spec->anchor.x - parent->content.x, .y = spec->anchor.y - parent->content.y, }; - int aw = yasl_scale_to_logical(spec->anchor.width, scale); - int ah = yasl_scale_to_logical(spec->anchor.height, scale); + int aw = yasl_private_scale_to_logical(spec->anchor.width, scale); + int ah = yasl_private_scale_to_logical(spec->anchor.height, scale); xdg_positioner_set_anchor_rect(pos, - yasl_scale_to_logical(at.x, scale), - yasl_scale_to_logical(at.y, scale), + yasl_private_scale_to_logical(at.x, scale), + yasl_private_scale_to_logical(at.y, scale), aw > 0 ? aw : 1, ah > 0 ? ah : 1); - xdg_positioner_set_anchor(pos, spec->beside ? XDG_POSITIONER_ANCHOR_TOP_RIGHT - : XDG_POSITIONER_ANCHOR_TOP_LEFT); - xdg_positioner_set_gravity(pos, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); - xdg_positioner_set_constraint_adjustment(pos, + uint32_t anchor = spec->positioner_explicit ? spec->anchor_edges : + (spec->beside ? XDG_POSITIONER_ANCHOR_TOP_RIGHT : XDG_POSITIONER_ANCHOR_TOP_LEFT); + uint32_t gravity = spec->positioner_explicit ? spec->gravity : + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT; + uint32_t constraints = spec->positioner_explicit ? spec->constraints : XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y; + xdg_positioner_set_anchor(pos, anchor); + xdg_positioner_set_gravity(pos, gravity); + xdg_positioner_set_constraint_adjustment(pos, constraints); if (xdg_positioner_get_version(pos) >= XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION) xdg_positioner_set_reactive(pos); return pos; } struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *parent, - const struct yasl_popup_spec *spec) + const struct yasl_private_popup_spec *spec) { struct wayland_display *c = parent ? parent->conn : NULL; struct seat *seat = c ? (c->active_seat ? c->active_seat : c->seats) : NULL; @@ -137,7 +151,8 @@ struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *par if (!w) return NULL; w->base.display = &c->base; - w->base.state = YASL_STATE_CSD; + w->base.state = YASL_PRIVATE_STATE_CSD; + w->base.presenter = YASL_PRIVATE_PRESENTER_CPU; w->input.leave_ends_press = true; w->conn = c; w->conn_next = c->surfaces; @@ -150,7 +165,7 @@ struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *par if (!w->surface) goto err; w->base.native_handle = w->surface; - w->base.size = (struct yasl_vector2i){spec->size.x, spec->size.y}; + w->base.size = (struct yasl_private_vector2i){spec->size.x, spec->size.y}; w->base.scale_120 = parent->scale_120; wl_surface_set_user_data(w->surface, w); if (surface_init_scaling(w) < 0) @@ -180,13 +195,13 @@ err: return NULL; } -bool wayland_surface_popup_reposition(struct wayland_surface *w, const struct yasl_popup_spec *spec) +bool wayland_surface_popup_reposition(struct wayland_surface *w, const struct yasl_private_popup_spec *spec) { if (!w || !w->popup || w->closed || !w->conn || w->conn->lost || !popup_spec_valid(w->parent, spec) || xdg_popup_get_version(w->popup) < XDG_POPUP_REPOSITION_SINCE_VERSION) return false; - struct yasl_popup_spec old = { + struct yasl_private_popup_spec old = { .size = { .x = w->width, .y = w->height }, .content_offset = { .x = w->content.x, .y = w->content.y }, .content_size = { .x = w->content.width, .y = w->content.height }, diff --git a/src/platform/wayland/shell.c b/src/platform/wayland/shell.c index fc2ce2e..c2578e7 100644 --- a/src/platform/wayland/shell.c +++ b/src/platform/wayland/shell.c @@ -173,7 +173,7 @@ uint32_t conn_output_scale_120(const struct wayland_display *c, uint64_t outputs for (const struct wl_conn_output *o = c->outputs; o; o = o->next) if ((o->mask & outputs) && o->scale > scale) scale = o->scale; - return (uint32_t)scale * YASL_SCALE_UNIT; + return (uint32_t)scale * YASL_PRIVATE_SCALE_UNIT; } static void registry_global(void *data, struct wl_registry *registry, @@ -227,6 +227,8 @@ static void registry_global(void *data, struct wl_registry *registry, } else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) { c->text_input_mgr = wl_registry_bind(registry, name, &zwp_text_input_manager_v3_interface, 1); + for (struct seat *seat = c->seats; seat; seat = seat->next) + seat_ensure_text_input(seat); } else if (strcmp(interface, wp_tearing_control_manager_v1_interface.name) == 0) { c->tearing_mgr = wl_registry_bind(registry, name, &wp_tearing_control_manager_v1_interface, 1); @@ -277,7 +279,7 @@ static void set_state(struct wayland_surface *w, uint32_t state) { if (state == w->base.state) return; w->base.state = state; - yasl_surface_notify_state(&w->base, state); + yasl_private_surface_notify_state(&w->base, state); } static void toplevel_configure(void *data, struct xdg_toplevel *toplevel, @@ -286,21 +288,21 @@ static void toplevel_configure(void *data, struct xdg_toplevel *toplevel, (void)toplevel; struct wayland_surface *w = data; - uint32_t state = w->base.state & ~(YASL_STATE_FULLSCREEN | - YASL_STATE_MAXIMIZED | YASL_STATE_ACTIVATED | - YASL_STATE_SUSPENDED | YASL_STATE_TILED); + uint32_t state = w->base.state & ~(YASL_PRIVATE_STATE_FULLSCREEN | + YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_ACTIVATED | + YASL_PRIVATE_STATE_SUSPENDED | YASL_PRIVATE_STATE_TILED); uint32_t *s; wl_array_for_each(s, states) { switch (*s) { - case XDG_TOPLEVEL_STATE_FULLSCREEN: state |= YASL_STATE_FULLSCREEN; break; - case XDG_TOPLEVEL_STATE_MAXIMIZED: state |= YASL_STATE_MAXIMIZED; break; - case XDG_TOPLEVEL_STATE_ACTIVATED: state |= YASL_STATE_ACTIVATED; break; - case XDG_TOPLEVEL_STATE_SUSPENDED: state |= YASL_STATE_SUSPENDED; break; + case XDG_TOPLEVEL_STATE_FULLSCREEN: state |= YASL_PRIVATE_STATE_FULLSCREEN; break; + case XDG_TOPLEVEL_STATE_MAXIMIZED: state |= YASL_PRIVATE_STATE_MAXIMIZED; break; + case XDG_TOPLEVEL_STATE_ACTIVATED: state |= YASL_PRIVATE_STATE_ACTIVATED; break; + case XDG_TOPLEVEL_STATE_SUSPENDED: state |= YASL_PRIVATE_STATE_SUSPENDED; break; case XDG_TOPLEVEL_STATE_TILED_LEFT: case XDG_TOPLEVEL_STATE_TILED_RIGHT: case XDG_TOPLEVEL_STATE_TILED_TOP: case XDG_TOPLEVEL_STATE_TILED_BOTTOM: - state |= YASL_STATE_TILED; + state |= YASL_PRIVATE_STATE_TILED; break; default: break; } @@ -316,7 +318,7 @@ static void toplevel_close(void *data, struct xdg_toplevel *toplevel) (void)toplevel; struct wayland_surface *w = data; if (w && !w->closed) - yasl_surface_notify_close(&w->base); + yasl_private_surface_notify_close(&w->base); } static void toplevel_configure_bounds(void *data, struct xdg_toplevel *toplevel, @@ -349,11 +351,21 @@ static const struct xdg_toplevel_listener toplevel_listener = { static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) { struct wayland_surface *w = data; - (void)xdg_surface; w->pending_serial = serial; w->has_pending_serial = true; w->size_pending = true; w->configured = true; + /* CPU surfaces acknowledge with their SHM commit. External presenters + * commit through EGL/Vulkan, so apply the configure and acknowledge it + * before renderer code can submit that first native buffer. */ + if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU) { + xdg_surface_ack_configure(xdg_surface, serial); + w->has_pending_serial = false; + if (apply_pending_geometry(w) < 0) { + surface_fail(w); + return; + } + } wayland_surface_schedule_redraw(w); } @@ -368,9 +380,9 @@ static void toplevel_decoration_configure(void *data, struct wayland_surface *w = data; uint32_t state = w->base.state; if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) - state &= ~YASL_STATE_CSD; + state &= ~YASL_PRIVATE_STATE_CSD; else - state |= YASL_STATE_CSD; + state |= YASL_PRIVATE_STATE_CSD; set_state(w, state); } @@ -387,11 +399,11 @@ int surface_init_shell(struct wayland_surface *w, const char *title) if (!w->toplevel) return -1; xdg_toplevel_add_listener(w->toplevel, &toplevel_listener, w); - wayland_surface_set_title(w, title ? title : "yasl_app"); + wayland_surface_set_title(w, title ? title : "yasl_private_app"); - const char *app_id = w->conn->app_id ? w->conn->app_id : "yasl_app"; + const char *app_id = w->conn->app_id ? w->conn->app_id : "yasl_private_app"; xdg_toplevel_set_app_id(w->toplevel, app_id); - xdg_toplevel_set_min_size(w->toplevel, YASL_MIN_LOGICAL_PX, YASL_MIN_LOGICAL_PX); + xdg_toplevel_set_min_size(w->toplevel, YASL_PRIVATE_MIN_LOGICAL_PX, YASL_PRIVATE_MIN_LOGICAL_PX); if (w->conn->decor_mgr) { w->toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration( @@ -400,7 +412,9 @@ int surface_init_shell(struct wayland_surface *w, const char *title) zxdg_toplevel_decoration_v1_add_listener(w->toplevel_decor, &toplevel_decoration_listener, w); zxdg_toplevel_decoration_v1_set_mode(w->toplevel_decor, - ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + (w->base.creation_flags & YASL_PRIVATE_SURFACE_UNDECORATED) + ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE + : ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } return 0; } diff --git a/src/platform/wayland/surface.c b/src/platform/wayland/surface.c index 2e85e2b..31096f4 100644 --- a/src/platform/wayland/surface.c +++ b/src/platform/wayland/surface.c @@ -52,7 +52,7 @@ static void display_lose(struct wayland_display *c) surface_fail(w); } display_leave(c); - yasl_display_notify_event(&c->base, YASL_EVENT_DISPLAY_LOST); + yasl_private_display_notify_event(&c->base, YASL_PRIVATE_EVENT_DISPLAY_LOST); } void surface_fail(struct wayland_surface *w) @@ -60,7 +60,7 @@ void surface_fail(struct wayland_surface *w) if (w->closed) return; w->closed = true; - yasl_surface_notify_close(&w->base); + yasl_private_surface_notify_close(&w->base); } static int display_ready(int fd, short revents, void *ud) @@ -80,7 +80,7 @@ static int display_ready(int fd, short revents, void *ud) if (revents & POLLOUT) { if (wl_display_flush(c->wl) >= 0) { if (c->loop && c->watch > 0) - yasl_loop_set_fd_events(c->loop, c->watch, POLLIN); + yasl_private_loop_set_fd_events(c->loop, c->watch, POLLIN); } else if (errno != EAGAIN) { display_lose(c); } @@ -113,7 +113,7 @@ static bool display_arm(struct wayland_display *c) events |= POLLOUT; } if (c->loop && c->watch > 0) - yasl_loop_set_fd_events(c->loop, c->watch, events); + yasl_private_loop_set_fd_events(c->loop, c->watch, events); return had_pending; } @@ -154,7 +154,7 @@ int wayland_display_dispatch_timeout(struct wayland_display *c, int timeout_ms) int n = 0; if (c->loop) { - n = yasl_loop_step(c->loop, timeout_ms); + n = yasl_private_loop_step(c->loop, timeout_ms); } if (c->reading) { @@ -190,7 +190,7 @@ void wayland_display_flush(struct wayland_display *c) static void display_free(struct wayland_display *c) { conn_drag_end(c); - if (c->loop && c->watch > 0) yasl_loop_del_fd(c->loop, c->watch); + if (c->loop && c->watch > 0) yasl_private_loop_del_fd(c->loop, c->watch); if (c->wl) display_cancel_read(c); while (c->seats) seat_destroy(c->seats); @@ -217,9 +217,12 @@ static void display_free(struct wayland_display *c) if (c->shm) wl_shm_destroy(c->shm); if (c->compositor) wl_compositor_destroy(c->compositor); if (c->registry) wl_registry_destroy(c->registry); +#if YASL_HAS_EGL + if (c->egl_initialized) eglTerminate(c->egl_display); +#endif if (c->wl) wl_display_disconnect(c->wl); if (c->owns_loop && c->loop) { - yasl_loop_destroy(c->loop); + yasl_private_loop_destroy(c->loop); c->loop = NULL; c->base.loop = NULL; } @@ -227,13 +230,13 @@ static void display_free(struct wayland_display *c) free(c); } -struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec) +struct wayland_display *wayland_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec) { struct wayland_display *c = calloc(1, sizeof(*c)); if (!c) return NULL; - c->base.ops = &yasl_wayland_backend; + c->base.ops = &yasl_private_wayland_backend; if (!loop) { - c->loop = yasl_loop_create(); + c->loop = yasl_private_loop_create(); c->owns_loop = true; } else { c->loop = loop; @@ -241,7 +244,7 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc c->base.loop = c->loop; if (!c->loop) goto err; if (spec) { - c->base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_display_cbs){0}; + c->base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_private_display_cbs){0}; c->cbs = &c->base.callbacks; c->ud = spec->ud; if (spec->app_id) c->app_id = strdup(spec->app_id); @@ -251,6 +254,13 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc c->wl = c->xkb_ctx ? wl_display_connect(NULL) : NULL; if (!c->wl) goto err; c->base.native_handle = c->wl; +#if YASL_HAS_EGL + c->egl_display = eglGetDisplay((EGLNativeDisplayType)c->wl); + if (c->egl_display != EGL_NO_DISPLAY) { + EGLint major = 0, minor = 0; + c->egl_initialized = eglInitialize(c->egl_display, &major, &minor) == EGL_TRUE; + } +#endif c->registry = wl_display_get_registry(c->wl); if (!c->registry) goto err; @@ -260,7 +270,7 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc surface_init_cursor(c); if (c->loop) { - c->watch = yasl_loop_add_fd(c->loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c); + c->watch = yasl_private_loop_add_fd(c->loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c); if (c->watch <= 0) { c->watch = 0; goto err; } } if (display_input_init(c) < 0) @@ -282,16 +292,18 @@ void wayland_display_close(struct wayland_display *c) uint32_t wayland_display_caps(const struct wayland_display *c) { if (!c) return 0; - uint32_t caps = YASL_CAP_POPUPS | YASL_CAP_CSD | YASL_CAP_FRAME_PACING; - if (c->tablet_mgr) caps |= YASL_CAP_TABLET; + uint32_t caps = YASL_PRIVATE_CAP_POPUPS | YASL_PRIVATE_CAP_CSD | + YASL_PRIVATE_CAP_FRAME_PACING | YASL_PRIVATE_CAP_NATIVE_GRAPHICS; + if (c->tablet_mgr) caps |= YASL_PRIVATE_CAP_TABLET; + if (c->text_input_mgr) caps |= YASL_PRIVATE_CAP_TEXT_INPUT; struct seat *s = c->active_seat ? c->active_seat : c->seats; const struct wl_data_device *device = s ? clipboard_data_device(s->clipboard) : NULL; if (device && wl_data_device_get_version((struct wl_data_device *)device) >= 3) - caps |= YASL_CAP_DRAG; + caps |= YASL_PRIVATE_CAP_DRAG; if (c->toplevel_drag_mgr) - caps |= YASL_CAP_DRAG_CARRY; + caps |= YASL_PRIVATE_CAP_DRAG_CARRY; if (c->primary_selection_mgr) - caps |= YASL_CAP_PRIMARY_SELECTION; + caps |= YASL_PRIVATE_CAP_PRIMARY_SELECTION; return caps; } @@ -321,15 +333,18 @@ static void conn_unlink(struct wayland_surface *w) } -static bool spec_valid(const struct yasl_window_spec *spec) +static bool spec_valid(const struct yasl_private_window_spec *spec) { size_t bytes; - return spec && spec->size.x > 0 && spec->size.y > 0 && - buffer_size(spec->size.x, spec->size.y, &bytes); + if (!spec || spec->size.x <= 0 || spec->size.y <= 0) + return false; + return spec->external_gpu && !(spec->flags & YASL_PRIVATE_SURFACE_CPU) + ? spec->size.x <= INT32_MAX && spec->size.y <= INT32_MAX + : buffer_size(spec->size.x, spec->size.y, &bytes); } struct wayland_surface *wayland_surface_create_toplevel(struct wayland_display *c, - const struct yasl_window_spec *spec, void *graphics_device) + const struct yasl_private_window_spec *spec, void *graphics_device) { (void)graphics_device; if (!c || c->lost || !spec_valid(spec)) @@ -340,28 +355,35 @@ struct wayland_surface *wayland_surface_create_toplevel(struct wayland_display * if (!w) return NULL; c->depth++; conn_link(c, w); - w->base.state = YASL_STATE_CSD; + w->base.state = YASL_PRIVATE_STATE_CSD; + w->base.creation_flags = spec->flags; + w->base.presenter = (spec->external_gpu && !(spec->flags & YASL_PRIVATE_SURFACE_CPU)) + ? YASL_PRIVATE_PRESENTER_NONE : YASL_PRIVATE_PRESENTER_CPU; wayland_surface_set_callbacks(w, NULL, NULL); - w->cursor = YASL_CURSOR_TEXT; + w->cursor = YASL_PRIVATE_CURSOR_TEXT; w->req_width = width; w->req_height = height; w->logical_width = width; w->logical_height = height; - w->scale_120 = YASL_SCALE_UNIT; - w->pending_scale_120 = YASL_SCALE_UNIT; + w->scale_120 = YASL_PRIVATE_SCALE_UNIT; + w->pending_scale_120 = YASL_PRIVATE_SCALE_UNIT; w->scale_factor = 1.0; w->size_pending = true; w->clock.refresh_ns = c->outputs && c->outputs->refresh_ns - ? c->outputs->refresh_ns : YASL_REFRESH_DEFAULT_NS; + ? c->outputs->refresh_ns : YASL_PRIVATE_REFRESH_DEFAULT_NS; w->surface = wl_compositor_create_surface(c->compositor); if (!w->surface) goto err; w->base.native_handle = w->surface; - w->base.size = (struct yasl_vector2i){width, height}; - w->base.scale_120 = YASL_SCALE_UNIT; + w->base.size = (struct yasl_private_vector2i){width, height}; + w->base.scale_120 = YASL_PRIVATE_SCALE_UNIT; wl_surface_set_user_data(w->surface, w); if (surface_init_scaling(w) < 0) goto err; if (surface_init_shell(w, spec->title) < 0) goto err; + if (spec->flags & YASL_PRIVATE_SURFACE_FIXED_SIZE) { + xdg_toplevel_set_min_size(w->toplevel, width, height); + xdg_toplevel_set_max_size(w->toplevel, width, height); + } w->opaque = spec->fullscreen; if (spec->fullscreen) xdg_toplevel_set_fullscreen(w->toplevel, NULL); @@ -389,10 +411,10 @@ err: return NULL; } -void wayland_surface_set_callbacks(struct wayland_surface *w, const struct yasl_window_cbs *cbs, void *ud) +void wayland_surface_set_callbacks(struct wayland_surface *w, const struct yasl_private_window_cbs *cbs, void *ud) { if (w && !w->closed) { - w->base.callbacks = cbs ? *cbs : (struct yasl_window_cbs){0}; + w->base.callbacks = cbs ? *cbs : (struct yasl_private_window_cbs){0}; w->base.ud = ud; w->cbs = &w->base.callbacks; w->ud = ud; @@ -410,6 +432,15 @@ void wayland_surface_destroy(struct wayland_surface *w) free(w->ime_commit); free(w->ime_shown); if (w->tearing_control) wp_tearing_control_v1_destroy(w->tearing_control); +#if YASL_HAS_EGL + if (w->egl_context) { + if (eglGetCurrentContext() == w->egl_context) + eglMakeCurrent(w->conn->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(w->conn->egl_display, w->egl_context); + } + if (w->egl_surface) eglDestroySurface(w->conn->egl_display, w->egl_surface); + if (w->egl_window) wl_egl_window_destroy(w->egl_window); +#endif if (w->fifo) wp_fifo_v1_destroy(w->fifo); if (w->commit_timer) wp_commit_timer_v1_destroy(w->commit_timer); surface_feedback_destroy(w); @@ -427,7 +458,7 @@ void wayland_surface_destroy(struct wayland_surface *w) } struct wayland_display *c = w->conn; conn_unlink(w); - static const struct yasl_window_cbs no_callbacks = {0}; + static const struct yasl_private_window_cbs no_callbacks = {0}; *w = (struct wayland_surface){ .base = w->base, .conn_next = w->conn_next, @@ -446,16 +477,20 @@ void wayland_surface_destroy(struct wayland_surface *w) void wayland_surface_schedule_redraw(struct wayland_surface *w) { if (!w || w->closed) return; + if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU) { + yasl_private_surface_notify_refresh(&w->base); + return; + } w->want_draw = true; if (w->conn && w->conn->loop) - yasl_loop_kick(w->conn->loop); + yasl_private_loop_kick(w->conn->loop); } -struct yasl_geometry wayland_surface_geometry(const struct wayland_surface *w) +struct yasl_private_geometry wayland_surface_geometry(const struct wayland_surface *w) { - return (struct yasl_geometry){ - .size = w ? (struct yasl_vector2i){w->width, w->height} : (struct yasl_vector2i){0}, - .scale_120 = w ? w->scale_120 : YASL_SCALE_UNIT, + return (struct yasl_private_geometry){ + .size = w ? (struct yasl_private_vector2i){w->width, w->height} : (struct yasl_private_vector2i){0}, + .scale_120 = w ? w->scale_120 : YASL_PRIVATE_SCALE_UNIT, }; } @@ -473,23 +508,23 @@ bool wayland_surface_start_interactive_move(struct wayland_surface *s) return true; } -bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_resize_edge edge) +bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_private_resize_edge edge) { - if (!s || !s->toplevel || !s->conn || edge == YASL_EDGE_NONE) return false; + if (!s || !s->toplevel || !s->conn || edge == YASL_PRIVATE_EDGE_NONE) return false; struct seat *seat = s->conn->active_seat ? s->conn->active_seat : s->conn->seats; if (!seat || !seat->proxy || !seat->press_serial) return false; xdg_toplevel_resize(s->toplevel, seat->proxy, seat->press_serial, (uint32_t)edge); return true; } -bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_vector2i pos) +bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_private_vector2i pos) { if (!s || !s->toplevel || !s->conn) return false; struct seat *seat = s->conn->active_seat ? s->conn->active_seat : s->conn->seats; if (!seat || !seat->proxy || !seat->press_serial) return false; - uint32_t scale = s->scale_120 ? s->scale_120 : YASL_SCALE_UNIT; + uint32_t scale = s->scale_120 ? s->scale_120 : YASL_PRIVATE_SCALE_UNIT; xdg_toplevel_show_window_menu(s->toplevel, seat->proxy, seat->press_serial, - yasl_scale_to_logical(pos.x, scale), - yasl_scale_to_logical(pos.y, scale)); + yasl_private_scale_to_logical(pos.x, scale), + yasl_private_scale_to_logical(pos.y, scale)); return true; } |
