mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-29 16:02:51 -05:00
niri: connect directly to socket rather than running commands
This commit is contained in:
@@ -3,6 +3,7 @@ import QtQuick.Controls
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
DankModal {
|
DankModal {
|
||||||
@@ -14,25 +15,20 @@ DankModal {
|
|||||||
property string powerConfirmMessage: ""
|
property string powerConfirmMessage: ""
|
||||||
|
|
||||||
function executePowerAction(action) {
|
function executePowerAction(action) {
|
||||||
|
|
||||||
let command = [];
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "logout":
|
case "logout":
|
||||||
command = ["niri", "msg", "action", "quit", "-s"];
|
NiriService.quit();
|
||||||
break;
|
break;
|
||||||
case "suspend":
|
case "suspend":
|
||||||
command = ["systemctl", "suspend"];
|
Quickshell.execDetached(["systemctl", "suspend"]);
|
||||||
break;
|
break;
|
||||||
case "reboot":
|
case "reboot":
|
||||||
command = ["systemctl", "reboot"];
|
Quickshell.execDetached(["systemctl", "reboot"]);
|
||||||
break;
|
break;
|
||||||
case "poweroff":
|
case "poweroff":
|
||||||
command = ["systemctl", "poweroff"];
|
Quickshell.execDetached(["systemctl", "poweroff"]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (command.length > 0) {
|
|
||||||
Quickshell.execDetached(command);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: powerConfirmVisible
|
visible: powerConfirmVisible
|
||||||
|
|||||||
@@ -928,7 +928,7 @@ Item {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
logoutDialog.close()
|
logoutDialog.close()
|
||||||
Quickshell.execDetached(["niri", "msg", "action", "quit", "-s"])
|
NiriService.quit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ Rectangle {
|
|||||||
enabled: !isPlaceholder
|
enabled: !isPlaceholder
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!isPlaceholder)
|
if (!isPlaceholder)
|
||||||
Quickshell.execDetached(["niri", "msg", "action", "focus-workspace", (modelData - 1).toString()]);
|
NiriService.switchToWorkspace(modelData - 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,371 +7,293 @@ import Quickshell.Io
|
|||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// Workspace management
|
// Workspace management
|
||||||
|
property var workspaces: ({})
|
||||||
property var allWorkspaces: []
|
property var allWorkspaces: []
|
||||||
property int focusedWorkspaceIndex: 0
|
property int focusedWorkspaceIndex: 0
|
||||||
property string focusedWorkspaceId: ""
|
property string focusedWorkspaceId: ""
|
||||||
property var currentOutputWorkspaces: []
|
property var currentOutputWorkspaces: []
|
||||||
property string currentOutput: ""
|
property string currentOutput: ""
|
||||||
|
|
||||||
// Window management
|
// Window management
|
||||||
property var windows: []
|
property var windows: []
|
||||||
property int focusedWindowIndex: -1
|
property int focusedWindowIndex: -1
|
||||||
property string focusedWindowTitle: "(No active window)"
|
property string focusedWindowTitle: "(No active window)"
|
||||||
property string focusedWindowId: ""
|
property string focusedWindowId: ""
|
||||||
|
|
||||||
// Overview state
|
// Overview state
|
||||||
property bool inOverview: false
|
property bool inOverview: false
|
||||||
|
|
||||||
signal windowOpenedOrChanged(var windowData)
|
signal windowOpenedOrChanged(var windowData)
|
||||||
|
|
||||||
// Feature availability
|
// Feature availability
|
||||||
property bool niriAvailable: false
|
property bool niriAvailable: false
|
||||||
|
|
||||||
Component.onCompleted: {
|
readonly property string socketPath: Quickshell.env("NIRI_SOCKET")
|
||||||
console.log("NiriService: Component.onCompleted - initializing service")
|
|
||||||
checkNiriAvailability()
|
Component.onCompleted: checkNiriAvailability()
|
||||||
}
|
|
||||||
|
|
||||||
// Check if niri is available
|
|
||||||
Process {
|
Process {
|
||||||
id: niriCheck
|
id: niriCheck
|
||||||
command: ["which", "niri"]
|
command: ["test", "-S", root.socketPath]
|
||||||
|
|
||||||
onExited: (exitCode) => {
|
onExited: exitCode => {
|
||||||
root.niriAvailable = exitCode === 0
|
root.niriAvailable = exitCode === 0;
|
||||||
if (root.niriAvailable) {
|
if (root.niriAvailable) {
|
||||||
console.log("NiriService: niri found, starting event stream and loading initial data")
|
eventStreamSocket.connected = true;
|
||||||
eventStreamProcess.running = true
|
|
||||||
loadInitialWorkspaceData()
|
|
||||||
} else {
|
|
||||||
console.log("NiriService: niri not found, workspace features disabled")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkNiriAvailability() {
|
function checkNiriAvailability() {
|
||||||
niriCheck.running = true
|
niriCheck.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load initial workspace data
|
Socket {
|
||||||
Process {
|
id: eventStreamSocket
|
||||||
id: initialDataQuery
|
path: root.socketPath
|
||||||
command: ["niri", "msg", "-j", "workspaces"]
|
connected: false
|
||||||
running: false
|
|
||||||
|
onConnectionStateChanged: {
|
||||||
stdout: StdioCollector {
|
if (connected) {
|
||||||
onStreamFinished: {
|
write('"EventStream"\n');
|
||||||
if (text && text.trim()) {
|
|
||||||
try {
|
|
||||||
console.log("NiriService: Loaded initial workspace data")
|
|
||||||
const workspaces = JSON.parse(text.trim())
|
|
||||||
// Initial query returns array directly, event stream wraps it in WorkspacesChanged
|
|
||||||
handleWorkspacesChanged({ workspaces: workspaces })
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("NiriService: Failed to parse initial workspace data:", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
parser: SplitParser {
|
||||||
// Load initial windows data
|
onRead: line => {
|
||||||
Process {
|
|
||||||
id: initialWindowsQuery
|
|
||||||
command: ["niri", "msg", "-j", "windows"]
|
|
||||||
running: false
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
if (text && text.trim()) {
|
|
||||||
try {
|
|
||||||
const windowsData = JSON.parse(text.trim())
|
|
||||||
if (windowsData && windowsData.windows) {
|
|
||||||
handleWindowsChanged(windowsData)
|
|
||||||
console.log("NiriService: Loaded", windowsData.windows.length, "initial windows")
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("NiriService: Failed to parse initial windows data:", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load initial focused window data
|
|
||||||
Process {
|
|
||||||
id: initialFocusedWindowQuery
|
|
||||||
command: ["niri", "msg", "-j", "focused-window"]
|
|
||||||
running: false
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
if (text && text.trim()) {
|
|
||||||
try {
|
|
||||||
const focusedData = JSON.parse(text.trim())
|
|
||||||
if (focusedData && focusedData.id) {
|
|
||||||
handleWindowFocusChanged({ id: focusedData.id })
|
|
||||||
console.log("NiriService: Loaded initial focused window:", focusedData.id)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("NiriService: Failed to parse initial focused window data:", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadInitialWorkspaceData() {
|
|
||||||
console.log("NiriService: Loading initial workspace data...")
|
|
||||||
initialDataQuery.running = true
|
|
||||||
initialWindowsQuery.running = true
|
|
||||||
initialFocusedWindowQuery.running = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event stream for real-time updates
|
|
||||||
Process {
|
|
||||||
id: eventStreamProcess
|
|
||||||
command: ["niri", "msg", "-j", "event-stream"]
|
|
||||||
running: false // Will be enabled after niri check
|
|
||||||
|
|
||||||
stdout: SplitParser {
|
|
||||||
onRead: data => {
|
|
||||||
try {
|
try {
|
||||||
const event = JSON.parse(data.trim())
|
const event = JSON.parse(line);
|
||||||
handleNiriEvent(event)
|
handleNiriEvent(event);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("NiriService: Failed to parse event:", data, e)
|
console.warn("NiriService: Failed to parse event:", line, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: (exitCode) => {
|
|
||||||
if (exitCode !== 0 && root.niriAvailable) {
|
|
||||||
console.warn("NiriService: Event stream exited with code", exitCode, "restarting immediately")
|
|
||||||
eventStreamProcess.running = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Socket {
|
||||||
|
id: requestSocket
|
||||||
|
path: root.socketPath
|
||||||
|
connected: root.niriAvailable
|
||||||
|
}
|
||||||
|
|
||||||
function handleNiriEvent(event) {
|
function handleNiriEvent(event) {
|
||||||
if (event.WorkspacesChanged) {
|
if (event.WorkspacesChanged) {
|
||||||
handleWorkspacesChanged(event.WorkspacesChanged)
|
handleWorkspacesChanged(event.WorkspacesChanged);
|
||||||
} else if (event.WorkspaceActivated) {
|
} else if (event.WorkspaceActivated) {
|
||||||
handleWorkspaceActivated(event.WorkspaceActivated)
|
handleWorkspaceActivated(event.WorkspaceActivated);
|
||||||
} else if (event.WindowsChanged) {
|
} else if (event.WindowsChanged) {
|
||||||
handleWindowsChanged(event.WindowsChanged)
|
handleWindowsChanged(event.WindowsChanged);
|
||||||
} else if (event.WindowClosed) {
|
} else if (event.WindowClosed) {
|
||||||
handleWindowClosed(event.WindowClosed)
|
handleWindowClosed(event.WindowClosed);
|
||||||
} else if (event.WindowFocusChanged) {
|
} else if (event.WindowFocusChanged) {
|
||||||
handleWindowFocusChanged(event.WindowFocusChanged)
|
handleWindowFocusChanged(event.WindowFocusChanged);
|
||||||
} else if (event.WindowOpenedOrChanged) {
|
} else if (event.WindowOpenedOrChanged) {
|
||||||
handleWindowOpenedOrChanged(event.WindowOpenedOrChanged)
|
handleWindowOpenedOrChanged(event.WindowOpenedOrChanged);
|
||||||
} else if (event.OverviewOpenedOrClosed) {
|
} else if (event.OverviewOpenedOrClosed) {
|
||||||
handleOverviewChanged(event.OverviewOpenedOrClosed)
|
handleOverviewChanged(event.OverviewOpenedOrClosed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWorkspacesChanged(data) {
|
function handleWorkspacesChanged(data) {
|
||||||
allWorkspaces = [...data.workspaces].sort((a, b) => a.idx - b.idx)
|
const workspaces = {};
|
||||||
|
|
||||||
// Update focused workspace
|
for (const ws of data.workspaces) {
|
||||||
focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.is_focused)
|
workspaces[ws.id] = ws;
|
||||||
if (focusedWorkspaceIndex >= 0) {
|
|
||||||
var focusedWs = allWorkspaces[focusedWorkspaceIndex]
|
|
||||||
focusedWorkspaceId = focusedWs.id
|
|
||||||
currentOutput = focusedWs.output || ""
|
|
||||||
} else {
|
|
||||||
focusedWorkspaceIndex = 0
|
|
||||||
focusedWorkspaceId = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCurrentOutputWorkspaces()
|
root.workspaces = workspaces;
|
||||||
|
allWorkspaces = [...data.workspaces].sort((a, b) => a.idx - b.idx);
|
||||||
|
|
||||||
|
focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.is_focused);
|
||||||
|
if (focusedWorkspaceIndex >= 0) {
|
||||||
|
var focusedWs = allWorkspaces[focusedWorkspaceIndex];
|
||||||
|
focusedWorkspaceId = focusedWs.id;
|
||||||
|
currentOutput = focusedWs.output || "";
|
||||||
|
} else {
|
||||||
|
focusedWorkspaceIndex = 0;
|
||||||
|
focusedWorkspaceId = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCurrentOutputWorkspaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWorkspaceActivated(data) {
|
function handleWorkspaceActivated(data) {
|
||||||
// Update focused workspace
|
const ws = root.workspaces[data.id];
|
||||||
focusedWorkspaceId = data.id
|
if (!ws)
|
||||||
focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.id === data.id)
|
return;
|
||||||
|
const output = ws.output;
|
||||||
if (focusedWorkspaceIndex >= 0) {
|
|
||||||
var activatedWs = allWorkspaces[focusedWorkspaceIndex]
|
for (const id in root.workspaces) {
|
||||||
|
const workspace = root.workspaces[id];
|
||||||
// Update workspace states properly
|
const got_activated = workspace.id === data.id;
|
||||||
// First, deactivate all workspaces on this output
|
|
||||||
for (var i = 0; i < allWorkspaces.length; i++) {
|
if (workspace.output === output) {
|
||||||
if (allWorkspaces[i].output === activatedWs.output) {
|
workspace.is_active = got_activated;
|
||||||
allWorkspaces[i].is_active = false
|
}
|
||||||
allWorkspaces[i].is_focused = false
|
|
||||||
}
|
if (data.focused) {
|
||||||
|
workspace.is_focused = got_activated;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then activate the new workspace
|
|
||||||
allWorkspaces[focusedWorkspaceIndex].is_active = true
|
|
||||||
allWorkspaces[focusedWorkspaceIndex].is_focused = data.focused || false
|
|
||||||
|
|
||||||
currentOutput = activatedWs.output || ""
|
|
||||||
|
|
||||||
updateCurrentOutputWorkspaces()
|
|
||||||
|
|
||||||
// Force property change notifications
|
|
||||||
allWorkspacesChanged()
|
|
||||||
} else {
|
|
||||||
focusedWorkspaceIndex = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
focusedWorkspaceId = data.id;
|
||||||
|
focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.id === data.id);
|
||||||
|
|
||||||
|
if (focusedWorkspaceIndex >= 0) {
|
||||||
|
currentOutput = allWorkspaces[focusedWorkspaceIndex].output || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
allWorkspaces = Object.values(root.workspaces).sort((a, b) => a.idx - b.idx);
|
||||||
|
|
||||||
|
updateCurrentOutputWorkspaces();
|
||||||
|
workspacesChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWindowsChanged(data) {
|
function handleWindowsChanged(data) {
|
||||||
windows = [...data.windows].sort((a, b) => a.id - b.id)
|
windows = [...data.windows].sort((a, b) => a.id - b.id);
|
||||||
updateFocusedWindow()
|
updateFocusedWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWindowClosed(data) {
|
function handleWindowClosed(data) {
|
||||||
windows = windows.filter(w => w.id !== data.id)
|
windows = windows.filter(w => w.id !== data.id);
|
||||||
updateFocusedWindow()
|
updateFocusedWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWindowFocusChanged(data) {
|
function handleWindowFocusChanged(data) {
|
||||||
if (data.id) {
|
if (data.id) {
|
||||||
focusedWindowId = data.id
|
focusedWindowId = data.id;
|
||||||
focusedWindowIndex = windows.findIndex(w => w.id === data.id)
|
focusedWindowIndex = windows.findIndex(w => w.id === data.id);
|
||||||
} else {
|
} else {
|
||||||
focusedWindowId = ""
|
focusedWindowId = "";
|
||||||
focusedWindowIndex = -1
|
focusedWindowIndex = -1;
|
||||||
}
|
}
|
||||||
updateFocusedWindow()
|
updateFocusedWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWindowOpenedOrChanged(data) {
|
function handleWindowOpenedOrChanged(data) {
|
||||||
if (!data.window) return;
|
if (!data.window)
|
||||||
|
return;
|
||||||
|
|
||||||
const window = data.window;
|
const window = data.window;
|
||||||
const existingIndex = windows.findIndex(w => w.id === window.id);
|
const existingIndex = windows.findIndex(w => w.id === window.id);
|
||||||
|
|
||||||
if (existingIndex >= 0) {
|
if (existingIndex >= 0) {
|
||||||
// Update existing window - create new array to trigger property change
|
|
||||||
let updatedWindows = [...windows];
|
let updatedWindows = [...windows];
|
||||||
updatedWindows[existingIndex] = window;
|
updatedWindows[existingIndex] = window;
|
||||||
windows = updatedWindows.sort((a, b) => a.id - b.id);
|
windows = updatedWindows.sort((a, b) => a.id - b.id);
|
||||||
} else {
|
} else {
|
||||||
// Add new window
|
|
||||||
windows = [...windows, window].sort((a, b) => a.id - b.id);
|
windows = [...windows, window].sort((a, b) => a.id - b.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update focused window if this window is focused
|
|
||||||
if (window.is_focused) {
|
if (window.is_focused) {
|
||||||
focusedWindowId = window.id;
|
focusedWindowId = window.id;
|
||||||
focusedWindowIndex = windows.findIndex(w => w.id === window.id);
|
focusedWindowIndex = windows.findIndex(w => w.id === window.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFocusedWindow();
|
updateFocusedWindow();
|
||||||
|
|
||||||
// Emit signal for other services to listen to
|
|
||||||
windowOpenedOrChanged(window);
|
windowOpenedOrChanged(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOverviewChanged(data) {
|
function handleOverviewChanged(data) {
|
||||||
inOverview = data.is_open
|
inOverview = data.is_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCurrentOutputWorkspaces() {
|
function updateCurrentOutputWorkspaces() {
|
||||||
if (!currentOutput) {
|
if (!currentOutput) {
|
||||||
currentOutputWorkspaces = allWorkspaces
|
currentOutputWorkspaces = allWorkspaces;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter workspaces for current output
|
var outputWs = allWorkspaces.filter(w => w.output === currentOutput);
|
||||||
var outputWs = allWorkspaces.filter(w => w.output === currentOutput)
|
currentOutputWorkspaces = outputWs;
|
||||||
currentOutputWorkspaces = outputWs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFocusedWindow() {
|
function updateFocusedWindow() {
|
||||||
if (focusedWindowIndex >= 0 && focusedWindowIndex < windows.length) {
|
if (focusedWindowIndex >= 0 && focusedWindowIndex < windows.length) {
|
||||||
var focusedWin = windows[focusedWindowIndex]
|
var focusedWin = windows[focusedWindowIndex];
|
||||||
focusedWindowTitle = focusedWin.title || "(Unnamed window)"
|
focusedWindowTitle = focusedWin.title || "(Unnamed window)";
|
||||||
} else {
|
} else {
|
||||||
focusedWindowTitle = "(No active window)"
|
focusedWindowTitle = "(No active window)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public API functions
|
function send(request) {
|
||||||
function switchToWorkspace(workspaceId) {
|
if (!niriAvailable || !requestSocket.connected)
|
||||||
if (!niriAvailable) return false
|
return false;
|
||||||
|
requestSocket.write(JSON.stringify(request) + "\n");
|
||||||
Quickshell.execDetached(["niri", "msg", "action", "focus-workspace", workspaceId.toString()])
|
return true;
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchToWorkspaceByIndex(index) {
|
function switchToWorkspace(workspaceIndex) {
|
||||||
if (!niriAvailable || index < 0 || index >= allWorkspaces.length) return false
|
return send({
|
||||||
|
Action: {
|
||||||
var workspace = allWorkspaces[index]
|
FocusWorkspace: {
|
||||||
return switchToWorkspace(workspace.id)
|
reference: {
|
||||||
|
Index: workspaceIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchToWorkspaceByNumber(number, output) {
|
|
||||||
if (!niriAvailable) return false
|
|
||||||
|
|
||||||
var targetOutput = output || currentOutput
|
|
||||||
if (!targetOutput) {
|
|
||||||
console.warn("NiriService: No output specified for workspace switching")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get workspaces for the target output, sorted by idx
|
|
||||||
var outputWorkspaces = allWorkspaces.filter(w => w.output === targetOutput).sort((a, b) => a.idx - b.idx)
|
|
||||||
|
|
||||||
// Use sequential index (number is 1-based, array is 0-based)
|
|
||||||
if (number >= 1 && number <= outputWorkspaces.length) {
|
|
||||||
var workspace = outputWorkspaces[number - 1]
|
|
||||||
return switchToWorkspace(workspace.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn("NiriService: No workspace", number, "found on output", targetOutput)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCurrentOutputWorkspaceNumbers() {
|
function getCurrentOutputWorkspaceNumbers() {
|
||||||
return currentOutputWorkspaces.map(w => w.idx + 1) // niri uses 0-based, UI shows 1-based
|
return currentOutputWorkspaces.map(w => w.idx + 1); // niri uses 0-based, UI shows 1-based
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentWorkspaceNumber() {
|
function getCurrentWorkspaceNumber() {
|
||||||
if (focusedWorkspaceIndex >= 0 && focusedWorkspaceIndex < allWorkspaces.length) {
|
if (focusedWorkspaceIndex >= 0 && focusedWorkspaceIndex < allWorkspaces.length) {
|
||||||
return allWorkspaces[focusedWorkspaceIndex].idx + 1
|
return allWorkspaces[focusedWorkspaceIndex].idx + 1;
|
||||||
}
|
}
|
||||||
return 1
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusWindow(windowId) {
|
function focusWindow(windowId) {
|
||||||
if (!niriAvailable) return false
|
return send({
|
||||||
|
Action: {
|
||||||
console.log("NiriService: Focusing window with command:", ["niri", "msg", "action", "focus-window", "--id", windowId.toString()])
|
FocusWindow: {
|
||||||
Quickshell.execDetached(["niri", "msg", "action", "focus-window", "--id", windowId.toString()])
|
id: windowId
|
||||||
return true
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeWindow(windowId) {
|
function closeWindow(windowId) {
|
||||||
if (!niriAvailable) return false
|
return send({
|
||||||
|
Action: {
|
||||||
console.log("NiriService: Closing window with command:", ["niri", "msg", "action", "close-window", "--id", windowId.toString()])
|
CloseWindow: {
|
||||||
Quickshell.execDetached(["niri", "msg", "action", "close-window", "--id", windowId.toString()])
|
id: windowId
|
||||||
return true
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function quit() {
|
||||||
|
return send({
|
||||||
|
Action: {
|
||||||
|
Quit: {
|
||||||
|
skip_confirmation: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getWindowsByAppId(appId) {
|
function getWindowsByAppId(appId) {
|
||||||
if (!appId) return []
|
if (!appId)
|
||||||
return windows.filter(w => w.app_id && w.app_id.toLowerCase() === appId.toLowerCase())
|
return [];
|
||||||
|
return windows.filter(w => w.app_id && w.app_id.toLowerCase() === appId.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRunningAppIds() {
|
function getRunningAppIds() {
|
||||||
var appIds = new Set()
|
var appIds = new Set();
|
||||||
windows.forEach(w => {
|
windows.forEach(w => {
|
||||||
if (w.app_id) {
|
if (w.app_id) {
|
||||||
appIds.add(w.app_id.toLowerCase())
|
appIds.add(w.app_id.toLowerCase());
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return Array.from(appIds)
|
return Array.from(appIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user