feat: add kernel clipboard manager

Adds a global kernel clipboard with write/read/len syscalls (IDs 54-56).
Exposes sys_clipboard_write/read/len() in userland libc and ui_clipboard_set/get()
in libui. Includes cliptest app for runtime verification (PASS confirmed in QEMU).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Keegan 2026-05-14 17:23:08 -06:00
parent 85c93cbcfa
commit e8a77054db
7 changed files with 139 additions and 0 deletions

View file

@ -27,6 +27,7 @@
#include "app_metadata.h"
#include "disk.h"
#include "mkfs_fat32.h"
#include "spinlock.h"
#define SYSTEM_CMD_DISK_GET_COUNT 100
#define SYSTEM_CMD_DISK_GET_INFO 101
@ -2207,6 +2208,39 @@ static uint64_t sys_cmd_get_keyboard_layout(const syscall_args_t *args) {
return (uint64_t)keymap_get_current();
}
#define CLIPBOARD_MAX_SIZE 4096
static char g_clipboard[CLIPBOARD_MAX_SIZE];
static int g_clipboard_len = 0;
static spinlock_t g_clipboard_lock = SPINLOCK_INIT;
static uint64_t sys_cmd_clipboard_write(const syscall_args_t *args) {
const char *buf = (const char *)args->arg2;
int len = (int)args->arg3;
if (!buf || len <= 0) return 0;
if (len > CLIPBOARD_MAX_SIZE) len = CLIPBOARD_MAX_SIZE;
uint64_t flags = spinlock_acquire_irqsave(&g_clipboard_lock);
for (int i = 0; i < len; i++) g_clipboard[i] = buf[i];
g_clipboard_len = len;
spinlock_release_irqrestore(&g_clipboard_lock, flags);
return (uint64_t)len;
}
static uint64_t sys_cmd_clipboard_read(const syscall_args_t *args) {
char *buf = (char *)args->arg2;
int max_len = (int)args->arg3;
if (!buf || max_len <= 0) return 0;
uint64_t flags = spinlock_acquire_irqsave(&g_clipboard_lock);
int n = g_clipboard_len < max_len ? g_clipboard_len : max_len;
for (int i = 0; i < n; i++) buf[i] = g_clipboard[i];
spinlock_release_irqrestore(&g_clipboard_lock, flags);
return (uint64_t)n;
}
static uint64_t sys_cmd_clipboard_len(const syscall_args_t *args) {
(void)args;
return (uint64_t)g_clipboard_len;
}
typedef struct {
char devname[16];
char label[32];
@ -2484,6 +2518,9 @@ static const syscall_handler_fn sys_cmd_table[SYS_CMD_TABLE_SIZE] = {
[SYSTEM_CMD_PARALLEL_RUN] = sys_cmd_parallel_run,
[SYSTEM_CMD_SET_KEYBOARD_LAYOUT] = sys_cmd_set_keyboard_layout,
[SYSTEM_CMD_GET_KEYBOARD_LAYOUT] = sys_cmd_get_keyboard_layout,
[SYSTEM_CMD_CLIPBOARD_WRITE] = sys_cmd_clipboard_write,
[SYSTEM_CMD_CLIPBOARD_READ] = sys_cmd_clipboard_read,
[SYSTEM_CMD_CLIPBOARD_LEN] = sys_cmd_clipboard_len,
[SYSTEM_CMD_SET_MOUSE_CURSOR_SCALE] = sys_cmd_set_mouse_cursor_scale,
[SYSTEM_CMD_GET_MOUSE_CURSOR_SCALE] = sys_cmd_get_mouse_cursor_scale,
[SYSTEM_CMD_TTY_CREATE] = sys_cmd_tty_create,

View file

@ -127,6 +127,10 @@ typedef struct {
#define SYSTEM_CMD_GET_ELF_METADATA 76
#define SYSTEM_CMD_GET_ELF_PRIMARY_IMAGE 77
#define SYSTEM_CMD_CLIPBOARD_WRITE 54
#define SYSTEM_CMD_CLIPBOARD_READ 55
#define SYSTEM_CMD_CLIPBOARD_LEN 56
void syscall_init(void);
uint64_t syscall_handler_c(registers_t *regs);

View file

@ -0,0 +1,61 @@
// Copyright (c) 2026 BoredOS Contributors
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
// BOREDOS_APP_DESC: Clipboard integration test.
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/copyq.png
#include "libc/syscall.h"
#include "libc/libui.h"
#include "libc/string.h"
#include <stdbool.h>
#include <stdint.h>
#define WIN_W 400
#define WIN_H 200
#define BG 0xFF1E1E2E
#define WHITE 0xFFCDD6F4
#define GREEN 0xFFA6E3A1
#define RED 0xFFF38BA8
#define GREY 0xFF45475A
static void draw(ui_window_t win, const char *written, const char *read_back, bool match) {
ui_draw_rect(win, 0, 0, WIN_W, WIN_H, BG);
ui_draw_string(win, 10, 20, "Clipboard Test", WHITE);
ui_draw_string(win, 10, 60, "Written:", GREY);
ui_draw_string(win, 90, 60, written, WHITE);
ui_draw_string(win, 10, 90, "Read back:", GREY);
ui_draw_string(win, 90, 90, read_back, WHITE);
ui_draw_string(win, 10, 130, "Result:", GREY);
if (match)
ui_draw_string(win, 90, 130, "PASS - write/read match", GREEN);
else
ui_draw_string(win, 90, 130, "FAIL - mismatch!", RED);
ui_mark_dirty(win, 0, 0, WIN_W, WIN_H);
}
int main(void) {
const char *test_str = "Hello, Clipboard!";
char read_buf[64] = {0};
ui_clipboard_set(test_str);
int n = ui_clipboard_get(read_buf, sizeof(read_buf));
bool match = (n > 0) && (strcmp(test_str, read_buf) == 0);
ui_window_t win = ui_window_create("Clipboard Test", 100, 100, WIN_W, WIN_H);
draw(win, test_str, read_buf, match);
gui_event_t ev;
while (1) {
if (!ui_get_event(win, &ev)) { sys_yield(); continue; }
if (ev.type == GUI_EVENT_CLOSE) break;
if (ev.type == GUI_EVENT_PAINT) draw(win, test_str, read_buf, match);
}
return 0;
}

View file

@ -102,3 +102,15 @@ void ui_window_set_resizable(ui_window_t win, bool resizable) {
void ui_set_font(ui_window_t win, const char *path) {
syscall3(SYS_GUI, GUI_CMD_SET_FONT, (uint64_t)win, (uint64_t)path);
}
void ui_clipboard_set(const char *text) {
if (!text) return;
int len = 0;
while (text[len]) len++;
sys_clipboard_write(text, len + 1);
}
int ui_clipboard_get(char *buf, int max_len) {
if (!buf || max_len <= 0) return 0;
return sys_clipboard_read(buf, max_len);
}

View file

@ -75,4 +75,8 @@ void ui_window_set_title(ui_window_t win, const char *title);
void ui_window_set_resizable(ui_window_t win, bool resizable);
void ui_set_font(ui_window_t win, const char *path);
// Clipboard API — text only, null-terminated strings
void ui_clipboard_set(const char *text);
int ui_clipboard_get(char *buf, int max_len);
#endif

View file

@ -89,6 +89,18 @@ int sys_system(int cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t ar
return (int)syscall5(SYS_SYSTEM, (uint64_t)cmd, arg1, arg2, arg3, arg4);
}
int sys_clipboard_write(const char *buf, int len) {
return sys_system(SYSTEM_CMD_CLIPBOARD_WRITE, (uint64_t)buf, (uint64_t)len, 0, 0);
}
int sys_clipboard_read(char *buf, int max_len) {
return sys_system(SYSTEM_CMD_CLIPBOARD_READ, (uint64_t)buf, (uint64_t)max_len, 0, 0);
}
int sys_clipboard_len(void) {
return sys_system(SYSTEM_CMD_CLIPBOARD_LEN, 0, 0, 0, 0);
}
int sys_open(const char *path, const char *mode) {
return (int)syscall3(SYS_FS, FS_CMD_OPEN, (uint64_t)path, (uint64_t)mode);
}

View file

@ -108,6 +108,10 @@
#define SYSTEM_CMD_GET_ELF_METADATA 76
#define SYSTEM_CMD_GET_ELF_PRIMARY_IMAGE 77
#define SYSTEM_CMD_CLIPBOARD_WRITE 54
#define SYSTEM_CMD_CLIPBOARD_READ 55
#define SYSTEM_CMD_CLIPBOARD_LEN 56
#define SPAWN_FLAG_TERMINAL 0x1
#define SPAWN_FLAG_INHERIT_TTY 0x2
#define SPAWN_FLAG_TTY_ID 0x4
@ -309,4 +313,9 @@ int sys_disk_sync(const char *mountpoint);
int sys_disk_rescan(const char *devname);
int sys_disk_replace_kernel(const char *src_path, const char *esp_mountpoint);
// Clipboard API
int sys_clipboard_write(const char *buf, int len);
int sys_clipboard_read(char *buf, int max_len);
int sys_clipboard_len(void);
#endif