Initial commit: hypr-rdp Control bar widget
Toggles the hypr-rdp systemd --user service, isolates its headless monitor's workspace via Omarchy's toggle-flag convention, shows what's running on that workspace, and manages hypr-rdp's connection credentials. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MLfSWFEMyY85ZDWEYicdaF
This commit is contained in:
124
Model.js
Normal file
124
Model.js
Normal file
@@ -0,0 +1,124 @@
|
||||
// Pure helpers for the hypr-rdp plugin: TOML-ish config patching and
|
||||
// hyprctl JSON parsing. No QML/Quickshell APIs here so this stays testable
|
||||
// with plain node/qjs.
|
||||
|
||||
function escapeTomlString(value) {
|
||||
return String(value === undefined || value === null ? "" : value)
|
||||
.replace(/\\/g, "\\\\")
|
||||
.replace(/"/g, "\\\"")
|
||||
}
|
||||
|
||||
function unescapeTomlString(value) {
|
||||
return String(value || "")
|
||||
.replace(/\\"/g, "\"")
|
||||
.replace(/\\\\/g, "\\")
|
||||
}
|
||||
|
||||
// Reads only the keys we ever show/edit (bind, username, password) from a
|
||||
// hypr-rdp config.toml. Everything else in the file is left completely
|
||||
// alone by serializeConfig below, comments included.
|
||||
function parseConfig(text) {
|
||||
var result = { bind: "", username: "", password: "" }
|
||||
var lines = String(text || "").split("\n")
|
||||
var re = /^\s*(bind|username|password)\s*=\s*"((?:[^"\\]|\\.)*)"\s*$/
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var m = lines[i].match(re)
|
||||
if (m) result[m[1]] = unescapeTomlString(m[2])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Line-level patch: replaces an existing `key = "..."` line in place,
|
||||
// appends a new one if the key was never set, and never touches any other
|
||||
// line (comments, capture_mode, bitrate, etc. survive untouched).
|
||||
function serializeConfig(originalText, patch) {
|
||||
var lines = String(originalText || "").split("\n")
|
||||
var keys = ["bind", "username", "password"]
|
||||
var seen = {}
|
||||
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
for (var k = 0; k < keys.length; k++) {
|
||||
var key = keys[k]
|
||||
if (patch[key] === undefined) continue
|
||||
var re = new RegExp("^\\s*" + key + "\\s*=")
|
||||
if (re.test(lines[i])) {
|
||||
lines[i] = key + " = \"" + escapeTomlString(patch[key]) + "\""
|
||||
seen[key] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var toAppend = []
|
||||
for (var k2 = 0; k2 < keys.length; k2++) {
|
||||
var key2 = keys[k2]
|
||||
if (patch[key2] !== undefined && !seen[key2]) {
|
||||
toAppend.push(key2 + " = \"" + escapeTomlString(patch[key2]) + "\"")
|
||||
}
|
||||
}
|
||||
|
||||
var out = lines.join("\n")
|
||||
if (toAppend.length > 0) {
|
||||
if (out.length > 0 && out.charAt(out.length - 1) !== "\n") out += "\n"
|
||||
out += toAppend.join("\n") + "\n"
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Content for the toggle flag file under
|
||||
// ~/.local/state/omarchy/toggles/hypr/. Its mere presence pins the
|
||||
// hypr-rdp headless output's workspace so Hyprland's normal
|
||||
// auto-assignment never reuses it; deleting the file removes the pin.
|
||||
function isolationLuaContent(workspaceId, outputName) {
|
||||
return "-- Managed by the jandieman.hypr-rdp bar widget's isolation\n" +
|
||||
"-- toggle. Do not hand-edit -- this file is overwritten or removed\n" +
|
||||
"-- automatically when the toggle is flipped.\n" +
|
||||
"--\n" +
|
||||
"-- Keeps the hypr-rdp headless monitor's workspace from being reused\n" +
|
||||
"-- by normal window/workspace auto-assignment, so it never silently\n" +
|
||||
"-- steals one of your visible workspaces while RDP is active.\n" +
|
||||
"hl.workspace_rule({ workspace = \"" + workspaceId + "\", monitor = \"" +
|
||||
outputName + "\", default = true, persistent = true })\n"
|
||||
}
|
||||
|
||||
function parseClients(raw, workspaceId) {
|
||||
var clients
|
||||
try {
|
||||
clients = raw ? JSON.parse(String(raw)) : []
|
||||
} catch (e) {
|
||||
clients = []
|
||||
}
|
||||
if (!Array.isArray(clients)) return []
|
||||
|
||||
var result = []
|
||||
for (var i = 0; i < clients.length; i++) {
|
||||
var c = clients[i]
|
||||
if (c && c.workspace && c.workspace.id === workspaceId) {
|
||||
result.push({
|
||||
title: String(c.title || c.initialTitle || "Untitled"),
|
||||
cls: String(c["class"] || c.initialClass || "")
|
||||
})
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function parseActiveWorkspaceId(raw) {
|
||||
try {
|
||||
var obj = JSON.parse(String(raw || ""))
|
||||
return typeof obj.id === "number" ? obj.id : -1
|
||||
} catch (e) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = {
|
||||
escapeTomlString: escapeTomlString,
|
||||
unescapeTomlString: unescapeTomlString,
|
||||
parseConfig: parseConfig,
|
||||
serializeConfig: serializeConfig,
|
||||
isolationLuaContent: isolationLuaContent,
|
||||
parseClients: parseClients,
|
||||
parseActiveWorkspaceId: parseActiveWorkspaceId
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user