mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-29 07:52:50 -05:00
Merge branch 'master' of github.com:bbedward/DankMaterialShell
This commit is contained in:
@@ -23,7 +23,7 @@ DankModal {
|
|||||||
function executePowerAction(action) {
|
function executePowerAction(action) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "logout":
|
case "logout":
|
||||||
NiriService.quit()
|
CompositorService.logout()
|
||||||
break
|
break
|
||||||
case "suspend":
|
case "suspend":
|
||||||
Quickshell.execDetached(["systemctl", "suspend"])
|
Quickshell.execDetached(["systemctl", "suspend"])
|
||||||
|
|||||||
@@ -1187,7 +1187,7 @@ Item {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
logoutDialog.close()
|
logoutDialog.close()
|
||||||
NiriService.quit()
|
CompositorService.logout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -378,11 +378,28 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "(Hyprland Soon™)"
|
text: "&"
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: `<a href="https://github.com/hyprwm/Hyprland" style="text-decoration:none; color:${Theme.primary};">hyprland</a>`
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
linkColor: Theme.primary
|
||||||
|
textFormat: Text.RichText
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
onLinkActivated: url => Qt.openUrlExternally(url)
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
propagateComposedEvents: true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
|
|||||||
@@ -24,35 +24,47 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayWorkspaces() {
|
function getDisplayWorkspaces() {
|
||||||
if (!CompositorService.isNiri
|
if (CompositorService.isNiri) {
|
||||||
|| NiriService.allWorkspaces.length === 0)
|
if (NiriService.allWorkspaces.length === 0)
|
||||||
return [1, 2]
|
return [1, 2]
|
||||||
|
|
||||||
if (!root.screenName)
|
if (!root.screenName)
|
||||||
return NiriService.getCurrentOutputWorkspaceNumbers()
|
return NiriService.getCurrentOutputWorkspaceNumbers()
|
||||||
|
|
||||||
var displayWorkspaces = []
|
var displayWorkspaces = []
|
||||||
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||||
var ws = NiriService.allWorkspaces[i]
|
var ws = NiriService.allWorkspaces[i]
|
||||||
if (ws.output === root.screenName)
|
if (ws.output === root.screenName)
|
||||||
displayWorkspaces.push(ws.idx + 1)
|
displayWorkspaces.push(ws.idx + 1)
|
||||||
|
}
|
||||||
|
return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2]
|
||||||
|
} else if (CompositorService.isHyprland) {
|
||||||
|
var workspaces = HyprlandService.getWorkspaceDisplayNumbers()
|
||||||
|
return workspaces.length > 0 ? workspaces : [1]
|
||||||
}
|
}
|
||||||
return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2]
|
|
||||||
|
return [1, 2]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayActiveWorkspace() {
|
function getDisplayActiveWorkspace() {
|
||||||
if (!CompositorService.isNiri
|
if (CompositorService.isNiri) {
|
||||||
|| NiriService.allWorkspaces.length === 0)
|
if (NiriService.allWorkspaces.length === 0)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if (!root.screenName)
|
||||||
|
return NiriService.getCurrentWorkspaceNumber()
|
||||||
|
|
||||||
|
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||||
|
var ws = NiriService.allWorkspaces[i]
|
||||||
|
if (ws.output === root.screenName && ws.is_active)
|
||||||
|
return ws.idx + 1
|
||||||
|
}
|
||||||
return 1
|
return 1
|
||||||
|
} else if (CompositorService.isHyprland) {
|
||||||
if (!root.screenName)
|
var activeWs = HyprlandService.getCurrentWorkspaceNumber()
|
||||||
return NiriService.getCurrentWorkspaceNumber()
|
return activeWs
|
||||||
|
|
||||||
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
|
||||||
var ws = NiriService.allWorkspaces[i]
|
|
||||||
if (ws.output === root.screenName && ws.is_active)
|
|
||||||
return ws.idx + 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +80,7 @@ Rectangle {
|
|||||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
|
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
|
||||||
baseColor.a * Theme.widgetTransparency)
|
baseColor.a * Theme.widgetTransparency)
|
||||||
}
|
}
|
||||||
visible: CompositorService.isNiri
|
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
function onAllWorkspacesChanged() {
|
function onAllWorkspacesChanged() {
|
||||||
@@ -84,6 +96,28 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
target: NiriService
|
target: NiriService
|
||||||
|
enabled: CompositorService.isNiri
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onWorkspacesUpdated() {
|
||||||
|
root.workspaceList
|
||||||
|
= SettingsData.showWorkspacePadding ? root.padWorkspaces(
|
||||||
|
root.getDisplayWorkspaces(
|
||||||
|
)) : root.getDisplayWorkspaces()
|
||||||
|
root.currentWorkspace = root.getDisplayActiveWorkspace()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFocusedWorkspaceUpdated() {
|
||||||
|
root.currentWorkspace = root.getDisplayActiveWorkspace()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFocusedMonitorUpdated() {
|
||||||
|
root.currentWorkspace = root.getDisplayActiveWorkspace()
|
||||||
|
}
|
||||||
|
|
||||||
|
target: HyprlandService
|
||||||
|
enabled: CompositorService.isHyprland
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -112,12 +146,22 @@ Rectangle {
|
|||||||
property bool isHovered: mouseArea.containsMouse
|
property bool isHovered: mouseArea.containsMouse
|
||||||
property int sequentialNumber: index + 1
|
property int sequentialNumber: index + 1
|
||||||
property var workspaceData: {
|
property var workspaceData: {
|
||||||
if (isPlaceholder || !CompositorService.isNiri)
|
if (isPlaceholder)
|
||||||
return null
|
return null
|
||||||
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
|
||||||
var ws = NiriService.allWorkspaces[i]
|
if (CompositorService.isNiri) {
|
||||||
if (ws.idx + 1 === modelData)
|
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||||
return ws
|
var ws = NiriService.allWorkspaces[i]
|
||||||
|
if (ws.idx + 1 === modelData)
|
||||||
|
return ws
|
||||||
|
}
|
||||||
|
} else if (CompositorService.isHyprland) {
|
||||||
|
var hyprWorkspaces = HyprlandService.getWorkspacesForMonitor(root.screenName)
|
||||||
|
for (var j = 0; j < hyprWorkspaces.length; j++) {
|
||||||
|
var hws = hyprWorkspaces[j]
|
||||||
|
if (hws.id === modelData)
|
||||||
|
return hws
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -140,8 +184,13 @@ Rectangle {
|
|||||||
cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor
|
cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor
|
||||||
enabled: !isPlaceholder
|
enabled: !isPlaceholder
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!isPlaceholder)
|
if (!isPlaceholder) {
|
||||||
NiriService.switchToWorkspace(modelData - 1)
|
if (CompositorService.isNiri) {
|
||||||
|
NiriService.switchToWorkspace(modelData - 1)
|
||||||
|
} else if (CompositorService.isHyprland) {
|
||||||
|
HyprlandService.switchToWorkspace(modelData)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import QtQuick
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -19,6 +20,7 @@ Singleton {
|
|||||||
readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
|
readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
|
||||||
|
|
||||||
property bool useNiriSorting: isNiri && NiriService
|
property bool useNiriSorting: isNiri && NiriService
|
||||||
|
property bool useHyprlandSorting: isHyprland && HyprlandService
|
||||||
|
|
||||||
// Unified sorted toplevels - automatically chooses sorting based on compositor
|
// Unified sorted toplevels - automatically chooses sorting based on compositor
|
||||||
property var sortedToplevels: {
|
property var sortedToplevels: {
|
||||||
@@ -31,12 +33,16 @@ Singleton {
|
|||||||
return NiriService.sortToplevels(ToplevelManager.toplevels.values)
|
return NiriService.sortToplevels(ToplevelManager.toplevels.values)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For non-niri compositors or when niri isn't ready yet, return unsorted toplevels
|
// Use Hyprland sorting when both compositor is Hyprland AND hyprland service is ready
|
||||||
|
if (useHyprlandSorting) {
|
||||||
|
return HyprlandService.sortToplevels(ToplevelManager.toplevels.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For other compositors or when services aren't ready yet, return unsorted toplevels
|
||||||
return ToplevelManager.toplevels.values
|
return ToplevelManager.toplevels.values
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
console.log("CompositorService: Starting detection...")
|
|
||||||
detectCompositor()
|
detectCompositor()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +52,7 @@ Singleton {
|
|||||||
isHyprland = true
|
isHyprland = true
|
||||||
isNiri = false
|
isNiri = false
|
||||||
compositor = "hyprland"
|
compositor = "hyprland"
|
||||||
console.log("CompositorService: Detected Hyprland with signature:", hyprlandSignature)
|
console.log("CompositorService: Detected Hyprland")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,4 +87,12 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
if (isNiri) {
|
||||||
|
NiriService.quit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Hyprland.dispatch("exit")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
176
Services/HyprlandService.qml
Normal file
176
Services/HyprlandService.qml
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
pragma ComponentBehavior
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool hyprlandAvailable: {
|
||||||
|
const signature = Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
|
||||||
|
return signature && signature.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
property var allWorkspaces: hyprlandAvailable && Hyprland.workspaces ? Hyprland.workspaces.values : []
|
||||||
|
property var focusedWorkspace: hyprlandAvailable ? Hyprland.focusedWorkspace : null
|
||||||
|
property var monitors: hyprlandAvailable ? Hyprland.monitors : []
|
||||||
|
property var focusedMonitor: hyprlandAvailable ? Hyprland.focusedMonitor : null
|
||||||
|
|
||||||
|
function getWorkspacesForMonitor(monitorName) {
|
||||||
|
if (!hyprlandAvailable) return []
|
||||||
|
|
||||||
|
const workspaces = Hyprland.workspaces ? Hyprland.workspaces.values : []
|
||||||
|
if (!workspaces || workspaces.length === 0) return []
|
||||||
|
|
||||||
|
// If no monitor name specified, return all workspaces
|
||||||
|
if (!monitorName) {
|
||||||
|
const allWorkspacesCopy = []
|
||||||
|
for (let i = 0; i < workspaces.length; i++) {
|
||||||
|
const workspace = workspaces[i]
|
||||||
|
if (workspace) {
|
||||||
|
allWorkspacesCopy.push(workspace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allWorkspacesCopy.sort((a, b) => a.id - b.id)
|
||||||
|
return allWorkspacesCopy
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtered = []
|
||||||
|
for (let i = 0; i < workspaces.length; i++) {
|
||||||
|
const workspace = workspaces[i]
|
||||||
|
if (workspace && workspace.monitor && workspace.monitor.name === monitorName) {
|
||||||
|
filtered.push(workspace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by workspace ID
|
||||||
|
filtered.sort((a, b) => a.id - b.id)
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentWorkspaceForMonitor(monitorName) {
|
||||||
|
if (!hyprlandAvailable) return null
|
||||||
|
|
||||||
|
// If no monitor name specified, return the globally focused workspace
|
||||||
|
if (!monitorName) {
|
||||||
|
return focusedWorkspace
|
||||||
|
}
|
||||||
|
|
||||||
|
if (focusedMonitor && focusedMonitor.name === monitorName) {
|
||||||
|
return focusedWorkspace
|
||||||
|
}
|
||||||
|
|
||||||
|
const monitorWorkspaces = getWorkspacesForMonitor(monitorName)
|
||||||
|
for (let i = 0; i < monitorWorkspaces.length; i++) {
|
||||||
|
const ws = monitorWorkspaces[i]
|
||||||
|
if (ws && ws.active) {
|
||||||
|
return ws
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchToWorkspace(workspaceId) {
|
||||||
|
if (!hyprlandAvailable) return
|
||||||
|
|
||||||
|
Hyprland.dispatch(`workspace ${workspaceId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchToWorkspaceByName(workspaceName) {
|
||||||
|
if (!hyprlandAvailable) return
|
||||||
|
|
||||||
|
Hyprland.dispatch(`workspace name:${workspaceName}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveToWorkspace(workspaceId) {
|
||||||
|
if (!hyprlandAvailable) return
|
||||||
|
|
||||||
|
Hyprland.dispatch(`movetoworkspace ${workspaceId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWorkspace(workspaceId) {
|
||||||
|
if (!hyprlandAvailable) return
|
||||||
|
|
||||||
|
Hyprland.dispatch(`workspace ${workspaceId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWorkspaceDisplayNumbers() {
|
||||||
|
if (!hyprlandAvailable) return [1, 2, 3, 4]
|
||||||
|
|
||||||
|
// Get all existing workspaces from Hyprland.workspaces.values
|
||||||
|
const workspaces = Hyprland.workspaces ? Hyprland.workspaces.values : []
|
||||||
|
if (!workspaces || workspaces.length === 0) {
|
||||||
|
// If no workspaces detected, show at least current + a few more
|
||||||
|
const current = getCurrentWorkspaceNumber()
|
||||||
|
return [Math.max(1, current - 1), current, current + 1, current + 2].filter((ws, i, arr) => arr.indexOf(ws) === i && ws > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get workspace IDs and ensure we show a reasonable range
|
||||||
|
const numbers = []
|
||||||
|
let maxId = 0
|
||||||
|
|
||||||
|
for (let i = 0; i < workspaces.length; i++) {
|
||||||
|
const ws = workspaces[i]
|
||||||
|
if (ws && ws.id > 0) {
|
||||||
|
numbers.push(ws.id)
|
||||||
|
maxId = Math.max(maxId, ws.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always ensure we have at least one workspace beyond the highest
|
||||||
|
// to allow easy navigation to new workspaces
|
||||||
|
if (maxId > 0 && numbers.indexOf(maxId + 1) === -1) {
|
||||||
|
numbers.push(maxId + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return numbers.sort((a, b) => a - b)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentWorkspaceNumber() {
|
||||||
|
if (!hyprlandAvailable) return 1
|
||||||
|
|
||||||
|
// Use the focused workspace directly
|
||||||
|
const focused = Hyprland.focusedWorkspace
|
||||||
|
return focused ? focused.id : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortToplevels(toplevels) {
|
||||||
|
if (!hyprlandAvailable || !toplevels) return []
|
||||||
|
|
||||||
|
// Create a copy of the array since the original might be readonly
|
||||||
|
const sortedArray = Array.from(toplevels)
|
||||||
|
|
||||||
|
return sortedArray.sort((a, b) => {
|
||||||
|
if (a.workspace && b.workspace) {
|
||||||
|
if (a.workspace.monitor && b.workspace.monitor) {
|
||||||
|
const monitorCompare = a.workspace.monitor.name.localeCompare(b.workspace.monitor.name)
|
||||||
|
if (monitorCompare !== 0) return monitorCompare
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaceCompare = a.workspace.id - b.workspace.id
|
||||||
|
if (workspaceCompare !== 0) return workspaceCompare
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signals for workspace changes that WorkspaceSwitcher can connect to
|
||||||
|
signal workspacesUpdated()
|
||||||
|
signal focusedWorkspaceUpdated()
|
||||||
|
signal focusedMonitorUpdated()
|
||||||
|
|
||||||
|
// Monitor changes to properties and emit our signals
|
||||||
|
onAllWorkspacesChanged: workspacesUpdated()
|
||||||
|
onFocusedWorkspaceChanged: focusedWorkspaceUpdated()
|
||||||
|
onFocusedMonitorChanged: focusedMonitorUpdated()
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (hyprlandAvailable) {
|
||||||
|
console.log("HyprlandService: Initialized with Hyprland support")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user