mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
hyprland: use raw events to determine window position updates
This commit is contained in:
@@ -21,21 +21,27 @@ Item {
|
||||
property real barThickness: 48
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
||||
property Item windowRoot: (Window.window ? Window.window.contentItem : null)
|
||||
property int _workspaceUpdateTrigger: 0
|
||||
property int _desktopEntriesUpdateTrigger: 0
|
||||
property int _toplevelsUpdateTrigger: 0
|
||||
|
||||
readonly property var sortedToplevels: {
|
||||
_workspaceUpdateTrigger
|
||||
_toplevelsUpdateTrigger
|
||||
const toplevels = CompositorService.sortedToplevels
|
||||
if (!toplevels || toplevels.length === 0)
|
||||
return []
|
||||
if (!toplevels || toplevels.length === 0) return []
|
||||
|
||||
if (SettingsData.runningAppsCurrentWorkspace) {
|
||||
const filtered = CompositorService.filterCurrentWorkspace(toplevels, parentScreen?.name)
|
||||
return filtered || []
|
||||
return CompositorService.filterCurrentWorkspace(toplevels, parentScreen?.name) || []
|
||||
}
|
||||
return toplevels
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CompositorService
|
||||
function onToplevelsChanged() {
|
||||
_toplevelsUpdateTrigger++
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DesktopEntries
|
||||
function onApplicationsChanged() {
|
||||
@@ -89,36 +95,6 @@ Item {
|
||||
height: isVertical ? calculatedSize : barThickness
|
||||
visible: windowCount > 0
|
||||
|
||||
Connections {
|
||||
target: NiriService
|
||||
function onAllWorkspacesChanged() {
|
||||
_workspaceUpdateTrigger++
|
||||
}
|
||||
function onWindowsChanged() {
|
||||
_workspaceUpdateTrigger++
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Hyprland
|
||||
function onFocusedWorkspaceChanged() {
|
||||
_workspaceUpdateTrigger++
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Hyprland.workspaces
|
||||
function onValuesChanged() {
|
||||
_workspaceUpdateTrigger++
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Hyprland.toplevels
|
||||
function onValuesChanged() {
|
||||
_workspaceUpdateTrigger++
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: visualBackground
|
||||
@@ -241,7 +217,10 @@ Item {
|
||||
|
||||
Repeater {
|
||||
id: windowRepeater
|
||||
model: SettingsData.runningAppsGroupByApp ? groupedWindows : sortedToplevels
|
||||
model: ScriptModel {
|
||||
values: SettingsData.runningAppsGroupByApp ? groupedWindows : sortedToplevels
|
||||
objectProp: SettingsData.runningAppsGroupByApp ? "appId" : "address"
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
@@ -470,7 +449,10 @@ Item {
|
||||
|
||||
Repeater {
|
||||
id: windowRepeater
|
||||
model: SettingsData.runningAppsGroupByApp ? groupedWindows : sortedToplevels
|
||||
model: ScriptModel {
|
||||
values: SettingsData.runningAppsGroupByApp ? groupedWindows : sortedToplevels
|
||||
objectProp: SettingsData.runningAppsGroupByApp ? "appId" : "address"
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
|
||||
@@ -238,7 +238,7 @@ Item {
|
||||
|
||||
Connections {
|
||||
target: CompositorService
|
||||
function onSortedToplevelsChanged() {
|
||||
function onToplevelsChanged() {
|
||||
dockModel.updateModel()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,17 +21,10 @@ Singleton {
|
||||
readonly property string swaySocket: Quickshell.env("SWAYSOCK")
|
||||
property bool useNiriSorting: isNiri && NiriService
|
||||
|
||||
property var sortedToplevels: sortedToplevelsCache
|
||||
property var sortedToplevelsCache: []
|
||||
|
||||
property var sortedToplevels: []
|
||||
property bool _sortScheduled: false
|
||||
property bool _refreshScheduled: false
|
||||
property bool _hasRefreshedOnce: false
|
||||
|
||||
property var _coordCache: ({})
|
||||
property int _refreshCount: 0
|
||||
property real _refreshWindowStart: 0
|
||||
readonly property int _maxRefreshesPerSecond: 3
|
||||
signal toplevelsChanged()
|
||||
|
||||
function getScreenScale(screen) {
|
||||
if (!screen) return 1
|
||||
@@ -59,46 +52,27 @@ Singleton {
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: refreshTimer
|
||||
interval: 40
|
||||
id: sortDebounceTimer
|
||||
interval: 100
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
try {
|
||||
Hyprland.refreshToplevels()
|
||||
} catch(e) {}
|
||||
_refreshScheduled = false
|
||||
_hasRefreshedOnce = true
|
||||
scheduleSort()
|
||||
_sortScheduled = false
|
||||
if (isHyprland) {
|
||||
try {
|
||||
Hyprland.refreshToplevels()
|
||||
} catch(e) {
|
||||
console.warn("CompositorService: Failed to refresh toplevels:", e)
|
||||
}
|
||||
}
|
||||
sortedToplevels = computeSortedToplevels()
|
||||
toplevelsChanged()
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleSort() {
|
||||
if (_sortScheduled) return
|
||||
_sortScheduled = true
|
||||
Qt.callLater(function() {
|
||||
_sortScheduled = false
|
||||
sortedToplevelsCache = computeSortedToplevels()
|
||||
})
|
||||
}
|
||||
|
||||
function scheduleRefresh() {
|
||||
if (!isHyprland) return
|
||||
if (_refreshScheduled) return
|
||||
|
||||
const now = Date.now()
|
||||
if (now - _refreshWindowStart > 1000) {
|
||||
_refreshCount = 0
|
||||
_refreshWindowStart = now
|
||||
}
|
||||
|
||||
if (_refreshCount >= _maxRefreshesPerSecond) {
|
||||
console.warn("CompositorService: Refresh rate limit exceeded, skipping refresh")
|
||||
return
|
||||
}
|
||||
|
||||
_refreshCount++
|
||||
_refreshScheduled = true
|
||||
refreshTimer.restart()
|
||||
sortDebounceTimer.restart()
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -106,19 +80,28 @@ Singleton {
|
||||
function onValuesChanged() { root.scheduleSort() }
|
||||
}
|
||||
Connections {
|
||||
target: Hyprland.toplevels
|
||||
function onValuesChanged() {
|
||||
root.scheduleSort()
|
||||
target: isHyprland ? Hyprland : null
|
||||
enabled: isHyprland
|
||||
|
||||
function onRawEvent(event) {
|
||||
if (event.name === "openwindow" ||
|
||||
event.name === "closewindow" ||
|
||||
event.name === "movewindow" ||
|
||||
event.name === "movewindowv2" ||
|
||||
event.name === "workspace" ||
|
||||
event.name === "workspacev2" ||
|
||||
event.name === "focusedmon" ||
|
||||
event.name === "focusedmonv2" ||
|
||||
event.name === "activewindow" ||
|
||||
event.name === "activewindowv2" ||
|
||||
event.name === "changefloatingmode" ||
|
||||
event.name === "fullscreen" ||
|
||||
event.name === "moveintogroup" ||
|
||||
event.name === "moveoutofgroup") {
|
||||
root.scheduleSort()
|
||||
}
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: Hyprland.workspaces
|
||||
function onValuesChanged() { root.scheduleSort() }
|
||||
}
|
||||
Connections {
|
||||
target: Hyprland
|
||||
function onFocusedWorkspaceChanged() { root.scheduleSort() }
|
||||
}
|
||||
Connections {
|
||||
target: NiriService
|
||||
function onWindowsChanged() { root.scheduleSort() }
|
||||
@@ -165,7 +148,6 @@ Singleton {
|
||||
|
||||
function sortHyprlandToplevelsSafe() {
|
||||
if (!Hyprland.toplevels || !Hyprland.toplevels.values) return []
|
||||
if (_refreshScheduled && sortedToplevelsCache.length > 0) return sortedToplevelsCache
|
||||
|
||||
const items = Array.from(Hyprland.toplevels.values)
|
||||
|
||||
@@ -177,21 +159,7 @@ Singleton {
|
||||
} catch(e) { return fb }
|
||||
}
|
||||
|
||||
let currentAddresses = new Set()
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const addr = items[i]?.address
|
||||
if (addr) currentAddresses.add(addr)
|
||||
}
|
||||
|
||||
for (let cachedAddr in _coordCache) {
|
||||
if (!currentAddresses.has(cachedAddr)) {
|
||||
delete _coordCache[cachedAddr]
|
||||
}
|
||||
}
|
||||
|
||||
let snap = []
|
||||
let missingAnyPosition = false
|
||||
let hasNewWindow = false
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const t = items[i]
|
||||
if (!t) continue
|
||||
@@ -208,23 +176,8 @@ Singleton {
|
||||
const wsId = _get(li, ["workspace", "id"], null) ?? _get(t, ["workspace", "id"], Number.MAX_SAFE_INTEGER)
|
||||
|
||||
const at = _get(li, ["at"], null)
|
||||
let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : NaN
|
||||
let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : NaN
|
||||
|
||||
if (!(atX === atX) || !(atY === atY)) {
|
||||
const cached = _coordCache[addr]
|
||||
if (cached) {
|
||||
atX = cached.x
|
||||
atY = cached.y
|
||||
} else {
|
||||
if (addr) hasNewWindow = true
|
||||
missingAnyPosition = true
|
||||
atX = 1e9
|
||||
atY = 1e9
|
||||
}
|
||||
} else if (addr) {
|
||||
_coordCache[addr] = { x: atX, y: atY }
|
||||
}
|
||||
let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : 1e9
|
||||
let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : 1e9
|
||||
|
||||
const relX = Number.isFinite(monX) ? (atX - monX) : atX
|
||||
const relY = Number.isFinite(monY) ? (atY - monY) : atY
|
||||
@@ -242,10 +195,6 @@ Singleton {
|
||||
})
|
||||
}
|
||||
|
||||
if (missingAnyPosition && hasNewWindow && !_hasRefreshedOnce) {
|
||||
scheduleRefresh()
|
||||
}
|
||||
|
||||
const groups = new Map()
|
||||
for (const it of snap) {
|
||||
const key = it.monKey + "::" + it.wsId
|
||||
@@ -400,9 +349,6 @@ Singleton {
|
||||
isSway = false
|
||||
compositor = "hyprland"
|
||||
console.info("CompositorService: Detected Hyprland")
|
||||
try {
|
||||
Hyprland.refreshToplevels()
|
||||
} catch(e) {}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -32,11 +32,9 @@ Singleton {
|
||||
}
|
||||
for (const appId of appIds){
|
||||
let icon = Quickshell.iconPath(entry?.icon, true)
|
||||
console.log(icon)
|
||||
if (icon && icon !== "") return icon
|
||||
|
||||
let execPath = entry?.execString?.replace(/\/bin.*/, "")
|
||||
console.log(execPath)
|
||||
if (!execPath) continue
|
||||
|
||||
//Check that the app is installed with nix/guix
|
||||
@@ -46,13 +44,11 @@ Singleton {
|
||||
|
||||
let iconPath = `${basePath}/share/icons/hicolor/scalable/apps/${appId}.svg`
|
||||
icon = Quickshell.iconPath(iconPath, true)
|
||||
console.log(icon)
|
||||
if (icon && icon !== "") return icon
|
||||
|
||||
for (const size of sizes) {
|
||||
iconPath = `${basePath}/share/icons/hicolor/${size}/apps/${appId}.png`
|
||||
icon = Quickshell.iconPath(iconPath, true)
|
||||
console.log(icon)
|
||||
if (icon && icon !== "") return icon
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,12 +118,12 @@ Singleton {
|
||||
import Quickshell.Wayland
|
||||
|
||||
IdleInhibitor {
|
||||
active: false
|
||||
enabled: false
|
||||
}
|
||||
`
|
||||
|
||||
mediaInhibitor = Qt.createQmlObject(inhibitorString, root, "IdleService.MediaInhibitor")
|
||||
mediaInhibitor.active = Qt.binding(() => root.idleInhibitorAvailable && SettingsData.preventIdleForMedia && root.mediaPlaying)
|
||||
mediaInhibitor.enabled = Qt.binding(() => root.idleInhibitorAvailable && SettingsData.preventIdleForMedia && root.mediaPlaying)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("IdleService: Error creating IdleMonitors:", e)
|
||||
|
||||
@@ -3,6 +3,7 @@ import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
Reference in New Issue
Block a user