summaryrefslogtreecommitdiff
path: root/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz
RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml')
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml1494
1 files changed, 0 insertions, 1494 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml
deleted file mode 100644
index 49748eb..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml
+++ /dev/null
@@ -1,1494 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property string socketPath: Quickshell.env("NIRI_SOCKET")
-
- property var workspaces: ({})
- property var allWorkspaces: []
- property int focusedWorkspaceIndex: 0
- property string focusedWorkspaceId: ""
- property var currentOutputWorkspaces: []
- property string currentOutput: ""
-
- property var outputs: ({})
- property var windows: []
- property var displayScales: ({})
-
- property var _realOutputs: ({})
-
- property bool inOverview: false
-
- property var casts: []
- property bool hasCasts: casts.length > 0
- property bool hasActiveCast: casts.some(c => c.is_active)
-
- property int currentKeyboardLayoutIndex: 0
- property var keyboardLayoutNames: []
-
- property string configValidationOutput: ""
- property bool hasInitialConnection: false
- property bool suppressConfigToast: true
- property bool suppressNextConfigToast: false
- property bool matugenSuppression: false
- property bool configGenerationPending: false
-
- readonly property string screenshotsDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.PicturesLocation)) + "/Screenshots"
- property string pendingScreenshotPath: ""
-
- signal windowUrgentChanged
- signal configReloaded
-
- function setWorkspaces(newMap) {
- root.workspaces = newMap;
- root.allWorkspaces = Object.values(newMap).sort((a, b) => a.idx - b.idx);
- }
-
- function validate() {
- validateProcess.running = true;
- }
-
- Component.onCompleted: fetchOutputs()
-
- Timer {
- id: suppressToastTimer
- interval: 3000
- onTriggered: root.suppressConfigToast = false
- }
-
- Timer {
- id: suppressResetTimer
- interval: 5000
- onTriggered: root.matugenSuppression = false
- }
-
- Timer {
- id: configGenerationDebounce
- interval: 100
- onTriggered: root.doGenerateNiriLayoutConfig()
- }
-
- property int _lastGapValue: -1
-
- Connections {
- target: SettingsData
- function onBarConfigsChanged() {
- const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4));
- if (newGaps === root._lastGapValue)
- return;
- root._lastGapValue = newGaps;
- generateNiriLayoutConfig();
- }
- }
-
- Process {
- id: validateProcess
- command: ["niri", "validate"]
- running: false
-
- stderr: StdioCollector {
- onStreamFinished: {
- const lines = text.split('\n');
- const trimmedLines = lines.map(line => line.replace(/\s+$/, '')).filter(line => line.length > 0);
- configValidationOutput = trimmedLines.join('\n').trim();
- }
- }
-
- onExited: exitCode => {
- if (exitCode === 0) {
- configValidationOutput = "";
- } else if (hasInitialConnection && configValidationOutput.length > 0) {
- ToastService.showError("niri: failed to load config", configValidationOutput, "", "niri-config");
- }
- }
- }
-
- Process {
- id: writeConfigProcess
- property string configContent: ""
- property string configPath: ""
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("NiriService: Generated layout config at", configPath);
- return;
- }
- console.warn("NiriService: Failed to write layout config, exit code:", exitCode);
- }
- }
-
- Process {
- id: writeAlttabProcess
- property string alttabContent: ""
- property string alttabPath: ""
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("NiriService: Generated alttab config at", alttabPath);
- return;
- }
- console.warn("NiriService: Failed to write alttab config, exit code:", exitCode);
- }
- }
-
- Process {
- id: writeBlurruleProcess
- property string blurrulePath: ""
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("NiriService: Generated wpblur config at", blurrulePath);
- return;
- }
- console.warn("NiriService: Failed to write wpblur config, exit code:", exitCode);
- }
- }
-
- Process {
- id: writeCursorProcess
- property string cursorContent: ""
- property string cursorPath: ""
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("NiriService: Generated cursor config at", cursorPath);
- return;
- }
- console.warn("NiriService: Failed to write cursor config, exit code:", exitCode);
- }
- }
-
- DankSocket {
- id: eventStreamSocket
- path: root.socketPath
- connected: CompositorService.isNiri
-
- onConnectionStateChanged: {
- if (connected) {
- send('"EventStream"');
- fetchOutputs();
- }
- }
-
- parser: SplitParser {
- onRead: line => {
- try {
- const event = JSON.parse(line);
- handleNiriEvent(event);
- } catch (e) {
- console.warn("NiriService: Failed to parse event:", line, e);
- }
- }
- }
- }
-
- DankSocket {
- id: requestSocket
- path: root.socketPath
- connected: CompositorService.isNiri
- }
-
- function fetchOutputs() {
- if (!CompositorService.isNiri)
- return;
- Proc.runCommand("niri-fetch-outputs", ["niri", "msg", "-j", "outputs"], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("NiriService: Failed to fetch outputs, exit code:", exitCode);
- return;
- }
- try {
- const outputsData = JSON.parse(output);
- outputs = outputsData;
- console.info("NiriService: Loaded", Object.keys(outputsData).length, "outputs");
- updateDisplayScales();
- if (windows.length > 0) {
- windows = sortWindowsByLayout(windows);
- }
- } catch (e) {
- console.warn("NiriService: Failed to parse outputs:", e);
- }
- });
- }
-
- function updateDisplayScales() {
- if (!outputs || Object.keys(outputs).length === 0)
- return;
- const scales = {};
- for (const outputName in outputs) {
- const output = outputs[outputName];
- if (output.logical && output.logical.scale !== undefined) {
- scales[outputName] = output.logical.scale;
- }
- }
-
- displayScales = scales;
- }
-
- function sortWindowsByLayout(windowList) {
- const enriched = windowList.map(w => {
- const ws = workspaces[w.workspace_id];
- if (!ws) {
- return {
- "window": w,
- "outputX": 999999,
- "outputY": 999999,
- "wsIdx": 999999,
- "col": 999999,
- "row": 999999
- };
- }
-
- const outputInfo = outputs[ws.output];
- const outputX = (outputInfo && outputInfo.logical) ? outputInfo.logical.x : 999999;
- const outputY = (outputInfo && outputInfo.logical) ? outputInfo.logical.y : 999999;
-
- const pos = w.layout?.pos_in_scrolling_layout;
- const col = (pos && pos.length >= 2) ? pos[0] : 999999;
- const row = (pos && pos.length >= 2) ? pos[1] : 999999;
-
- return {
- "window": w,
- "outputX": outputX,
- "outputY": outputY,
- "wsIdx": ws.idx,
- "col": col,
- "row": row
- };
- });
-
- enriched.sort((a, b) => {
- if (a.outputX !== b.outputX)
- return a.outputX - b.outputX;
- if (a.outputY !== b.outputY)
- return a.outputY - b.outputY;
- if (a.wsIdx !== b.wsIdx)
- return a.wsIdx - b.wsIdx;
- if (a.col !== b.col)
- return a.col - b.col;
- if (a.row !== b.row)
- return a.row - b.row;
- return a.window.id - b.window.id;
- });
-
- return enriched.map(e => e.window);
- }
-
- function handleNiriEvent(event) {
- const eventType = Object.keys(event)[0];
-
- switch (eventType) {
- case 'WorkspacesChanged':
- handleWorkspacesChanged(event.WorkspacesChanged);
- break;
- case 'WorkspaceActivated':
- handleWorkspaceActivated(event.WorkspaceActivated);
- break;
- case 'WorkspaceActiveWindowChanged':
- handleWorkspaceActiveWindowChanged(event.WorkspaceActiveWindowChanged);
- break;
- case 'WindowFocusChanged':
- handleWindowFocusChanged(event.WindowFocusChanged);
- break;
- case 'WindowsChanged':
- handleWindowsChanged(event.WindowsChanged);
- break;
- case 'WindowClosed':
- handleWindowClosed(event.WindowClosed);
- break;
- case 'WindowOpenedOrChanged':
- handleWindowOpenedOrChanged(event.WindowOpenedOrChanged);
- break;
- case 'WindowLayoutsChanged':
- handleWindowLayoutsChanged(event.WindowLayoutsChanged);
- break;
- case 'OutputsChanged':
- handleOutputsChanged(event.OutputsChanged);
- break;
- case 'OverviewOpenedOrClosed':
- handleOverviewChanged(event.OverviewOpenedOrClosed);
- break;
- case 'ConfigLoaded':
- handleConfigLoaded(event.ConfigLoaded);
- break;
- case 'KeyboardLayoutsChanged':
- handleKeyboardLayoutsChanged(event.KeyboardLayoutsChanged);
- break;
- case 'KeyboardLayoutSwitched':
- handleKeyboardLayoutSwitched(event.KeyboardLayoutSwitched);
- break;
- case 'WorkspaceUrgencyChanged':
- handleWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged);
- break;
- case 'WindowUrgencyChanged':
- handleWindowUrgencyChanged(event.WindowUrgencyChanged);
- break;
- case 'ScreenshotCaptured':
- handleScreenshotCaptured(event.ScreenshotCaptured);
- break;
- case 'CastsChanged':
- handleCastsChanged(event.CastsChanged);
- break;
- case 'CastStartedOrChanged':
- handleCastStartedOrChanged(event.CastStartedOrChanged);
- break;
- case 'CastStopped':
- handleCastStopped(event.CastStopped);
- break;
- }
- }
-
- function handleWorkspacesChanged(data) {
- const newWorkspaces = {};
-
- for (const ws of data.workspaces) {
- const oldWs = root.workspaces[ws.id];
- newWorkspaces[ws.id] = ws;
- if (oldWs && oldWs.active_window_id !== undefined) {
- newWorkspaces[ws.id].active_window_id = oldWs.active_window_id;
- }
- }
-
- setWorkspaces(newWorkspaces);
-
- focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.is_focused);
- if (focusedWorkspaceIndex >= 0) {
- const focusedWs = allWorkspaces[focusedWorkspaceIndex];
- focusedWorkspaceId = focusedWs.id;
- currentOutput = focusedWs.output || "";
- } else {
- focusedWorkspaceIndex = 0;
- focusedWorkspaceId = "";
- }
-
- updateCurrentOutputWorkspaces();
- }
-
- function handleWorkspaceActivated(data) {
- const ws = root.workspaces[data.id];
- if (!ws) {
- return;
- }
- const output = ws.output;
-
- const updatedWorkspaces = {};
-
- for (const id in root.workspaces) {
- const workspace = root.workspaces[id];
- const got_activated = workspace.id === data.id;
-
- const updatedWs = {};
- for (let prop in workspace) {
- updatedWs[prop] = workspace[prop];
- }
-
- if (workspace.output === output) {
- updatedWs.is_active = got_activated;
- }
-
- if (data.focused) {
- updatedWs.is_focused = got_activated;
- }
-
- updatedWorkspaces[id] = updatedWs;
- }
-
- setWorkspaces(updatedWorkspaces);
-
- focusedWorkspaceId = data.id;
- focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.id === data.id);
-
- if (focusedWorkspaceIndex >= 0) {
- currentOutput = allWorkspaces[focusedWorkspaceIndex].output || "";
- }
-
- updateCurrentOutputWorkspaces();
- }
-
- function handleWindowFocusChanged(data) {
- const focusedWindowId = data.id;
-
- let focusedWindow = null;
- const updatedWindows = [];
-
- for (var i = 0; i < windows.length; i++) {
- const w = windows[i];
- const updatedWindow = {};
-
- for (let prop in w) {
- updatedWindow[prop] = w[prop];
- }
-
- updatedWindow.is_focused = (w.id === focusedWindowId);
- if (updatedWindow.is_focused) {
- focusedWindow = updatedWindow;
- }
-
- updatedWindows.push(updatedWindow);
- }
-
- windows = updatedWindows;
-
- if (focusedWindow) {
- const ws = root.workspaces[focusedWindow.workspace_id];
- if (ws && ws.active_window_id !== focusedWindowId) {
- const updatedWs = {};
- for (let prop in ws) {
- updatedWs[prop] = ws[prop];
- }
- updatedWs.active_window_id = focusedWindowId;
-
- const updatedWorkspaces = {};
- for (const id in root.workspaces) {
- updatedWorkspaces[id] = id === focusedWindow.workspace_id ? updatedWs : root.workspaces[id];
- }
- setWorkspaces(updatedWorkspaces);
- }
- }
- }
-
- function handleWorkspaceActiveWindowChanged(data) {
- const ws = root.workspaces[data.workspace_id];
- if (ws) {
- const updatedWs = {};
- for (let prop in ws) {
- updatedWs[prop] = ws[prop];
- }
- updatedWs.active_window_id = data.active_window_id;
-
- const updatedWorkspaces = {};
- for (const id in root.workspaces) {
- updatedWorkspaces[id] = id === data.workspace_id ? updatedWs : root.workspaces[id];
- }
- setWorkspaces(updatedWorkspaces);
- }
-
- const updatedWindows = [];
-
- for (var i = 0; i < windows.length; i++) {
- const w = windows[i];
- const updatedWindow = {};
-
- for (let prop in w) {
- updatedWindow[prop] = w[prop];
- }
-
- if (data.active_window_id !== null && data.active_window_id !== undefined) {
- updatedWindow.is_focused = (w.id == data.active_window_id);
- } else {
- updatedWindow.is_focused = w.workspace_id == data.workspace_id ? false : w.is_focused;
- }
-
- updatedWindows.push(updatedWindow);
- }
-
- windows = updatedWindows;
- }
-
- function handleWindowsChanged(data) {
- windows = sortWindowsByLayout(data.windows);
- }
-
- function handleWindowClosed(data) {
- windows = windows.filter(w => w.id !== data.id);
- }
-
- function handleWindowOpenedOrChanged(data) {
- if (!data.window)
- return;
- const window = data.window;
- const existingIndex = windows.findIndex(w => w.id === window.id);
-
- if (existingIndex >= 0) {
- const updatedWindows = [...windows];
- updatedWindows[existingIndex] = window;
- windows = sortWindowsByLayout(updatedWindows);
- } else {
- windows = sortWindowsByLayout([...windows, window]);
- }
- }
-
- function handleWindowLayoutsChanged(data) {
- if (!data.changes)
- return;
- const updatedWindows = [...windows];
- let hasChanges = false;
-
- for (const change of data.changes) {
- const windowId = change[0];
- const layoutData = change[1];
-
- const windowIndex = updatedWindows.findIndex(w => w.id === windowId);
- if (windowIndex < 0)
- continue;
- const updatedWindow = {};
- for (var prop in updatedWindows[windowIndex]) {
- updatedWindow[prop] = updatedWindows[windowIndex][prop];
- }
- updatedWindow.layout = layoutData;
- updatedWindows[windowIndex] = updatedWindow;
- hasChanges = true;
- }
-
- if (!hasChanges)
- return;
- windows = sortWindowsByLayout(updatedWindows);
- }
-
- function handleOutputsChanged(data) {
- if (!data.outputs)
- return;
- outputs = data.outputs;
- updateDisplayScales();
- windows = sortWindowsByLayout(windows);
- }
-
- function handleOverviewChanged(data) {
- inOverview = data.is_open;
- }
-
- function handleConfigLoaded(data) {
- if (data.failed) {
- validateProcess.running = true;
- return;
- }
-
- configValidationOutput = "";
- ToastService.dismissCategory("niri-config");
- fetchOutputs();
- configReloaded();
-
- if (hasInitialConnection && !suppressConfigToast && !suppressNextConfigToast && !matugenSuppression) {
- ToastService.showInfo("niri: config reloaded", "", "", "niri-config");
- } else if (suppressNextConfigToast) {
- suppressNextConfigToast = false;
- suppressResetTimer.stop();
- }
-
- if (!hasInitialConnection) {
- hasInitialConnection = true;
- suppressToastTimer.start();
- }
- }
-
- function handleKeyboardLayoutsChanged(data) {
- keyboardLayoutNames = data.keyboard_layouts.names;
- currentKeyboardLayoutIndex = data.keyboard_layouts.current_idx;
- }
-
- function handleKeyboardLayoutSwitched(data) {
- currentKeyboardLayoutIndex = data.idx;
- }
-
- function handleWorkspaceUrgencyChanged(data) {
- const ws = root.workspaces[data.id];
- if (!ws)
- return;
- const updatedWs = {};
- for (let prop in ws) {
- updatedWs[prop] = ws[prop];
- }
- updatedWs.is_urgent = data.urgent;
-
- const updatedWorkspaces = {};
- for (const id in root.workspaces) {
- updatedWorkspaces[id] = id === data.id ? updatedWs : root.workspaces[id];
- }
- setWorkspaces(updatedWorkspaces);
-
- windowUrgentChanged();
- }
-
- function handleWindowUrgencyChanged(data) {
- const windowIndex = windows.findIndex(w => w.id === data.id);
- if (windowIndex < 0)
- return;
- const updatedWindows = [...windows];
- const updatedWindow = {};
- for (let prop in updatedWindows[windowIndex]) {
- updatedWindow[prop] = updatedWindows[windowIndex][prop];
- }
- updatedWindow.is_urgent = data.urgent;
- updatedWindows[windowIndex] = updatedWindow;
- windows = updatedWindows;
-
- windowUrgentChanged();
- }
-
- function handleScreenshotCaptured(data) {
- if (!data.path)
- return;
- if (pendingScreenshotPath && data.path === pendingScreenshotPath) {
- const editor = Quickshell.env("DMS_SCREENSHOT_EDITOR");
- let command;
- if (editor === "satty" || !editor) {
- command = ["satty", "-f", data.path];
- } else if (editor === "swappy") {
- command = ["swappy", "-f", data.path];
- } else {
- // Custom command with %path% placeholder
- command = editor.split(" ").map(arg => arg === "%path%" ? data.path : arg);
- }
- Quickshell.execDetached({
- "command": command
- });
- pendingScreenshotPath = "";
- }
- }
-
- function handleCastsChanged(data) {
- casts = data.casts || [];
- }
-
- function handleCastStartedOrChanged(data) {
- if (!data.cast)
- return;
- const cast = data.cast;
- const existingIndex = casts.findIndex(c => c.stream_id === cast.stream_id);
- if (existingIndex >= 0) {
- const updatedCasts = [...casts];
- updatedCasts[existingIndex] = cast;
- casts = updatedCasts;
- } else {
- casts = [...casts, cast];
- }
- }
-
- function handleCastStopped(data) {
- casts = casts.filter(c => c.stream_id !== data.stream_id);
- }
-
- function updateCurrentOutputWorkspaces() {
- if (!currentOutput) {
- currentOutputWorkspaces = allWorkspaces;
- return;
- }
-
- const outputWs = allWorkspaces.filter(w => w.output === currentOutput);
- currentOutputWorkspaces = outputWs;
- }
-
- function send(request) {
- if (!CompositorService.isNiri || !requestSocket.connected)
- return false;
- requestSocket.send(request);
- return true;
- }
-
- function doScreenTransition() {
- return send({
- "Action": {
- "DoScreenTransition": {
- "delay_ms": 0
- }
- }
- });
- }
-
- function toggleOverview() {
- return send({
- "Action": {
- "ToggleOverview": {}
- }
- });
- }
-
- function moveColumnLeft() {
- return send({
- "Action": {
- "FocusColumnLeft": {}
- }
- });
- }
-
- function moveColumnRight() {
- return send({
- "Action": {
- "FocusColumnRight": {}
- }
- });
- }
-
- function moveWorkspaceDown() {
- return send({
- "Action": {
- "FocusWorkspaceDown": {}
- }
- });
- }
-
- function moveWorkspaceUp() {
- return send({
- "Action": {
- "FocusWorkspaceUp": {}
- }
- });
- }
-
- function switchToWorkspace(workspaceIndex) {
- return send({
- "Action": {
- "FocusWorkspace": {
- "reference": {
- "Index": workspaceIndex
- }
- }
- }
- });
- }
-
- function focusWindow(windowId) {
- return send({
- "Action": {
- "FocusWindow": {
- "id": windowId
- }
- }
- });
- }
-
- function powerOffMonitors() {
- return send({
- "Action": {
- "PowerOffMonitors": {}
- }
- });
- }
-
- function powerOnMonitors() {
- return send({
- "Action": {
- "PowerOnMonitors": {}
- }
- });
- }
-
- function cycleKeyboardLayout() {
- return send({
- "Action": {
- "SwitchLayout": {
- "layout": "Next"
- }
- }
- });
- }
-
- function quit() {
- return send({
- "Action": {
- "Quit": {
- "skip_confirmation": true
- }
- }
- });
- }
-
- function screenshot() {
- pendingScreenshotPath = "";
- const timestamp = Date.now();
- const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`;
- pendingScreenshotPath = path;
-
- return send({
- "Action": {
- "Screenshot": {
- "show_pointer": true,
- "path": path
- }
- }
- });
- }
-
- function screenshotScreen() {
- pendingScreenshotPath = "";
- const timestamp = Date.now();
- const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`;
- pendingScreenshotPath = path;
-
- return send({
- "Action": {
- "ScreenshotScreen": {
- "write_to_disk": true,
- "show_pointer": true,
- "path": path
- }
- }
- });
- }
-
- function screenshotWindow() {
- pendingScreenshotPath = "";
- const timestamp = Date.now();
- const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`;
- pendingScreenshotPath = path;
-
- return send({
- "Action": {
- "ScreenshotWindow": {
- "write_to_disk": true,
- "show_pointer": true,
- "path": path
- }
- }
- });
- }
-
- function getCurrentOutputWorkspaceNumbers() {
- return currentOutputWorkspaces.map(w => w.idx + 1);
- }
-
- function getCurrentOutputWorkspaces() {
- return currentOutputWorkspaces.slice();
- }
-
- function getCurrentWorkspaceNumber() {
- if (focusedWorkspaceIndex >= 0 && focusedWorkspaceIndex < allWorkspaces.length) {
- return allWorkspaces[focusedWorkspaceIndex].idx;
- }
- return 1;
- }
-
- function getCurrentKeyboardLayoutName() {
- if (currentKeyboardLayoutIndex >= 0 && currentKeyboardLayoutIndex < keyboardLayoutNames.length) {
- return keyboardLayoutNames[currentKeyboardLayoutIndex];
- }
- return "";
- }
-
- function suppressNextToast() {
- matugenSuppression = true;
- suppressResetTimer.restart();
- }
-
- function findNiriWindow(toplevel) {
- if (!toplevel.appId)
- return null;
-
- for (var j = 0; j < windows.length; j++) {
- const niriWindow = windows[j];
- if (niriWindow.app_id === toplevel.appId) {
- if (!niriWindow.title || niriWindow.title === toplevel.title) {
- return {
- "niriIndex": j,
- "niriWindow": niriWindow
- };
- }
- }
- }
- return null;
- }
-
- function sortToplevels(toplevels) {
- if (!toplevels || toplevels.length === 0 || !CompositorService.isNiri || windows.length === 0) {
- return [...toplevels];
- }
-
- const usedToplevels = new Set();
- const enrichedToplevels = [];
-
- for (const niriWindow of sortWindowsByLayout(windows)) {
- let bestMatch = null;
- let bestScore = -1;
-
- for (const toplevel of toplevels) {
- if (usedToplevels.has(toplevel))
- continue;
- if (toplevel.appId === niriWindow.app_id) {
- let score = 1;
-
- if (niriWindow.title && toplevel.title) {
- if (toplevel.title === niriWindow.title) {
- score = 3;
- } else if (toplevel.title.includes(niriWindow.title) || niriWindow.title.includes(toplevel.title)) {
- score = 2;
- }
- }
-
- if (score > bestScore) {
- bestScore = score;
- bestMatch = toplevel;
- if (score === 3)
- break;
- }
- }
- }
-
- if (!bestMatch)
- continue;
- usedToplevels.add(bestMatch);
-
- const workspace = workspaces[niriWindow.workspace_id];
- const isFocused = niriWindow.is_focused ?? (workspace && workspace.active_window_id === niriWindow.id) ?? false;
-
- const enrichedToplevel = {
- "appId": bestMatch.appId,
- "title": bestMatch.title,
- "activated": isFocused,
- "niriWindowId": niriWindow.id,
- "niriWorkspaceId": niriWindow.workspace_id,
- "activate": function () {
- return NiriService.focusWindow(niriWindow.id);
- },
- "close": function () {
- if (bestMatch.close) {
- return bestMatch.close();
- }
- return false;
- }
- };
-
- for (let prop in bestMatch) {
- if (!(prop in enrichedToplevel)) {
- enrichedToplevel[prop] = bestMatch[prop];
- }
- }
-
- enrichedToplevels.push(enrichedToplevel);
- }
-
- for (const toplevel of toplevels) {
- if (!usedToplevels.has(toplevel)) {
- enrichedToplevels.push(toplevel);
- }
- }
-
- return enrichedToplevels;
- }
-
- function _matchAndEnrichToplevels(toplevels, niriWindows) {
- const usedToplevels = new Set();
- const result = [];
-
- for (const niriWindow of niriWindows) {
- let bestMatch = null;
- let bestScore = -1;
-
- for (const toplevel of toplevels) {
- if (usedToplevels.has(toplevel))
- continue;
- if (toplevel.appId !== niriWindow.app_id)
- continue;
-
- let score = 1;
- if (niriWindow.title && toplevel.title) {
- if (toplevel.title === niriWindow.title) {
- score = 3;
- } else if (toplevel.title.includes(niriWindow.title) || niriWindow.title.includes(toplevel.title)) {
- score = 2;
- }
- }
-
- if (score > bestScore) {
- bestScore = score;
- bestMatch = toplevel;
- if (score === 3)
- break;
- }
- }
-
- if (!bestMatch)
- continue;
- usedToplevels.add(bestMatch);
-
- const workspace = workspaces[niriWindow.workspace_id];
- const isFocused = niriWindow.is_focused ?? (workspace && workspace.active_window_id === niriWindow.id) ?? false;
-
- const enrichedToplevel = {
- "appId": bestMatch.appId,
- "title": bestMatch.title,
- "activated": isFocused,
- "niriWindowId": niriWindow.id,
- "niriWorkspaceId": niriWindow.workspace_id,
- "activate": function () {
- return NiriService.focusWindow(niriWindow.id);
- },
- "close": function () {
- if (bestMatch.close)
- return bestMatch.close();
- return false;
- }
- };
-
- for (let prop in bestMatch) {
- if (!(prop in enrichedToplevel))
- enrichedToplevel[prop] = bestMatch[prop];
- }
-
- result.push(enrichedToplevel);
- }
-
- return result;
- }
-
- function filterCurrentWorkspace(toplevels, screenName) {
- let currentWorkspaceId = null;
-
- for (var i = 0; i < allWorkspaces.length; i++) {
- const ws = allWorkspaces[i];
- if (ws.output === screenName && ws.is_active) {
- currentWorkspaceId = ws.id;
- break;
- }
- }
-
- if (currentWorkspaceId === null)
- return toplevels;
-
- if (toplevels.length > 0 && toplevels[0].niriWorkspaceId !== undefined)
- return toplevels.filter(t => t.niriWorkspaceId === currentWorkspaceId);
-
- return _matchAndEnrichToplevels(toplevels, windows.filter(nw => nw.workspace_id === currentWorkspaceId));
- }
-
- function filterCurrentDisplay(toplevels, screenName) {
- if (!toplevels || toplevels.length === 0 || !screenName)
- return toplevels;
-
- const outputWorkspaceIds = new Set();
- for (var i = 0; i < allWorkspaces.length; i++) {
- const ws = allWorkspaces[i];
- if (ws.output === screenName)
- outputWorkspaceIds.add(ws.id);
- }
-
- if (outputWorkspaceIds.size === 0)
- return toplevels;
-
- if (toplevels.length > 0 && toplevels[0].niriWorkspaceId !== undefined)
- return toplevels.filter(t => outputWorkspaceIds.has(t.niriWorkspaceId));
-
- return _matchAndEnrichToplevels(toplevels, windows.filter(nw => outputWorkspaceIds.has(nw.workspace_id)));
- }
-
- function generateNiriLayoutConfig() {
- if (!CompositorService.isNiri || configGenerationPending)
- return;
- suppressNextToast();
- configGenerationPending = true;
- configGenerationDebounce.restart();
- }
-
- function doGenerateNiriLayoutConfig() {
- console.log("NiriService: Generating layout config...");
-
- const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
- const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
- const defaultBorderSize = 2;
-
- const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutRadiusOverride >= 0) ? SettingsData.niriLayoutRadiusOverride : defaultRadius;
- const gaps = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutGapsOverride >= 0) ? SettingsData.niriLayoutGapsOverride : defaultGaps;
- const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize;
-
- const dmsWarning = `// ! DO NOT EDIT !
- // ! AUTO-GENERATED BY DMS !
- // ! CHANGES WILL BE OVERWRITTEN !
- // ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE !
-
- `;
-
- const configContent = dmsWarning + `layout {
- gaps ${gaps}
-
- border {
- width ${borderSize}
- }
-
- focus-ring {
- width ${borderSize}
- }
- }
- window-rule {
- geometry-corner-radius ${cornerRadius}
- clip-to-geometry true
- tiled-state true
- draw-border-with-background false
- }`;
-
- const alttabContent = dmsWarning + `recent-windows {
- highlight {
- corner-radius ${cornerRadius}
- }
- }`;
-
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
- const niriDmsDir = configDir + "/niri/dms";
- const configPath = niriDmsDir + "/layout.kdl";
- const alttabPath = niriDmsDir + "/alttab.kdl";
-
- writeConfigProcess.configContent = configContent;
- writeConfigProcess.configPath = configPath;
- writeConfigProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${configPath}" << 'EOF'\n${configContent}\nEOF`];
- writeConfigProcess.running = true;
-
- writeAlttabProcess.alttabContent = alttabContent;
- writeAlttabProcess.alttabPath = alttabPath;
- writeAlttabProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${alttabPath}" << 'EOF'\n${alttabContent}\nEOF`];
- writeAlttabProcess.running = true;
-
- for (const name of ["outputs", "binds", "cursor", "windowrules", "colors", "alttab", "layout"]) {
- const path = niriDmsDir + "/" + name + ".kdl";
- Proc.runCommand("niri-ensure-" + name, ["sh", "-c", `mkdir -p "${niriDmsDir}" && [ ! -f "${path}" ] && touch "${path}" || true`], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("NiriService: Failed to ensure " + name + ".kdl, exit code:", exitCode);
- });
- }
-
- configGenerationPending = false;
- }
-
- function generateNiriBlurrule() {
- console.log("NiriService: Generating wpblur config...");
-
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
- const niriDmsDir = configDir + "/niri/dms";
- const blurrulePath = niriDmsDir + "/wpblur.kdl";
- const sourceBlurrulePath = Paths.strip(Qt.resolvedUrl("niri-wpblur.kdl"));
-
- writeBlurruleProcess.blurrulePath = blurrulePath;
- writeBlurruleProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cp --no-preserve=mode "${sourceBlurrulePath}" "${blurrulePath}"`];
- writeBlurruleProcess.running = true;
- }
-
- function generateNiriCursorConfig() {
- if (!CompositorService.isNiri)
- return;
-
- console.log("NiriService: Generating cursor config...");
-
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
- const niriDmsDir = configDir + "/niri/dms";
- const cursorPath = niriDmsDir + "/cursor.kdl";
-
- const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null;
- if (!settings) {
- writeCursorProcess.cursorContent = "";
- writeCursorProcess.cursorPath = cursorPath;
- writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && : > "${cursorPath}"`];
- writeCursorProcess.running = true;
- return;
- }
-
- const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme;
- const size = settings.size || 24;
- const hideWhenTyping = settings.niri?.hideWhenTyping || false;
- const hideAfterMs = settings.niri?.hideAfterInactiveMs || 0;
-
- const isDefaultConfig = !themeName && size === 24 && !hideWhenTyping && hideAfterMs === 0;
- if (isDefaultConfig) {
- writeCursorProcess.cursorContent = "";
- writeCursorProcess.cursorPath = cursorPath;
- writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && : > "${cursorPath}"`];
- writeCursorProcess.running = true;
- return;
- }
-
- const dmsWarning = `// ! DO NOT EDIT !
-// ! AUTO-GENERATED BY DMS !
-// ! CHANGES WILL BE OVERWRITTEN !
-// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE !
-
-`;
-
- let cursorContent = dmsWarning + `cursor {\n`;
-
- if (themeName)
- cursorContent += ` xcursor-theme "${themeName}"\n`;
-
- cursorContent += ` xcursor-size ${size}\n`;
-
- if (hideWhenTyping)
- cursorContent += ` hide-when-typing\n`;
-
- if (hideAfterMs > 0)
- cursorContent += ` hide-after-inactive-ms ${hideAfterMs}\n`;
-
- cursorContent += `}`;
-
- writeCursorProcess.cursorContent = cursorContent;
- writeCursorProcess.cursorPath = cursorPath;
-
- const escapedCursorContent = cursorContent.replace(/'/g, "'\\''");
-
- writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && printf '%s' '${escapedCursorContent}' > "${cursorPath}"`];
- writeCursorProcess.running = true;
- }
-
- function updateOutputPosition(outputName, x, y) {
- if (!outputs || !outputs[outputName])
- return;
- const updatedOutputs = {};
- for (const name in outputs) {
- const output = outputs[name];
- if (name === outputName && output.logical) {
- updatedOutputs[name] = JSON.parse(JSON.stringify(output));
- updatedOutputs[name].logical.x = x;
- updatedOutputs[name].logical.y = y;
- } else {
- updatedOutputs[name] = output;
- }
- }
- outputs = updatedOutputs;
- }
-
- function applyOutputConfig(outputName, config, callback) {
- if (!CompositorService.isNiri || !outputName) {
- if (callback)
- callback(false, "Invalid config");
- return;
- }
-
- const commands = [];
-
- if (config.position !== undefined) {
- commands.push(`niri msg output "${outputName}" position ${config.position.x} ${config.position.y}`);
- }
-
- if (config.mode !== undefined) {
- commands.push(`niri msg output "${outputName}" mode ${config.mode}`);
- }
-
- if (config.vrr !== undefined) {
- commands.push(`niri msg output "${outputName}" vrr ${config.vrr ? "on" : "off"}`);
- }
-
- if (config.scale !== undefined) {
- commands.push(`niri msg output "${outputName}" scale ${config.scale}`);
- }
-
- if (config.transform !== undefined) {
- commands.push(`niri msg output "${outputName}" transform "${config.transform}"`);
- }
-
- if (commands.length === 0) {
- if (callback)
- callback(true, "No changes");
- return;
- }
-
- const fullCommand = commands.join(" && ");
- Proc.runCommand("niri-output-config", ["sh", "-c", fullCommand], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("NiriService: Failed to apply output config:", output);
- if (callback)
- callback(false, output);
- return;
- }
- console.info("NiriService: Applied output config for", outputName);
- fetchOutputs();
- if (callback)
- callback(true, "Success");
- });
- }
-
- function getOutputIdentifier(output, outputName) {
- if (SettingsData.displayNameMode === "model" && output.make && output.model) {
- const serial = output.serial || "Unknown";
- return output.make + " " + output.model + " " + serial;
- }
- return outputName;
- }
-
- function generateOutputsConfig(outputsData) {
- const data = outputsData || outputs;
- if (!data || Object.keys(data).length === 0)
- return;
- let kdlContent = `// Auto-generated by DMS - do not edit manually\n\n`;
-
- const sortedNames = Object.keys(data).sort((a, b) => {
- const la = data[a].logical || {};
- const lb = data[b].logical || {};
- return (la.x ?? 0) - (lb.x ?? 0) || (la.y ?? 0) - (lb.y ?? 0);
- });
- for (const outputName of sortedNames) {
- const output = data[outputName];
- const identifier = getOutputIdentifier(output, outputName);
- const niriSettings = SettingsData.getNiriOutputSettings(identifier);
-
- kdlContent += `output "${identifier}" {\n`;
-
- if (niriSettings.disabled) {
- kdlContent += ` off\n`;
- }
-
- if (output.current_mode !== undefined && output.modes && output.modes[output.current_mode]) {
- const mode = output.modes[output.current_mode];
- kdlContent += ` mode "${mode.width}x${mode.height}@${(mode.refresh_rate / 1000).toFixed(3)}"\n`;
- }
-
- if (output.logical) {
- kdlContent += ` scale ${output.logical.scale || 1.0}\n`;
-
- if (output.logical.transform && output.logical.transform !== "Normal") {
- const transformMap = {
- "Normal": "normal",
- "90": "90",
- "180": "180",
- "270": "270",
- "Flipped": "flipped",
- "Flipped90": "flipped-90",
- "Flipped180": "flipped-180",
- "Flipped270": "flipped-270"
- };
- kdlContent += ` transform "${transformMap[output.logical.transform] || "normal"}"\n`;
- }
-
- if (output.logical.x !== undefined && output.logical.y !== undefined) {
- kdlContent += ` position x=${output.logical.x} y=${output.logical.y}\n`;
- }
- }
-
- if (output.vrr_enabled || niriSettings.vrrOnDemand) {
- const vrrOnDemand = niriSettings.vrrOnDemand ?? false;
- kdlContent += vrrOnDemand ? ` variable-refresh-rate on-demand=true\n` : ` variable-refresh-rate\n`;
- }
-
- if (niriSettings.focusAtStartup) {
- kdlContent += ` focus-at-startup\n`;
- }
-
- if (niriSettings.backdropColor) {
- kdlContent += ` backdrop-color "${niriSettings.backdropColor}"\n`;
- }
-
- kdlContent += generateHotCornersBlock(niriSettings);
- kdlContent += generateLayoutBlock(niriSettings);
-
- kdlContent += `}\n\n`;
- }
-
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
- const niriDmsDir = configDir + "/niri/dms";
- const outputsPath = niriDmsDir + "/outputs.kdl";
-
- Proc.runCommand("niri-write-outputs", ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${kdlContent}EOF`], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("NiriService: Failed to write outputs config:", output);
- return;
- }
- console.info("NiriService: Generated outputs config at", outputsPath);
- });
- }
-
- function generateHotCornersBlock(niriSettings) {
- if (!niriSettings.hotCorners)
- return "";
- const hc = niriSettings.hotCorners;
- if (hc.off)
- return ` hot-corners {\n off\n }\n`;
- const corners = hc.corners || [];
- if (corners.length === 0)
- return "";
- let block = ` hot-corners {\n`;
- for (const corner of corners) {
- block += ` ${corner}\n`;
- }
- block += ` }\n`;
- return block;
- }
-
- function generateLayoutBlock(niriSettings) {
- if (!niriSettings.layout)
- return "";
- const layout = niriSettings.layout;
- const hasSettings = layout.gaps !== undefined || layout.defaultColumnWidth || layout.presetColumnWidths || layout.alwaysCenterSingleColumn !== undefined;
- if (!hasSettings)
- return "";
- let block = ` layout {\n`;
- if (layout.gaps !== undefined)
- block += ` gaps ${layout.gaps}\n`;
- if (layout.defaultColumnWidth?.type === "proportion") {
- const val = layout.defaultColumnWidth.value;
- const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString();
- block += ` default-column-width { proportion ${formatted}; }\n`;
- }
- if (layout.presetColumnWidths && layout.presetColumnWidths.length > 0) {
- block += ` preset-column-widths {\n`;
- for (const preset of layout.presetColumnWidths) {
- if (preset.type === "proportion") {
- const val = preset.value;
- const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString();
- block += ` proportion ${formatted}\n`;
- }
- }
- block += ` }\n`;
- }
- if (layout.alwaysCenterSingleColumn !== undefined)
- block += layout.alwaysCenterSingleColumn ? ` always-center-single-column\n` : ` always-center-single-column false\n`;
- block += ` }\n`;
- return block;
- }
-
- function renameWorkspace(name) {
- if (!name || name.trim() === "") {
- return send({
- "Action": {
- "UnsetWorkspaceName": {
- "workspace": null
- }
- }
- });
- }
- return send({
- "Action": {
- "SetWorkspaceName": {
- "name": name,
- "workspace": null
- }
- }
- });
- }
-
- function moveWorkspaceToIndex(workspaceIdx, targetIndex) {
- return send({
- "Action": {
- "MoveWorkspaceToIndex": {
- "index": targetIndex,
- "reference": {
- "Index": workspaceIdx
- }
- }
- }
- });
- }
-
- IpcHandler {
- function screenshot(): string {
- if (!CompositorService.isNiri) {
- return "NIRI_NOT_AVAILABLE";
- }
- if (NiriService.screenshot()) {
- return "SCREENSHOT_SUCCESS";
- }
- return "SCREENSHOT_FAILED";
- }
-
- function screenshotScreen(): string {
- if (!CompositorService.isNiri) {
- return "NIRI_NOT_AVAILABLE";
- }
- if (NiriService.screenshotScreen()) {
- return "SCREENSHOT_SCREEN_SUCCESS";
- }
- return "SCREENSHOT_SCREEN_FAILED";
- }
-
- function screenshotWindow(): string {
- if (!CompositorService.isNiri) {
- return "NIRI_NOT_AVAILABLE";
- }
- if (NiriService.screenshotWindow()) {
- return "SCREENSHOT_WINDOW_SUCCESS";
- }
- return "SCREENSHOT_WINDOW_FAILED";
- }
-
- target: "niri"
- }
-}