Files
MontaukOS/kernel/src/Api/Clipboard.hpp
T

221 lines
6.0 KiB
C++

/*
* Clipboard.hpp
* SYS_CLIPBOARD_* plain-text clipboard syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Sched/Scheduler.hpp>
#include <Memory/Heap.hpp>
#include <CppLib/Spinlock.hpp>
#include "Syscall.hpp"
namespace montauk::abi {
static constexpr int ClipboardMaxSlots = 32;
struct ClipboardSlot {
bool inUse;
char user[32];
char* text;
uint32_t len;
uint64_t serial;
};
static ClipboardSlot g_clipboardSlots[ClipboardMaxSlots];
static kcp::Mutex g_clipboardLock;
static int Sys_ClipboardClear();
static const char* ClipboardCurrentUser() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return nullptr;
return proc->user[0] ? proc->user : "default";
}
static void ClipboardCopyUser(char dst[32], const char* src) {
if (src == nullptr || src[0] == '\0') src = "default";
int i = 0;
for (; i < 31 && src[i]; i++)
dst[i] = src[i];
dst[i] = '\0';
}
static bool ClipboardUserEquals(const char* a, const char* b) {
int i = 0;
while (a[i] && b[i]) {
if (a[i] != b[i]) return false;
i++;
}
return a[i] == b[i];
}
static uint64_t ClipboardNextSerial(uint64_t serial) {
serial++;
return serial == 0 ? 1 : serial;
}
static ClipboardSlot* ClipboardFindSlotLocked(const char* user) {
for (int i = 0; i < ClipboardMaxSlots; i++) {
if (g_clipboardSlots[i].inUse && ClipboardUserEquals(g_clipboardSlots[i].user, user))
return &g_clipboardSlots[i];
}
return nullptr;
}
static ClipboardSlot* ClipboardEnsureSlotLocked(const char* user) {
ClipboardSlot* freeSlot = nullptr;
for (int i = 0; i < ClipboardMaxSlots; i++) {
ClipboardSlot* slot = &g_clipboardSlots[i];
if (slot->inUse) {
if (ClipboardUserEquals(slot->user, user))
return slot;
} else if (freeSlot == nullptr) {
freeSlot = slot;
}
}
if (freeSlot == nullptr) return nullptr;
freeSlot->inUse = true;
ClipboardCopyUser(freeSlot->user, user);
freeSlot->text = nullptr;
freeSlot->len = 0;
freeSlot->serial = 0;
return freeSlot;
}
static int Sys_ClipboardSetText(const char* data, uint32_t len) {
if (len == 0)
return Sys_ClipboardClear();
if (data == nullptr || len > CLIPBOARD_MAX_TEXT_BYTES || Memory::g_heap == nullptr)
return -1;
for (uint32_t i = 0; i < len; i++) {
if (data[i] == '\0')
return -1;
}
const char* currentUser = ClipboardCurrentUser();
if (currentUser == nullptr) return -1;
char user[32];
ClipboardCopyUser(user, currentUser);
char* newText = (char*)Memory::g_heap->Request(len + 1);
if (newText == nullptr) return -1;
for (uint32_t i = 0; i < len; i++)
newText[i] = data[i];
newText[len] = '\0';
char* oldText = nullptr;
g_clipboardLock.Acquire();
ClipboardSlot* slot = ClipboardEnsureSlotLocked(user);
if (slot == nullptr) {
g_clipboardLock.Release();
Memory::g_heap->Free(newText);
return -1;
}
oldText = slot->text;
slot->text = newText;
slot->len = len;
slot->serial = ClipboardNextSerial(slot->serial);
g_clipboardLock.Release();
if (oldText != nullptr)
Memory::g_heap->Free(oldText);
return 0;
}
static int Sys_ClipboardGetInfo(ClipboardInfo* out) {
if (out == nullptr) return -1;
out->textBytes = 0;
out->_pad = 0;
out->serial = 0;
const char* currentUser = ClipboardCurrentUser();
if (currentUser == nullptr) return -1;
char user[32];
ClipboardCopyUser(user, currentUser);
g_clipboardLock.Acquire();
ClipboardSlot* slot = ClipboardFindSlotLocked(user);
if (slot != nullptr) {
out->textBytes = slot->len;
out->serial = slot->serial;
}
g_clipboardLock.Release();
return 0;
}
static int Sys_ClipboardGetText(char* buffer, uint32_t bufferLen, uint32_t* outLen, uint64_t* outSerial) {
if (outLen == nullptr) return -1;
*outLen = 0;
if (outSerial != nullptr) *outSerial = 0;
const char* currentUser = ClipboardCurrentUser();
if (currentUser == nullptr) return -1;
char user[32];
ClipboardCopyUser(user, currentUser);
g_clipboardLock.Acquire();
ClipboardSlot* slot = ClipboardFindSlotLocked(user);
if (slot == nullptr || slot->len == 0) {
if (slot != nullptr && outSerial != nullptr)
*outSerial = slot->serial;
g_clipboardLock.Release();
return 0;
}
*outLen = slot->len;
if (outSerial != nullptr) *outSerial = slot->serial;
if (buffer == nullptr || bufferLen < slot->len) {
g_clipboardLock.Release();
return -1;
}
for (uint32_t i = 0; i < slot->len; i++)
buffer[i] = slot->text[i];
g_clipboardLock.Release();
return 0;
}
static int Sys_ClipboardClear() {
const char* currentUser = ClipboardCurrentUser();
if (currentUser == nullptr) return -1;
char user[32];
ClipboardCopyUser(user, currentUser);
char* oldText = nullptr;
g_clipboardLock.Acquire();
ClipboardSlot* slot = ClipboardEnsureSlotLocked(user);
if (slot == nullptr) {
g_clipboardLock.Release();
return -1;
}
oldText = slot->text;
slot->text = nullptr;
slot->len = 0;
slot->serial = ClipboardNextSerial(slot->serial);
g_clipboardLock.Release();
if (oldText != nullptr)
Memory::g_heap->Free(oldText);
return 0;
}
}