diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2025-01-20 04:44:20 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2025-01-20 04:44:20 +0100 |
commit | cc074713176fd83151150125e69b8391cb33f218 (patch) | |
tree | 9c191e7dfcd914a2eaa037d9981bb5d130bf96ff | |
parent | e1a7b1c703823aac2ad2ac278a34725c377c0b63 (diff) | |
download | reduced_system_layer-cc074713176fd83151150125e69b8391cb33f218.zip |
Impl screenshot on Wayland
-rwxr-xr-x | build_all.sh | 1 | ||||
-rw-r--r-- | examples/screenshot.c | 10 | ||||
-rwxr-xr-x | graphics.c | 62 | ||||
-rw-r--r-- | reduced_system_layer.c | 468 |
4 files changed, 206 insertions, 335 deletions
diff --git a/build_all.sh b/build_all.sh index 061a00f..eb44f68 100755 --- a/build_all.sh +++ b/build_all.sh @@ -7,6 +7,7 @@ FLAGS_X11=" \ -Wno-unused-parameter \ -Wno-overlength-strings \ -D NDEBUG \ + -D NO_WAYLAND=0 \ -O3 \ -fsanitize=undefined,address,leak \ -lX11 -lm -lasound \ diff --git a/examples/screenshot.c b/examples/screenshot.c index 55bec95..ebadc99 100644 --- a/examples/screenshot.c +++ b/examples/screenshot.c @@ -12,11 +12,11 @@ void update_and_render_frame(void) { p_wait_events(); - draw_pixels((Brush) {0}, 0, 0, width, height, (Pixel_Buffer) { - .width = width, - .height = height, - .line_size = width, - .pixels = g_platform.sketch, + draw_pixels((Brush) {0}, 0, 0, g_platform.real_width, g_platform.real_height, (Pixel_Buffer) { + .width = width, + .height = height, + .stride = width, + .pixels = g_platform.sketch, }); p_render_frame(); @@ -73,7 +73,7 @@ vec4_f32 vec4_f32_lerp (vec4_f32 a, vec4_f32 b, f32 t); typedef struct { i64 width; i64 height; - i64 line_size; + i64 stride; vec4_f32 *pixels; } Pixel_Buffer; @@ -214,11 +214,11 @@ static f64 gamma_re_(f64 x) { } static void put_pixel_color_(Brush brush, i64 x, i64 y) { - brush.buffer.pixels[y * brush.buffer.line_size + x] = brush.color; + brush.buffer.pixels[y * brush.buffer.stride + x] = brush.color; } static void put_pixel_alpha_(Brush brush, i64 x, i64 y) { - i64 n = y * brush.buffer.line_size + x; + i64 n = y * brush.buffer.stride + x; vec4_f32 dst = brush.buffer.pixels[n]; f64 a = brush.color.w; @@ -232,7 +232,7 @@ static void put_pixel_alpha_(Brush brush, i64 x, i64 y) { } static void put_pixel_xor_(Brush brush, i64 x, i64 y) { - i64 n = y * brush.buffer.line_size + x; + i64 n = y * brush.buffer.stride + x; vec3_f32 c = rgb_f32_from_u32( rgb_u32_from_f32(vec3_from_vec4_f32(brush.buffer.pixels[n])) @@ -350,10 +350,10 @@ void draw_pixels_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer i64 n = 0; for (i64 jj = src_j0; jj < src_j1; ++jj) for (i64 ii = src_i0; ii < src_i1; ++ii) { - brush.color.x += gamma_re_(src.pixels[jj * src.line_size + ii].x); - brush.color.y += gamma_re_(src.pixels[jj * src.line_size + ii].y); - brush.color.z += gamma_re_(src.pixels[jj * src.line_size + ii].z); - brush.color.w += gamma_re_(src.pixels[jj * src.line_size + ii].w); + brush.color.x += gamma_re_(src.pixels[jj * src.stride + ii].x); + brush.color.y += gamma_re_(src.pixels[jj * src.stride + ii].y); + brush.color.z += gamma_re_(src.pixels[jj * src.stride + ii].z); + brush.color.w += gamma_re_(src.pixels[jj * src.stride + ii].w); ++n; } if (n == 0) @@ -373,7 +373,7 @@ void draw_pixels_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer for (i64 i = i0; i <= i1; ++i) { i64 src_i = (i64) floor(((i - x0) * src.width) * w_inv + .5); if (src_i < 0 || src_i >= src.width) continue; - brush.color = src.pixels[src_j * src.line_size + src_i]; + brush.color = src.pixels[src_j * src.stride + src_i]; put_pixel_(brush, i, j); } } @@ -890,8 +890,8 @@ static Brush brush_defaults_(Brush b) { if (b.buffer.pixels == NULL) b.buffer = frame_pixels(); - if (b.buffer.line_size == 0) - b.buffer.line_size = b.buffer.width; + if (b.buffer.stride == 0) + b.buffer.stride = b.buffer.width; return b; } @@ -1204,10 +1204,10 @@ b8 line_contains(f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py) { Pixel_Buffer frame_pixels(void) { return (Pixel_Buffer) { - .width = g_platform.frame_width, - .height = g_platform.frame_height, - .line_size = g_platform.frame_width, - .pixels = g_platform.pixels, + .width = g_platform.frame_width, + .height = g_platform.frame_height, + .stride = g_platform.frame_width, + .pixels = g_platform.pixels, }; } @@ -1223,29 +1223,29 @@ Pixel_Buffer sketch_pixels(i64 width, i64 height) { } return (Pixel_Buffer) { - .width = width, - .height = height, - .line_size = width, - .pixels = g_platform.sketch, + .width = width, + .height = height, + .stride = width, + .pixels = g_platform.sketch, }; } Pixel_Buffer subimage(Pixel_Buffer image, i64 x, i64 y, i64 width, i64 height) { if (x < 0 || y < 0 || width <= 0 || height <= 0 || x + width > image.width || y + height > image.height || image.pixels == NULL) return (Pixel_Buffer) { - .width = 0, - .height = 0, - .line_size = 0, + .width = 0, + .height = 0, + .stride = 0, // Set pixels pointer to prevent default initialization. .pixels = g_platform.sketch, }; return (Pixel_Buffer) { - .width = width, - .height = height, - .line_size = image.line_size, - .pixels = image.pixels + (y * image.line_size + x), + .width = width, + .height = height, + .stride = image.stride, + .pixels = image.pixels + (y * image.stride + x), }; } @@ -1259,7 +1259,7 @@ void put_pixel(Brush brush, i64 x, i64 y) { } void draw_pixels(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer src) { - if (width < EPSILON || height < EPSILON || src.width <= 0 || src.height <= 0 || src.line_size <= 0 || src.pixels == NULL) + if (width < EPSILON || height < EPSILON || src.width <= 0 || src.height <= 0 || src.stride <= 0 || src.pixels == NULL) return; draw_pixels_(brush_defaults_(brush), x, y, width, height, src); @@ -1611,10 +1611,10 @@ TEST("colors") { Brush brush = { .buffer = { - .width = 1280, - .height = 720, - .line_size = 1280, - .pixels = g_platform.pixels, + .width = 1280, + .height = 720, + .stride = 1280, + .pixels = g_platform.pixels, }, .position = { 0.f, 0.f, }, .scale = { 1.f, 1.f, }, diff --git a/reduced_system_layer.c b/reduced_system_layer.c index b1fb813..08e5fad 100644 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -56,6 +56,10 @@ // - TCP // - Switching canvases - Web // - Long term +// - dlopen - load libraries conditionally +// - X11 +// - Wayland +// - ALSA // - Allocator // - Parsing // - Printing @@ -96,7 +100,7 @@ // - Anti-aliasing // - System // - Window - X11, Web -// - Screenshot +// - Screenshot - X11, Wayland // - Sound - ALSA, Web // - Networking // - Unix UDP sockets @@ -172,6 +176,14 @@ i32 main(i32 argc, c8 **argv); // // ================================================================ +#ifndef NO_WAYLAND +#define NO_WAYLAND 0 +#endif + +#ifndef NO_X11 +#define NO_X11 0 +#endif + #ifndef MAX_NUM_PIXELS #define MAX_NUM_PIXELS (10 * 1024 * 1024) #endif @@ -1451,7 +1463,7 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { // // ================================================================ -#if defined(__linux__) && !defined(NO_WAYLAND) +#if defined(__linux__) && !NO_WAYLAND #include <sys/mman.h> #include <wayland-client.h> @@ -1569,17 +1581,6 @@ static void zxdg_output_v1_destroy(void *zxdg_output_v1) { wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_v1, 0, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1), WL_MARSHAL_FLAG_DESTROY); } -static i32 zxdg_output_v1_add_listener(void *zxdg_output_v1, struct zxdg_output_v1_listener *listener, void *data) { - return wl_proxy_add_listener((struct wl_proxy *) zxdg_output_v1, (void (**)(void)) listener, data); -} - -static void *zxdg_output_manager_v1_get_xdg_output(void *zxdg_output_manager_v1, struct wl_output *output) { - struct wl_proxy *id; - id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_manager_v1, - 1, &zxdg_output_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1), 0, NULL, output); - return (void *) id; -} - static void zxdg_output_manager_v1_destroy(void *zxdg_output_manager_v1) { wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_manager_v1, 0, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1), WL_MARSHAL_FLAG_DESTROY); @@ -1613,6 +1614,7 @@ typedef struct { void * screencopy_manager; struct wl_list outputs; u64 n_done; + b8 ok; } WL_State_; typedef struct { @@ -1631,100 +1633,37 @@ typedef struct { } WL_Box_; typedef struct { - WL_State_ * state; - struct wl_output * output; - void *xdg_output; - struct wl_list link; - WL_Box_ geometry; - i32 transform; - i32 scale; - WL_Box_ local_geometry; - WL_Box_ logical_geometry; - f64 logical_scale; - c8 * name; - WL_Buffer_ * buffer; - void * screencopy_frame; - u32 screencopy_frame_flags; + WL_State_ * state; + struct wl_output *output; + void * xdg_output; + struct wl_list link; + WL_Box_ geometry; + i32 transform; + i32 scale; + WL_Box_ local_geometry; + WL_Box_ logical_geometry; + f64 logical_scale; + c8 * name; + WL_Buffer_ * buffer; + void * screencopy_frame; + u32 screencopy_frame_flags; } WL_Output_; -// ================================================================ - -static void get_output_layout_extents(WL_State_ *state, WL_Box_ *box) { - i32 x1 = 0x10000000, y1 = 0x10000000; - i32 x2 = -0x10000000, y2 = -0x10000000; - - WL_Output_ *output; - wl_list_for_each(output, &state->outputs, link) { - if (output->logical_geometry.x < x1) - x1 = output->logical_geometry.x; - if (output->logical_geometry.y < y1) - y1 = output->logical_geometry.y; - if (output->logical_geometry.x + output->logical_geometry.width > x2) - x2 = output->logical_geometry.x + output->logical_geometry.width; - if (output->logical_geometry.y + output->logical_geometry.height > y2) - y2 = output->logical_geometry.y + output->logical_geometry.height; - } - - box->x = x1; - box->y = y1; - box->width = x2 - x1; - box->height = y2 - y1; -} - -static void apply_output_transform(enum wl_output_transform transform, i32 *width, i32 *height) { - if ((transform & WL_OUTPUT_TRANSFORM_90) != 0) { - i32 tmp = *width; - *width = *height; - *height = tmp; - } -} - -static f64 get_output_rotation(enum wl_output_transform transform) { - switch (transform & ~WL_OUTPUT_TRANSFORM_FLIPPED) { - case WL_OUTPUT_TRANSFORM_90: return M_PI / 2; - case WL_OUTPUT_TRANSFORM_180: return M_PI; - case WL_OUTPUT_TRANSFORM_270: return 3 * M_PI / 2; - } - return 0; -} - -static i32 get_output_flipped(enum wl_output_transform transform) { - return (transform & WL_OUTPUT_TRANSFORM_FLIPPED) != 0 ? -1 : 1; -} - -static void guess_output_logical_geometry(WL_Output_ *output) { - output->logical_geometry.x = output->geometry.x; - output->logical_geometry.y = output->geometry.y; - output->logical_geometry.width = output->geometry.width / output->scale; - output->logical_geometry.height = output->geometry.height / output->scale; - apply_output_transform( - output->transform, - &output->logical_geometry.width, - &output->logical_geometry.height - ); - - output->logical_scale = output->scale; -} - -static void randname(c8 *buf) { - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - long r = ts.tv_nsec; - for (int i = 0; i < 6; ++i) { - buf[i] = 'A'+(r&15)+(r&16)*2; - r >>= 5; - } -} - static i32 anonymous_shm_open(void) { - c8 name[] = "/tmp/scr_XXXXXX"; + c8 name[] = "scr_XXXXXX"; i32 retries = 100; do { - randname(name + sizeof name - 7); - --retries; + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + u64 r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + name[sizeof name - 7 + i] = 'A' + (r&15) + (r&16) * 2; + r >>= 5; + } + i32 fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); if (fd >= 0) { shm_unlink(name); @@ -1781,13 +1720,15 @@ static WL_Buffer_ *create_buffer(struct wl_shm *shm, enum wl_shm_format format, return NULL; } - buffer->buffer = wl_buffer; - buffer->data = data; - buffer->width = width; - buffer->height = height; - buffer->stride = stride; - buffer->size = size; - buffer->format = format; + *buffer = (WL_Buffer_) { + .buffer = wl_buffer, + .data = data, + .width = width, + .height = height, + .stride = stride, + .size = size, + .format = format, + }; return buffer; } @@ -1801,28 +1742,29 @@ static void destroy_buffer(WL_Buffer_ *buffer) { } static void screencopy_frame_handle_buffer( - void * data, + void *data, void *frame, - u32 format, - u32 width, - u32 height, - u32 stride + u32 format, + u32 width, + u32 height, + u32 stride ) { WL_Output_ *output = data; output->buffer = create_buffer(output->state->shm, format, width, height, stride); - if (output->buffer == NULL) - // FAIL + if (output->buffer == NULL) { + output->state->ok = 0; return; + } zwlr_screencopy_frame_v1_copy(frame, output->buffer->buffer); } static void screencopy_frame_handle_flags( - void * data, + void *data, void *frame, - u32 flags + u32 flags ) { WL_Output_ *output = data; output->screencopy_frame_flags = flags; @@ -1844,7 +1786,7 @@ static void screencopy_frame_handle_failed( void *frame ) { WL_Output_ *output = data; - // FAIL + output->state->ok = 0; LOG_ERROR("Screenshot copy failed."); } @@ -1855,53 +1797,6 @@ static struct zwlr_screencopy_frame_v1_listener screencopy_frame_listener = { .failed = screencopy_frame_handle_failed, }; -static void xdg_output_handle_logical_position( - void * data, - void *xdg_output, - i32 x, - i32 y -) { - WL_Output_ *output = data; - - output->logical_geometry.x = x; - output->logical_geometry.y = y; -} - -static void xdg_output_handle_logical_size( - void * data, - void *xdg_output, - i32 width, - i32 height -) { - WL_Output_ *output = data; - - output->logical_geometry.width = width; - output->logical_geometry.height = height; -} - -static void xdg_output_handle_done( - void * data, - void *xdg_output -) { - WL_Output_ *output = data; - - i32 width = output->geometry.width; - i32 height = output->geometry.height; - apply_output_transform(output->transform, &width, &height); - output->logical_scale = (f64) width / output->logical_geometry.width; -} - -static void xdg_output_handle_name( - void * data, - void *xdg_output, - c8 * name -) { - WL_Output_ *output = data; - output->name = strdup(name); -} - -static void xdg_output_handle_description(void *data, void *xdg_output, c8 *name) { } - static void output_handle_geometry( void * data, struct wl_output *wl_output, @@ -1974,9 +1869,9 @@ static void handle_global( output->output = wl_registry_bind(registry, name, &wl_output_interface, 3); wl_output_add_listener(output->output, &(struct wl_output_listener) { .geometry = output_handle_geometry, - .mode = output_handle_mode, - .done = output_handle_done, - .scale = output_handle_scale, + .mode = output_handle_mode, + .done = output_handle_done, + .scale = output_handle_scale, }, output); wl_list_insert(&state->outputs, &output->link); } else if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) @@ -1995,45 +1890,33 @@ static struct wl_registry_listener _wayland_registry_listener = { .global_remove = handle_global_remove, }; -static b8 is_empty_box(WL_Box_ *box) { - return box->width <= 0 || box->height <= 0; -} - -static b8 intersect_box(WL_Box_ *a, WL_Box_ *b) { - if (is_empty_box(a) || is_empty_box(b)) { - return 0; +b8 check_format_(i32 format) { + switch (format) { + case WL_SHM_FORMAT_ARGB8888: + case WL_SHM_FORMAT_XRGB8888: + case WL_SHM_FORMAT_ABGR8888: + case WL_SHM_FORMAT_XBGR8888: + case WL_SHM_FORMAT_BGRA8888: + case WL_SHM_FORMAT_BGRX8888: + case WL_SHM_FORMAT_RGBA8888: + case WL_SHM_FORMAT_RGBX8888: + return 1; + default:; } - - i32 x1 = fmax(a->x, b->x); - i32 y1 = fmax(a->y, b->y); - i32 x2 = fmin(a->x + a->width, b->x + b->width); - i32 y2 = fmin(a->y + a->height, b->y + b->height); - - WL_Box_ box = { - .x = x1, - .y = y1, - .width = x2 - x1, - .height = y2 - y1, - }; - - return !is_empty_box(&box); + return 0; } -void wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { - f32 scale = 1.0; - b8 use_greatest_scale = 1; +b8 wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { + b8 ok = 0; - WL_Box_ *geometry = NULL; - c8 * geometry_output = NULL; - - WL_State_ state = {0}; + WL_State_ state = { .ok = 1, }; wl_list_init(&state.outputs); state.display = wl_display_connect(NULL); if (state.display == NULL) { LOG_ERROR("wl_display_connect failed."); - return; + goto finalize; } state.registry = wl_display_get_registry(state.display); @@ -2046,74 +1929,22 @@ void wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 * if (state.shm == NULL) { LOG_ERROR("Compositor does not support wl_shm."); - return; + goto finalize; } if (wl_list_empty(&state.outputs)) { LOG_ERROR("No wl_output."); - return; - } - - if (state.xdg_output_manager != NULL) { - WL_Output_ *output; - wl_list_for_each(output, &state.outputs, link) { - output->xdg_output = zxdg_output_manager_v1_get_xdg_output( - state.xdg_output_manager, - output->output - ); - - zxdg_output_v1_add_listener( - output->xdg_output, - &(struct zxdg_output_v1_listener) { - .logical_position = xdg_output_handle_logical_position, - .logical_size = xdg_output_handle_logical_size, - .done = xdg_output_handle_done, - .name = xdg_output_handle_name, - .description = xdg_output_handle_description, - }, - output - ); - } - - wl_display_roundtrip(state.display); - } else { - WL_Output_ *output; - wl_list_for_each(output, &state.outputs, link) { - guess_output_logical_geometry(output); - } + goto finalize; } if (state.screencopy_manager == NULL) { LOG_ERROR("Compositor does not support wlr-screencopy-unstable-v1."); - return; - } - - if (geometry_output != NULL) { - WL_Output_ *output; - wl_list_for_each(output, &state.outputs, link) { - if (output->name != NULL && strcmp(output->name, geometry_output) == 0) { - geometry = calloc(1, sizeof(WL_Box_)); - if (geometry == NULL) { - LOG_ERROR("calloc failed.\n"); - } else - memcpy(geometry, &output->logical_geometry, sizeof(WL_Box_)); - } - } - - if (geometry == NULL) { - LOG_ERROR("Unknown output for: %s", geometry_output); - return; - } + goto finalize; } u64 n_pending = 0; WL_Output_ *output; wl_list_for_each(output, &state.outputs, link) { - if (geometry != NULL && !intersect_box(geometry, &output->logical_geometry)) - continue; - if (use_greatest_scale && output->logical_scale > scale) - scale = output->logical_scale; - output->screencopy_frame = zwlr_screencopy_manager_v1_capture_output( state.screencopy_manager, 1, @@ -2131,31 +1962,71 @@ void wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 * if (n_pending == 0) { LOG_ERROR("Supplied geometry did not intersect with any outputs."); - return; + goto finalize; } b8 done = 0; + while (!done && wl_display_dispatch(state.display) != -1) { + if (!state.ok) + goto finalize; done = (state.n_done == n_pending); } + if (!done) { LOG_ERROR("Failed to screenshoot all outputs."); - return; + goto finalize; + } + + *width = 0; + *height = 0; + + wl_list_for_each(output, &state.outputs, link) { + WL_Buffer_ *buffer = output->buffer; + if (buffer == NULL) continue; + if (!check_format_(buffer->format)) continue; + + if (*width < buffer->width) + *width = buffer->width; + *height += buffer->height; } - if (geometry == NULL) { - geometry = calloc(1, sizeof(WL_Box_)); - get_output_layout_extents(&state, geometry); + if (pixels == NULL || *width * *height > max_num_pixels) { + ok = 1; + goto finalize; } - // - // TODO: - // SAVE - // - (void) get_output_flipped; - (void) get_output_rotation; + for (i32 i = 0; i < *width * *height; ++i) + pixels[i] = (vec4_f32) { 0.f, 0.f, 0.f, 1.f }; + + i32 y0 = 0; + + wl_list_for_each(output, &state.outputs, link) { + WL_Buffer_ *buffer = output->buffer; + if (buffer == NULL) continue; + if (!check_format_(buffer->format)) continue; + + for (i32 j = 0; j < buffer->height; ++j) + for (i32 i = 0; i < buffer->width; ++i) { + fflush(stdout); + vec3_f32 c = rgb_f32_from_u32_(((u32 *) buffer->data)[j * (buffer->stride / 4) + i]); + + pixels[(y0 + j) * *width + i] = (vec4_f32) { + .x = c.x, + .y = c.y, + .z = c.z, + .w = 1.f, + }; + } + + y0 += buffer->height; + } + + ok = 1; WL_Output_ *output_tmp; + +finalize: wl_list_for_each_safe(output, output_tmp, &state.outputs, link) { wl_list_remove(&output->link); free(output->name); @@ -2171,15 +2042,14 @@ void wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 * if (state.xdg_output_manager != NULL) zxdg_output_manager_v1_destroy(state.xdg_output_manager); - wl_shm_destroy(state.shm); - wl_registry_destroy(state.registry); - wl_display_disconnect(state.display); + if (state.shm != NULL) wl_shm_destroy(state.shm); + if (state.registry != NULL) wl_registry_destroy(state.registry); + if (state.display != NULL) wl_display_disconnect(state.display); - free(geometry); - free(geometry_output); + return ok; } -#endif // defined(__linux__) && !defined(NO_WAYLAND) +#endif // defined(__linux__) && !NO_WAYLAND // ================================================================ // @@ -2187,7 +2057,7 @@ void wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 * // // ================================================================ -#if defined(__linux__) && !defined(NO_X11) +#if defined(__linux__) && !NO_X11 #include <sys/stat.h> #include <X11/Xlib.h> @@ -2222,7 +2092,6 @@ static Atom _dnd_action_copy = 0; static Atom _dnd_selection = 0; static Atom _text_uri_list = 0; static Window _dnd_source = 0; -static b8 _ignore_errors = 0; static i16 _key_table [MAX_NUM_KEYS] = {0}; static b8 _key_repeat [MAX_NUM_KEYS] = {0}; @@ -2238,11 +2107,8 @@ static b8 sub_str_eq_(c8 *a, c8 *b, i64 len) { } i32 x11_error_handler_(Display *display, XErrorEvent *event) { - if (!_ignore_errors) { - XGetErrorText(display, event->error_code, _error_buffer, sizeof _error_buffer - 1); - LOG_ERROR("X11: %s", _error_buffer); - } - + XGetErrorText(display, event->error_code, _error_buffer, sizeof _error_buffer - 1); + LOG_ERROR("%s", _error_buffer); return 0; } @@ -2991,46 +2857,28 @@ void p_clipboard_write(i64 size, c8 *data) { memcpy(g_platform.clipboard, data, g_platform.clipboard_size); } -void x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { - if (width == NULL || height == NULL) { - LOG_ERROR("Invalid arguments."); - return; - } - - *width = 0; - *height = 0; - +b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { if (_display == NULL) { LOG_ERROR("No display."); - return; + return 0; } i32 screen = DefaultScreen(_display); i32 display_width = DisplayWidth (_display, screen); i32 display_height = DisplayHeight(_display, screen); - _ignore_errors = 1; - XImage *image = XGetImage(_display, _root_window, 0, 0, display_width, display_height, AllPlanes, ZPixmap); - _ignore_errors = 0; - if (image == NULL) { - #if !defined(NO_WAYLAND) - // Fallback for Wayland. - wayland_screenshot_(max_num_pixels, width, height, pixels); - return; - #else LOG_ERROR("XGetImage failed."); - return; - #endif + return 0; } *width = image->width; *height = image->height; if (pixels == NULL || image->width * image->height > max_num_pixels) - return; + return 1; for (i64 j = 0; j < image->height; ++j) for (i64 i = 0; i < image->width; ++i) { @@ -3043,13 +2891,35 @@ void x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixe .w = 1.f, }; } + + return 1; } +#endif // defined(__linux__) && !NO_X11 + +// ================================================================ + +#if defined(__linux__) && (!NO_X11 || !NO_WAYLAND) void p_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { - x11_screenshot_(max_num_pixels, width, height, pixels); -} + if (width == NULL || height == NULL) { + LOG_ERROR("Invalid arguments."); + return; + } + + #if !NO_X11 + if (x11_screenshot_(max_num_pixels, width, height, pixels)) + return; + #endif -#endif // defined(__linux__) && !defined(NO_X11) + #if !NO_WAYLAND + if (wayland_screenshot_(max_num_pixels, width, height, pixels)) + return; + #endif + + *width = 0; + *height = 0; + } +#endif // defined(__linux__) && (!NO_X11 || !NO_WAYLAND) // ================================================================ // |