diff options
| author | AlexanderCurl <alexc@alexc.hu> | 2026-04-18 17:46:06 +0100 |
|---|---|---|
| committer | AlexanderCurl <alexc@alexc.hu> | 2026-04-18 17:46:06 +0100 |
| commit | 70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch) | |
| tree | ab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml | |
| parent | 5d94c0a7d44a2255b81815a52a7056a94a39842d (diff) | |
| download | RaveOS-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.qml | 1494 |
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" - } -} |