summaryrefslogtreecommitdiff
path: root/reduced_system_layer.c
diff options
context:
space:
mode:
Diffstat (limited to 'reduced_system_layer.c')
-rw-r--r--reduced_system_layer.c468
1 files changed, 169 insertions, 299 deletions
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)
// ================================================================
//