summaryrefslogtreecommitdiff
path: root/src/platform/wayland/backend.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 23:41:31 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 23:41:31 +0300
commit76073fe5fad8799e5850805f2f090af2cb62c741 (patch)
tree9658019babe4760a3634bdab4da0731a10e42e68 /src/platform/wayland/backend.c
parentdd1775a9927922c14f8679ccbc4d3ca8d5917e20 (diff)
Simplify the public event and CPU API
Applications now need far less ceremony: hello.c is a 20-line loop that handles REFRESH, CLOSE and QUIT and draws into the surface's own pixels. - Fold GEOMETRY, STATE and FOCUS into one WINDOW event carrying size, scale and state; unchanged values send nothing. - Guarantee REFRESH once a window has a size and after every resize, never at size zero. - Merge DROP_HOVER into DROP with over/leave/data actions and give drag and drop actions enums. - Keep event strings valid until the next wait and drop yasl_event_release; empty or failed waits report NONE. - Replace copy-in presentation with a lent pixel buffer: yasl_cpu_pixels and yasl_cpu_present. - Remove yasl_poll_event, yasl_cpu_read_pixels, unused event fields and comments that restated names. - Wayland: resize floating windows in request_size instead of reporting it unsupported, and stop marking new GPU surfaces as Vulkan so yasl_vulkan_create_surface no longer fails with NATIVE_WINDOW_IN_USE. Also includes the in-progress public API refactor that was uncommitted in the tree (removal of the app/loop layer, new surface, GL and Vulkan entry points). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'src/platform/wayland/backend.c')
-rw-r--r--src/platform/wayland/backend.c236
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,