1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-08 06:25:37 -05:00

niri: improve toplevel sorting

This commit is contained in:
bbedward
2025-10-23 10:33:24 -04:00
parent beab1a7b01
commit 4e43c797e2
2 changed files with 186 additions and 103 deletions

View File

@@ -37,7 +37,7 @@ Singleton {
property bool matugenSuppression: false
property bool configGenerationPending: false
signal windowUrgentChanged()
signal windowUrgentChanged
Component.onCompleted: fetchOutputs()
@@ -140,28 +140,30 @@ Singleton {
}
function fetchOutputs() {
if (!CompositorService.isNiri) return
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.log("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)
}
})
if (exitCode !== 0) {
console.warn("NiriService: Failed to fetch outputs, exit code:", exitCode)
return
}
try {
const outputsData = JSON.parse(output)
outputs = outputsData
console.log("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
if (!outputs || Object.keys(outputs).length === 0)
return
const scales = {}
for (const outputName in outputs) {
@@ -176,48 +178,48 @@ Singleton {
function sortWindowsByLayout(windowList) {
return [...windowList].sort((a, b) => {
const aWorkspace = workspaces[a.workspace_id]
const bWorkspace = workspaces[b.workspace_id]
const aWorkspace = workspaces[a.workspace_id]
const bWorkspace = workspaces[b.workspace_id]
if (aWorkspace && bWorkspace) {
const aOutput = aWorkspace.output
const bOutput = bWorkspace.output
if (aWorkspace && bWorkspace) {
const aOutput = aWorkspace.output
const bOutput = bWorkspace.output
const aOutputInfo = outputs[aOutput]
const bOutputInfo = outputs[bOutput]
const aOutputInfo = outputs[aOutput]
const bOutputInfo = outputs[bOutput]
if (aOutputInfo && bOutputInfo && aOutputInfo.logical && bOutputInfo.logical) {
if (aOutputInfo.logical.x !== bOutputInfo.logical.x) {
return aOutputInfo.logical.x - bOutputInfo.logical.x
}
if (aOutputInfo.logical.y !== bOutputInfo.logical.y) {
return aOutputInfo.logical.y - bOutputInfo.logical.y
}
}
if (aOutputInfo && bOutputInfo && aOutputInfo.logical && bOutputInfo.logical) {
if (aOutputInfo.logical.x !== bOutputInfo.logical.x) {
return aOutputInfo.logical.x - bOutputInfo.logical.x
}
if (aOutputInfo.logical.y !== bOutputInfo.logical.y) {
return aOutputInfo.logical.y - bOutputInfo.logical.y
}
}
if (aOutput === bOutput && aWorkspace.idx !== bWorkspace.idx) {
return aWorkspace.idx - bWorkspace.idx
}
}
if (aOutput === bOutput && aWorkspace.idx !== bWorkspace.idx) {
return aWorkspace.idx - bWorkspace.idx
}
}
if (a.workspace_id === b.workspace_id && a.layout && b.layout) {
if (a.layout.pos_in_scrolling_layout && b.layout.pos_in_scrolling_layout) {
const aPos = a.layout.pos_in_scrolling_layout
const bPos = b.layout.pos_in_scrolling_layout
if (a.workspace_id === b.workspace_id && a.layout && b.layout) {
if (a.layout.pos_in_scrolling_layout && b.layout.pos_in_scrolling_layout) {
const aPos = a.layout.pos_in_scrolling_layout
const bPos = b.layout.pos_in_scrolling_layout
if (aPos.length > 1 && bPos.length > 1) {
if (aPos[0] !== bPos[0]) {
return aPos[0] - bPos[0]
}
if (aPos[1] !== bPos[1]) {
return aPos[1] - bPos[1]
}
}
}
}
if (aPos.length > 1 && bPos.length > 1) {
if (aPos[0] !== bPos[0]) {
return aPos[0] - bPos[0]
}
if (aPos[1] !== bPos[1]) {
return aPos[1] - bPos[1]
}
}
}
}
return a.id - b.id
})
return a.id - b.id
})
}
function handleNiriEvent(event) {
@@ -354,7 +356,8 @@ Singleton {
}
function handleWindowOpenedOrChanged(data) {
if (!data.window) return
if (!data.window)
return
const window = data.window
const existingIndex = windows.findIndex(w => w.id === window.id)
@@ -370,7 +373,8 @@ Singleton {
}
function handleWindowLayoutsChanged(data) {
if (!data.changes) return
if (!data.changes)
return
const updatedWindows = [...windows]
let hasChanges = false
@@ -380,7 +384,8 @@ Singleton {
const layoutData = change[1]
const windowIndex = updatedWindows.findIndex(w => w.id === windowId)
if (windowIndex < 0) continue
if (windowIndex < 0)
continue
const updatedWindow = {}
for (var prop in updatedWindows[windowIndex]) {
@@ -391,14 +396,16 @@ Singleton {
hasChanges = true
}
if (!hasChanges) return
if (!hasChanges)
return
windows = sortWindowsByLayout(updatedWindows)
windowsChanged()
}
function handleOutputsChanged(data) {
if (!data.outputs) return
if (!data.outputs)
return
outputs = data.outputs
updateDisplayScales()
windows = sortWindowsByLayout(windows)
@@ -442,7 +449,8 @@ Singleton {
function handleWorkspaceUrgencyChanged(data) {
const ws = root.workspaces[data.id]
if (!ws) return
if (!ws)
return
ws.is_urgent = data.urgent
@@ -465,41 +473,86 @@ Singleton {
}
function send(request) {
if (!CompositorService.isNiri || !requestSocket.connected) return false
if (!CompositorService.isNiri || !requestSocket.connected)
return false
requestSocket.send(request)
return true
}
function doScreenTransition() {
return send({"Action": {"DoScreenTransition": {"delay_ms": 0}}})
return send({
"Action": {
"DoScreenTransition": {
"delay_ms": 0
}
}
})
}
function toggleOverview() {
return send({"Action": {"ToggleOverview": {}}})
return send({
"Action": {
"ToggleOverview": {}
}
})
}
function switchToWorkspace(workspaceIndex) {
return send({"Action": {"FocusWorkspace": {"reference": {"Index": workspaceIndex}}}})
return send({
"Action": {
"FocusWorkspace": {
"reference": {
"Index": workspaceIndex
}
}
}
})
}
function focusWindow(windowId) {
return send({"Action": {"FocusWindow": {"id": windowId}}})
return send({
"Action": {
"FocusWindow": {
"id": windowId
}
}
})
}
function powerOffMonitors() {
return send({"Action": {"PowerOffMonitors": {}}})
return send({
"Action": {
"PowerOffMonitors": {}
}
})
}
function powerOnMonitors() {
return send({"Action": {"PowerOnMonitors": {}}})
return send({
"Action": {
"PowerOnMonitors": {}
}
})
}
function cycleKeyboardLayout() {
return send({"Action": {"SwitchLayout": {"layout": "Next"}}})
return send({
"Action": {
"SwitchLayout": {
"layout": "Next"
}
}
})
}
function quit() {
return send({"Action": {"Quit": {"skip_confirmation": true}}})
return send({
"Action": {
"Quit": {
"skip_confirmation": true
}
}
})
}
function getCurrentOutputWorkspaceNumbers() {
@@ -526,13 +579,17 @@ Singleton {
}
function findNiriWindow(toplevel) {
if (!toplevel.appId) return null
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 {
"niriIndex": j,
"niriWindow": niriWindow
}
}
}
}
@@ -549,35 +606,47 @@ Singleton {
for (const niriWindow of sortWindowsByLayout(windows)) {
let bestMatch = null
let bestScore = -1
for (const toplevel of toplevels) {
if (usedToplevels.has(toplevel)) continue
if (usedToplevels.has(toplevel))
continue
if (toplevel.appId === niriWindow.app_id) {
if (niriWindow.title && toplevel.title === niriWindow.title) {
bestMatch = toplevel
break
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 (!niriWindow.title && !bestMatch) {
if (score > bestScore) {
bestScore = score
bestMatch = toplevel
if (score === 3)
break
}
}
}
if (!bestMatch) continue
if (!bestMatch)
continue
usedToplevels.add(bestMatch)
const enrichedToplevel = {
appId: bestMatch.appId,
title: bestMatch.title,
activated: bestMatch.activated,
niriWindowId: niriWindow.id,
niriWorkspaceId: niriWindow.workspace_id,
activate: function() {
"appId": bestMatch.appId,
"title": bestMatch.title,
"activated": bestMatch.activated,
"niriWindowId": niriWindow.id,
"niriWorkspaceId": niriWindow.workspace_id,
"activate": function () {
return NiriService.focusWindow(niriWindow.id)
},
close: function() {
"close": function () {
if (bestMatch.close) {
return bestMatch.close()
}
@@ -614,7 +683,8 @@ Singleton {
}
}
if (currentWorkspaceId === null) return toplevels
if (currentWorkspaceId === null)
return toplevels
const workspaceWindows = windows.filter(niriWindow => niriWindow.workspace_id === currentWorkspaceId)
const usedToplevels = new Set()
@@ -622,35 +692,47 @@ Singleton {
for (const niriWindow of workspaceWindows) {
let bestMatch = null
let bestScore = -1
for (const toplevel of toplevels) {
if (usedToplevels.has(toplevel)) continue
if (usedToplevels.has(toplevel))
continue
if (toplevel.appId === niriWindow.app_id) {
if (niriWindow.title && toplevel.title === niriWindow.title) {
bestMatch = toplevel
break
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 (!niriWindow.title && !bestMatch) {
if (score > bestScore) {
bestScore = score
bestMatch = toplevel
if (score === 3)
break
}
}
}
if (!bestMatch) continue
if (!bestMatch)
continue
usedToplevels.add(bestMatch)
const enrichedToplevel = {
appId: bestMatch.appId,
title: bestMatch.title,
activated: bestMatch.activated,
niriWindowId: niriWindow.id,
niriWorkspaceId: niriWindow.workspace_id,
activate: function() {
"appId": bestMatch.appId,
"title": bestMatch.title,
"activated": bestMatch.activated,
"niriWindowId": niriWindow.id,
"niriWorkspaceId": niriWindow.workspace_id,
"activate": function () {
return NiriService.focusWindow(niriWindow.id)
},
close: function() {
"close": function () {
if (bestMatch.close) {
return bestMatch.close()
}
@@ -672,8 +754,10 @@ Singleton {
function generateNiriLayoutConfig() {
const niriSocket = Quickshell.env("NIRI_SOCKET")
if (!niriSocket || niriSocket.length === 0) return
if (configGenerationPending) return
if (!niriSocket || niriSocket.length === 0)
return
if (configGenerationPending)
return
configGenerationPending = true
configGenerationDebounce.restart()
@@ -696,7 +780,6 @@ Singleton {
width 2
}
}
window-rule {
geometry-corner-radius ${cornerRadius}
clip-to-geometry true
@@ -727,4 +810,4 @@ window-rule {
writeBindsProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cp --no-preserve=mode "${sourceBindsPath}" "${bindsPath}"`]
writeBindsProcess.running = true
}
}
}