From 795fd34111e1d30fe0460e16ede894418626a5bb Mon Sep 17 00:00:00 2001 From: Rakarake Date: Sun, 22 Feb 2026 17:03:10 +0100 Subject: [PATCH 1/8] egl surfaces created after wayland surface --- wayland.c | 206 +++++++++++++++++++++++++++--------------------------- 1 file changed, 102 insertions(+), 104 deletions(-) diff --git a/wayland.c b/wayland.c index cf40a7c..9317537 100644 --- a/wayland.c +++ b/wayland.c @@ -63,6 +63,105 @@ struct client_state { /// Starting values. int width = 700, height = 700; +static void egl_init(struct client_state *state) { + EGLint config_attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT | EGL_OPENGL_BIT, + EGL_MIN_SWAP_INTERVAL, 0, // make sure that swapping buffers don't block the thread + EGL_NONE + }; + + static const EGLint context_attribs[] = { + //EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_MAJOR_VERSION, 4, + EGL_CONTEXT_MINOR_VERSION, 6, + EGL_CONTEXT_OPENGL_PROFILE_MASK, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + EGL_NONE + }; + + state->egl_display = eglGetDisplay((EGLNativeDisplayType) state->wl_display); + + if (state->egl_display == EGL_NO_DISPLAY) { + fprintf(stderr, "Can't create egl display\n"); + exit(1); + } else { + fprintf(stderr, "Created egl display\n"); + } + + EGLint major, minor; + if (eglInitialize(state->egl_display, &major, &minor) != EGL_TRUE) { + fprintf(stderr, "Can't initialise egl display\n"); + exit(1); + } + printf("EGL major: %d, minor %d\n", major, minor); + + // Desktop GL? + if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) { + printf("eglBindAPI failed\n"); + exit(1); + } + + EGLint count; + eglGetConfigs(state->egl_display, NULL, 0, &count); + printf("EGL has %d configs\n", count); + + EGLConfig *configs = calloc(count, sizeof *configs); + + EGLint n; + eglChooseConfig(state->egl_display, config_attribs, + configs, count, &n); + + for (int i = 0; i < n; i++) { + EGLint size; + eglGetConfigAttrib(state->egl_display, + configs[i], EGL_BUFFER_SIZE, &size); + printf("Buffer size for config %d is %d\n", i, size); + eglGetConfigAttrib(state->egl_display, + configs[i], EGL_RED_SIZE, &size); + printf("Red size for config %d is %d\n", i, size); + // just choose the first one + state->egl_config = configs[i]; + break; + } + + state->egl_context = + eglCreateContext(state->egl_display, + state->egl_config, + EGL_NO_CONTEXT, context_attribs); + if (state->egl_context == EGL_NO_CONTEXT) { + printf("Failed to create EGL context\n"); + exit(1); + } +} + +void egl_init_surface(struct client_state *state, struct surface *surface) { + printf("Creating egl window of size: %dx%d\n", surface->width, surface->height); + surface->egl_window = wl_egl_window_create(surface->wl_surface, + surface->width, surface->height); + if (surface->egl_window == EGL_NO_SURFACE) { + fprintf(stderr, "Can't create egl window\n"); + exit(1); + } else { + fprintf(stderr, "Created egl window\n"); + } + + surface->egl_surface = + eglCreateWindowSurface(state->egl_display, + state->egl_config, + (unsigned long) surface->egl_window, NULL); + + if (eglMakeCurrent(state->egl_display, surface->egl_surface, + surface->egl_surface, state->egl_context)) { + fprintf(stderr, "Made current\n"); + } else { + fprintf(stderr, "Made current failed\n"); + } +} + static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer) { /* Sent by the compositor when it's no longer using this buffer */ wl_buffer_destroy(wl_buffer); @@ -291,6 +390,7 @@ static void registry_handle_global( // frame callback struct wl_callback *cb = wl_surface_frame(wl_surface); wl_callback_add_listener(cb, &wl_surface_frame_listener, &state->surface_list->data); + egl_init_surface(state, &state->surface_list->data); } if ((strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) && (state->output_type == OUTPUT_LAYER)) { state->zwlr_layer_shell_v1 = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 4); @@ -343,6 +443,7 @@ static void registry_handle_global( // frame callback struct wl_callback *cb = wl_surface_frame(wl_surface); wl_callback_add_listener(cb, &wl_surface_frame_listener, surface_location); + egl_init_surface(state, surface_location); } } @@ -359,109 +460,6 @@ static const struct wl_registry_listener wl_registry_listener = { .global_remove = registry_handle_global_remove, }; -static void egl_init(struct client_state *state) { - EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT | EGL_OPENGL_BIT, - EGL_MIN_SWAP_INTERVAL, 0, // make sure that swapping buffers don't block the thread - EGL_NONE - }; - - static const EGLint context_attribs[] = { - //EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_CONTEXT_MAJOR_VERSION, 4, - EGL_CONTEXT_MINOR_VERSION, 6, - EGL_CONTEXT_OPENGL_PROFILE_MASK, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - EGL_NONE - }; - - state->egl_display = eglGetDisplay((EGLNativeDisplayType) state->wl_display); - - if (state->egl_display == EGL_NO_DISPLAY) { - fprintf(stderr, "Can't create egl display\n"); - exit(1); - } else { - fprintf(stderr, "Created egl display\n"); - } - - EGLint major, minor; - if (eglInitialize(state->egl_display, &major, &minor) != EGL_TRUE) { - fprintf(stderr, "Can't initialise egl display\n"); - exit(1); - } - printf("EGL major: %d, minor %d\n", major, minor); - - // Desktop GL? - if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) { - printf("eglBindAPI failed\n"); - exit(1); - } - - EGLint count; - eglGetConfigs(state->egl_display, NULL, 0, &count); - printf("EGL has %d configs\n", count); - - EGLConfig *configs = calloc(count, sizeof *configs); - - EGLint n; - eglChooseConfig(state->egl_display, config_attribs, - configs, count, &n); - - for (int i = 0; i < n; i++) { - EGLint size; - eglGetConfigAttrib(state->egl_display, - configs[i], EGL_BUFFER_SIZE, &size); - printf("Buffer size for config %d is %d\n", i, size); - eglGetConfigAttrib(state->egl_display, - configs[i], EGL_RED_SIZE, &size); - printf("Red size for config %d is %d\n", i, size); - // just choose the first one - state->egl_config = configs[i]; - break; - } - - state->egl_context = - eglCreateContext(state->egl_display, - state->egl_config, - EGL_NO_CONTEXT, context_attribs); - if (state->egl_context == EGL_NO_CONTEXT) { - printf("Failed to create EGL context\n"); - exit(1); - } - - // EGL window - struct surface_list *next = state->surface_list; - while (next != NULL) { - printf("Creating egl window of size: %dx%d\n", next->data.width, next->data.height); - next->data.egl_window = wl_egl_window_create(next->data.wl_surface, - next->data.width, next->data.height); - if (next->data.egl_window == EGL_NO_SURFACE) { - fprintf(stderr, "Can't create egl window\n"); - exit(1); - } else { - fprintf(stderr, "Created egl window\n"); - } - - next->data.egl_surface = - eglCreateWindowSurface(state->egl_display, - state->egl_config, - (unsigned long) next->data.egl_window, NULL); - - if (eglMakeCurrent(state->egl_display, next->data.egl_surface, - next->data.egl_surface, state->egl_context)) { - fprintf(stderr, "Made current\n"); - } else { - fprintf(stderr, "Made current failed\n"); - } - - next = next->next; - } -} - /// Initializes wayland and creates an opengl context struct client_state* wayland_init(int output_type) { struct client_state *state = malloc(sizeof(struct client_state)); @@ -471,6 +469,7 @@ struct client_state* wayland_init(int output_type) { state->wl_registry = wl_display_get_registry(state->wl_display); state->surface_list = NULL; state->surface_list_next = NULL; + egl_init(state); wl_registry_add_listener(state->wl_registry, &wl_registry_listener, state); wl_display_roundtrip(state->wl_display); @@ -482,7 +481,6 @@ struct client_state* wayland_init(int output_type) { next = next->next; } - egl_init(state); return state; } From de525136e730ef2622593dcbfb952bbc79ee08c0 Mon Sep 17 00:00:00 2001 From: Rakarake Date: Sun, 22 Feb 2026 17:31:31 +0100 Subject: [PATCH 2/8] nice refactor --- wayland.c | 167 +++++++++++++++++++++++++++++------------------------- 1 file changed, 90 insertions(+), 77 deletions(-) diff --git a/wayland.c b/wayland.c index 9317537..80a16f6 100644 --- a/wayland.c +++ b/wayland.c @@ -319,6 +319,87 @@ const struct wl_pointer_listener wl_pointer_listener = { .axis = pointer_axis_handler }; +/// Creates a toplevel surface, and adds it as the only surface in the surface +/// list (TODO this is bad, make it generic - add it to the list instead). +void xdg_tolevel_new(struct client_state *state) { + // create window + struct wl_surface *wl_surface = wl_compositor_create_surface(state->wl_compositor); + struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface( + state->xdg_wm_base, wl_surface); + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, state); + struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); + xdg_toplevel_set_title(xdg_toplevel, "GLONKERS! 🕴️"); + xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, state); + + // save all the pointers + struct surface surface = { + .wl_surface = wl_surface, + .xdg_surface = xdg_surface, + .xdg_toplevel = xdg_toplevel, + .dirty = false, + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + }; + state->surface_list = malloc(sizeof(struct surface_list)); + state->surface_list->data = surface; + state->surface_list->next = NULL; + + // frame callback + struct wl_callback *cb = wl_surface_frame(wl_surface); + wl_callback_add_listener(cb, &wl_surface_frame_listener, &state->surface_list->data); + egl_init_surface(state, &state->surface_list->data); + wl_surface_commit(wl_surface); +} + +void layer_new(struct client_state *state, struct wl_output *wl_output) { + struct wl_surface *wl_surface = wl_compositor_create_surface(state->wl_compositor); + + // wlr_layer_shell + int layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; + struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1 = + zwlr_layer_shell_v1_get_layer_surface( + state->zwlr_layer_shell_v1, + wl_surface, + wl_output, + layer, + "wallpaper" + ); + zwlr_layer_surface_v1_set_anchor(zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP + | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); + zwlr_layer_surface_v1_set_size(zwlr_layer_surface_v1, 0, 0); + zwlr_layer_surface_v1_add_listener(zwlr_layer_surface_v1, &zwlr_layer_surface_v1_listener, state); + + struct surface surface = { + .wl_surface = wl_surface, + .zwlr_layer_surface_v1 = zwlr_layer_surface_v1, + .dirty = false, + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + }; + // persistent pointer for the callback + struct surface *surface_location; + if (state->surface_list == NULL) { + state->surface_list = malloc(sizeof(struct surface_list)); + state->surface_list->data = surface; + state->surface_list->next = NULL; + surface_location = &state->surface_list->data; + } else { + struct surface_list *next = state->surface_list; + while (next->next != NULL) { next = next->next; } + next->next = malloc(sizeof(struct surface_list)); + next->next->data = surface; + next->next->next = NULL; + surface_location = &next->next->data; + } + + // frame callback + struct wl_callback *cb = wl_surface_frame(wl_surface); + wl_callback_add_listener(cb, &wl_surface_frame_listener, surface_location); + egl_init_surface(state, surface_location); + wl_surface_commit(wl_surface); +} + static void registry_handle_global( void *data, struct wl_registry *registry, @@ -364,33 +445,6 @@ static void registry_handle_global( registry, name, &xdg_wm_base_interface, 1); xdg_wm_base_add_listener(state->xdg_wm_base, &xdg_wm_base_listener, state); - - // create window - struct wl_surface *wl_surface = wl_compositor_create_surface(state->wl_compositor); - struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface( - state->xdg_wm_base, wl_surface); - xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, state); - struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); - xdg_toplevel_set_title(xdg_toplevel, "GLONKERS! 🕴️"); - xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, state); - - // save all the pointers - struct surface surface = { - .wl_surface = wl_surface, - .xdg_surface = xdg_surface, - .xdg_toplevel = xdg_toplevel, - .dirty = false, - .width = DEFAULT_WIDTH, - .height = DEFAULT_HEIGHT, - }; - state->surface_list = malloc(sizeof(struct surface_list)); - state->surface_list->data = surface; - state->surface_list->next = NULL; - - // frame callback - struct wl_callback *cb = wl_surface_frame(wl_surface); - wl_callback_add_listener(cb, &wl_surface_frame_listener, &state->surface_list->data); - egl_init_surface(state, &state->surface_list->data); } if ((strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) && (state->output_type == OUTPUT_LAYER)) { state->zwlr_layer_shell_v1 = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 4); @@ -398,52 +452,7 @@ static void registry_handle_global( if (strcmp(interface, wl_output_interface.name) == 0 && state->output_type == OUTPUT_LAYER) { struct wl_output *wl_output = wl_registry_bind( registry, name, &wl_output_interface, 4); - - struct wl_surface *wl_surface = wl_compositor_create_surface(state->wl_compositor); - - // wlr_layer_shell - int layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; - struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1 = - zwlr_layer_shell_v1_get_layer_surface( - state->zwlr_layer_shell_v1, - wl_surface, - wl_output, - layer, - "wallpaper" - ); - zwlr_layer_surface_v1_set_anchor(zwlr_layer_surface_v1, - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); - zwlr_layer_surface_v1_set_size(zwlr_layer_surface_v1, 0, 0); - zwlr_layer_surface_v1_add_listener(zwlr_layer_surface_v1, &zwlr_layer_surface_v1_listener, state); - - struct surface surface = { - .wl_surface = wl_surface, - .zwlr_layer_surface_v1 = zwlr_layer_surface_v1, - .dirty = false, - .width = DEFAULT_WIDTH, - .height = DEFAULT_HEIGHT, - }; - // persistent pointer for the callback - struct surface *surface_location; - if (state->surface_list == NULL) { - state->surface_list = malloc(sizeof(struct surface_list)); - state->surface_list->data = surface; - state->surface_list->next = NULL; - surface_location = &state->surface_list->data; - } else { - struct surface_list *next = state->surface_list; - while (next->next != NULL) { next = next->next; } - next->next = malloc(sizeof(struct surface_list)); - next->next->data = surface; - next->next->next = NULL; - surface_location = &next->next->data; - } - - // frame callback - struct wl_callback *cb = wl_surface_frame(wl_surface); - wl_callback_add_listener(cb, &wl_surface_frame_listener, surface_location); - egl_init_surface(state, surface_location); + layer_new(state, wl_output); } } @@ -475,10 +484,14 @@ struct client_state* wayland_init(int output_type) { wl_seat_get_pointer(state->wl_seat); - struct surface_list *next = state->surface_list; - while (next != NULL) { - wl_surface_commit(next->data.wl_surface); - next = next->next; + //struct surface_list *next = state->surface_list; + //while (next != NULL) { + // wl_surface_commit(next->data.wl_surface); + // next = next->next; + //} + + if (state->output_type == OUTPUT_WINDOW) { + xdg_tolevel_new(state); } return state; From e0776cf8e088f61ca109ae4881f34eb8898bb69f Mon Sep 17 00:00:00 2001 From: Rakarake Date: Sun, 22 Feb 2026 17:42:12 +0100 Subject: [PATCH 3/8] boilerplate for wl_output --- wayland.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/wayland.c b/wayland.c index 80a16f6..0fb2750 100644 --- a/wayland.c +++ b/wayland.c @@ -162,6 +162,40 @@ void egl_init_surface(struct client_state *state, struct surface *surface) { } } +static void wl_output_name(void *data, struct wl_output *wl_output, const char *name) { + printf("output name: %s\n", name); +} + +static void wl_output_description(void *data, struct wl_output *wl_output, const char *description) { +} +static void wl_output_done(void *data, struct wl_output *wl_output) { +} +static void wl_output_geometry( + void *data, struct wl_output *wl_output, + int x, + int y, + int physical_width, + int physical_height, + int subpixel, + const char *make, + const char *model, + int transform + ) { +} +static void wl_output_mode(void *data, struct wl_output *wl_output, unsigned int mode, int width, int height, int refresh) { +} +static void wl_output_scale(void *data, struct wl_output *wl_output, int factor) { +} + +static const struct wl_output_listener wl_output_listener = { + .description = wl_output_description, + .done = wl_output_done, + .geometry = wl_output_geometry, + .mode = wl_output_mode, + .name = wl_output_name, + .scale = wl_output_scale, +}; + static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer) { /* Sent by the compositor when it's no longer using this buffer */ wl_buffer_destroy(wl_buffer); @@ -452,6 +486,7 @@ static void registry_handle_global( if (strcmp(interface, wl_output_interface.name) == 0 && state->output_type == OUTPUT_LAYER) { struct wl_output *wl_output = wl_registry_bind( registry, name, &wl_output_interface, 4); + wl_output_add_listener(wl_output, &wl_output_listener, state); layer_new(state, wl_output); } } From ace849747817af24c6c94717223d5e2d5bf4d87f Mon Sep 17 00:00:00 2001 From: Rakarake Date: Sun, 22 Feb 2026 17:56:44 +0100 Subject: [PATCH 4/8] creating layers after output name event works --- wayland.c | 186 ++++++++++++++++++++++++++---------------------------- 1 file changed, 91 insertions(+), 95 deletions(-) diff --git a/wayland.c b/wayland.c index 0fb2750..4fe4c7e 100644 --- a/wayland.c +++ b/wayland.c @@ -162,8 +162,99 @@ void egl_init_surface(struct client_state *state, struct surface *surface) { } } +static const struct wl_callback_listener wl_surface_frame_listener; + +static void +wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { + struct surface *surface = data; + surface->time = time; + + /* Destroy this callback */ + wl_callback_destroy(cb); + + surface->dirty = true; +} + +static const struct wl_callback_listener wl_surface_frame_listener = { + .done = wl_surface_frame_done, +}; + +static void zwlr_layer_surface_v1_configure(void *data, struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t serial, uint32_t width, uint32_t height) { + struct client_state *state = data; + struct surface_list *next = state->surface_list; + while (next->data.zwlr_layer_surface_v1 != zwlr_layer_surface_v1) { next = next->next; } + next->data.width = width; + next->data.height = height; + wl_egl_window_resize(next->data.egl_window, width, height, 0, 0); + zwlr_layer_surface_v1_ack_configure(zwlr_layer_surface_v1, serial); + // draw new frame! + next->data.dirty = true; +} + +static void zwlr_layer_surface_v1_closed(void *data, struct zwlr_layer_surface_v1 * zwlr_layer_surface_v1) { + struct client_state *state = data; + state->running = 0; +} + +static const struct zwlr_layer_surface_v1_listener zwlr_layer_surface_v1_listener = { + .configure = zwlr_layer_surface_v1_configure, + .closed = zwlr_layer_surface_v1_closed, +}; + +void layer_new(struct client_state *state, struct wl_output *wl_output) { + struct wl_surface *wl_surface = wl_compositor_create_surface(state->wl_compositor); + + // wlr_layer_shell + int layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; + struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1 = + zwlr_layer_shell_v1_get_layer_surface( + state->zwlr_layer_shell_v1, + wl_surface, + wl_output, + layer, + "wallpaper" + ); + zwlr_layer_surface_v1_set_anchor(zwlr_layer_surface_v1, + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP + | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); + zwlr_layer_surface_v1_set_size(zwlr_layer_surface_v1, 0, 0); + zwlr_layer_surface_v1_add_listener(zwlr_layer_surface_v1, &zwlr_layer_surface_v1_listener, state); + + struct surface surface = { + .wl_surface = wl_surface, + .zwlr_layer_surface_v1 = zwlr_layer_surface_v1, + .dirty = false, + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + }; + // persistent pointer for the callback + struct surface *surface_location; + if (state->surface_list == NULL) { + state->surface_list = malloc(sizeof(struct surface_list)); + state->surface_list->data = surface; + state->surface_list->next = NULL; + surface_location = &state->surface_list->data; + } else { + struct surface_list *next = state->surface_list; + while (next->next != NULL) { next = next->next; } + next->next = malloc(sizeof(struct surface_list)); + next->next->data = surface; + next->next->next = NULL; + surface_location = &next->next->data; + } + + // frame callback + struct wl_callback *cb = wl_surface_frame(wl_surface); + wl_callback_add_listener(cb, &wl_surface_frame_listener, surface_location); + egl_init_surface(state, surface_location); + wl_surface_commit(wl_surface); +} + + static void wl_output_name(void *data, struct wl_output *wl_output, const char *name) { + struct client_state *state = data; printf("output name: %s\n", name); + layer_new(state, wl_output); } static void wl_output_description(void *data, struct wl_output *wl_output, const char *description) { @@ -260,45 +351,6 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = { .wm_capabilities = xdg_toplevel_wm_capabilities, }; -static void zwlr_layer_surface_v1_configure(void *data, struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t serial, uint32_t width, uint32_t height) { - struct client_state *state = data; - struct surface_list *next = state->surface_list; - while (next->data.zwlr_layer_surface_v1 != zwlr_layer_surface_v1) { next = next->next; } - next->data.width = width; - next->data.height = height; - wl_egl_window_resize(next->data.egl_window, width, height, 0, 0); - zwlr_layer_surface_v1_ack_configure(zwlr_layer_surface_v1, serial); - // draw new frame! - next->data.dirty = true; -} - -static void zwlr_layer_surface_v1_closed(void *data, struct zwlr_layer_surface_v1 * zwlr_layer_surface_v1) { - struct client_state *state = data; - state->running = 0; -} - -static const struct zwlr_layer_surface_v1_listener zwlr_layer_surface_v1_listener = { - .configure = zwlr_layer_surface_v1_configure, - .closed = zwlr_layer_surface_v1_closed, -}; - -static const struct wl_callback_listener wl_surface_frame_listener; - -static void -wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { - struct surface *surface = data; - surface->time = time; - - /* Destroy this callback */ - wl_callback_destroy(cb); - - surface->dirty = true; -} - -static const struct wl_callback_listener wl_surface_frame_listener = { - .done = wl_surface_frame_done, -}; - void pointer_enter_handler ( void *data, struct wl_pointer *pointer, @@ -385,55 +437,6 @@ void xdg_tolevel_new(struct client_state *state) { wl_surface_commit(wl_surface); } -void layer_new(struct client_state *state, struct wl_output *wl_output) { - struct wl_surface *wl_surface = wl_compositor_create_surface(state->wl_compositor); - - // wlr_layer_shell - int layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; - struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1 = - zwlr_layer_shell_v1_get_layer_surface( - state->zwlr_layer_shell_v1, - wl_surface, - wl_output, - layer, - "wallpaper" - ); - zwlr_layer_surface_v1_set_anchor(zwlr_layer_surface_v1, - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); - zwlr_layer_surface_v1_set_size(zwlr_layer_surface_v1, 0, 0); - zwlr_layer_surface_v1_add_listener(zwlr_layer_surface_v1, &zwlr_layer_surface_v1_listener, state); - - struct surface surface = { - .wl_surface = wl_surface, - .zwlr_layer_surface_v1 = zwlr_layer_surface_v1, - .dirty = false, - .width = DEFAULT_WIDTH, - .height = DEFAULT_HEIGHT, - }; - // persistent pointer for the callback - struct surface *surface_location; - if (state->surface_list == NULL) { - state->surface_list = malloc(sizeof(struct surface_list)); - state->surface_list->data = surface; - state->surface_list->next = NULL; - surface_location = &state->surface_list->data; - } else { - struct surface_list *next = state->surface_list; - while (next->next != NULL) { next = next->next; } - next->next = malloc(sizeof(struct surface_list)); - next->next->data = surface; - next->next->next = NULL; - surface_location = &next->next->data; - } - - // frame callback - struct wl_callback *cb = wl_surface_frame(wl_surface); - wl_callback_add_listener(cb, &wl_surface_frame_listener, surface_location); - egl_init_surface(state, surface_location); - wl_surface_commit(wl_surface); -} - static void registry_handle_global( void *data, struct wl_registry *registry, @@ -487,7 +490,6 @@ static void registry_handle_global( struct wl_output *wl_output = wl_registry_bind( registry, name, &wl_output_interface, 4); wl_output_add_listener(wl_output, &wl_output_listener, state); - layer_new(state, wl_output); } } @@ -519,12 +521,6 @@ struct client_state* wayland_init(int output_type) { wl_seat_get_pointer(state->wl_seat); - //struct surface_list *next = state->surface_list; - //while (next != NULL) { - // wl_surface_commit(next->data.wl_surface); - // next = next->next; - //} - if (state->output_type == OUTPUT_WINDOW) { xdg_tolevel_new(state); } From 24de6d41333ceeb3a6c20465c67d32becf31f928 Mon Sep 17 00:00:00 2001 From: Rakarake Date: Sun, 22 Feb 2026 18:08:24 +0100 Subject: [PATCH 5/8] parsing output arguments --- glonkers.c | 19 +++++++++++++++++-- wayland.c | 2 +- wayland.h | 3 ++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/glonkers.c b/glonkers.c index 2acd567..8693fa5 100644 --- a/glonkers.c +++ b/glonkers.c @@ -14,15 +14,30 @@ int main(int argc, char *argv[]) { char *shader_path = NULL; int output_type = OUTPUT_WINDOW; + bool currently_reading_output = false; + char **output_list = NULL; + int output_count = 0; // syntax: --window for a normal window or --layer for a wallpaper for (int i = 1; i < argc; i++) { if (strcmp("--window", argv[i]) == 0) { output_type = OUTPUT_WINDOW; + currently_reading_output = false; } else if (strcmp("--layer", argv[i]) == 0) { output_type = OUTPUT_LAYER; + currently_reading_output = false; } - else { + else if (strcmp("--output", argv[i]) == 0) { + output_list = &argv[i]; + currently_reading_output = true; + } + else if (strcmp("--", argv[i]) == 0) { + currently_reading_output = false; + } + else if (currently_reading_output) { + output_count++; + } + else if (!currently_reading_output) { // path to fragment shader if (shader_path != NULL) { fprintf(stderr, "tried supplying '%s' as a shader file while one has already been selected\n", argv[i]); @@ -36,7 +51,7 @@ int main(int argc, char *argv[]) { return 1; } - struct client_state *state = wayland_init(output_type); + struct client_state *state = wayland_init(output_type, output_list, output_count); Renderer renderer = new_renderer(); diff --git a/wayland.c b/wayland.c index 4fe4c7e..d2b2fba 100644 --- a/wayland.c +++ b/wayland.c @@ -507,7 +507,7 @@ static const struct wl_registry_listener wl_registry_listener = { }; /// Initializes wayland and creates an opengl context -struct client_state* wayland_init(int output_type) { +struct client_state* wayland_init(int output_type, char *output_list[], int output_list_len) { struct client_state *state = malloc(sizeof(struct client_state)); state->running = 1; state->output_type = output_type; diff --git a/wayland.h b/wayland.h index 8639a30..21e7e57 100644 --- a/wayland.h +++ b/wayland.h @@ -31,7 +31,8 @@ struct event { } data; }; -struct client_state* wayland_init(int output_type); +/// output_list: if not NULL, only select outputs should be drawn to +struct client_state* wayland_init(int output_type, char *output_list[], int output_list_len); void commit(struct client_state *state); struct event wait_for_event(struct client_state *state); void swap_buffers(struct client_state *state, struct surface *surface); From 71f458b7f204662b878f2cf580076d99fc5b295e Mon Sep 17 00:00:00 2001 From: Rakarake Date: Sun, 22 Feb 2026 18:13:04 +0100 Subject: [PATCH 6/8] fixes --- glonkers.c | 5 +++-- wayland.c | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/glonkers.c b/glonkers.c index 8693fa5..28dd566 100644 --- a/glonkers.c +++ b/glonkers.c @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) { int output_type = OUTPUT_WINDOW; bool currently_reading_output = false; char **output_list = NULL; - int output_count = 0; + int output_count; // syntax: --window for a normal window or --layer for a wallpaper for (int i = 1; i < argc; i++) { if (strcmp("--window", argv[i]) == 0) { @@ -28,7 +28,8 @@ int main(int argc, char *argv[]) { currently_reading_output = false; } else if (strcmp("--output", argv[i]) == 0) { - output_list = &argv[i]; + output_count = 0; + output_list = &argv[i + 1]; currently_reading_output = true; } else if (strcmp("--", argv[i]) == 0) { diff --git a/wayland.c b/wayland.c index d2b2fba..26a4a08 100644 --- a/wayland.c +++ b/wayland.c @@ -508,6 +508,9 @@ static const struct wl_registry_listener wl_registry_listener = { /// Initializes wayland and creates an opengl context struct client_state* wayland_init(int output_type, char *output_list[], int output_list_len) { + for (int i = 0; i < output_list_len; i++) { + printf("output name selected: %s\n", output_list[i]); + } struct client_state *state = malloc(sizeof(struct client_state)); state->running = 1; state->output_type = output_type; From ba7b581b4d0645a693e6b19c558842174724e0f7 Mon Sep 17 00:00:00 2001 From: Rakarake Date: Sun, 22 Feb 2026 18:27:20 +0100 Subject: [PATCH 7/8] can now specify montor --- wayland.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/wayland.c b/wayland.c index 26a4a08..19d1432 100644 --- a/wayland.c +++ b/wayland.c @@ -36,6 +36,9 @@ struct surface_list { struct client_state { bool running; int output_type; + /// Names of enabled outputs, or NULL for every output. + char **output_list; + int output_list_len; /* Globals */ struct wl_display *wl_display; struct wl_registry *wl_registry; @@ -254,7 +257,15 @@ void layer_new(struct client_state *state, struct wl_output *wl_output) { static void wl_output_name(void *data, struct wl_output *wl_output, const char *name) { struct client_state *state = data; printf("output name: %s\n", name); - layer_new(state, wl_output); + if (state->output_list != NULL) { + for (int i = 0; i < state->output_list_len; i++) { + if (strcmp(state->output_list[i], name) == 0) { + layer_new(state, wl_output); + } + } + } else { + layer_new(state, wl_output); + } } static void wl_output_description(void *data, struct wl_output *wl_output, const char *description) { @@ -508,10 +519,14 @@ static const struct wl_registry_listener wl_registry_listener = { /// Initializes wayland and creates an opengl context struct client_state* wayland_init(int output_type, char *output_list[], int output_list_len) { - for (int i = 0; i < output_list_len; i++) { - printf("output name selected: %s\n", output_list[i]); + if (output_list != NULL) { + for (int i = 0; i < output_list_len; i++) { + printf("output name selected: %s\n", output_list[i]); + } } struct client_state *state = malloc(sizeof(struct client_state)); + state->output_list = output_list; + state->output_list_len = output_list_len; state->running = 1; state->output_type = output_type; state->wl_display = wl_display_connect(NULL); From d4c078875b720505f9fa59d55614ec6ba7fb4a7b Mon Sep 17 00:00:00 2001 From: Rakarake Date: Sun, 22 Feb 2026 18:35:44 +0100 Subject: [PATCH 8/8] no outputs can be specified --- glonkers.c | 7 +++++- wayland.c | 64 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/glonkers.c b/glonkers.c index 28dd566..632deea 100644 --- a/glonkers.c +++ b/glonkers.c @@ -54,7 +54,8 @@ int main(int argc, char *argv[]) { struct client_state *state = wayland_init(output_type, output_list, output_count); - Renderer renderer = new_renderer(); + bool renderer_initialized = false; + Renderer renderer; bool running = true; while (running) { @@ -63,6 +64,10 @@ int main(int argc, char *argv[]) { int width = event.data.draw.width; int height = event.data.draw.height; double time = event.data.draw.time / 1000.0; + if (!renderer_initialized) { + renderer = new_renderer(); + renderer_initialized = true; + } render(&renderer, width, height, time, shader_path, 0); swap_buffers(state, event.data.draw.surface); } diff --git a/wayland.c b/wayland.c index 19d1432..bca0a74 100644 --- a/wayland.c +++ b/wayland.c @@ -556,39 +556,41 @@ struct event wait_for_event(struct client_state *state) { struct event event = { .type = EVENT_EXIT }; return event; } - while (true) { - if (next == NULL) { - next = state->surface_list; - } - - // do here - if (next->data.dirty) { - next->data.dirty = false; - state->surface_list_next = next->next; - - if (eglMakeCurrent(state->egl_display, next->data.egl_surface, - next->data.egl_surface, state->egl_context)) { - } else { - fprintf(stderr, "Made current failed\n"); + if (state->surface_list != NULL) { + while (true) { + if (next == NULL) { + next = state->surface_list; } - struct event event = { - .type = EVENT_DRAW, - .data = { - .draw = { - .width = next->data.width, - .height = next->data.height, - .time = next->data.time, - .surface = &next->data, - } + + // do here + if (next->data.dirty) { + next->data.dirty = false; + state->surface_list_next = next->next; + + if (eglMakeCurrent(state->egl_display, next->data.egl_surface, + next->data.egl_surface, state->egl_context)) { + } else { + fprintf(stderr, "Made current failed\n"); } - }; - return event; - } - - next = next->next; - if (next == original) { - state->surface_list_next = next; - break; + struct event event = { + .type = EVENT_DRAW, + .data = { + .draw = { + .width = next->data.width, + .height = next->data.height, + .time = next->data.time, + .surface = &next->data, + } + } + }; + return event; + } + + next = next->next; + if (next == original) { + state->surface_list_next = next; + break; + } } } wl_display_dispatch(state->wl_display);