diff options
Diffstat (limited to 'src/platform/wayland/backend.c')
| -rw-r--r-- | src/platform/wayland/backend.c | 236 |
1 files changed, 198 insertions, 38 deletions
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, |
