summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-01-22 17:27:34 +0100
committerMitya Selivanov <automainint@guattari.tech>2025-01-22 17:27:34 +0100
commitc0c52a07376d22339a06d031892af649c2eb8acc (patch)
tree5532ebac932b5c0414cee7d7099f3151b5bcbd01
parentfede6d46ef07c088f320db7f90a9e1479a3985bf (diff)
downloadreduced_system_layer-c0c52a07376d22339a06d031892af649c2eb8acc.zip
Clipboard image and sound proc decls
-rwxr-xr-xbuild_all.sh6
-rw-r--r--examples/julia_set.c2
-rw-r--r--examples/ui.c8
-rwxr-xr-xgraphics.c111
-rw-r--r--index.htm2
-rw-r--r--reduced_system_layer.c269
-rwxr-xr-xstackless_coroutine.c2
7 files changed, 260 insertions, 140 deletions
diff --git a/build_all.sh b/build_all.sh
index 5946fad..eb44f68 100755
--- a/build_all.sh
+++ b/build_all.sh
@@ -31,7 +31,7 @@ mkdir -p bin/x11
mkdir -p bin/web
# gcc $FLAGS_X11 -o ./bin/x11/graph ./examples/graph.c
-gcc $FLAGS_X11 -o ./bin/x11/julia_set ./examples/julia_set.c
+# gcc $FLAGS_X11 -o ./bin/x11/julia_set ./examples/julia_set.c
# gcc $FLAGS_X11 -o ./bin/x11/game_of_life ./examples/game_of_life.c
# gcc $FLAGS_X11 -o ./bin/x11/labyrinth ./examples/labyrinth.c
# gcc $FLAGS_X11 -o ./bin/x11/sinewave ./examples/sinewave.c
@@ -41,10 +41,10 @@ gcc $FLAGS_X11 -o ./bin/x11/julia_set ./examples/julia_set.c
# gcc $FLAGS_X11 -o ./bin/x11/particles ./examples/particles.c
# gcc $FLAGS_X11 -o ./bin/x11/echo ./examples/echo.c
-# gcc $FLAGS_X11 -o ./bin/x11/screenshot ./examples/screenshot.c
+gcc $FLAGS_X11 -o ./bin/x11/screenshot ./examples/screenshot.c
# clang $FLAGS_WEB -o ./bin/web/graph.wasm ./examples/graph.c
-clang $FLAGS_WEB -o ./bin/web/julia_set.wasm ./examples/julia_set.c
+# clang $FLAGS_WEB -o ./bin/web/julia_set.wasm ./examples/julia_set.c
# clang $FLAGS_WEB -o ./bin/web/game_of_life.wasm ./examples/game_of_life.c
# clang $FLAGS_WEB -o ./bin/web/labyrinth.wasm ./examples/labyrinth.c
# clang $FLAGS_WEB -o ./bin/web/sinewave.wasm ./examples/sinewave.c
diff --git a/examples/julia_set.c b/examples/julia_set.c
index e819ca5..288dac2 100644
--- a/examples/julia_set.c
+++ b/examples/julia_set.c
@@ -22,7 +22,7 @@ void apply_scale(f64 delta) {
}
f64 ds = view_s * delta * .1;
- if (view_s + ds < EPSILON)
+ if (view_s + ds < 1e-12)
return;
f64 dx = (g_platform.cursor_x * 1. - g_platform.real_width * .5);
f64 dy = (g_platform.cursor_y * 1. - g_platform.real_height * .5);
diff --git a/examples/ui.c b/examples/ui.c
index c10a9c6..022a463 100644
--- a/examples/ui.c
+++ b/examples/ui.c
@@ -80,8 +80,8 @@ void update_and_render_frame(void) {
text_len -= i1 - i0;
}
- for (i64 n = 0; n < g_platform.clipboard_size;) {
- UTF8_Char c = utf8_read(g_platform.clipboard_size - n, g_platform.clipboard + n);
+ for (i64 n = 0; n < g_platform.clipboard_text_len;) {
+ UTF8_Char c = utf8_read(g_platform.clipboard_text_len - n, g_platform.clipboard_text + n);
if (text_len < (i64) (sizeof text / sizeof *text)) {
for (i64 j = text_len; j > cursor; --j)
@@ -104,7 +104,7 @@ void update_and_render_frame(void) {
len += utf8_write(text[i0 + i], buf + len);
if (len > 0)
- p_clipboard_write(len, buf);
+ p_clipboard_write_text(len, buf);
for (i64 i = 0; i1 + i < text_len; ++i)
text[i0 + i] = text[i1 + i];
@@ -123,7 +123,7 @@ void update_and_render_frame(void) {
len += utf8_write(text[i0 + i], buf + len);
if (len > 0)
- p_clipboard_write(len, buf);
+ p_clipboard_write_text(len, buf);
} break;
default:;
diff --git a/graphics.c b/graphics.c
index 3b9f071..eb0db72 100755
--- a/graphics.c
+++ b/graphics.c
@@ -71,6 +71,7 @@ vec4_f32 vec4_f32_lerp (vec4_f32 a, vec4_f32 b, f32 t);
// ================================================================
typedef struct {
+ // NOTE: Dimensions are in pixels.
i64 width;
i64 height;
i64 stride;
@@ -79,6 +80,8 @@ typedef struct {
typedef struct {
Pixel_Buffer buffer;
+ i64 sketch_size;
+ vec4_f32 *sketch;
vec2 position;
vec2 scale;
b8 quick : 1; // If set, anti-aliasing is skipped.
@@ -94,10 +97,9 @@ vec3_f32 lch_from_lab(vec3_f32 lab);
vec3_f32 rgb_from_lch(vec3_f32 lch);
vec3_f32 lch_from_rgb(vec3_f32 rgb);
-// NOTE:
-// General rule to work with gamma is removing it,
-// then doing computations like blending, interpolation, etc,
-// then adding it back.
+// NOTE: General rule to work with gamma is removing it,
+// then doing computations like blending, interpolation, etc,
+// then adding it back.
vec3_f32 rgb_gamma_add (vec3_f32 rgb);
vec3_f32 rgb_gamma_remove (vec3_f32 rgb);
@@ -128,7 +130,6 @@ b8 ellipse_contains (f64 x0, f64 y0, f64 width, f64 height,
b8 line_contains (f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py);
Pixel_Buffer frame_pixels (void);
-Pixel_Buffer sketch_pixels(i64 width, i64 height);
Pixel_Buffer subimage (Pixel_Buffer image, i64 x, i64 y, i64 width, i64 height);
void put_pixel (Brush brush, i64 x, i64 y);
@@ -279,20 +280,52 @@ void transform_box_(Brush brush, f64 x, f64 y, f64 width, f64 height, f64 *x0, f
}
}
+Pixel_Buffer sketch_pixels_(Brush brush, i64 width, i64 height) {
+ vec4_f32 *buffer_end = brush.buffer.pixels + brush.buffer.stride * (brush.buffer.height - 1) + brush.buffer.width;
+ vec4_f32 *sketch_end = brush.sketch + brush.sketch_size;
+
+ b8 is_inside_sketch_area = buffer_end > brush.sketch && brush.buffer.pixels < sketch_end;
+
+ b8 offset = is_inside_sketch_area
+ ? buffer_end - brush.sketch
+ : 0;
+
+ if (brush.sketch_size - offset < width * height)
+ return (Pixel_Buffer) {
+ .width = 0,
+ .height = 0,
+ .stride = 0,
+ .pixels = brush.sketch,
+ };
+
+ return (Pixel_Buffer) {
+ .width = width,
+ .height = height,
+ .stride = width,
+ .pixels = brush.sketch + offset,
+ };
+}
+
Brush antialiasing_brush_(Brush brush) {
return (Brush) {
- .buffer = sketch_pixels(brush.buffer.width * ANTIALIASING_SCALE, brush.buffer.height * ANTIALIASING_SCALE),
- .position = brush.position,
- .scale = {
+ .buffer = sketch_pixels_(
+ brush,
+ brush.buffer.width * ANTIALIASING_SCALE,
+ brush.buffer.height * ANTIALIASING_SCALE
+ ),
+ .sketch_size = brush.sketch_size,
+ .sketch = brush.sketch,
+ .position = brush.position,
+ .scale = {
.x = brush.scale.x * ANTIALIASING_SCALE,
.y = brush.scale.y * ANTIALIASING_SCALE,
},
- .quick = 1,
- .alpha = 0,
- .xor_color = 0,
- .color = brush.alpha
- ? brush.color
- : vec4_from_vec3_f32(vec3_from_vec4_f32(brush.color), 1.f),
+ .quick = 1,
+ .alpha = 0,
+ .xor_color = 0,
+ .color = brush.alpha
+ ? brush.color
+ : vec4_from_vec3_f32(vec3_from_vec4_f32(brush.color), 1.f),
};
}
@@ -366,14 +399,31 @@ void draw_pixels_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer
put_pixel_(brush, i, j);
}
}
- else
+ else if (!brush.alpha && !brush.xor_color) {
+ i32 iw = (i32) floor(w + .5);
+ i32 ih = (i32) floor(h + .5);
+ i32 ix0 = (i32) floor(x0 + .5);
+ i32 iy0 = (i32) floor(y0 + .5);
+ for (i32 j = j0; j <= j1; ++j) {
+ i32 src_j = ((j - iy0) * src.height) / ih;
+ i32 dst_j = j * brush.buffer.stride;
+ if (src_j < 0 || src_j >= src.height) continue;
+ src_j *= src.stride;
+ for (i32 i = i0; i <= i1; ++i) {
+ i32 src_i = ((i - ix0) * src.width) / iw;
+ if (src_i < 0 || src_i >= src.width) continue;
+ brush.buffer.pixels[dst_j + i] = src.pixels[src_j + src_i];
+ }
+ }
+ } else
for (i64 j = j0; j <= j1; ++j) {
i64 src_j = (i64) floor(((j - y0) * src.height) * h_inv + .5);
if (src_j < 0 || src_j >= src.height) continue;
+ src_j *= src.stride;
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.stride + src_i];
+ brush.color = src.pixels[src_j + src_i];
put_pixel_(brush, i, j);
}
}
@@ -569,6 +619,8 @@ void fill_triangle_(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2)
i64 i1 = (i64) ceil (max3_(x0, x1, x2));
i64 j1 = (i64) ceil (max3_(y0, y1, y2));
+ if (i0 < 0) i0 = 0;
+ if (i1 >= brush.buffer.width) i1 = brush.buffer.width - 1;
if (j0 < 0) j0 = 0;
if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1;
@@ -588,9 +640,6 @@ void fill_triangle_(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2)
break;
}
- if (left < 0) left = 0;
- if (right >= brush.buffer.width) right = brush.buffer.width - 1;
-
if (brush.xor_color)
for (i64 i = left; i <= right; ++i)
put_pixel_xor_(brush, i, j);
@@ -893,6 +942,11 @@ static Brush brush_defaults_(Brush b) {
if (b.buffer.stride == 0)
b.buffer.stride = b.buffer.width;
+ if (b.sketch_size == 0 && b.sketch == NULL) {
+ b.sketch_size = MAX_NUM_PIXELS;
+ b.sketch = g_platform.sketch;
+ }
+
return b;
}
@@ -1211,25 +1265,6 @@ Pixel_Buffer frame_pixels(void) {
};
}
-Pixel_Buffer sketch_pixels(i64 width, i64 height) {
- if (width <= 0 || height <= 0) {
- width = g_platform.frame_width;
- height = g_platform.frame_height;
- }
-
- if (width * height > MAX_NUM_PIXELS) {
- width = 0;
- height = 0;
- }
-
- return (Pixel_Buffer) {
- .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) {
diff --git a/index.htm b/index.htm
index e610586..5e0dd3c 100644
--- a/index.htm
+++ b/index.htm
@@ -34,7 +34,7 @@
fd_seek : () => { throw new Error("Unexpected fd_seek call"); },
},
env : {
- p_clipboard_write_impl : (size, text) => {
+ p_clipboard_write_text_impl : (size, text) => {
let text_buffer = new ArrayBuffer(size);
new Uint8Array(text_buffer).set(new Uint8Array(this.memory_buffer, text, size));
diff --git a/reduced_system_layer.c b/reduced_system_layer.c
index 088a8a5..758b5d9 100644
--- a/reduced_system_layer.c
+++ b/reduced_system_layer.c
@@ -28,8 +28,12 @@
// To-Do list
//
// - Work in progress
+// - Clipboard
+// - Images
+// - Sound
// - Seldom allocator
// - Logging
+// - Graphics perf
// - Examples
// - Conway's Game of Life
// - Julia Set
@@ -54,8 +58,6 @@
// - Networking
// - Windows sockets
// - TCP
-// - Clipboard
-// - Images
// - Switching canvases - Web
// - Long term
// - dlopen - load libraries conditionally
@@ -104,7 +106,7 @@
// - Window - X11, Web
// - Screenshot - X11, Wayland
// - Clipboard
-// - Text - X11
+// - Text - X11, Web
// - Sound - ALSA, Web
// - Networking
// - Unix UDP sockets
@@ -571,7 +573,10 @@ typedef struct {
i32 real_width;
i32 real_height;
i64 input_size;
- i64 clipboard_size;
+ i64 clipboard_text_len;
+ i64 clipboard_image_width;
+ i64 clipboard_image_height;
+ i64 num_clipboard_sound_samples;
i32 cursor_x;
i32 cursor_y;
i32 cursor_dx;
@@ -583,12 +588,14 @@ typedef struct {
i64 num_drop_files;
Drop_File *drop_files;
- vec4_f32 pixels [MAX_NUM_PIXELS];
- vec4_f32 sketch [MAX_NUM_PIXELS];
- Input_Key input [MAX_INPUT_SIZE];
- c8 clipboard [MAX_CLIPBOARD_SIZE];
- b8 key_down [MAX_NUM_KEYS];
- b8 key_pressed [MAX_NUM_KEYS];
+ vec4_f32 pixels [MAX_NUM_PIXELS];
+ vec4_f32 sketch [MAX_NUM_PIXELS];
+ Input_Key input [MAX_INPUT_SIZE];
+ c8 clipboard_text [MAX_CLIPBOARD_SIZE];
+ vec4_f32 clipboard_image [MAX_CLIPBOARD_SIZE];
+ f32 clipboard_sound [MAX_CLIPBOARD_SIZE];
+ b8 key_down [MAX_NUM_KEYS];
+ b8 key_pressed [MAX_NUM_KEYS];
} Platform;
// UTF-8
@@ -613,7 +620,9 @@ void p_render_frame(void);
void p_event_loop(void);
// Clipboard
-void p_clipboard_write(i64 size, c8 *data);
+void p_clipboard_write_text(i64 size, c8 *data);
+void p_clipboard_write_image(i64 width, i64 heiht, vec4_f32 *pixels);
+void p_clipboard_write_sound(i8 num_channels, i64 num_samples, f32 *frames);
// Take a screenshot
void p_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels);
@@ -1457,6 +1466,9 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) {
//
// Wayland
//
+// FIXME: Remove dynamic memory management.
+// Use arena allocator for a static buffer.
+//
// ================================================================
#if defined(__linux__) && !NO_WAYLAND
@@ -1578,18 +1590,15 @@ static void zxdg_output_v1_destroy(void *zxdg_output_v1) {
}
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);
+ 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);
}
static void zwlr_screencopy_frame_v1_destroy(void *zwlr_screencopy_frame_v1) {
- wl_proxy_marshal_flags((struct wl_proxy *) zwlr_screencopy_frame_v1,
- 1, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_screencopy_frame_v1), WL_MARSHAL_FLAG_DESTROY);
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_screencopy_frame_v1, 1, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_screencopy_frame_v1), WL_MARSHAL_FLAG_DESTROY);
}
static void zwlr_screencopy_frame_v1_copy(void *zwlr_screencopy_frame_v1, struct wl_buffer *buffer) {
- wl_proxy_marshal_flags((struct wl_proxy *) zwlr_screencopy_frame_v1,
- 0, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_screencopy_frame_v1), 0, buffer);
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_screencopy_frame_v1, 0, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_screencopy_frame_v1), 0, buffer);
}
static i32 zwlr_screencopy_frame_v1_add_listener(void *zwlr_screencopy_frame_v1, struct zwlr_screencopy_frame_v1_listener *listener, void *data) {
@@ -1756,18 +1765,18 @@ static void screencopy_frame_handle_flags(
}
static void screencopy_frame_handle_ready(
- void * data,
+ void *data,
void *frame,
- u32 tv_sec_hi,
- u32 tv_sec_lo,
- u32 tv_nsec
+ u32 tv_sec_hi,
+ u32 tv_sec_lo,
+ u32 tv_nsec
) {
WL_Output_ *output = data;
++output->state->n_done;
}
static void screencopy_frame_handle_failed(
- void * data,
+ void *data,
void *frame
) {
WL_Output_ *output = data;
@@ -1910,6 +1919,7 @@ b8 wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pi
while (!done && wl_display_dispatch(state.display) != -1) {
if (!state.ok)
goto finalize;
+ usleep(0);
done = (state.n_done == n_pending);
}
@@ -1948,7 +1958,6 @@ b8 wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pi
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) {
@@ -2007,32 +2016,37 @@ finalize:
#define FILE_PATH_PREFIX_ "file://"
#define FILE_PATH_PREFIX_LEN_ ((sizeof FILE_PATH_PREFIX_) - 1)
-static i64 _frame_time = 0;
-static XImage _image = {0};
-static Display *_display = NULL;
-static Window _root_window = 0;
-static GC _gc = NULL;
-static XIM _im = NULL;
-static XIC _ic = NULL;
-static Window _window = 0;
-static Window _drop_source = 0;
-static Atom _wm_delete_window = 0;
-static Atom _clipboard = 0;
-static Atom _targets = 0;
-static Atom _utf8_string = 0;
-static Atom _target = 0;
-static Atom _dnd_aware = 0;
-static Atom _dnd_enter = 0;
-static Atom _dnd_position = 0;
-static Atom _dnd_status = 0;
-static Atom _dnd_leave = 0;
-static Atom _dnd_drop = 0;
-static Atom _dnd_finished = 0;
-static Atom _dnd_action_copy = 0;
-static Atom _dnd_selection = 0;
-static Atom _text_uri_list = 0;
-static Window _dnd_source = 0;
-static b8 _mapped = 0;
+static i64 _frame_time = 0;
+static XImage _image = {0};
+static Display *_display = NULL;
+static Window _root_window = 0;
+static GC _gc = NULL;
+static XIM _im = NULL;
+static XIC _ic = NULL;
+static Window _window = 0;
+static Window _drop_source = 0;
+static Atom _wm_delete_window = 0;
+static Atom _clipboard = 0;
+static Atom _targets = 0;
+static Atom _text_plain = 0;
+static Atom _utf8_string = 0;
+static Atom _image_bmp = 0;
+static Atom _image_ppm = 0;
+static Atom _audio_wav = 0;
+static Atom _dnd_aware = 0;
+static Atom _dnd_enter = 0;
+static Atom _dnd_position = 0;
+static Atom _dnd_status = 0;
+static Atom _dnd_leave = 0;
+static Atom _dnd_drop = 0;
+static Atom _dnd_finished = 0;
+static Atom _dnd_action_copy = 0;
+static Atom _dnd_selection = 0;
+static Atom _text_uri_list = 0;
+static Window _dnd_source = 0;
+static b8 _mapped = 0;
+static b8 _requested_clipboard = 0;
+
static i16 _key_table [MAX_NUM_KEYS] = {0};
static b8 _key_repeat [MAX_NUM_KEYS] = {0};
@@ -2244,9 +2258,11 @@ void p_init(void) {
_wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", False);
_clipboard = XInternAtom(_display, "CLIPBOARD", False);
_targets = XInternAtom(_display, "TARGETS", False);
+ _text_plain = XInternAtom(_display, "text/plain", False);
_utf8_string = XInternAtom(_display, "UTF8_STRING", False);
-
- _target = None;
+ _image_bmp = XInternAtom(_display, "image/bmp", False);
+ _image_ppm = XInternAtom(_display, "image/ppm", False);
+ _audio_wav = XInternAtom(_display, "audio/wav", False);
XSetICFocus(_ic);
XSetWMProtocols(_display, _window, &_wm_delete_window, 1);
@@ -2310,8 +2326,6 @@ i32 p_handle_events(void) {
XEvent ev;
- b8 requested_clipboard = 0;
-
while (XEventsQueued(_display, QueuedAlready) > 0) {
++num_events;
@@ -2352,9 +2366,9 @@ i32 p_handle_events(void) {
case Button5 + 2: g_platform.wheel_dx += MOUSE_WHEEL_FACTOR; break;
default:;
}
- if (!requested_clipboard) {
+ if (!_requested_clipboard) {
XConvertSelection(_display, _clipboard, _targets, _clipboard, _window, CurrentTime);
- requested_clipboard = 1;
+ _requested_clipboard = 1;
}
break;
@@ -2417,9 +2431,9 @@ i32 p_handle_events(void) {
}
}
- if (!requested_clipboard) {
+ if (!_requested_clipboard) {
XConvertSelection(_display, _clipboard, _targets, _clipboard, _window, CurrentTime);
- requested_clipboard = 1;
+ _requested_clipboard = 1;
}
} break;
@@ -2446,18 +2460,37 @@ i32 p_handle_events(void) {
ev.xselectionrequest.selection == _clipboard &&
XGetSelectionOwner(_display, _clipboard) == _window) {
if (ev.xselectionrequest.property != None) {
- if (ev.xselectionrequest.target == _targets)
- XChangeProperty(
- ev.xselectionrequest.display,
- ev.xselectionrequest.requestor,
- ev.xselectionrequest.property,
- XA_ATOM,
- 32,
- PropModeReplace,
- (u8 *) &_utf8_string,
- 1
- );
- else if (ev.xselectionrequest.target == _utf8_string)
+ if (ev.xselectionrequest.target == _targets) {
+ b8 has_text = g_platform.clipboard_text_len > 0;
+ b8 has_image = g_platform.clipboard_image_width > 0 && g_platform.clipboard_image_height > 0;
+ b8 has_sound = g_platform.num_clipboard_sound_samples > 0;
+
+ if (!has_text && !has_image && !has_sound)
+ XDeleteProperty(
+ ev.xselectionrequest.display,
+ ev.xselectionrequest.requestor,
+ ev.xselectionrequest.property
+ );
+ else
+ XChangeProperty(
+ ev.xselectionrequest.display,
+ ev.xselectionrequest.requestor,
+ ev.xselectionrequest.property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ has_text && has_image && has_sound ? (u8 *) &(Atom[]) { XA_STRING, _text_plain, _utf8_string, _image_ppm, _image_bmp, _audio_wav, }
+ : has_text && has_image ? (u8 *) &(Atom[]) { XA_STRING, _text_plain, _utf8_string, _image_ppm, _image_bmp, }
+ : has_text && has_sound ? (u8 *) &(Atom[]) { XA_STRING, _text_plain, _utf8_string, _audio_wav, }
+ : has_image && has_sound ? (u8 *) &(Atom[]) { _image_ppm, _image_bmp, _audio_wav, }
+ : has_text ? (u8 *) &(Atom[]) { XA_STRING, _text_plain, _utf8_string, }
+ : has_image ? (u8 *) &(Atom[]) { _image_ppm, _image_bmp, }
+ : (u8 *) &(Atom[]) { _audio_wav, },
+ has_text * 3 + has_image * 2 + has_sound * 1
+ );
+ } else if (ev.xselectionrequest.target == XA_STRING
+ || ev.xselectionrequest.target == _text_plain
+ || ev.xselectionrequest.target == _utf8_string) {
XChangeProperty(
ev.xselectionrequest.display,
ev.xselectionrequest.requestor,
@@ -2465,9 +2498,19 @@ i32 p_handle_events(void) {
ev.xselectionrequest.target,
8,
PropModeReplace,
- (u8 *) g_platform.clipboard,
- g_platform.clipboard_size
+ (u8 *) g_platform.clipboard_text,
+ g_platform.clipboard_text_len
);
+ } else if (ev.xselectionrequest.target == _image_bmp) {
+ // TODO
+ LOG_ERROR("Send BMP image - not implemented.");
+ } else if (ev.xselectionrequest.target == _image_ppm) {
+ // TODO
+ LOG_ERROR("Send PPM image - not implemented.");
+ } else if (ev.xselectionrequest.target == _audio_wav) {
+ // TODO
+ LOG_ERROR("Send WAV audio - not implemented.");
+ }
}
XSendEvent(_display, ev.xselectionrequest.requestor, 0, 0, (XEvent *) &(XSelectionEvent) {
@@ -2560,26 +2603,67 @@ i32 p_handle_events(void) {
);
if (ev.xselection.target == _targets) {
- Atom *list = (Atom *) data;
- _target = None;
- len /= 4;
+ Atom *list = (Atom *) data;
+ Atom target_text = None;
+ Atom target_image = None;
+ Atom target_sound = None;
+ len /= 4;
for (i64 i = 0; i < len; i++)
if (list[i] == XA_STRING)
- _target = XA_STRING;
+ target_text = XA_STRING;
+ else if (list[i] == _text_plain)
+ target_text = _text_plain;
else if (list[i] == _utf8_string) {
- _target = _utf8_string;
+ target_text = _utf8_string;
+ break;
+ }
+
+ for (i64 i = 0; i < len; i++)
+ if (list[i] == _image_ppm)
+ target_image = _image_ppm;
+ else if (list[i] == _image_bmp) {
+ target_image = _image_bmp;
break;
}
- if (_target != None)
- XConvertSelection(_display, _clipboard, _target, _clipboard, _window, CurrentTime);
- } else if (ev.xselection.target == _target) {
- if (len > MAX_CLIPBOARD_SIZE)
- len = MAX_CLIPBOARD_SIZE;
- g_platform.clipboard_size = len;
+ for (i64 i = 0; i < len; i++)
+ if (list[i] == _audio_wav) {
+ target_sound = _audio_wav;
+ break;
+ }
+
+ if (target_text != None)
+ XConvertSelection(_display, _clipboard, target_text, _clipboard, _window, CurrentTime);
+
+ if (target_image != None)
+ XConvertSelection(_display, _clipboard, target_image, _clipboard, _window, CurrentTime);
+
+ if (target_sound != None)
+ XConvertSelection(_display, _clipboard, target_sound, _clipboard, _window, CurrentTime);
+
+ if (target_text == None && target_image == None && target_sound == None)
+ _requested_clipboard = 0;
+ } else if (ev.xselection.target == XA_STRING || ev.xselection.target == _text_plain || ev.xselection.target == _utf8_string) {
+ if (len >= MAX_CLIPBOARD_SIZE)
+ len = MAX_CLIPBOARD_SIZE - 1;
+ g_platform.clipboard_text_len = len;
if (len > 0)
- memcpy(g_platform.clipboard, data, len);
+ memcpy(g_platform.clipboard_text, data, len);
+ g_platform.clipboard_text[len] = '\0';
+ _requested_clipboard = 0;
+ } else if (ev.xselection.target == _image_bmp) {
+ // TODO
+ LOG_ERROR("Receive BMP image - not implemented.");
+ _requested_clipboard = 0;
+ } else if (ev.xselection.target == _image_ppm) {
+ // TODO
+ LOG_ERROR("Receive PPM image - not implemented.");
+ _requested_clipboard = 0;
+ } else if (ev.xselection.target == _audio_wav) {
+ // TODO
+ LOG_ERROR("Receive WAV audio - not implemented.");
+ _requested_clipboard = 0;
}
if (data)
@@ -2594,9 +2678,9 @@ i32 p_handle_events(void) {
case FocusIn:
g_platform.has_focus = 1;
- if (!requested_clipboard) {
+ if (!_requested_clipboard) {
XConvertSelection(_display, _clipboard, _targets, _clipboard, _window, CurrentTime);
- requested_clipboard = 1;
+ _requested_clipboard = 1;
}
break;
@@ -2790,7 +2874,7 @@ void p_render_frame(void) {
pixel_size_calubrate_(p_time() - _frame_time);
}
-void p_clipboard_write(i64 size, c8 *data) {
+void p_clipboard_write_text(i64 size, c8 *data) {
if (size > MAX_CLIPBOARD_SIZE) {
LOG_ERROR("Size is too big %lld.", size);
return;
@@ -2798,9 +2882,10 @@ void p_clipboard_write(i64 size, c8 *data) {
XSetSelectionOwner(_display, _clipboard, _window, CurrentTime);
- g_platform.clipboard_size = size < MAX_CLIPBOARD_SIZE ? size : MAX_CLIPBOARD_SIZE;
- if (g_platform.clipboard_size > 0)
- memcpy(g_platform.clipboard, data, g_platform.clipboard_size);
+ g_platform.clipboard_text_len = size < MAX_CLIPBOARD_SIZE ? size : MAX_CLIPBOARD_SIZE - 1;
+ if (g_platform.clipboard_text_len > 0)
+ memcpy(g_platform.clipboard_text, data, g_platform.clipboard_text_len);
+ g_platform.clipboard_text[g_platform.clipboard_text_len] = '\0';
}
b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) {
@@ -3117,9 +3202,9 @@ void p_render_frame(void) {
}
}
-void p_clipboard_write_impl(i32 size, c8 *data);
+void p_clipboard_write_text_impl(i32 size, c8 *data);
-void p_clipboard_write(i64 size, c8 *data) {
+void p_clipboard_write_text(i64 size, c8 *data) {
if (size < 0 || data == NULL)
return;
if (size > MAX_CLIPBOARD_SIZE)
@@ -3129,7 +3214,7 @@ void p_clipboard_write(i64 size, c8 *data) {
for (i64 i = 0; i < size; ++i)
g_platform.clipboard[i] = data[i];
- p_clipboard_write_impl((i32) size, data);
+ p_clipboard_write_text_impl((i32) size, data);
}
void p_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) {
diff --git a/stackless_coroutine.c b/stackless_coroutine.c
index a8f0cb2..705d11c 100755
--- a/stackless_coroutine.c
+++ b/stackless_coroutine.c
@@ -407,7 +407,7 @@ i32 main(i32 argc, c8 **argv) {
}
#endif
-#endif
+#endif // STACKLESS_COROUTINE_TEST_SUITE
#endif // STACKLESS_COROUTINE_IMPL_GUARD_
#endif // STACKLESS_COROUTINE_HEADER