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.c269
1 files changed, 177 insertions, 92 deletions
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) {