diff --git a/include/chroma.h b/include/chroma.h index 393c62b..843c2d1 100644 --- a/include/chroma.h +++ b/include/chroma.h @@ -212,6 +212,7 @@ int chroma_surface_create(chroma_state_t *state, chroma_output_t *output); void chroma_surface_destroy(chroma_output_t *output); int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output); void chroma_buffer_destroy(chroma_output_t *output); +void chroma_buffer_unmap(chroma_output_t *output); int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output); // Layer shell functions diff --git a/src/core.c b/src/core.c index 6974ec4..4b3a75a 100644 --- a/src/core.c +++ b/src/core.c @@ -137,9 +137,7 @@ static int assign_wallpaper_to_output(chroma_state_t *state, old_filter_quality != output->filter_quality || old_anchor != output->anchor || old_anchor_x != output->anchor_x || old_anchor_y != output->anchor_y)) { - chroma_log("DEBUG", - "Configuration changed for output %u", - output->id); + chroma_log("DEBUG", "Configuration changed for output %u", output->id); } } else { output->config_loaded = false; @@ -158,8 +156,8 @@ static int assign_wallpaper_to_output(chroma_state_t *state, // Render wallpaper int ret = chroma_render_wallpaper(state, output); if (ret != CHROMA_OK) { - chroma_log("ERROR", "Failed to render wallpaper for output %u: %s", output->id, - chroma_error_string(ret)); + chroma_log("ERROR", "Failed to render wallpaper for output %u: %s", + output->id, chroma_error_string(ret)); return ret; } diff --git a/src/render.c b/src/render.c index 626d693..12eb6a7 100644 --- a/src/render.c +++ b/src/render.c @@ -33,6 +33,22 @@ void chroma_buffer_destroy(chroma_output_t *output) { } } +// Unmap client-side memory while keeping the wl_buffer proxy alive. +// The compositor retains its own fd reference and mapping, so the +// wallpaper remains visible after this call. +void chroma_buffer_unmap(chroma_output_t *output) { + if (!output || !output->shm_data) { + return; + } + + if (munmap(output->shm_data, output->shm_size) < 0) { + chroma_log("WARN", "munmap failed: %s", strerror(errno)); + } + output->shm_data = NULL; + output->shm_size = 0; + output->shm_stride = 0; +} + // Create shared memory buffer for an output int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output) { if (!state || !output || !state->shm) { @@ -80,8 +96,7 @@ int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output) { // Fill with black memset(data, 0, size); - struct wl_shm_pool *pool = - wl_shm_create_pool(state->shm, fd, (int32_t)size); + struct wl_shm_pool *pool = wl_shm_create_pool(state->shm, fd, (int32_t)size); if (!pool) { chroma_log("ERROR", "wl_shm_create_pool failed"); munmap(data, size); @@ -109,8 +124,7 @@ int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output) { } // Sample a pixel from image data (grayscale, grayscale+alpha, RGB, or RGBA) -static inline uint32_t sample_pixel(const chroma_image_t *image, int x, - int y) { +static inline uint32_t sample_pixel(const chroma_image_t *image, int x, int y) { if (!image || !image->data || x < 0 || y < 0 || x >= image->width || y >= image->height) { return 0xFF000000; // black with full alpha @@ -147,8 +161,7 @@ static inline uint32_t sample_pixel(const chroma_image_t *image, int x, } // Draw scaled image into the shared memory buffer -static void draw_scaled_image(chroma_output_t *output, - chroma_image_t *image) { +static void draw_scaled_image(chroma_output_t *output, chroma_image_t *image) { if (!output || !image || !output->shm_data) { return; } @@ -263,10 +276,8 @@ static void draw_scaled_image(chroma_output_t *output, default: { if (img_w <= out_w && img_h <= out_h) { // Image fits entirely - position with anchor - float offset_x = - (anchor_x / 100.0f) * ((float)out_w - (float)img_w); - float offset_y = - (anchor_y / 100.0f) * ((float)out_h - (float)img_h); + float offset_x = (anchor_x / 100.0f) * ((float)out_w - (float)img_w); + float offset_y = (anchor_y / 100.0f) * ((float)out_h - (float)img_h); for (int y = 0; y < img_h; y++) { for (int x = 0; x < img_w; x++) { @@ -279,10 +290,8 @@ static void draw_scaled_image(chroma_output_t *output, } } else { // Image is larger than output - clip with anchor - float src_offset_x = - (anchor_x / 100.0f) * ((float)img_w - (float)out_w); - float src_offset_y = - (anchor_y / 100.0f) * ((float)img_h - (float)out_h); + float src_offset_x = (anchor_x / 100.0f) * ((float)img_w - (float)out_w); + float src_offset_y = (anchor_y / 100.0f) * ((float)img_h - (float)out_h); if (src_offset_x < 0) src_offset_x = 0; @@ -333,19 +342,16 @@ int chroma_surface_create(chroma_state_t *state, chroma_output_t *output) { } // Configure layer surface - zwlr_layer_surface_v1_set_size(output->layer_surface, - (uint32_t)output->width, + zwlr_layer_surface_v1_set_size(output->layer_surface, (uint32_t)output->width, (uint32_t)output->height); - zwlr_layer_surface_v1_set_anchor( - output->layer_surface, - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); + zwlr_layer_surface_v1_set_anchor(output->layer_surface, + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1); zwlr_layer_surface_v1_set_keyboard_interactivity( - output->layer_surface, - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE); + output->layer_surface, ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE); // Add layer surface listener zwlr_layer_surface_v1_add_listener( @@ -417,11 +423,18 @@ int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output) { wl_surface_damage_buffer(output->surface, 0, 0, output->width, output->height); wl_surface_commit(output->surface); - wl_display_flush(state->display); + if (wl_display_flush(state->display) < 0) { + chroma_log("ERROR", "Failed to flush Wayland display for output %u: %s", + output->id, strerror(errno)); + return CHROMA_ERROR_WAYLAND; + } chroma_log("INFO", "Rendered wallpaper to output %u (%dx%d)", output->id, output->width, output->height); + // Unmap client-side memory; compositor keeps its own fd reference + chroma_buffer_unmap(output); + // Release image reference and free CPU data if no longer needed if (output->image) { chroma_image_t *image = output->image;