Files
dms-gamebar/GameBarDaemon.qml
T
2026-09-21 21:50:32 +02:00

256 lines
7.5 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Modules.Plugins
import qs.Services
PluginComponent {
id: root
pluginId: "gameBar"
pluginService: PluginService
readonly property bool overlayOpen: overlay.shouldBeVisible
// Widget catalogue. `id` is the persistence key, the rest drives the top bar
// toggles and the default placement (fractions of the screen size).
readonly property var widgetDefs: [
{
"id": "audio",
"title": "Audio",
"icon": "volume_up",
"width": 430,
"height": 470,
"x": 0.04,
"y": 0.14,
"defaultVisible": true
},
{
"id": "apps",
"title": "Apps",
"icon": "tune",
"width": 400,
"height": 360,
"x": 0.30,
"y": 0.14,
"defaultVisible": true
},
{
"id": "media",
"title": "Media",
"icon": "music_note",
"width": 430,
"height": 300,
"x": 0.04,
"y": 0.56,
"defaultVisible": true
},
{
"id": "home",
"title": "Home",
"icon": "home",
"width": 420,
"height": 420,
"x": 0.56,
"y": 0.50,
"defaultVisible": false
},
{
"id": "system",
"title": "Performance",
"icon": "speed",
"width": 380,
"height": 330,
"x": 0.56,
"y": 0.14,
"defaultVisible": false
}
]
function widgetDef(widgetId) {
return widgetDefs.find(def => def.id === widgetId) || null;
}
// ── Visibility ───────────────────────────────────────────────────────────
function savePluginValue(key, value) {
if (pluginService)
pluginService.savePluginData(pluginId, key, value);
}
function isWidgetVisible(widgetId) {
const stored = pluginData.visibleWidgets;
if (stored && stored[widgetId] !== undefined)
return stored[widgetId] === true;
const def = widgetDef(widgetId);
return def ? def.defaultVisible === true : false;
}
function setWidgetVisible(widgetId, visible) {
const stored = Object.assign({}, pluginData.visibleWidgets || {});
stored[widgetId] = visible === true;
root.savePluginValue("visibleWidgets", stored);
}
function toggleWidget(widgetId) {
root.setWidgetVisible(widgetId, !root.isWidgetVisible(widgetId));
}
// ── Positions ────────────────────────────────────────────────────────────
// Stored per screen as fractions of the screen size, so the same layout
// survives monitors of different resolutions (and is re-clamped on load).
function screenKey(screen) {
if (!screen)
return "default";
return SettingsData.getScreenDisplayName(screen) || screen.name || "default";
}
function widgetPosition(screen, widgetId) {
const layout = pluginData.layout || {};
const perScreen = layout[root.screenKey(screen)];
const saved = perScreen ? perScreen[widgetId] : null;
if (saved && saved.x !== undefined && saved.y !== undefined)
return saved;
const def = widgetDef(widgetId);
return def ? ({
"x": def.x,
"y": def.y
}) : ({
"x": 0.1,
"y": 0.15
});
}
function saveWidgetPosition(screen, widgetId, fractionX, fractionY) {
const layout = JSON.parse(JSON.stringify(pluginData.layout || {}));
const key = root.screenKey(screen);
if (!layout[key])
layout[key] = {};
layout[key][widgetId] = {
"x": fractionX,
"y": fractionY
};
root.savePluginValue("layout", layout);
}
function resetLayout() {
root.savePluginValue("layout", {});
}
// ── Overlay ──────────────────────────────────────────────────────────────
function openOverlay() {
if (overlay.shouldBeVisible)
return;
if (typeof PopoutService !== "undefined" && PopoutService)
PopoutService.closeControlCenter();
overlay.shouldBeVisible = true;
overlay.open();
}
function closeOverlay() {
if (!overlay.shouldBeVisible)
return;
overlay.shouldBeVisible = false;
overlay.close();
}
function toggleOverlay() {
if (overlay.shouldBeVisible)
root.closeOverlay();
else
root.openOverlay();
}
IpcHandler {
target: "gameBar"
enabled: true
function toggle() : string {
root.toggleOverlay();
return "SUCCESS";
}
function open() : string {
root.openOverlay();
return "SUCCESS";
}
function close() : string {
root.closeOverlay();
return "SUCCESS";
}
function widget(name: string) : string {
if (!root.widgetDef(name))
return "UNKNOWN_WIDGET: " + name;
root.toggleWidget(name);
return "SUCCESS";
}
function homeToggle(entityId: string) : string {
if (!entityId)
return "USAGE: homeToggle <entity_id>";
const domain = haService.domainOf(entityId);
if (["scene", "script", "button", "input_button"].indexOf(domain) !== -1)
haService.press(entityId);
else
haService.toggle(entityId);
return "SUCCESS";
}
function homeStatus() : string {
const picked = Array.isArray(root.pluginData.haEntities) ? root.pluginData.haEntities.length : 0;
return "configured=" + haService.configured + " url=" + (haService.baseUrl || "(none)") + " tokenChars=" + haService.token.length + " http=" + haService.lastStatus + " entities=" + haService.entityList.length + " picked=" + picked + " error=" + (haService.lastError || "(none)");
}
function homeRefresh() : string {
haService.refresh();
return "SUCCESS";
}
function resetLayout() : string {
root.resetLayout();
return "SUCCESS";
}
}
readonly property alias homeService: haService
GameBarHomeService {
id: haService
daemon: root
}
GameBarOverlay {
id: overlay
daemon: root
}
Component.onCompleted: {
if (pluginService && pluginId) {
const instances = Object.assign({}, pluginService.pluginInstances);
instances[pluginId] = root;
pluginService.pluginInstances = instances;
}
}
Component.onDestruction: {
if (pluginService && pluginService.pluginInstances[pluginId] === root) {
const instances = Object.assign({}, pluginService.pluginInstances);
delete instances[pluginId];
pluginService.pluginInstances = instances;
}
}
}