aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Jamison <jackqjamison@gmail.com>2025-10-23 13:58:43 -0400
committerJack Jamison <jackqjamison@gmail.com>2025-10-23 13:58:43 -0400
commit6933f5438f303cd90346ae779af141f910a4a1b1 (patch)
treeedd477d1d42f35bdcbc13e5dc0aef9b1c44899e6
parent9d8db4146d025e3a967700414a9fc68fa186045e (diff)
clipboard with wl-paste
-rw-r--r--data-device.c80
-rw-r--r--input_field.c18
-rw-r--r--registry.c5
-rw-r--r--seat.c1
-rw-r--r--state.h5
-rw-r--r--wayland.h1
6 files changed, 94 insertions, 16 deletions
diff --git a/data-device.c b/data-device.c
new file mode 100644
index 0000000..3d04f1e
--- /dev/null
+++ b/data-device.c
@@ -0,0 +1,80 @@
+#include "wayland.h"
+#include <unistd.h>
+
+struct wl_data_device_listener data_device_listener;
+
+void setup_data_device(client_state* state) {
+ state->data_device = wl_data_device_manager_get_data_device(state->data_device_manager, state->seat);
+ wl_data_device_add_listener(state->data_device, &data_device_listener, state);
+}
+
+static void data_offer_handle_offer(void *data, struct wl_data_offer *offer,
+ const char *mime_type) {
+}
+
+static const struct wl_data_offer_listener data_offer_listener = {
+ .offer = data_offer_handle_offer,
+};
+
+static void data_device_handle_data_offer(void *data,
+ struct wl_data_device *data_device, struct wl_data_offer *offer) {
+ // An application has created a new data source
+ wl_data_offer_add_listener(offer, &data_offer_listener, NULL);
+}
+
+static void data_device_handle_selection(void *data,
+ struct wl_data_device *data_device, struct wl_data_offer *offer) {
+
+ client_state *state = data;
+ state->data_offer = offer;
+
+ // free old clipboard
+ free(state->clipboard);
+
+ // no clipboard contents
+ if (offer == NULL) {
+ state->clipboard = "";
+ return;
+ }
+
+ // get contents in fd
+ int fds[2];
+ pipe(fds);
+ wl_data_offer_receive(offer, "text/plain", fds[1]);
+ close(fds[1]);
+ wl_display_roundtrip(state->display);
+
+ // read fd
+ state->clipboard_size = 64;
+ state->clipboard = malloc(state->clipboard_size);
+ size_t current_clip = 0;
+ while (true) {
+ ssize_t n = read(fds[0], state->clipboard + current_clip, state->clipboard_size - current_clip);
+ if (n <= 0) {
+ break;
+ }
+ current_clip += n;
+ if (current_clip == state->clipboard_size) {
+ state->clipboard_size *= 2;
+ state->clipboard = realloc(state->clipboard, state->clipboard_size);
+ }
+ }
+ close(fds[0]);
+
+ state->clipboard_size = current_clip; // we don't need the ACTUAL length of the buffer anymore, just the string :D
+ // remove newlines
+ int i, j;
+ for (i = 0, j = 0; i < state->clipboard_size; i++) {
+ if (state->clipboard[i] != '\n' && state->clipboard[i] != '\r') {
+ state->clipboard[j++] = state->clipboard[i];
+ }
+ }
+ state->clipboard_size = j;
+
+ wl_data_offer_destroy(offer);
+}
+
+struct wl_data_device_listener data_device_listener = {
+ .data_offer = data_device_handle_data_offer,
+ .selection = data_device_handle_selection,
+};
diff --git a/input_field.c b/input_field.c
index a0d5cc6..6b34b1f 100644
--- a/input_field.c
+++ b/input_field.c
@@ -123,26 +123,14 @@ bool type_key(client_state* state, xkb_keysym_t keysym) {
// paste
if (keysym == XKB_KEY_v && ctrl) {
- FILE* fp = popen("wl-paste --no-newline --type text/plain 2>/dev/null", "r");
- if (!fp) return false;
- char* buffer = NULL;
- size_t size = 0;
- ssize_t len = getdelim(&buffer, &size, '\0', fp);
- int status = pclose(fp);
-
- if (status != 0 || len <= 0) {
- free(buffer);
- return false;
- }
-
- for (size_t i = 0; i < len; ++i) {
- array_add(state->input_buffer, buffer[i]);
+ for (size_t i = 0; i < state->clipboard_size; ++i) {
+ array_insert(state->input_buffer, state->cursor_index, state->clipboard[i]);
+ ++state->cursor_index;
}
update_text_buffer(state);
- free(buffer);
return true;
}
diff --git a/registry.c b/registry.c
index 13041b8..df41580 100644
--- a/registry.c
+++ b/registry.c
@@ -24,7 +24,7 @@ void global(void *data, struct wl_registry *wl_registry, uint32_t name, const ch
state->compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 1);
}
else if (!strcmp(interface, wl_seat_interface.name)) {
- state->seat = wl_registry_bind(state->registry, name, &wl_seat_interface, 4);
+ state->seat = wl_registry_bind(wl_registry, name, &wl_seat_interface, 4);
}
else if (!strcmp(interface, zwlr_layer_shell_v1_interface.name)) {
state->layer_shell = wl_registry_bind(wl_registry, name, &zwlr_layer_shell_v1_interface, 5);
@@ -32,6 +32,9 @@ void global(void *data, struct wl_registry *wl_registry, uint32_t name, const ch
else if (!strcmp(interface, wp_cursor_shape_manager_v1_interface.name)) {
state->cursor_shape_manager = wl_registry_bind( wl_registry, name, &wp_cursor_shape_manager_v1_interface, 1);
}
+ else if (!strcmp(interface, wl_data_device_manager_interface.name)) {
+ state->data_device_manager = wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3);
+ }
else {
}
diff --git a/seat.c b/seat.c
index f90935c..fb5ffb1 100644
--- a/seat.c
+++ b/seat.c
@@ -12,6 +12,7 @@ void setup_seat(client_state* state) {
void capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) {
client_state* state = data;
+ setup_data_device(state);
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD && !state->keyboard) {
setup_keyboard(state);
}
diff --git a/state.h b/state.h
index 1c677ec..1225f6a 100644
--- a/state.h
+++ b/state.h
@@ -60,6 +60,9 @@ typedef struct {
struct zwlr_layer_shell_v1* layer_shell;
struct zwlr_layer_surface_v1* layer_surface;
struct wl_seat* seat;
+ struct wl_data_device_manager *data_device_manager;
+ struct wl_data_device *data_device;
+ struct wl_data_offer *data_offer;
struct wl_keyboard* keyboard;
struct wl_pointer* pointer;
struct wp_cursor_shape_manager_v1* cursor_shape_manager;
@@ -113,6 +116,8 @@ typedef struct {
// state
uint32_t width, height;
+ char* clipboard;
+ size_t clipboard_size;
char* input_buffer;
item_t* items;
item_display_t* filtered_items;
diff --git a/wayland.h b/wayland.h
index b6c93a3..635cfcb 100644
--- a/wayland.h
+++ b/wayland.h
@@ -6,6 +6,7 @@
void setup_registry_and_globals(client_state* state);
void create_surface(client_state* state);
void setup_seat(client_state* state);
+void setup_data_device(client_state* state);
void setup_pointer(client_state* state);
void setup_keyboard(client_state* state);