From c0c52a07376d22339a06d031892af649c2eb8acc Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Wed, 22 Jan 2025 17:27:34 +0100 Subject: Clipboard image and sound proc decls --- build_all.sh | 6 +- examples/julia_set.c | 2 +- examples/ui.c | 8 +- graphics.c | 111 +++++++++++++------- index.htm | 2 +- reduced_system_layer.c | 269 ++++++++++++++++++++++++++++++++----------------- stackless_coroutine.c | 2 +- 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 -- cgit v1.2.3