mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-14 09:42:10 -04:00
miraclewm: add support for Miracle WM
This commit is contained in:
@@ -19,7 +19,7 @@ Built with [Quickshell](https://quickshell.org/) and [Go](https://go.dev/)
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
DankMaterialShell is a complete desktop shell for [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [MangoWC](https://github.com/DreamMaoMao/mangowc), [Sway](https://swaywm.org), [labwc](https://labwc.github.io/), [Scroll](https://github.com/dawsers/scroll), and other Wayland compositors. It replaces waybar, swaylock, swayidle, mako, fuzzel, polkit, and everything else you'd normally stitch together to make a desktop.
|
DankMaterialShell is a complete desktop shell for [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [MangoWC](https://github.com/DreamMaoMao/mangowc), [Sway](https://swaywm.org), [labwc](https://labwc.github.io/), [Scroll](https://github.com/dawsers/scroll), [Miracle WM](https://github.com/miracle-wm-org/miracle-wm), and other Wayland compositors. It replaces waybar, swaylock, swayidle, mako, fuzzel, polkit, and everything else you'd normally stitch together to make a desktop.
|
||||||
|
|
||||||
## Repository Structure
|
## Repository Structure
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ Extend functionality with the [plugin registry](https://plugins.danklinux.com).
|
|||||||
|
|
||||||
## Supported Compositors
|
## Supported Compositors
|
||||||
|
|
||||||
Works best with [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [Sway](https://swaywm.org/), [MangoWC](https://github.com/DreamMaoMao/mangowc), [labwc](https://labwc.github.io/), and [Scroll](https://github.com/dawsers/scroll) with full workspace switching, overview integration, and monitor management. Other Wayland compositors work with reduced features.
|
Works best with [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [Sway](https://swaywm.org/), [MangoWC](https://github.com/DreamMaoMao/mangowc), [labwc](https://labwc.github.io/), [Scroll](https://github.com/dawsers/scroll), and [Miracle WM](https://github.com/miracle-wm-org/miracle-wm) with full workspace switching, overview integration, and monitor management. Other Wayland compositors work with reduced features.
|
||||||
|
|
||||||
[Compositor configuration guide](https://danklinux.com/docs/dankmaterialshell/compositors)
|
[Compositor configuration guide](https://danklinux.com/docs/dankmaterialshell/compositors)
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,11 @@ func initializeProviders() {
|
|||||||
log.Warnf("Failed to register Scroll provider: %v", err)
|
log.Warnf("Failed to register Scroll provider: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
miracleProvider := providers.NewMiracleProvider("$HOME/.config/miracle-wm")
|
||||||
|
if err := registry.Register(miracleProvider); err != nil {
|
||||||
|
log.Warnf("Failed to register Miracle WM provider: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
swayProvider := providers.NewSwayProvider("$HOME/.config/sway")
|
swayProvider := providers.NewSwayProvider("$HOME/.config/sway")
|
||||||
if err := registry.Register(swayProvider); err != nil {
|
if err := registry.Register(swayProvider); err != nil {
|
||||||
log.Warnf("Failed to register Sway provider: %v", err)
|
log.Warnf("Failed to register Sway provider: %v", err)
|
||||||
@@ -144,6 +149,8 @@ func makeProviderWithPath(name, path string) keybinds.Provider {
|
|||||||
return providers.NewSwayProvider(path)
|
return providers.NewSwayProvider(path)
|
||||||
case "scroll":
|
case "scroll":
|
||||||
return providers.NewSwayProvider(path)
|
return providers.NewSwayProvider(path)
|
||||||
|
case "miracle":
|
||||||
|
return providers.NewMiracleProvider(path)
|
||||||
case "niri":
|
case "niri":
|
||||||
return providers.NewNiriProvider(path)
|
return providers.NewNiriProvider(path)
|
||||||
default:
|
default:
|
||||||
|
|||||||
10
core/go.mod
10
core/go.mod
@@ -19,7 +19,7 @@ require (
|
|||||||
github.com/yuin/goldmark v1.7.16
|
github.com/yuin/goldmark v1.7.16
|
||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||||
go.etcd.io/bbolt v1.4.3
|
go.etcd.io/bbolt v1.4.3
|
||||||
golang.org/x/exp v0.0.0-20260211191109-2735e65f0518
|
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a
|
||||||
golang.org/x/image v0.36.0
|
golang.org/x/image v0.36.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ require (
|
|||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
||||||
github.com/clipperhouse/displaywidth v0.10.0 // indirect
|
github.com/clipperhouse/displaywidth v0.10.0 // indirect
|
||||||
github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
|
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||||
github.com/cloudflare/circl v1.6.3 // indirect
|
github.com/cloudflare/circl v1.6.3 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
||||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||||
@@ -36,7 +36,7 @@ require (
|
|||||||
github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3 // indirect
|
github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.1 // indirect
|
github.com/go-logfmt/logfmt v0.6.1 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
github.com/kevinburke/ssh_config v1.6.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
||||||
github.com/sergi/go-diff v1.4.0 // indirect
|
github.com/sergi/go-diff v1.4.0 // indirect
|
||||||
@@ -55,7 +55,7 @@ require (
|
|||||||
github.com/charmbracelet/x/term v0.2.2 // indirect
|
github.com/charmbracelet/x/term v0.2.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/go-git/go-git/v6 v6.0.0-20260210102253-e4d10f0e569a
|
github.com/go-git/go-git/v6 v6.0.0-20260216160506-e6a3f881772f
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.3.0
|
github.com/lucasb-eyer/go-colorful v1.3.0
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
@@ -71,7 +71,7 @@ require (
|
|||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
golang.org/x/sys v0.41.0
|
golang.org/x/sys v0.41.0
|
||||||
golang.org/x/text v0.34.0
|
golang.org/x/text v0.34.0
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
// v0.0.1 tag is missing a LICENSE file; master has it.
|
// v0.0.1 tag is missing a LICENSE file; master has it.
|
||||||
|
|||||||
16
core/go.sum
16
core/go.sum
@@ -40,8 +40,8 @@ github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSg
|
|||||||
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||||
github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g=
|
github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g=
|
||||||
github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs=
|
github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs=
|
||||||
github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos=
|
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||||
github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
|
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
@@ -68,8 +68,8 @@ github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3 h1:UU7oARtwQ5g8
|
|||||||
github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3/go.mod h1:ZW9JC5gionMP1kv5uiaOaV23q0FFmNrVOV8VW+y/acc=
|
github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3/go.mod h1:ZW9JC5gionMP1kv5uiaOaV23q0FFmNrVOV8VW+y/acc=
|
||||||
github.com/go-git/go-git-fixtures/v5 v5.1.2-0.20260122163445-0622d7459a67 h1:3hutPZF+/FBjR/9MdsLJ7e1mlt9pwHgwxMW7CrbmWII=
|
github.com/go-git/go-git-fixtures/v5 v5.1.2-0.20260122163445-0622d7459a67 h1:3hutPZF+/FBjR/9MdsLJ7e1mlt9pwHgwxMW7CrbmWII=
|
||||||
github.com/go-git/go-git-fixtures/v5 v5.1.2-0.20260122163445-0622d7459a67/go.mod h1:xKt0pNHST9tYHvbiLxSY27CQWFwgIxBJuDrOE0JvbZw=
|
github.com/go-git/go-git-fixtures/v5 v5.1.2-0.20260122163445-0622d7459a67/go.mod h1:xKt0pNHST9tYHvbiLxSY27CQWFwgIxBJuDrOE0JvbZw=
|
||||||
github.com/go-git/go-git/v6 v6.0.0-20260210102253-e4d10f0e569a h1:LLju0NuXQqR4WmGl1Dm86b9ZXsvXgLYbx/aaAjdQr6w=
|
github.com/go-git/go-git/v6 v6.0.0-20260216160506-e6a3f881772f h1:TBkCJv9YwPOuXq1OG0r01bcxRrvs15Hp/DtZuPt4H6s=
|
||||||
github.com/go-git/go-git/v6 v6.0.0-20260210102253-e4d10f0e569a/go.mod h1:IdXOePSwsMKGpuAbpczsm+f0Uy5fdHHjwgDPOymKA78=
|
github.com/go-git/go-git/v6 v6.0.0-20260216160506-e6a3f881772f/go.mod h1:B88nWzfnhTlIikoJ4d84Nc9noKS5mJoA7SgDdkt0aPU=
|
||||||
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
|
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
|
||||||
github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=
|
github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=
|
||||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
@@ -86,8 +86,8 @@ github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83 h1:B+A58zGFuDrvE
|
|||||||
github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83/go.mod h1:iHAf8OIncO2gcQ8XOjS7CMJ2aPbX2Bs0wl5pZyanEqk=
|
github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83/go.mod h1:iHAf8OIncO2gcQ8XOjS7CMJ2aPbX2Bs0wl5pZyanEqk=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
|
github.com/kevinburke/ssh_config v1.6.0 h1:J1FBfmuVosPHf5GRdltRLhPJtJpTlMdKTBjRgTaQBFY=
|
||||||
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
github.com/kevinburke/ssh_config v1.6.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -152,8 +152,8 @@ go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
|||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||||
golang.org/x/exp v0.0.0-20260211191109-2735e65f0518 h1:2E1CW7v5QB+Wi3N+MXllOtVR6SFmI8iJM8EdzgxrgrU=
|
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o=
|
||||||
golang.org/x/exp v0.0.0-20260211191109-2735e65f0518/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
||||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||||
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||||
|
|||||||
97
core/internal/keybinds/providers/miracle.go
Normal file
97
core/internal/keybinds/providers/miracle.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package providers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds"
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MiracleProvider struct {
|
||||||
|
configPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMiracleProvider(configPath string) *MiracleProvider {
|
||||||
|
if configPath == "" {
|
||||||
|
configDir, err := os.UserConfigDir()
|
||||||
|
if err == nil {
|
||||||
|
configPath = filepath.Join(configDir, "miracle-wm")
|
||||||
|
} else {
|
||||||
|
configPath = "$HOME/.config/miracle-wm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &MiracleProvider{configPath: configPath}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MiracleProvider) Name() string {
|
||||||
|
return "miracle"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MiracleProvider) GetCheatSheet() (*keybinds.CheatSheet, error) {
|
||||||
|
config, err := ParseMiracleConfig(m.configPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse miracle-wm config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings := MiracleConfigToBindings(config)
|
||||||
|
categorizedBinds := make(map[string][]keybinds.Keybind)
|
||||||
|
|
||||||
|
for _, kb := range bindings {
|
||||||
|
category := m.categorizeAction(kb.Action)
|
||||||
|
bind := keybinds.Keybind{
|
||||||
|
Key: m.formatKey(kb),
|
||||||
|
Description: kb.Comment,
|
||||||
|
Action: kb.Action,
|
||||||
|
}
|
||||||
|
categorizedBinds[category] = append(categorizedBinds[category], bind)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &keybinds.CheatSheet{
|
||||||
|
Title: "Miracle WM Keybinds",
|
||||||
|
Provider: m.Name(),
|
||||||
|
Binds: categorizedBinds,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MiracleProvider) GetOverridePath() string {
|
||||||
|
expanded, err := utils.ExpandPath(m.configPath)
|
||||||
|
if err != nil {
|
||||||
|
return filepath.Join(m.configPath, "config.yaml")
|
||||||
|
}
|
||||||
|
return filepath.Join(expanded, "config.yaml")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MiracleProvider) formatKey(kb MiracleKeyBinding) string {
|
||||||
|
parts := make([]string, 0, len(kb.Mods)+1)
|
||||||
|
parts = append(parts, kb.Mods...)
|
||||||
|
parts = append(parts, kb.Key)
|
||||||
|
return strings.Join(parts, "+")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MiracleProvider) categorizeAction(action string) string {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(action, "select_workspace_") || strings.HasPrefix(action, "move_to_workspace_"):
|
||||||
|
return "Workspace"
|
||||||
|
case strings.Contains(action, "select_") || strings.Contains(action, "move_"):
|
||||||
|
return "Window"
|
||||||
|
case action == "toggle_resize" || strings.HasPrefix(action, "resize_"):
|
||||||
|
return "Window"
|
||||||
|
case action == "fullscreen" || action == "toggle_floating" || action == "quit_active_window" || action == "toggle_pinned_to_workspace":
|
||||||
|
return "Window"
|
||||||
|
case action == "toggle_tabbing" || action == "toggle_stacking" || action == "request_vertical" || action == "request_horizontal":
|
||||||
|
return "Layout"
|
||||||
|
case action == "quit_compositor":
|
||||||
|
return "System"
|
||||||
|
case action == "terminal":
|
||||||
|
return "Execute"
|
||||||
|
case strings.HasPrefix(action, "magnifier_"):
|
||||||
|
return "Accessibility"
|
||||||
|
case strings.HasPrefix(action, "dms ") || strings.Contains(action, "dms ipc"):
|
||||||
|
return "Execute"
|
||||||
|
default:
|
||||||
|
return "Execute"
|
||||||
|
}
|
||||||
|
}
|
||||||
320
core/internal/keybinds/providers/miracle_parser.go
Normal file
320
core/internal/keybinds/providers/miracle_parser.go
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
package providers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MiracleConfig struct {
|
||||||
|
Terminal string `yaml:"terminal"`
|
||||||
|
ActionKey string `yaml:"action_key"`
|
||||||
|
DefaultActionOverrides []MiracleActionOverride `yaml:"default_action_overrides"`
|
||||||
|
CustomActions []MiracleCustomAction `yaml:"custom_actions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MiracleActionOverride struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Action string `yaml:"action"`
|
||||||
|
Modifiers []string `yaml:"modifiers"`
|
||||||
|
Key string `yaml:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MiracleCustomAction struct {
|
||||||
|
Command string `yaml:"command"`
|
||||||
|
Action string `yaml:"action"`
|
||||||
|
Modifiers []string `yaml:"modifiers"`
|
||||||
|
Key string `yaml:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MiracleKeyBinding struct {
|
||||||
|
Mods []string
|
||||||
|
Key string
|
||||||
|
Action string
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
var miracleDefaultBinds = []MiracleKeyBinding{
|
||||||
|
{Mods: []string{"Super"}, Key: "Return", Action: "terminal", Comment: "Open terminal"},
|
||||||
|
{Mods: []string{"Super"}, Key: "v", Action: "request_vertical", Comment: "Layout windows vertically"},
|
||||||
|
{Mods: []string{"Super"}, Key: "h", Action: "request_horizontal", Comment: "Layout windows horizontally"},
|
||||||
|
{Mods: []string{"Super"}, Key: "Up", Action: "select_up", Comment: "Select window above"},
|
||||||
|
{Mods: []string{"Super"}, Key: "Down", Action: "select_down", Comment: "Select window below"},
|
||||||
|
{Mods: []string{"Super"}, Key: "Left", Action: "select_left", Comment: "Select window left"},
|
||||||
|
{Mods: []string{"Super"}, Key: "Right", Action: "select_right", Comment: "Select window right"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "Up", Action: "move_up", Comment: "Move window up"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "Down", Action: "move_down", Comment: "Move window down"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "Left", Action: "move_left", Comment: "Move window left"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "Right", Action: "move_right", Comment: "Move window right"},
|
||||||
|
{Mods: []string{"Super"}, Key: "r", Action: "toggle_resize", Comment: "Toggle resize mode"},
|
||||||
|
{Mods: []string{"Super"}, Key: "f", Action: "fullscreen", Comment: "Toggle fullscreen"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "q", Action: "quit_active_window", Comment: "Close window"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "e", Action: "quit_compositor", Comment: "Exit compositor"},
|
||||||
|
{Mods: []string{"Super"}, Key: "Space", Action: "toggle_floating", Comment: "Toggle floating"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "p", Action: "toggle_pinned_to_workspace", Comment: "Toggle pinned to workspace"},
|
||||||
|
{Mods: []string{"Super"}, Key: "w", Action: "toggle_tabbing", Comment: "Toggle tabbing layout"},
|
||||||
|
{Mods: []string{"Super"}, Key: "s", Action: "toggle_stacking", Comment: "Toggle stacking layout"},
|
||||||
|
{Mods: []string{"Super"}, Key: "1", Action: "select_workspace_0", Comment: "Workspace 1"},
|
||||||
|
{Mods: []string{"Super"}, Key: "2", Action: "select_workspace_1", Comment: "Workspace 2"},
|
||||||
|
{Mods: []string{"Super"}, Key: "3", Action: "select_workspace_2", Comment: "Workspace 3"},
|
||||||
|
{Mods: []string{"Super"}, Key: "4", Action: "select_workspace_3", Comment: "Workspace 4"},
|
||||||
|
{Mods: []string{"Super"}, Key: "5", Action: "select_workspace_4", Comment: "Workspace 5"},
|
||||||
|
{Mods: []string{"Super"}, Key: "6", Action: "select_workspace_5", Comment: "Workspace 6"},
|
||||||
|
{Mods: []string{"Super"}, Key: "7", Action: "select_workspace_6", Comment: "Workspace 7"},
|
||||||
|
{Mods: []string{"Super"}, Key: "8", Action: "select_workspace_7", Comment: "Workspace 8"},
|
||||||
|
{Mods: []string{"Super"}, Key: "9", Action: "select_workspace_8", Comment: "Workspace 9"},
|
||||||
|
{Mods: []string{"Super"}, Key: "0", Action: "select_workspace_9", Comment: "Workspace 10"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "1", Action: "move_to_workspace_0", Comment: "Move to workspace 1"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "2", Action: "move_to_workspace_1", Comment: "Move to workspace 2"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "3", Action: "move_to_workspace_2", Comment: "Move to workspace 3"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "4", Action: "move_to_workspace_3", Comment: "Move to workspace 4"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "5", Action: "move_to_workspace_4", Comment: "Move to workspace 5"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "6", Action: "move_to_workspace_5", Comment: "Move to workspace 6"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "7", Action: "move_to_workspace_6", Comment: "Move to workspace 7"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "8", Action: "move_to_workspace_7", Comment: "Move to workspace 8"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "9", Action: "move_to_workspace_8", Comment: "Move to workspace 9"},
|
||||||
|
{Mods: []string{"Super", "Shift"}, Key: "0", Action: "move_to_workspace_9", Comment: "Move to workspace 10"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseMiracleConfig(configPath string) (*MiracleConfig, error) {
|
||||||
|
expanded, err := utils.ExpandPath(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(expanded)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var configFile string
|
||||||
|
if info.IsDir() {
|
||||||
|
configFile = filepath.Join(expanded, "config.yaml")
|
||||||
|
} else {
|
||||||
|
configFile = expanded
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(configFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var config MiracleConfig
|
||||||
|
if err := yaml.Unmarshal(data, &config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.ActionKey == "" {
|
||||||
|
config.ActionKey = "meta"
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveMiracleModifier(mod, actionKey string) string {
|
||||||
|
switch mod {
|
||||||
|
case "primary":
|
||||||
|
return resolveActionKey(actionKey)
|
||||||
|
case "alt", "alt_left", "alt_right":
|
||||||
|
return "Alt"
|
||||||
|
case "shift", "shift_left", "shift_right":
|
||||||
|
return "Shift"
|
||||||
|
case "ctrl", "ctrl_left", "ctrl_right":
|
||||||
|
return "Ctrl"
|
||||||
|
case "meta", "meta_left", "meta_right":
|
||||||
|
return "Super"
|
||||||
|
default:
|
||||||
|
return mod
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveActionKey(actionKey string) string {
|
||||||
|
switch actionKey {
|
||||||
|
case "meta":
|
||||||
|
return "Super"
|
||||||
|
case "alt":
|
||||||
|
return "Alt"
|
||||||
|
case "ctrl":
|
||||||
|
return "Ctrl"
|
||||||
|
default:
|
||||||
|
return "Super"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func miracleKeyCodeToName(keyCode string) string {
|
||||||
|
name := strings.TrimPrefix(keyCode, "KEY_")
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
|
||||||
|
switch name {
|
||||||
|
case "enter":
|
||||||
|
return "Return"
|
||||||
|
case "space":
|
||||||
|
return "Space"
|
||||||
|
case "up":
|
||||||
|
return "Up"
|
||||||
|
case "down":
|
||||||
|
return "Down"
|
||||||
|
case "left":
|
||||||
|
return "Left"
|
||||||
|
case "right":
|
||||||
|
return "Right"
|
||||||
|
case "tab":
|
||||||
|
return "Tab"
|
||||||
|
case "escape", "esc":
|
||||||
|
return "Escape"
|
||||||
|
case "delete":
|
||||||
|
return "Delete"
|
||||||
|
case "backspace":
|
||||||
|
return "BackSpace"
|
||||||
|
case "home":
|
||||||
|
return "Home"
|
||||||
|
case "end":
|
||||||
|
return "End"
|
||||||
|
case "pageup":
|
||||||
|
return "Page_Up"
|
||||||
|
case "pagedown":
|
||||||
|
return "Page_Down"
|
||||||
|
case "print":
|
||||||
|
return "Print"
|
||||||
|
case "pause":
|
||||||
|
return "Pause"
|
||||||
|
case "volumeup":
|
||||||
|
return "XF86AudioRaiseVolume"
|
||||||
|
case "volumedown":
|
||||||
|
return "XF86AudioLowerVolume"
|
||||||
|
case "mute":
|
||||||
|
return "XF86AudioMute"
|
||||||
|
case "micmute":
|
||||||
|
return "XF86AudioMicMute"
|
||||||
|
case "brightnessup":
|
||||||
|
return "XF86MonBrightnessUp"
|
||||||
|
case "brightnessdown":
|
||||||
|
return "XF86MonBrightnessDown"
|
||||||
|
case "kbdillumup":
|
||||||
|
return "XF86KbdBrightnessUp"
|
||||||
|
case "kbdillumdown":
|
||||||
|
return "XF86KbdBrightnessDown"
|
||||||
|
case "comma":
|
||||||
|
return "comma"
|
||||||
|
case "minus":
|
||||||
|
return "minus"
|
||||||
|
case "equal":
|
||||||
|
return "equal"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(name) == 1 {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func MiracleConfigToBindings(config *MiracleConfig) []MiracleKeyBinding {
|
||||||
|
overridden := make(map[string]bool)
|
||||||
|
var bindings []MiracleKeyBinding
|
||||||
|
|
||||||
|
for _, override := range config.DefaultActionOverrides {
|
||||||
|
mods := make([]string, 0, len(override.Modifiers))
|
||||||
|
for _, mod := range override.Modifiers {
|
||||||
|
mods = append(mods, resolveMiracleModifier(mod, config.ActionKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings = append(bindings, MiracleKeyBinding{
|
||||||
|
Mods: mods,
|
||||||
|
Key: miracleKeyCodeToName(override.Key),
|
||||||
|
Action: override.Name,
|
||||||
|
Comment: miracleActionDescription(override.Name),
|
||||||
|
})
|
||||||
|
overridden[override.Name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, def := range miracleDefaultBinds {
|
||||||
|
if overridden[def.Action] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bindings = append(bindings, def)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, custom := range config.CustomActions {
|
||||||
|
mods := make([]string, 0, len(custom.Modifiers))
|
||||||
|
for _, mod := range custom.Modifiers {
|
||||||
|
mods = append(mods, resolveMiracleModifier(mod, config.ActionKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings = append(bindings, MiracleKeyBinding{
|
||||||
|
Mods: mods,
|
||||||
|
Key: miracleKeyCodeToName(custom.Key),
|
||||||
|
Action: custom.Command,
|
||||||
|
Comment: custom.Command,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings
|
||||||
|
}
|
||||||
|
|
||||||
|
func miracleActionDescription(action string) string {
|
||||||
|
switch action {
|
||||||
|
case "terminal":
|
||||||
|
return "Open terminal"
|
||||||
|
case "request_vertical":
|
||||||
|
return "Layout windows vertically"
|
||||||
|
case "request_horizontal":
|
||||||
|
return "Layout windows horizontally"
|
||||||
|
case "select_up":
|
||||||
|
return "Select window above"
|
||||||
|
case "select_down":
|
||||||
|
return "Select window below"
|
||||||
|
case "select_left":
|
||||||
|
return "Select window left"
|
||||||
|
case "select_right":
|
||||||
|
return "Select window right"
|
||||||
|
case "move_up":
|
||||||
|
return "Move window up"
|
||||||
|
case "move_down":
|
||||||
|
return "Move window down"
|
||||||
|
case "move_left":
|
||||||
|
return "Move window left"
|
||||||
|
case "move_right":
|
||||||
|
return "Move window right"
|
||||||
|
case "toggle_resize":
|
||||||
|
return "Toggle resize mode"
|
||||||
|
case "fullscreen":
|
||||||
|
return "Toggle fullscreen"
|
||||||
|
case "quit_active_window":
|
||||||
|
return "Close window"
|
||||||
|
case "quit_compositor":
|
||||||
|
return "Exit compositor"
|
||||||
|
case "toggle_floating":
|
||||||
|
return "Toggle floating"
|
||||||
|
case "toggle_pinned_to_workspace":
|
||||||
|
return "Toggle pinned to workspace"
|
||||||
|
case "toggle_tabbing":
|
||||||
|
return "Toggle tabbing layout"
|
||||||
|
case "toggle_stacking":
|
||||||
|
return "Toggle stacking layout"
|
||||||
|
case "magnifier_on":
|
||||||
|
return "Enable magnifier"
|
||||||
|
case "magnifier_off":
|
||||||
|
return "Disable magnifier"
|
||||||
|
case "magnifier_increase_size":
|
||||||
|
return "Increase magnifier area"
|
||||||
|
case "magnifier_decrease_size":
|
||||||
|
return "Decrease magnifier area"
|
||||||
|
case "magnifier_increase_scale":
|
||||||
|
return "Increase magnifier scale"
|
||||||
|
case "magnifier_decrease_scale":
|
||||||
|
return "Decrease magnifier scale"
|
||||||
|
}
|
||||||
|
|
||||||
|
if num, ok := strings.CutPrefix(action, "select_workspace_"); ok {
|
||||||
|
return "Workspace " + num
|
||||||
|
}
|
||||||
|
if num, ok := strings.CutPrefix(action, "move_to_workspace_"); ok {
|
||||||
|
return "Move to workspace " + num
|
||||||
|
}
|
||||||
|
|
||||||
|
return action
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ func NewSwayProvider(configPath string) *SwayProvider {
|
|||||||
configPath = "$HOME/.config/sway"
|
configPath = "$HOME/.config/sway"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Determine isScroll based on the provided config path
|
|
||||||
isScroll = strings.Contains(configPath, "scroll")
|
isScroll = strings.Contains(configPath, "scroll")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,16 +35,16 @@ func NewSwayProvider(configPath string) *SwayProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SwayProvider) Name() string {
|
func (s *SwayProvider) Name() string {
|
||||||
if s != nil && s.isScroll {
|
|
||||||
return "scroll"
|
|
||||||
}
|
|
||||||
if s == nil {
|
if s == nil {
|
||||||
_, ok := os.LookupEnv("SCROLLSOCK")
|
if os.Getenv("SCROLLSOCK") != "" {
|
||||||
if ok {
|
|
||||||
return "scroll"
|
return "scroll"
|
||||||
}
|
}
|
||||||
|
return "sway"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.isScroll {
|
||||||
|
return "scroll"
|
||||||
|
}
|
||||||
return "sway"
|
return "sway"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const (
|
|||||||
CompositorNiri
|
CompositorNiri
|
||||||
CompositorDWL
|
CompositorDWL
|
||||||
CompositorScroll
|
CompositorScroll
|
||||||
|
CompositorMiracle
|
||||||
)
|
)
|
||||||
|
|
||||||
var detectedCompositor Compositor = -1
|
var detectedCompositor Compositor = -1
|
||||||
@@ -34,6 +35,7 @@ func DetectCompositor() Compositor {
|
|||||||
niriSocket := os.Getenv("NIRI_SOCKET")
|
niriSocket := os.Getenv("NIRI_SOCKET")
|
||||||
swaySocket := os.Getenv("SWAYSOCK")
|
swaySocket := os.Getenv("SWAYSOCK")
|
||||||
scrollSocket := os.Getenv("SCROLLSOCK")
|
scrollSocket := os.Getenv("SCROLLSOCK")
|
||||||
|
miracleSocket := os.Getenv("MIRACLESOCK")
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case niriSocket != "":
|
case niriSocket != "":
|
||||||
@@ -46,7 +48,11 @@ func DetectCompositor() Compositor {
|
|||||||
detectedCompositor = CompositorScroll
|
detectedCompositor = CompositorScroll
|
||||||
return detectedCompositor
|
return detectedCompositor
|
||||||
}
|
}
|
||||||
|
case miracleSocket != "":
|
||||||
|
if _, err := os.Stat(miracleSocket); err == nil {
|
||||||
|
detectedCompositor = CompositorMiracle
|
||||||
|
return detectedCompositor
|
||||||
|
}
|
||||||
case swaySocket != "":
|
case swaySocket != "":
|
||||||
if _, err := os.Stat(swaySocket); err == nil {
|
if _, err := os.Stat(swaySocket); err == nil {
|
||||||
detectedCompositor = CompositorSway
|
detectedCompositor = CompositorSway
|
||||||
@@ -260,6 +266,25 @@ func getScrollFocusedMonitor() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMiracleFocusedMonitor() string {
|
||||||
|
output, err := exec.Command("miraclemsg", "-t", "get_workspaces").Output()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var workspaces []swayWorkspace
|
||||||
|
if err := json.Unmarshal(output, &workspaces); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ws := range workspaces {
|
||||||
|
if ws.Focused {
|
||||||
|
return ws.Output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type niriWorkspace struct {
|
type niriWorkspace struct {
|
||||||
Output string `json:"output"`
|
Output string `json:"output"`
|
||||||
IsFocused bool `json:"is_focused"`
|
IsFocused bool `json:"is_focused"`
|
||||||
@@ -407,6 +432,8 @@ func GetFocusedMonitor() string {
|
|||||||
return getSwayFocusedMonitor()
|
return getSwayFocusedMonitor()
|
||||||
case CompositorScroll:
|
case CompositorScroll:
|
||||||
return getScrollFocusedMonitor()
|
return getScrollFocusedMonitor()
|
||||||
|
case CompositorMiracle:
|
||||||
|
return getMiracleFocusedMonitor()
|
||||||
case CompositorNiri:
|
case CompositorNiri:
|
||||||
return getNiriFocusedMonitor()
|
return getNiriFocusedMonitor()
|
||||||
case CompositorDWL:
|
case CompositorDWL:
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ in
|
|||||||
"labwc"
|
"labwc"
|
||||||
"mango"
|
"mango"
|
||||||
"scroll"
|
"scroll"
|
||||||
|
"miracle"
|
||||||
];
|
];
|
||||||
description = "Compositor to run greeter in";
|
description = "Compositor to run greeter in";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ Item {
|
|||||||
if (CompositorService.isNiri && NiriService.currentOutput) {
|
if (CompositorService.isNiri && NiriService.currentOutput) {
|
||||||
return NiriService.currentOutput;
|
return NiriService.currentOutput;
|
||||||
}
|
}
|
||||||
if ((CompositorService.isSway || CompositorService.isScroll) && I3.workspaces?.values) {
|
if ((CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) && I3.workspaces?.values) {
|
||||||
const focusedWs = I3.workspaces.values.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces.values.find(ws => ws.focused === true);
|
||||||
return focusedWs?.monitor?.name || "";
|
return focusedWs?.monitor?.name || "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ Item {
|
|||||||
focusedScreenName = Hyprland.focusedWorkspace.monitor.name;
|
focusedScreenName = Hyprland.focusedWorkspace.monitor.name;
|
||||||
} else if (CompositorService.isNiri && NiriService.currentOutput) {
|
} else if (CompositorService.isNiri && NiriService.currentOutput) {
|
||||||
focusedScreenName = NiriService.currentOutput;
|
focusedScreenName = NiriService.currentOutput;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
focusedScreenName = focusedWs?.monitor?.name || "";
|
focusedScreenName = focusedWs?.monitor?.name || "";
|
||||||
} else if (CompositorService.isDwl && DwlService.activeOutput) {
|
} else if (CompositorService.isDwl && DwlService.activeOutput) {
|
||||||
@@ -125,7 +125,7 @@ Item {
|
|||||||
focusedScreenName = Hyprland.focusedWorkspace.monitor.name;
|
focusedScreenName = Hyprland.focusedWorkspace.monitor.name;
|
||||||
} else if (CompositorService.isNiri && NiriService.currentOutput) {
|
} else if (CompositorService.isNiri && NiriService.currentOutput) {
|
||||||
focusedScreenName = NiriService.currentOutput;
|
focusedScreenName = NiriService.currentOutput;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
focusedScreenName = focusedWs?.monitor?.name || "";
|
focusedScreenName = focusedWs?.monitor?.name || "";
|
||||||
} else if (CompositorService.isDwl && DwlService.activeOutput) {
|
} else if (CompositorService.isDwl && DwlService.activeOutput) {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ Item {
|
|||||||
}, (_, i) => i);
|
}, (_, i) => i);
|
||||||
}
|
}
|
||||||
return DwlService.getVisibleTags(barWindow.screenName);
|
return DwlService.getVisibleTags(barWindow.screenName);
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
const workspaces = I3.workspaces?.values || [];
|
const workspaces = I3.workspaces?.values || [];
|
||||||
if (workspaces.length === 0)
|
if (workspaces.length === 0)
|
||||||
return [
|
return [
|
||||||
@@ -145,7 +145,7 @@ Item {
|
|||||||
return 0;
|
return 0;
|
||||||
const activeTags = DwlService.getActiveTags(barWindow.screenName);
|
const activeTags = DwlService.getActiveTags(barWindow.screenName);
|
||||||
return activeTags.length > 0 ? activeTags[0] : 0;
|
return activeTags.length > 0 ? activeTags[0] : 0;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
if (!barWindow.screenName || SettingsData.workspaceFollowFocus) {
|
if (!barWindow.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
return focusedWs ? focusedWs.num : 1;
|
return focusedWs ? focusedWs.num : 1;
|
||||||
@@ -194,7 +194,7 @@ Item {
|
|||||||
if (nextIndex !== validIndex) {
|
if (nextIndex !== validIndex) {
|
||||||
DwlService.switchToTag(barWindow.screenName, realWorkspaces[nextIndex]);
|
DwlService.switchToTag(barWindow.screenName, realWorkspaces[nextIndex]);
|
||||||
}
|
}
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
const currentWs = getCurrentWorkspace();
|
const currentWs = getCurrentWorkspace();
|
||||||
const currentIndex = realWorkspaces.findIndex(ws => ws.num === currentWs);
|
const currentIndex = realWorkspaces.findIndex(ws => ws.num === currentWs);
|
||||||
const validIndex = currentIndex === -1 ? 0 : currentIndex;
|
const validIndex = currentIndex === -1 ? 0 : currentIndex;
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ BasePill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isLabwc)
|
visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle || CompositorService.isLabwc)
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.noBackground)
|
width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.noBackground)
|
||||||
height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.noBackground)
|
height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.noBackground)
|
||||||
@@ -72,6 +72,8 @@ BasePill {
|
|||||||
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
||||||
} else if (CompositorService.isScroll) {
|
} else if (CompositorService.isScroll) {
|
||||||
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
||||||
|
} else if (CompositorService.isMiracle) {
|
||||||
|
return "file://" + Theme.shellDir + "/assets/miraclewm.svg";
|
||||||
} else if (CompositorService.isLabwc) {
|
} else if (CompositorService.isLabwc) {
|
||||||
return "file://" + Theme.shellDir + "/assets/labwc.png";
|
return "file://" + Theme.shellDir + "/assets/labwc.png";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ Item {
|
|||||||
return DwlService.activeOutput || root.screenName;
|
return DwlService.activeOutput || root.screenName;
|
||||||
case "sway":
|
case "sway":
|
||||||
case "scroll":
|
case "scroll":
|
||||||
|
case "miracle":
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
return focusedWs?.monitor?.name || root.screenName;
|
return focusedWs?.monitor?.name || root.screenName;
|
||||||
default:
|
default:
|
||||||
@@ -44,7 +45,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool useExtWorkspace: DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && ExtWorkspaceService.extWorkspaceAvailable)
|
readonly property bool useExtWorkspace: DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle && ExtWorkspaceService.extWorkspaceAvailable)
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: DesktopEntries
|
target: DesktopEntries
|
||||||
@@ -67,6 +68,7 @@ Item {
|
|||||||
return activeTags.length > 0 ? activeTags[0] : -1;
|
return activeTags.length > 0 ? activeTags[0] : -1;
|
||||||
case "sway":
|
case "sway":
|
||||||
case "scroll":
|
case "scroll":
|
||||||
|
case "miracle":
|
||||||
return getSwayActiveWorkspace();
|
return getSwayActiveWorkspace();
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
@@ -97,6 +99,7 @@ Item {
|
|||||||
break;
|
break;
|
||||||
case "sway":
|
case "sway":
|
||||||
case "scroll":
|
case "scroll":
|
||||||
|
case "miracle":
|
||||||
baseList = getSwayWorkspaces();
|
baseList = getSwayWorkspaces();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -114,12 +117,23 @@ Item {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function mapWorkspace(ws) {
|
||||||
|
return {
|
||||||
|
"num": ws.number,
|
||||||
|
"name": ws.name,
|
||||||
|
"focused": ws.focused,
|
||||||
|
"active": ws.active,
|
||||||
|
"urgent": ws.urgent,
|
||||||
|
"monitor": ws.monitor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (!root.screenName || SettingsData.workspaceFollowFocus) {
|
if (!root.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
return workspaces.slice().sort((a, b) => a.num - b.num);
|
return workspaces.slice().sort((a, b) => a.num - b.num).map(mapWorkspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === root.screenName);
|
const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === root.screenName);
|
||||||
return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num) : [
|
return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num).map(mapWorkspace) : [
|
||||||
{
|
{
|
||||||
"num": 1
|
"num": 1
|
||||||
}
|
}
|
||||||
@@ -222,7 +236,7 @@ Item {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
targetWorkspaceId = ws.tag;
|
targetWorkspaceId = ws.tag;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
targetWorkspaceId = ws.num !== undefined ? ws.num : ws;
|
targetWorkspaceId = ws.num !== undefined ? ws.num : ws;
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
@@ -234,7 +248,7 @@ Item {
|
|||||||
let isActiveWs = false;
|
let isActiveWs = false;
|
||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
isActiveWs = NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active);
|
isActiveWs = NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active);
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
isActiveWs = focusedWs ? (focusedWs.num === targetWorkspaceId) : false;
|
isActiveWs = focusedWs ? (focusedWs.num === targetWorkspaceId) : false;
|
||||||
} else if (CompositorService.isDwl) {
|
} else if (CompositorService.isDwl) {
|
||||||
@@ -255,7 +269,7 @@ Item {
|
|||||||
let winWs = null;
|
let winWs = null;
|
||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
winWs = w.workspace_id;
|
winWs = w.workspace_id;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
winWs = w.workspace?.num;
|
winWs = w.workspace?.num;
|
||||||
} else {
|
} else {
|
||||||
const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []);
|
const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []);
|
||||||
@@ -322,7 +336,7 @@ Item {
|
|||||||
placeholder = {
|
placeholder = {
|
||||||
"tag": -1
|
"tag": -1
|
||||||
};
|
};
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
placeholder = {
|
placeholder = {
|
||||||
"num": -1
|
"num": -1
|
||||||
};
|
};
|
||||||
@@ -516,7 +530,7 @@ Item {
|
|||||||
return ws && ws.id !== -1;
|
return ws && ws.id !== -1;
|
||||||
if (CompositorService.isDwl)
|
if (CompositorService.isDwl)
|
||||||
return ws && ws.tag !== -1;
|
return ws && ws.tag !== -1;
|
||||||
if (CompositorService.isSway || CompositorService.isScroll)
|
if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle)
|
||||||
return ws && ws.num !== -1;
|
return ws && ws.num !== -1;
|
||||||
return ws !== -1;
|
return ws !== -1;
|
||||||
});
|
});
|
||||||
@@ -588,7 +602,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DwlService.switchToTag(root.screenName, realWorkspaces[nextIndex].tag);
|
DwlService.switchToTag(root.screenName, realWorkspaces[nextIndex].tag);
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
const realWorkspaces = getRealWorkspaces();
|
const realWorkspaces = getRealWorkspaces();
|
||||||
if (realWorkspaces.length < 2) {
|
if (realWorkspaces.length < 2) {
|
||||||
return;
|
return;
|
||||||
@@ -617,7 +631,7 @@ Item {
|
|||||||
return modelData?.id || "";
|
return modelData?.id || "";
|
||||||
if (CompositorService.isDwl)
|
if (CompositorService.isDwl)
|
||||||
return (modelData?.tag !== undefined) ? (modelData.tag + 1) : "";
|
return (modelData?.tag !== undefined) ? (modelData.tag + 1) : "";
|
||||||
if (CompositorService.isSway || CompositorService.isScroll)
|
if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle)
|
||||||
return modelData?.num || "";
|
return modelData?.num || "";
|
||||||
return modelData - 1;
|
return modelData - 1;
|
||||||
}
|
}
|
||||||
@@ -632,7 +646,7 @@ Item {
|
|||||||
isPlaceholder = modelData?.id === -1;
|
isPlaceholder = modelData?.id === -1;
|
||||||
} else if (CompositorService.isDwl) {
|
} else if (CompositorService.isDwl) {
|
||||||
isPlaceholder = modelData?.tag === -1;
|
isPlaceholder = modelData?.tag === -1;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
isPlaceholder = modelData?.num === -1;
|
isPlaceholder = modelData?.num === -1;
|
||||||
} else {
|
} else {
|
||||||
isPlaceholder = modelData === -1;
|
isPlaceholder = modelData === -1;
|
||||||
@@ -665,7 +679,7 @@ Item {
|
|||||||
return getWorkspaceIndexFallback(modelData, index);
|
return getWorkspaceIndexFallback(modelData, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool hasNativeWorkspaceSupport: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll
|
readonly property bool hasNativeWorkspaceSupport: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle
|
||||||
readonly property bool hasWorkspaces: getRealWorkspaces().length > 0
|
readonly property bool hasWorkspaces: getRealWorkspaces().length > 0
|
||||||
readonly property bool shouldShow: hasNativeWorkspaceSupport || (useExtWorkspace && hasWorkspaces)
|
readonly property bool shouldShow: hasNativeWorkspaceSupport || (useExtWorkspace && hasWorkspaces)
|
||||||
|
|
||||||
@@ -865,7 +879,7 @@ Item {
|
|||||||
return !!(modelData && modelData.id === root.currentWorkspace);
|
return !!(modelData && modelData.id === root.currentWorkspace);
|
||||||
if (CompositorService.isDwl)
|
if (CompositorService.isDwl)
|
||||||
return !!(modelData && root.dwlActiveTags.includes(modelData.tag));
|
return !!(modelData && root.dwlActiveTags.includes(modelData.tag));
|
||||||
if (CompositorService.isSway || CompositorService.isScroll)
|
if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle)
|
||||||
return !!(modelData && modelData.num === root.currentWorkspace);
|
return !!(modelData && modelData.num === root.currentWorkspace);
|
||||||
return modelData === root.currentWorkspace;
|
return modelData === root.currentWorkspace;
|
||||||
}
|
}
|
||||||
@@ -889,7 +903,7 @@ Item {
|
|||||||
return !!(modelData && modelData.id === -1);
|
return !!(modelData && modelData.id === -1);
|
||||||
if (CompositorService.isDwl)
|
if (CompositorService.isDwl)
|
||||||
return !!(modelData && modelData.tag === -1);
|
return !!(modelData && modelData.tag === -1);
|
||||||
if (CompositorService.isSway || CompositorService.isScroll)
|
if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle)
|
||||||
return !!(modelData && modelData.num === -1);
|
return !!(modelData && modelData.num === -1);
|
||||||
return modelData === -1;
|
return modelData === -1;
|
||||||
}
|
}
|
||||||
@@ -906,7 +920,7 @@ Item {
|
|||||||
return loadedIsUrgent;
|
return loadedIsUrgent;
|
||||||
if (CompositorService.isDwl)
|
if (CompositorService.isDwl)
|
||||||
return modelData?.state === 2;
|
return modelData?.state === 2;
|
||||||
if (CompositorService.isSway || CompositorService.isScroll)
|
if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle)
|
||||||
return loadedIsUrgent;
|
return loadedIsUrgent;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -927,7 +941,7 @@ Item {
|
|||||||
targetWorkspaceId = modelData?.id;
|
targetWorkspaceId = modelData?.id;
|
||||||
} else if (CompositorService.isDwl) {
|
} else if (CompositorService.isDwl) {
|
||||||
targetWorkspaceId = modelData?.tag;
|
targetWorkspaceId = modelData?.tag;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
targetWorkspaceId = modelData?.num;
|
targetWorkspaceId = modelData?.num;
|
||||||
}
|
}
|
||||||
if (targetWorkspaceId === undefined || targetWorkspaceId === null)
|
if (targetWorkspaceId === undefined || targetWorkspaceId === null)
|
||||||
@@ -946,7 +960,7 @@ Item {
|
|||||||
let winWs = null;
|
let winWs = null;
|
||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
winWs = w.workspace_id;
|
winWs = w.workspace_id;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
winWs = w.workspace?.num;
|
winWs = w.workspace?.num;
|
||||||
} else if (CompositorService.isHyprland) {
|
} else if (CompositorService.isHyprland) {
|
||||||
const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []);
|
const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []);
|
||||||
@@ -971,7 +985,7 @@ Item {
|
|||||||
readonly property real baseWidth: root.isVertical ? (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5) : (isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7)
|
readonly property real baseWidth: root.isVertical ? (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5) : (isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7)
|
||||||
readonly property real baseHeight: root.isVertical ? (isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7) : (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5)
|
readonly property real baseHeight: root.isVertical ? (isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7) : (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5)
|
||||||
readonly property bool hasWorkspaceName: SettingsData.showWorkspaceName && modelData?.name && modelData.name !== ""
|
readonly property bool hasWorkspaceName: SettingsData.showWorkspaceName && modelData?.name && modelData.name !== ""
|
||||||
readonly property bool workspaceNamesEnabled: SettingsData.showWorkspaceName && CompositorService.isNiri
|
readonly property bool workspaceNamesEnabled: SettingsData.showWorkspaceName && (CompositorService.isNiri || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle)
|
||||||
readonly property real contentImplicitWidth: (hasWorkspaceName || loadedHasIcon) ? (appIconsLoader.item?.contentWidth ?? 0) : 0
|
readonly property real contentImplicitWidth: (hasWorkspaceName || loadedHasIcon) ? (appIconsLoader.item?.contentWidth ?? 0) : 0
|
||||||
readonly property real contentImplicitHeight: (workspaceNamesEnabled || loadedHasIcon) ? (appIconsLoader.item?.contentHeight ?? 0) : 0
|
readonly property real contentImplicitHeight: (workspaceNamesEnabled || loadedHasIcon) ? (appIconsLoader.item?.contentHeight ?? 0) : 0
|
||||||
|
|
||||||
@@ -1123,9 +1137,7 @@ Item {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!dragHandler.dragging) {
|
if (!dragHandler.dragging) {
|
||||||
const distance = root.isVertical
|
const distance = root.isVertical ? Math.abs(mouse.y - dragHandler.dragStartPos.y) : Math.abs(mouse.x - dragHandler.dragStartPos.x);
|
||||||
? Math.abs(mouse.y - dragHandler.dragStartPos.y)
|
|
||||||
: Math.abs(mouse.x - dragHandler.dragStartPos.x);
|
|
||||||
if (distance > 5) {
|
if (distance > 5) {
|
||||||
dragHandler.dragging = true;
|
dragHandler.dragging = true;
|
||||||
root.dragSourceIndex = index;
|
root.dragSourceIndex = index;
|
||||||
@@ -1136,9 +1148,7 @@ Item {
|
|||||||
if (!dragHandler.dragging)
|
if (!dragHandler.dragging)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const rawAxisOffset = root.isVertical
|
const rawAxisOffset = root.isVertical ? (mouse.y - dragHandler.dragStartPos.y) : (mouse.x - dragHandler.dragStartPos.x);
|
||||||
? (mouse.y - dragHandler.dragStartPos.y)
|
|
||||||
: (mouse.x - dragHandler.dragStartPos.x);
|
|
||||||
|
|
||||||
const itemSize = (root.isVertical ? delegateRoot.height : delegateRoot.width) + Theme.spacingS;
|
const itemSize = (root.isVertical ? delegateRoot.height : delegateRoot.width) + Theme.spacingS;
|
||||||
const maxOffsetPositive = (root.workspaceList.length - 1 - index) * itemSize;
|
const maxOffsetPositive = (root.workspaceList.length - 1 - index) * itemSize;
|
||||||
@@ -1189,7 +1199,7 @@ Item {
|
|||||||
Hyprland.dispatch(`workspace ${modelData.id}`);
|
Hyprland.dispatch(`workspace ${modelData.id}`);
|
||||||
} else if (CompositorService.isDwl && modelData?.tag !== undefined) {
|
} else if (CompositorService.isDwl && modelData?.tag !== undefined) {
|
||||||
DwlService.switchToTag(root.screenName, modelData.tag);
|
DwlService.switchToTag(root.screenName, modelData.tag);
|
||||||
} else if ((CompositorService.isSway || CompositorService.isScroll) && modelData?.num) {
|
} else if ((CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) && modelData?.num) {
|
||||||
try {
|
try {
|
||||||
I3.dispatch(`workspace number ${modelData.num}`);
|
I3.dispatch(`workspace number ${modelData.num}`);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@@ -1228,7 +1238,7 @@ Item {
|
|||||||
wsData = modelData;
|
wsData = modelData;
|
||||||
} else if (CompositorService.isDwl) {
|
} else if (CompositorService.isDwl) {
|
||||||
wsData = modelData;
|
wsData = modelData;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
wsData = modelData;
|
wsData = modelData;
|
||||||
}
|
}
|
||||||
delegateRoot.loadedWorkspaceData = wsData;
|
delegateRoot.loadedWorkspaceData = wsData;
|
||||||
@@ -1247,7 +1257,7 @@ Item {
|
|||||||
delegateRoot.loadedHasIcon = icData !== null;
|
delegateRoot.loadedHasIcon = icData !== null;
|
||||||
|
|
||||||
if (SettingsData.showWorkspaceApps) {
|
if (SettingsData.showWorkspaceApps) {
|
||||||
if (CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll) {
|
if (CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
delegateRoot.loadedIcons = root.getWorkspaceIcons(modelData);
|
delegateRoot.loadedIcons = root.getWorkspaceIcons(modelData);
|
||||||
} else if (CompositorService.isNiri) {
|
} else if (CompositorService.isNiri) {
|
||||||
delegateRoot.loadedIcons = root.getWorkspaceIcons(isPlaceholder ? null : modelData);
|
delegateRoot.loadedIcons = root.getWorkspaceIcons(isPlaceholder ? null : modelData);
|
||||||
@@ -1760,7 +1770,7 @@ Item {
|
|||||||
}
|
}
|
||||||
Connections {
|
Connections {
|
||||||
target: I3.workspaces
|
target: I3.workspaces
|
||||||
enabled: (CompositorService.isSway || CompositorService.isScroll)
|
enabled: (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle)
|
||||||
function onValuesChanged() {
|
function onValuesChanged() {
|
||||||
delegateRoot.updateAllData();
|
delegateRoot.updateAllData();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ Card {
|
|||||||
return "on Sway";
|
return "on Sway";
|
||||||
if (CompositorService.isScroll)
|
if (CompositorService.isScroll)
|
||||||
return "on Scroll";
|
return "on Scroll";
|
||||||
|
if (CompositorService.isMiracle)
|
||||||
|
return "on Miracle WM";
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
visible: SettingsData.dockLauncherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isLabwc)
|
visible: SettingsData.dockLauncherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle || CompositorService.isLabwc)
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
||||||
height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
||||||
@@ -253,6 +253,8 @@ Item {
|
|||||||
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
||||||
} else if (CompositorService.isScroll) {
|
} else if (CompositorService.isScroll) {
|
||||||
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
||||||
|
} else if (CompositorService.isMiracle) {
|
||||||
|
return "file://" + Theme.shellDir + "/assets/miraclewm.svg";
|
||||||
} else if (CompositorService.isLabwc) {
|
} else if (CompositorService.isLabwc) {
|
||||||
return "file://" + Theme.shellDir + "/assets/labwc.png";
|
return "file://" + Theme.shellDir + "/assets/labwc.png";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ dms-greeter - DankMaterialShell greeter launcher
|
|||||||
Usage: dms-greeter --command COMPOSITOR [OPTIONS]
|
Usage: dms-greeter --command COMPOSITOR [OPTIONS]
|
||||||
|
|
||||||
Required:
|
Required:
|
||||||
--command COMPOSITOR Compositor to use (niri, hyprland, sway, scroll, mango, or labwc)
|
--command COMPOSITOR Compositor to use (niri, hyprland, sway, scroll, miracle, mango, or labwc)
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-C, --config PATH Custom compositor config file
|
-C, --config PATH Custom compositor config file
|
||||||
@@ -244,6 +244,24 @@ SCROLL_EOF
|
|||||||
exec scroll -c "$COMPOSITOR_CONFIG"
|
exec scroll -c "$COMPOSITOR_CONFIG"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
miracle|miracle-wm)
|
||||||
|
if [[ -z "$COMPOSITOR_CONFIG" ]]; then
|
||||||
|
TEMP_CONFIG=$(mktemp)
|
||||||
|
cat > "$TEMP_CONFIG" << MIRACLE_EOF
|
||||||
|
exec "$QS_CMD; miraclemsg exit"
|
||||||
|
MIRACLE_EOF
|
||||||
|
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||||
|
else
|
||||||
|
TEMP_CONFIG=$(mktemp)
|
||||||
|
cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG"
|
||||||
|
cat >> "$TEMP_CONFIG" << MIRACLE_EOF
|
||||||
|
|
||||||
|
exec "$QS_CMD; miraclemsg exit"
|
||||||
|
MIRACLE_EOF
|
||||||
|
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||||
|
fi
|
||||||
|
exec miracle-wm -c "$COMPOSITOR_CONFIG"
|
||||||
|
;;
|
||||||
|
|
||||||
labwc)
|
labwc)
|
||||||
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
|
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
|
||||||
@@ -263,7 +281,7 @@ SCROLL_EOF
|
|||||||
|
|
||||||
*)
|
*)
|
||||||
echo "Error: Unsupported compositor: $COMPOSITOR" >&2
|
echo "Error: Unsupported compositor: $COMPOSITOR" >&2
|
||||||
echo "Supported compositors: niri, hyprland, sway, scroll, mango, labwc" >&2
|
echo "Supported compositors: niri, hyprland, sway, scroll, miracle, mango, labwc" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Item {
|
|||||||
property bool isNiri: CompositorService.isNiri
|
property bool isNiri: CompositorService.isNiri
|
||||||
property bool isSway: CompositorService.isSway
|
property bool isSway: CompositorService.isSway
|
||||||
property bool isScroll: CompositorService.isScroll
|
property bool isScroll: CompositorService.isScroll
|
||||||
|
property bool isMiracle: CompositorService.isMiracle
|
||||||
property bool isDwl: CompositorService.isDwl
|
property bool isDwl: CompositorService.isDwl
|
||||||
property bool isLabwc: CompositorService.isLabwc
|
property bool isLabwc: CompositorService.isLabwc
|
||||||
|
|
||||||
@@ -24,6 +25,8 @@ Item {
|
|||||||
return "sway";
|
return "sway";
|
||||||
if (isScroll)
|
if (isScroll)
|
||||||
return "scroll";
|
return "scroll";
|
||||||
|
if (isMiracle)
|
||||||
|
return "miracle";
|
||||||
if (isDwl)
|
if (isDwl)
|
||||||
return "mangowc";
|
return "mangowc";
|
||||||
if (isLabwc)
|
if (isLabwc)
|
||||||
@@ -38,6 +41,8 @@ Item {
|
|||||||
return "/assets/sway.svg";
|
return "/assets/sway.svg";
|
||||||
if (isScroll)
|
if (isScroll)
|
||||||
return "/assets/sway.svg";
|
return "/assets/sway.svg";
|
||||||
|
if (isMiracle)
|
||||||
|
return "/assets/miraclewm.svg";
|
||||||
if (isDwl)
|
if (isDwl)
|
||||||
return "/assets/mango.png";
|
return "/assets/mango.png";
|
||||||
if (isLabwc)
|
if (isLabwc)
|
||||||
@@ -52,6 +57,8 @@ Item {
|
|||||||
return "https://swaywm.org";
|
return "https://swaywm.org";
|
||||||
if (isScroll)
|
if (isScroll)
|
||||||
return "https://github.com/dawsers/scroll";
|
return "https://github.com/dawsers/scroll";
|
||||||
|
if (isMiracle)
|
||||||
|
return "https://github.com/miracle-wm-org/miracle-wm";
|
||||||
if (isDwl)
|
if (isDwl)
|
||||||
return "https://github.com/DreamMaoMao/mangowc";
|
return "https://github.com/DreamMaoMao/mangowc";
|
||||||
if (isLabwc)
|
if (isLabwc)
|
||||||
@@ -66,6 +73,8 @@ Item {
|
|||||||
return "Sway Website";
|
return "Sway Website";
|
||||||
if (isScroll)
|
if (isScroll)
|
||||||
return "Scroll Github";
|
return "Scroll Github";
|
||||||
|
if (isMiracle)
|
||||||
|
return "Miracle WM GitHub";
|
||||||
if (isDwl)
|
if (isDwl)
|
||||||
return "mangowc GitHub";
|
return "mangowc GitHub";
|
||||||
if (isLabwc)
|
if (isLabwc)
|
||||||
@@ -98,9 +107,9 @@ Item {
|
|||||||
property string ircUrl: "https://web.libera.chat/gamja/?channels=#labwc"
|
property string ircUrl: "https://web.libera.chat/gamja/?channels=#labwc"
|
||||||
property string ircTooltip: "LabWC IRC Channel"
|
property string ircTooltip: "LabWC IRC Channel"
|
||||||
|
|
||||||
property bool showMatrix: isNiri && !isHyprland && !isSway && !isScroll && !isDwl && !isLabwc
|
property bool showMatrix: isNiri && !isHyprland && !isSway && !isScroll && !isMiracle && !isDwl && !isLabwc
|
||||||
property bool showCompositorDiscord: isHyprland || isDwl
|
property bool showCompositorDiscord: isHyprland || isDwl
|
||||||
property bool showReddit: isNiri && !isHyprland && !isSway && !isScroll && !isDwl && !isLabwc
|
property bool showReddit: isNiri && !isHyprland && !isSway && !isScroll && !isMiracle && !isDwl && !isLabwc
|
||||||
property bool showIrc: isLabwc
|
property bool showIrc: isLabwc
|
||||||
|
|
||||||
DankFlickable {
|
DankFlickable {
|
||||||
|
|||||||
@@ -264,6 +264,8 @@ Item {
|
|||||||
modes.push("Sway");
|
modes.push("Sway");
|
||||||
} else if (CompositorService.isScroll) {
|
} else if (CompositorService.isScroll) {
|
||||||
modes.push("Scroll");
|
modes.push("Scroll");
|
||||||
|
} else if (CompositorService.isMiracle) {
|
||||||
|
modes.push("Miracle");
|
||||||
} else {
|
} else {
|
||||||
modes.push(I18n.tr("Compositor"));
|
modes.push(I18n.tr("Compositor"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ Item {
|
|||||||
modes.push("Sway");
|
modes.push("Sway");
|
||||||
} else if (CompositorService.isScroll) {
|
} else if (CompositorService.isScroll) {
|
||||||
modes.push("Scroll");
|
modes.push("Scroll");
|
||||||
|
} else if (CompositorService.isMiracle) {
|
||||||
|
modes.push("Miracle");
|
||||||
} else {
|
} else {
|
||||||
modes.push(I18n.tr("Compositor"));
|
modes.push(I18n.tr("Compositor"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ Item {
|
|||||||
text: I18n.tr("Follow Monitor Focus")
|
text: I18n.tr("Follow Monitor Focus")
|
||||||
description: I18n.tr("Show workspaces of the currently focused monitor")
|
description: I18n.tr("Show workspaces of the currently focused monitor")
|
||||||
checked: SettingsData.workspaceFollowFocus
|
checked: SettingsData.workspaceFollowFocus
|
||||||
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll
|
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle
|
||||||
onToggled: checked => SettingsData.set("workspaceFollowFocus", checked)
|
onToggled: checked => SettingsData.set("workspaceFollowFocus", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,12 +296,12 @@ Item {
|
|||||||
height: 1
|
height: 1
|
||||||
color: Theme.outline
|
color: Theme.outline
|
||||||
opacity: 0.15
|
opacity: 0.15
|
||||||
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll
|
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsButtonGroupRow {
|
SettingsButtonGroupRow {
|
||||||
text: I18n.tr("Urgent Color")
|
text: I18n.tr("Urgent Color")
|
||||||
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll
|
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle
|
||||||
model: ["err", "pri", "sec", "s", "sc"]
|
model: ["err", "pri", "sec", "s", "sc"]
|
||||||
buttonHeight: 22
|
buttonHeight: 22
|
||||||
minButtonWidth: 36
|
minButtonWidth: 36
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ Singleton {
|
|||||||
return Hyprland.focusedWorkspace.monitor.name;
|
return Hyprland.focusedWorkspace.monitor.name;
|
||||||
if (CompositorService.isNiri && NiriService.currentOutput)
|
if (CompositorService.isNiri && NiriService.currentOutput)
|
||||||
return NiriService.currentOutput;
|
return NiriService.currentOutput;
|
||||||
if (CompositorService.isSway || CompositorService.isScroll) {
|
if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
return focusedWs?.monitor?.name || "";
|
return focusedWs?.monitor?.name || "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ Singleton {
|
|||||||
property bool isDwl: false
|
property bool isDwl: false
|
||||||
property bool isSway: false
|
property bool isSway: false
|
||||||
property bool isScroll: false
|
property bool isScroll: false
|
||||||
|
property bool isMiracle: false
|
||||||
property bool isLabwc: false
|
property bool isLabwc: false
|
||||||
property string compositor: "unknown"
|
property string compositor: "unknown"
|
||||||
readonly property bool useHyprlandFocusGrab: isHyprland && Quickshell.env("DMS_HYPRLAND_EXCLUSIVE_FOCUS") !== "1"
|
readonly property bool useHyprlandFocusGrab: isHyprland && Quickshell.env("DMS_HYPRLAND_EXCLUSIVE_FOCUS") !== "1"
|
||||||
@@ -24,6 +25,7 @@ Singleton {
|
|||||||
readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
|
readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
|
||||||
readonly property string swaySocket: Quickshell.env("SWAYSOCK")
|
readonly property string swaySocket: Quickshell.env("SWAYSOCK")
|
||||||
readonly property string scrollSocket: Quickshell.env("SWAYSOCK")
|
readonly property string scrollSocket: Quickshell.env("SWAYSOCK")
|
||||||
|
readonly property string miracleSocket: Quickshell.env("MIRACLESOCK")
|
||||||
readonly property string labwcPid: Quickshell.env("LABWC_PID")
|
readonly property string labwcPid: Quickshell.env("LABWC_PID")
|
||||||
property bool useNiriSorting: isNiri && NiriService
|
property bool useNiriSorting: isNiri && NiriService
|
||||||
|
|
||||||
@@ -74,7 +76,7 @@ Singleton {
|
|||||||
screenName = Hyprland.focusedWorkspace.monitor.name;
|
screenName = Hyprland.focusedWorkspace.monitor.name;
|
||||||
else if (isNiri && NiriService.currentOutput)
|
else if (isNiri && NiriService.currentOutput)
|
||||||
screenName = NiriService.currentOutput;
|
screenName = NiriService.currentOutput;
|
||||||
else if (isSway || isScroll) {
|
else if (isSway || isScroll || isMiracle) {
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
screenName = focusedWs?.monitor?.name || "";
|
screenName = focusedWs?.monitor?.name || "";
|
||||||
} else if (isDwl && DwlService.activeOutput)
|
} else if (isDwl && DwlService.activeOutput)
|
||||||
@@ -443,12 +445,13 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function detectCompositor() {
|
function detectCompositor() {
|
||||||
if (hyprlandSignature && hyprlandSignature.length > 0 && !niriSocket && !swaySocket && !scrollSocket && !labwcPid) {
|
if (hyprlandSignature && hyprlandSignature.length > 0 && !niriSocket && !swaySocket && !scrollSocket && !miracleSocket && !labwcPid) {
|
||||||
isHyprland = true;
|
isHyprland = true;
|
||||||
isNiri = false;
|
isNiri = false;
|
||||||
isDwl = false;
|
isDwl = false;
|
||||||
isSway = false;
|
isSway = false;
|
||||||
isScroll = false;
|
isScroll = false;
|
||||||
|
isMiracle = false;
|
||||||
isLabwc = false;
|
isLabwc = false;
|
||||||
compositor = "hyprland";
|
compositor = "hyprland";
|
||||||
console.info("CompositorService: Detected Hyprland");
|
console.info("CompositorService: Detected Hyprland");
|
||||||
@@ -463,6 +466,7 @@ Singleton {
|
|||||||
isDwl = false;
|
isDwl = false;
|
||||||
isSway = false;
|
isSway = false;
|
||||||
isScroll = false;
|
isScroll = false;
|
||||||
|
isMiracle = false;
|
||||||
isLabwc = false;
|
isLabwc = false;
|
||||||
compositor = "niri";
|
compositor = "niri";
|
||||||
console.info("CompositorService: Detected Niri with socket:", niriSocket);
|
console.info("CompositorService: Detected Niri with socket:", niriSocket);
|
||||||
@@ -472,7 +476,7 @@ Singleton {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swaySocket && swaySocket.length > 0 && !scrollSocket && scrollSocket.length == 0) {
|
if (swaySocket && swaySocket.length > 0 && !scrollSocket && scrollSocket.length == 0 && !miracleSocket) {
|
||||||
Proc.runCommand("swaySocketCheck", ["test", "-S", swaySocket], (output, exitCode) => {
|
Proc.runCommand("swaySocketCheck", ["test", "-S", swaySocket], (output, exitCode) => {
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
isNiri = false;
|
isNiri = false;
|
||||||
@@ -480,6 +484,7 @@ Singleton {
|
|||||||
isDwl = false;
|
isDwl = false;
|
||||||
isSway = true;
|
isSway = true;
|
||||||
isScroll = false;
|
isScroll = false;
|
||||||
|
isMiracle = false;
|
||||||
isLabwc = false;
|
isLabwc = false;
|
||||||
compositor = "sway";
|
compositor = "sway";
|
||||||
console.info("CompositorService: Detected Sway with socket:", swaySocket);
|
console.info("CompositorService: Detected Sway with socket:", swaySocket);
|
||||||
@@ -488,7 +493,24 @@ Singleton {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrollSocket && scrollSocket.length > 0) {
|
if (miracleSocket && miracleSocket.length > 0) {
|
||||||
|
Proc.runCommand("miracleSocketCheck", ["test", "-S", miracleSocket], (output, exitCode) => {
|
||||||
|
if (exitCode === 0) {
|
||||||
|
isNiri = false;
|
||||||
|
isHyprland = false;
|
||||||
|
isDwl = false;
|
||||||
|
isSway = false;
|
||||||
|
isScroll = false;
|
||||||
|
isMiracle = true;
|
||||||
|
isLabwc = false;
|
||||||
|
compositor = "miracle";
|
||||||
|
console.info("CompositorService: Detected Miracle WM with socket:", miracleSocket);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollSocket && scrollSocket.length > 0 && !miracleSocket) {
|
||||||
Proc.runCommand("scrollSocketCheck", ["test", "-S", scrollSocket], (output, exitCode) => {
|
Proc.runCommand("scrollSocketCheck", ["test", "-S", scrollSocket], (output, exitCode) => {
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
isNiri = false;
|
isNiri = false;
|
||||||
@@ -496,6 +518,7 @@ Singleton {
|
|||||||
isDwl = false;
|
isDwl = false;
|
||||||
isSway = false;
|
isSway = false;
|
||||||
isScroll = true;
|
isScroll = true;
|
||||||
|
isMiracle = false;
|
||||||
isLabwc = false;
|
isLabwc = false;
|
||||||
compositor = "scroll";
|
compositor = "scroll";
|
||||||
console.info("CompositorService: Detected Scroll with socket:", scrollSocket);
|
console.info("CompositorService: Detected Scroll with socket:", scrollSocket);
|
||||||
@@ -510,6 +533,7 @@ Singleton {
|
|||||||
isDwl = false;
|
isDwl = false;
|
||||||
isSway = false;
|
isSway = false;
|
||||||
isScroll = false;
|
isScroll = false;
|
||||||
|
isMiracle = false;
|
||||||
isLabwc = true;
|
isLabwc = true;
|
||||||
compositor = "labwc";
|
compositor = "labwc";
|
||||||
console.info("CompositorService: Detected LabWC with PID:", labwcPid);
|
console.info("CompositorService: Detected LabWC with PID:", labwcPid);
|
||||||
@@ -524,6 +548,7 @@ Singleton {
|
|||||||
isDwl = false;
|
isDwl = false;
|
||||||
isSway = false;
|
isSway = false;
|
||||||
isScroll = false;
|
isScroll = false;
|
||||||
|
isMiracle = false;
|
||||||
isLabwc = false;
|
isLabwc = false;
|
||||||
compositor = "unknown";
|
compositor = "unknown";
|
||||||
console.warn("CompositorService: No compositor detected");
|
console.warn("CompositorService: No compositor detected");
|
||||||
@@ -546,6 +571,7 @@ Singleton {
|
|||||||
isDwl = true;
|
isDwl = true;
|
||||||
isSway = false;
|
isSway = false;
|
||||||
isScroll = false;
|
isScroll = false;
|
||||||
|
isMiracle = false;
|
||||||
isLabwc = false;
|
isLabwc = false;
|
||||||
compositor = "dwl";
|
compositor = "dwl";
|
||||||
console.info("CompositorService: Detected DWL via DMS capability");
|
console.info("CompositorService: Detected DWL via DMS capability");
|
||||||
@@ -559,7 +585,7 @@ Singleton {
|
|||||||
return Hyprland.dispatch("dpms off");
|
return Hyprland.dispatch("dpms off");
|
||||||
if (isDwl)
|
if (isDwl)
|
||||||
return _dwlPowerOffMonitors();
|
return _dwlPowerOffMonitors();
|
||||||
if (isSway || isScroll) {
|
if (isSway || isScroll || isMiracle) {
|
||||||
try {
|
try {
|
||||||
I3.dispatch("output * dpms off");
|
I3.dispatch("output * dpms off");
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@@ -578,7 +604,7 @@ Singleton {
|
|||||||
return Hyprland.dispatch("dpms on");
|
return Hyprland.dispatch("dpms on");
|
||||||
if (isDwl)
|
if (isDwl)
|
||||||
return _dwlPowerOnMonitors();
|
return _dwlPowerOnMonitors();
|
||||||
if (isSway || isScroll) {
|
if (isSway || isScroll || isMiracle) {
|
||||||
try {
|
try {
|
||||||
I3.dispatch("output * dpms on");
|
I3.dispatch("output * dpms on");
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|||||||
@@ -11,83 +11,83 @@ Singleton {
|
|||||||
property var groups: []
|
property var groups: []
|
||||||
property var _cachedWorkspaces: ({})
|
property var _cachedWorkspaces: ({})
|
||||||
|
|
||||||
signal stateChanged()
|
signal stateChanged
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: DMSService
|
target: DMSService
|
||||||
function onCapabilitiesReceived() {
|
function onCapabilitiesReceived() {
|
||||||
checkCapabilities()
|
checkCapabilities();
|
||||||
}
|
}
|
||||||
function onConnectionStateChanged() {
|
function onConnectionStateChanged() {
|
||||||
if (DMSService.isConnected) {
|
if (DMSService.isConnected) {
|
||||||
checkCapabilities()
|
checkCapabilities();
|
||||||
} else {
|
} else {
|
||||||
extWorkspaceAvailable = false
|
extWorkspaceAvailable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function onExtWorkspaceStateUpdate(data) {
|
function onExtWorkspaceStateUpdate(data) {
|
||||||
if (extWorkspaceAvailable) {
|
if (extWorkspaceAvailable) {
|
||||||
handleStateUpdate(data)
|
handleStateUpdate(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (DMSService.dmsAvailable) {
|
if (DMSService.dmsAvailable) {
|
||||||
checkCapabilities()
|
checkCapabilities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCapabilities() {
|
function checkCapabilities() {
|
||||||
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
|
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
|
||||||
extWorkspaceAvailable = false
|
extWorkspaceAvailable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasExtWorkspace = DMSService.capabilities.includes("extworkspace")
|
const hasExtWorkspace = DMSService.capabilities.includes("extworkspace");
|
||||||
if (hasExtWorkspace && !extWorkspaceAvailable) {
|
if (hasExtWorkspace && !extWorkspaceAvailable) {
|
||||||
if (typeof CompositorService !== "undefined") {
|
if (typeof CompositorService !== "undefined") {
|
||||||
const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll)
|
const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle);
|
||||||
if (!useExtWorkspace) {
|
if (!useExtWorkspace) {
|
||||||
console.info("ExtWorkspaceService: ext-workspace available but compositor has native support")
|
console.info("ExtWorkspaceService: ext-workspace available but compositor has native support");
|
||||||
extWorkspaceAvailable = false
|
extWorkspaceAvailable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extWorkspaceAvailable = true
|
extWorkspaceAvailable = true;
|
||||||
console.info("ExtWorkspaceService: ext-workspace capability detected")
|
console.info("ExtWorkspaceService: ext-workspace capability detected");
|
||||||
DMSService.addSubscription("extworkspace")
|
DMSService.addSubscription("extworkspace");
|
||||||
requestState()
|
requestState();
|
||||||
} else if (!hasExtWorkspace) {
|
} else if (!hasExtWorkspace) {
|
||||||
extWorkspaceAvailable = false
|
extWorkspaceAvailable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestState() {
|
function requestState() {
|
||||||
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("extworkspace.getState", null, response => {
|
DMSService.sendRequest("extworkspace.getState", null, response => {
|
||||||
if (response.result) {
|
if (response.result) {
|
||||||
handleStateUpdate(response.result)
|
handleStateUpdate(response.result);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleStateUpdate(state) {
|
function handleStateUpdate(state) {
|
||||||
groups = state.groups || []
|
groups = state.groups || [];
|
||||||
if (groups.length === 0) {
|
if (groups.length === 0) {
|
||||||
console.warn("ExtWorkspaceService: Received empty workspace groups from backend")
|
console.warn("ExtWorkspaceService: Received empty workspace groups from backend");
|
||||||
} else {
|
} else {
|
||||||
console.log("ExtWorkspaceService: Updated with", groups.length, "workspace groups")
|
console.log("ExtWorkspaceService: Updated with", groups.length, "workspace groups");
|
||||||
}
|
}
|
||||||
stateChanged()
|
stateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
function activateWorkspace(workspaceID, groupID = "") {
|
function activateWorkspace(workspaceID, groupID = "") {
|
||||||
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("extworkspace.activateWorkspace", {
|
DMSService.sendRequest("extworkspace.activateWorkspace", {
|
||||||
@@ -95,14 +95,14 @@ Singleton {
|
|||||||
"groupID": groupID
|
"groupID": groupID
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.warn("ExtWorkspaceService: activateWorkspace error:", response.error)
|
console.warn("ExtWorkspaceService: activateWorkspace error:", response.error);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deactivateWorkspace(workspaceID, groupID = "") {
|
function deactivateWorkspace(workspaceID, groupID = "") {
|
||||||
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("extworkspace.deactivateWorkspace", {
|
DMSService.sendRequest("extworkspace.deactivateWorkspace", {
|
||||||
@@ -110,14 +110,14 @@ Singleton {
|
|||||||
"groupID": groupID
|
"groupID": groupID
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.warn("ExtWorkspaceService: deactivateWorkspace error:", response.error)
|
console.warn("ExtWorkspaceService: deactivateWorkspace error:", response.error);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeWorkspace(workspaceID, groupID = "") {
|
function removeWorkspace(workspaceID, groupID = "") {
|
||||||
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("extworkspace.removeWorkspace", {
|
DMSService.sendRequest("extworkspace.removeWorkspace", {
|
||||||
@@ -125,14 +125,14 @@ Singleton {
|
|||||||
"groupID": groupID
|
"groupID": groupID
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.warn("ExtWorkspaceService: removeWorkspace error:", response.error)
|
console.warn("ExtWorkspaceService: removeWorkspace error:", response.error);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWorkspace(groupID, name) {
|
function createWorkspace(groupID, name) {
|
||||||
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
if (!DMSService.isConnected || !extWorkspaceAvailable) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("extworkspace.createWorkspace", {
|
DMSService.sendRequest("extworkspace.createWorkspace", {
|
||||||
@@ -140,134 +140,138 @@ Singleton {
|
|||||||
"name": name
|
"name": name
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.warn("ExtWorkspaceService: createWorkspace error:", response.error)
|
console.warn("ExtWorkspaceService: createWorkspace error:", response.error);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGroupForOutput(outputName) {
|
function getGroupForOutput(outputName) {
|
||||||
for (const group of groups) {
|
for (const group of groups) {
|
||||||
if (group.outputs && group.outputs.includes(outputName)) {
|
if (group.outputs && group.outputs.includes(outputName)) {
|
||||||
return group
|
return group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWorkspacesForOutput(outputName) {
|
function getWorkspacesForOutput(outputName) {
|
||||||
const group = getGroupForOutput(outputName)
|
const group = getGroupForOutput(outputName);
|
||||||
return group ? (group.workspaces || []) : []
|
return group ? (group.workspaces || []) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveWorkspaces() {
|
function getActiveWorkspaces() {
|
||||||
const active = []
|
const active = [];
|
||||||
for (const group of groups) {
|
for (const group of groups) {
|
||||||
if (!group.workspaces) continue
|
if (!group.workspaces)
|
||||||
|
continue;
|
||||||
for (const ws of group.workspaces) {
|
for (const ws of group.workspaces) {
|
||||||
if (ws.active) {
|
if (ws.active) {
|
||||||
active.push({
|
active.push({
|
||||||
workspace: ws,
|
workspace: ws,
|
||||||
group: group,
|
group: group,
|
||||||
outputs: group.outputs || []
|
outputs: group.outputs || []
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return active
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveWorkspaceForOutput(outputName) {
|
function getActiveWorkspaceForOutput(outputName) {
|
||||||
const group = getGroupForOutput(outputName)
|
const group = getGroupForOutput(outputName);
|
||||||
if (!group || !group.workspaces) return null
|
if (!group || !group.workspaces)
|
||||||
|
return null;
|
||||||
|
|
||||||
for (const ws of group.workspaces) {
|
for (const ws of group.workspaces) {
|
||||||
if (ws.active) {
|
if (ws.active) {
|
||||||
return ws
|
return ws;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVisibleWorkspaces(outputName) {
|
function getVisibleWorkspaces(outputName) {
|
||||||
const workspaces = getWorkspacesForOutput(outputName)
|
const workspaces = getWorkspacesForOutput(outputName);
|
||||||
let visible = workspaces.filter(ws => !ws.hidden)
|
let visible = workspaces.filter(ws => !ws.hidden);
|
||||||
|
|
||||||
const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0)
|
const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0);
|
||||||
if (hasValidCoordinates) {
|
if (hasValidCoordinates) {
|
||||||
visible = visible.sort((a, b) => {
|
visible = visible.sort((a, b) => {
|
||||||
const coordsA = a.coordinates || [0, 0]
|
const coordsA = a.coordinates || [0, 0];
|
||||||
const coordsB = b.coordinates || [0, 0]
|
const coordsB = b.coordinates || [0, 0];
|
||||||
if (coordsA[0] !== coordsB[0]) return coordsA[0] - coordsB[0]
|
if (coordsA[0] !== coordsB[0])
|
||||||
return coordsA[1] - coordsB[1]
|
return coordsA[0] - coordsB[0];
|
||||||
})
|
return coordsA[1] - coordsB[1];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheKey = outputName
|
const cacheKey = outputName;
|
||||||
if (!_cachedWorkspaces[cacheKey]) {
|
if (!_cachedWorkspaces[cacheKey]) {
|
||||||
_cachedWorkspaces[cacheKey] = {
|
_cachedWorkspaces[cacheKey] = {
|
||||||
workspaces: [],
|
workspaces: [],
|
||||||
lastNames: []
|
lastNames: []
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const cache = _cachedWorkspaces[cacheKey]
|
const cache = _cachedWorkspaces[cacheKey];
|
||||||
const currentNames = visible.map(ws => ws.name || ws.id)
|
const currentNames = visible.map(ws => ws.name || ws.id);
|
||||||
const namesChanged = JSON.stringify(cache.lastNames) !== JSON.stringify(currentNames)
|
const namesChanged = JSON.stringify(cache.lastNames) !== JSON.stringify(currentNames);
|
||||||
|
|
||||||
if (namesChanged || cache.workspaces.length !== visible.length) {
|
if (namesChanged || cache.workspaces.length !== visible.length) {
|
||||||
cache.workspaces = visible.map(ws => ({
|
cache.workspaces = visible.map(ws => ({
|
||||||
id: ws.id,
|
id: ws.id,
|
||||||
name: ws.name,
|
name: ws.name,
|
||||||
coordinates: ws.coordinates,
|
coordinates: ws.coordinates,
|
||||||
state: ws.state,
|
state: ws.state,
|
||||||
active: ws.active,
|
active: ws.active,
|
||||||
urgent: ws.urgent,
|
urgent: ws.urgent,
|
||||||
hidden: ws.hidden
|
hidden: ws.hidden
|
||||||
}))
|
}));
|
||||||
cache.lastNames = currentNames
|
cache.lastNames = currentNames;
|
||||||
return cache.workspaces
|
return cache.workspaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < visible.length; i++) {
|
for (let i = 0; i < visible.length; i++) {
|
||||||
const src = visible[i]
|
const src = visible[i];
|
||||||
const dst = cache.workspaces[i]
|
const dst = cache.workspaces[i];
|
||||||
dst.id = src.id
|
dst.id = src.id;
|
||||||
dst.name = src.name
|
dst.name = src.name;
|
||||||
dst.coordinates = src.coordinates
|
dst.coordinates = src.coordinates;
|
||||||
dst.state = src.state
|
dst.state = src.state;
|
||||||
dst.active = src.active
|
dst.active = src.active;
|
||||||
dst.urgent = src.urgent
|
dst.urgent = src.urgent;
|
||||||
dst.hidden = src.hidden
|
dst.hidden = src.hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cache.workspaces
|
return cache.workspaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUrgentWorkspaces() {
|
function getUrgentWorkspaces() {
|
||||||
const urgent = []
|
const urgent = [];
|
||||||
for (const group of groups) {
|
for (const group of groups) {
|
||||||
if (!group.workspaces) continue
|
if (!group.workspaces)
|
||||||
|
continue;
|
||||||
for (const ws of group.workspaces) {
|
for (const ws of group.workspaces) {
|
||||||
if (ws.urgent) {
|
if (ws.urgent) {
|
||||||
urgent.push({
|
urgent.push({
|
||||||
workspace: ws,
|
workspace: ws,
|
||||||
group: group,
|
group: group,
|
||||||
outputs: group.outputs || []
|
outputs: group.outputs || []
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return urgent
|
return urgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchToWorkspace(outputName, workspaceName) {
|
function switchToWorkspace(outputName, workspaceName) {
|
||||||
const workspaces = getWorkspacesForOutput(outputName)
|
const workspaces = getWorkspacesForOutput(outputName);
|
||||||
for (const ws of workspaces) {
|
for (const ws of workspaces) {
|
||||||
if (ws.name === workspaceName || ws.id === workspaceName) {
|
if (ws.name === workspaceName || ws.id === workspaceName) {
|
||||||
activateWorkspace(ws.name || ws.id)
|
activateWorkspace(ws.name || ws.id);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.warn("ExtWorkspaceService: workspace not found:", workspaceName)
|
console.warn("ExtWorkspaceService: workspace not found:", workspaceName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ Singleton {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CompositorService.isSway || CompositorService.isScroll) {
|
if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
|
||||||
try {
|
try {
|
||||||
I3.dispatch("exit");
|
I3.dispatch("exit");
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|||||||
1198
quickshell/assets/miraclewm.svg
Normal file
1198
quickshell/assets/miraclewm.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 131 KiB |
Reference in New Issue
Block a user