feat(quickshell): idle chain, drifting wallpaper, and a few fixes
- Idle is handled in the shell instead of hypridle: the screen dims slowly at 4 minutes, locks at 5, powers down at 6, and suspends at 15 on battery. Idle inhibitors hold every stage off; Super+Shift+I does the same by hand and puts a cup on the rail. - The shell draws the wallpaper (backdrop/), so hyprpaper is gone. The picture is drawn a little larger than the screen and drifts with the workspace a beat after the windows, and dims a shade while windows are open. The path lives in quickshell/wallpaper. - The lock screen and power menu say "Take your time." instead of the NieR slogan. - hyprpaper is no longer launched twice, the media module keeps the player that played last instead of an empty browser tab, and grouped windows show thin untitled tabs with their place in the group (2/3) in the bar title. - qt6ct uses Darkly; the package list gains adw-gtk-theme and darkly-bin.
This commit is contained in:
1 parent
864420281b
commit
c36a74e861
20 files changed
+396
-128
No files matched your search
@@ -10,7 +10,8 @@ hl.on("hyprland.start", function()
|
|||||||
hl.exec_cmd("uwsm app -- qs")
|
hl.exec_cmd("uwsm app -- qs")
|
||||||
|
|
||||||
hl.exec_cmd("uwsm app -- nm-applet --indicator")
|
hl.exec_cmd("uwsm app -- nm-applet --indicator")
|
||||||
hl.exec_cmd("uwsm app -- hyprpaper")
|
-- hyprpaper is not started here: its systemd unit is enabled for
|
||||||
|
-- graphical-session.target, and a second copy here ran alongside it.
|
||||||
|
|
||||||
-- clipboard history, text and images
|
-- clipboard history, text and images
|
||||||
hl.exec_cmd("wl-paste --type text --watch cliphist store")
|
hl.exec_cmd("wl-paste --type text --watch cliphist store")
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ shell("power", { key = mod .. " + P", description = "power menu" })
|
|||||||
shell("ask", { key = mod .. " + A", description = "ask claude" })
|
shell("ask", { key = mod .. " + A", description = "ask claude" })
|
||||||
shell("dashboard", { key = mod .. " + D", description = "dashboard" })
|
shell("dashboard", { key = mod .. " + D", description = "dashboard" })
|
||||||
shell("toggleDnd", { key = mod .. " + SHIFT + N", description = "toggle do not disturb" })
|
shell("toggleDnd", { key = mod .. " + SHIFT + N", description = "toggle do not disturb" })
|
||||||
|
shell("toggleStayAwake", { key = mod .. " + SHIFT + I", description = "keep the screen awake" })
|
||||||
shell("clearNotifications", { key = mod .. " + CTRL + SHIFT + N", description = "clear notifications" })
|
shell("clearNotifications", { key = mod .. " + CTRL + SHIFT + N", description = "clear notifications" })
|
||||||
shell("reloadConfig", { key = mod .. " + SHIFT + R", description = "reload shell config" })
|
shell("reloadConfig", { key = mod .. " + SHIFT + R", description = "reload shell config" })
|
||||||
|
|
||||||
|
|||||||
+1
-8
@@ -79,9 +79,6 @@ local function reconcile(ignore)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- First decision of the session, and it agrees with what lua/monitors.lua
|
|
||||||
-- already applied: nothing actually moved, so no daemon needs poking.
|
|
||||||
local settled = panel_off == nil and not want_off
|
|
||||||
panel_off = want_off
|
panel_off = want_off
|
||||||
|
|
||||||
if want_off then
|
if want_off then
|
||||||
@@ -91,11 +88,7 @@ local function reconcile(ignore)
|
|||||||
end
|
end
|
||||||
monitors.apply_external()
|
monitors.apply_external()
|
||||||
|
|
||||||
-- Quickshell follows monitor hotplug by itself; only the wallpaper daemon
|
-- Quickshell follows monitor hotplug by itself, wallpaper included.
|
||||||
-- needs a kick.
|
|
||||||
if not settled then
|
|
||||||
hl.exec_cmd("systemctl restart --user hyprpaper")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ------------------------------------------------------------------ triggers
|
-- ------------------------------------------------------------------ triggers
|
||||||
|
|||||||
+18
-22
@@ -74,6 +74,10 @@ hl.config({
|
|||||||
font_family = "FiraCode Nerd Font",
|
font_family = "FiraCode Nerd Font",
|
||||||
background_color = c.base,
|
background_color = c.base,
|
||||||
focus_on_activate = true,
|
focus_on_activate = true,
|
||||||
|
-- The shell powers displays down after idle (quickshell/services/Idle.qml)
|
||||||
|
-- and back up when idle ends; these wake them even if it is not running.
|
||||||
|
key_press_enables_dpms = true,
|
||||||
|
mouse_move_enables_dpms = true,
|
||||||
},
|
},
|
||||||
|
|
||||||
group = {
|
group = {
|
||||||
@@ -82,37 +86,29 @@ hl.config({
|
|||||||
border_inactive = c.overlay,
|
border_inactive = c.overlay,
|
||||||
},
|
},
|
||||||
|
|
||||||
-- Tabs are solid slabs of the hull, not titles painted over the
|
-- Tabs are thin rounded lines, not titled slabs. The bar already
|
||||||
-- wallpaper. Hyprland paints a tab's fill and its indicator from the
|
-- writes the focused title and its place in the group ("2/3", in
|
||||||
-- same colour, so the current tab is told apart by being lifted a step
|
-- quickshell/bar/ActiveWindow.qml), so titles here only repeated it in
|
||||||
-- and by its title taking the light, not by an accent fill — a light
|
-- a second font. Hyprland paints a tab's indicator in the same colour
|
||||||
-- fill would swallow its own title.
|
-- as its fill, so with no fill the current tab is simply the light one.
|
||||||
groupbar = {
|
groupbar = {
|
||||||
font_family = "Noto Sans",
|
render_titles = false,
|
||||||
font_size = 10,
|
gradients = false,
|
||||||
font_weight_active = "medium",
|
|
||||||
font_weight_inactive = "normal",
|
|
||||||
|
|
||||||
height = 22,
|
indicator_height = 3,
|
||||||
indicator_height = 1,
|
|
||||||
indicator_gap = 0,
|
indicator_gap = 0,
|
||||||
gradients = true,
|
rounding = 2,
|
||||||
rounding = 6,
|
round_only_edges = false,
|
||||||
gradient_rounding = 6,
|
|
||||||
round_only_edges = true,
|
|
||||||
gradient_round_only_edges = true,
|
|
||||||
keep_upper_gap = false,
|
keep_upper_gap = false,
|
||||||
gaps_in = 2,
|
gaps_in = 4,
|
||||||
gaps_out = 0,
|
gaps_out = 0,
|
||||||
|
|
||||||
col = {
|
col = {
|
||||||
active = c.overlay,
|
active = c.accent,
|
||||||
inactive = c.surface,
|
inactive = c.overlay,
|
||||||
locked_active = c.alarm,
|
locked_active = c.alarm,
|
||||||
locked_inactive = c.surface,
|
locked_inactive = c.overlay,
|
||||||
},
|
},
|
||||||
text_color = c.accent,
|
|
||||||
text_color_inactive = c.muted,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -49,10 +49,9 @@ local function mirror_all(panel)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- The bar and popouts stay on the outputs they were created for, so
|
-- The bar, popouts and wallpaper stay on the outputs they were created for,
|
||||||
-- respawn the shell the same way lua/autostart.lua starts it.
|
-- so respawn the shell the same way lua/autostart.lua starts it.
|
||||||
local function restart_clients()
|
local function restart_clients()
|
||||||
hl.exec_cmd("systemctl restart --user hyprpaper")
|
|
||||||
hl.exec_cmd("sh -c 'qs kill; exec uwsm app -- qs'")
|
hl.exec_cmd("sh -c 'qs kill; exec uwsm app -- qs'")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ aalib
|
|||||||
abseil-cpp
|
abseil-cpp
|
||||||
acl
|
acl
|
||||||
acpi
|
acpi
|
||||||
|
adw-gtk-theme
|
||||||
adwaita-cursors
|
adwaita-cursors
|
||||||
adwaita-fonts
|
adwaita-fonts
|
||||||
adwaita-icon-theme
|
adwaita-icon-theme
|
||||||
@@ -87,7 +88,6 @@ calibre
|
|||||||
cargo-audit
|
cargo-audit
|
||||||
catppuccin-gtk-theme-mocha
|
catppuccin-gtk-theme-mocha
|
||||||
catppuccin-qt5ct-git
|
catppuccin-qt5ct-git
|
||||||
catppuccinifier-cli-git
|
|
||||||
cbindgen
|
cbindgen
|
||||||
cblas
|
cblas
|
||||||
cdparanoia
|
cdparanoia
|
||||||
@@ -111,6 +111,7 @@ cups-pk-helper
|
|||||||
curl
|
curl
|
||||||
cxxbridge
|
cxxbridge
|
||||||
cython
|
cython
|
||||||
|
darkly-bin
|
||||||
dav1d
|
dav1d
|
||||||
db5.3
|
db5.3
|
||||||
dbus
|
dbus
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ color_scheme_path=/home/narl/.config/qt6ct/colors/yorha.conf
|
|||||||
custom_palette=true
|
custom_palette=true
|
||||||
icon_theme=Papirus-Dark
|
icon_theme=Papirus-Dark
|
||||||
standard_dialogs=default
|
standard_dialogs=default
|
||||||
style=Fusion
|
style=Darkly
|
||||||
|
|
||||||
[Fonts]
|
[Fonts]
|
||||||
fixed="Sans Serif,9,-1,5,400,0,0,0,0,0,0,0,0,0,0,1"
|
fixed="Sans Serif,9,-1,5,400,0,0,0,0,0,0,0,0,0,0,1"
|
||||||
|
|||||||
+42
-4
@@ -66,6 +66,7 @@ bar/ the two surfaces and their modules
|
|||||||
popouts/ hover panels hanging off rail and bar modules
|
popouts/ hover panels hanging off rail and bar modules
|
||||||
overlays/ power menu, notification toasts, volume/brightness OSD
|
overlays/ power menu, notification toasts, volume/brightness OSD
|
||||||
lock/ session lock
|
lock/ session lock
|
||||||
|
backdrop/ the wallpaper, drawn by the shell
|
||||||
assets/ halftone and stripe tiles, generated with ImageMagick
|
assets/ halftone and stripe tiles, generated with ImageMagick
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -143,6 +144,7 @@ Set in `~/.config/hypr/lua/binds/shell.lua`:
|
|||||||
- `Super+Ctrl+L` — lock
|
- `Super+Ctrl+L` — lock
|
||||||
- `Super+P` — power menu
|
- `Super+P` — power menu
|
||||||
- `Super+Shift+N` — toggle do not disturb
|
- `Super+Shift+N` — toggle do not disturb
|
||||||
|
- `Super+Shift+I` — stay awake (no dim, lock or screen-off until toggled back)
|
||||||
- `Super+Ctrl+Shift+N` — clear notifications
|
- `Super+Ctrl+Shift+N` — clear notifications
|
||||||
- `Super+A` — ask panel
|
- `Super+A` — ask panel
|
||||||
- `Super+Shift+R` — reload the shell
|
- `Super+Shift+R` — reload the shell
|
||||||
@@ -153,6 +155,8 @@ All of these go through Quickshell's IPC, so they work from any script:
|
|||||||
qs ipc call shell lock
|
qs ipc call shell lock
|
||||||
qs ipc call shell power
|
qs ipc call shell power
|
||||||
qs ipc call shell toggleDnd
|
qs ipc call shell toggleDnd
|
||||||
|
qs ipc call shell toggleStayAwake
|
||||||
|
qs ipc call shell wallpaper ~/.wallpapers/space-1.jpg
|
||||||
qs ipc call shell ask
|
qs ipc call shell ask
|
||||||
qs ipc call shell askAbout "why is the sky blue"
|
qs ipc call shell askAbout "why is the sky blue"
|
||||||
qs ipc call shell clearNotifications
|
qs ipc call shell clearNotifications
|
||||||
@@ -211,6 +215,34 @@ NetworkManager for Wi-Fi, UPower for battery, MPRIS for media, and Quickshell's
|
|||||||
own notification server. These are event-driven, so the bar and OSD react the
|
own notification server. These are event-driven, so the bar and OSD react the
|
||||||
instant a volume key is pressed instead of on the next poll.
|
instant a volume key is pressed instead of on the next poll.
|
||||||
|
|
||||||
|
## Wallpaper
|
||||||
|
|
||||||
|
`backdrop/Backdrop.qml` draws it on the background layer; there is no
|
||||||
|
hyprpaper. The picture is drawn 8% larger than the screen and drifts with the
|
||||||
|
workspace: 1 sits at the top of it and each step down moves it a fixed
|
||||||
|
distance, a little slower than Hyprland's own slide, so the windows arrive
|
||||||
|
first and the scene behind catches up. It never moves on its own, so an idle
|
||||||
|
desktop costs the compositor nothing. While the workspace holds windows it
|
||||||
|
settles a shade darker.
|
||||||
|
|
||||||
|
The choice is one line in `quickshell/wallpaper` (`~` allowed), watched live.
|
||||||
|
`qs ipc call shell wallpaper <path>` rewrites it.
|
||||||
|
|
||||||
|
## Idle
|
||||||
|
|
||||||
|
`services/Idle.qml`, on Wayland's idle-notify protocol instead of hypridle:
|
||||||
|
|
||||||
|
| After | Does |
|
||||||
|
|---|---|
|
||||||
|
| 4 min | the screen dims slowly (`overlays/IdleDim.qml`); any input lifts it |
|
||||||
|
| 5 min | lock |
|
||||||
|
| 6 min | displays off; any input wakes them |
|
||||||
|
| 15 min | suspend, on battery only |
|
||||||
|
|
||||||
|
Every stage respects idle inhibitors, so a fullscreen video holds them all
|
||||||
|
off. `Super+Shift+I` does the same by hand and puts a cup on the rail while it
|
||||||
|
is on.
|
||||||
|
|
||||||
## Lock screen
|
## Lock screen
|
||||||
|
|
||||||
Authenticates through `/etc/pam.d/hyprlock`, which on this box is just
|
Authenticates through `/etc/pam.d/hyprlock`, which on this box is just
|
||||||
@@ -219,7 +251,8 @@ styled in an ordinary window (`qs -p lockpreview.qml`) without locking the
|
|||||||
session.
|
session.
|
||||||
|
|
||||||
It is the wallpaper, barely softened, with the face set in the dark of the
|
It is the wallpaper, barely softened, with the face set in the dark of the
|
||||||
porthole: the mark, the time in light display type, the date, a status log
|
porthole: the mark, the time in light display type, the date, "Take your
|
||||||
|
time.", a status log
|
||||||
(battery, network, what is playing, unread notices), and a rounded field that
|
(battery, network, what is playing, unread notices), and a rounded field that
|
||||||
fills with dots as you type. The dots breathe while PAM checks; a wrong
|
fills with dots as you type. The dots breathe while PAM checks; a wrong
|
||||||
password turns them and the field's rim to rust and nudges the field once.
|
password turns them and the field's rim to rust and nudges the field once.
|
||||||
@@ -231,6 +264,9 @@ means restarting Hyprland from a TTY.
|
|||||||
## What was retired
|
## What was retired
|
||||||
|
|
||||||
- `waybar.service` — disabled. Its config is still in `~/.config/waybar`.
|
- `waybar.service` — disabled. Its config is still in `~/.config/waybar`.
|
||||||
|
- `hyprpaper` — replaced by `backdrop/`. Turn its unit off with
|
||||||
|
`systemctl --user disable --now hyprpaper`.
|
||||||
|
- `hypridle` — never installed; `services/Idle.qml` does the job.
|
||||||
- `dunst.service` — masked, so it cannot be D-Bus activated and steal
|
- `dunst.service` — masked, so it cannot be D-Bus activated and steal
|
||||||
`org.freedesktop.Notifications`. Undo with
|
`org.freedesktop.Notifications`. Undo with
|
||||||
`systemctl --user unmask dunst.service`.
|
`systemctl --user unmask dunst.service`.
|
||||||
@@ -311,8 +347,9 @@ network and bluetooth, but keep running as the secret and pairing agents.
|
|||||||
the opening's 18px corners at a 10px gap (`Theme.frameRadius - gaps_out`);
|
the opening's 18px corners at a 10px gap (`Theme.frameRadius - gaps_out`);
|
||||||
change one and the others follow. No blur, both opacities at `1.0`, 1px
|
change one and the others follow. No blur, both opacities at `1.0`, 1px
|
||||||
borders running from the light into the suit's grey. The shadow is soft and
|
borders running from the light into the suit's grey. The shadow is soft and
|
||||||
wide, so windows float in the opening. Group tabs are solid hull slabs, the
|
wide, so windows float in the opening. Group tabs are thin rounded lines with
|
||||||
current one lifted a step with its title in the light. Motion
|
no titles, the current one in the light; the bar writes the title once and
|
||||||
|
adds the window's place in the group (`2/3`). Motion
|
||||||
(`hypr/lua/animations.lua`) glides and settles with no overshoot: windows
|
(`hypr/lua/animations.lua`) glides and settles with no overshoot: windows
|
||||||
resolve in from a hair smaller, workspaces drift a short way vertically and
|
resolve in from a hair smaller, workspaces drift a short way vertically and
|
||||||
fade (sliding behind the hull), the `SUPER+S` scratchpad lowers out from
|
fade (sliding behind the hull), the `SUPER+S` scratchpad lowers out from
|
||||||
@@ -335,7 +372,8 @@ network and bluetooth, but keep running as the secret and pairing agents.
|
|||||||
The theme name is also in `xsettingsd/xsettingsd.conf` and has to be set with
|
The theme name is also in `xsettingsd/xsettingsd.conf` and has to be set with
|
||||||
`gsettings` for portal-aware apps.
|
`gsettings` for portal-aware apps.
|
||||||
- **Qt** — qt6ct with `qt6ct/colors/yorha.conf`, the same palette in
|
- **Qt** — qt6ct with `qt6ct/colors/yorha.conf`, the same palette in
|
||||||
`QPalette` roles. The style is Fusion unless Darkly is installed.
|
`QPalette` roles, drawn with the Darkly style (package `darkly-bin`) for
|
||||||
|
rounded controls. Fusion is the fallback if Darkly is missing.
|
||||||
- **zathura** — `zathura/yorha`, included from `zathurarc`. Pages are
|
- **zathura** — `zathura/yorha`, included from `zathurarc`. Pages are
|
||||||
recoloured onto the hull with text in bone; images keep their colours.
|
recoloured onto the hull with text in bone; images keep their colours.
|
||||||
Search hits are a soft bone wash, and the current hit is sand.
|
Search hits are a soft bone wash, and the current hit is sand.
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import "root:/config"
|
||||||
|
import "root:/services"
|
||||||
|
|
||||||
|
// The wallpaper, seen through the porthole. It is drawn a little larger than
|
||||||
|
// the screen and drifts when the workspace changes: windows slide past
|
||||||
|
// vertically (hypr/lua/animations.lua) and the scene behind them moves a few
|
||||||
|
// pixels the same way and a little later, the way distant things do out of a
|
||||||
|
// moving window. Only on switches — it never moves on its own, so an idle
|
||||||
|
// desktop costs the compositor nothing.
|
||||||
|
//
|
||||||
|
// It also settles a shade darker while the workspace holds windows, so the
|
||||||
|
// band of wallpaper round them reads as the far side of the glass rather than
|
||||||
|
// as part of the desktop.
|
||||||
|
PanelWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
screen: modelData
|
||||||
|
|
||||||
|
WlrLayershell.layer: WlrLayer.Background
|
||||||
|
WlrLayershell.namespace: "takemi-backdrop"
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||||
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
anchors { top: true; bottom: true; left: true; right: true }
|
||||||
|
color: Theme.ink
|
||||||
|
mask: Region {}
|
||||||
|
|
||||||
|
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
|
||||||
|
readonly property HyprlandWorkspace workspace: root.monitor?.activeWorkspace ?? null
|
||||||
|
|
||||||
|
// Overscan: how much bigger than the screen the picture is drawn, which is
|
||||||
|
// the room it has to drift in.
|
||||||
|
readonly property real overscan: 1.08
|
||||||
|
readonly property real slack: root.height * (root.overscan - 1)
|
||||||
|
|
||||||
|
// Workspaces 1–10 spread across the slack, so 1 sits at the top of the
|
||||||
|
// picture and each step down moves it a fixed distance. Special and
|
||||||
|
// named workspaces (negative ids) leave it where it was.
|
||||||
|
property real drift: 0
|
||||||
|
readonly property int wsId: root.workspace?.id ?? 1
|
||||||
|
onWsIdChanged: if (root.wsId > 0) root.drift = Math.min(root.wsId - 1, 9) / 9
|
||||||
|
|
||||||
|
readonly property bool occupied: (root.workspace?.toplevels?.values?.length ?? 0) > 0
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: picture
|
||||||
|
width: root.width * root.overscan
|
||||||
|
height: root.height * root.overscan
|
||||||
|
x: -(width - root.width) / 2
|
||||||
|
y: -root.drift * root.slack
|
||||||
|
source: Wallpaper.forMonitor(root.screen?.name ?? "")
|
||||||
|
sourceSize: Qt.size(width, height)
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
asynchronous: true
|
||||||
|
smooth: true
|
||||||
|
cache: false
|
||||||
|
|
||||||
|
opacity: status === Image.Ready ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: Theme.durLazy; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Longer than Hyprland's 550ms workspace slide, on the same curve, so
|
||||||
|
// the windows arrive first and the scene catches up.
|
||||||
|
Behavior on y {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 900
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: [0.35, 0.0, 0.15, 1.0, 1.0, 1.0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Theme.ink
|
||||||
|
opacity: root.occupied ? 0.18 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: Theme.durLazy; easing.type: Easing.InOutSine }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: root.drift = Math.min(Math.max(root.wsId, 1) - 1, 9) / 9
|
||||||
|
}
|
||||||
@@ -20,6 +20,31 @@ Item {
|
|||||||
|| toplevel.monitor.id === root.monitor.id)
|
|| toplevel.monitor.id === root.monitor.id)
|
||||||
|
|
||||||
readonly property string incomingTitle: mine && toplevel.title ? toplevel.title : "—"
|
readonly property string incomingTitle: mine && toplevel.title ? toplevel.title : "—"
|
||||||
|
|
||||||
|
// Where the focused window sits in its group, as "2/3", or "" when it is
|
||||||
|
// not grouped. Hyprland's group bar draws only indicator lines (see
|
||||||
|
// hypr/lua/look.lua), so the bar is the one place the title is written.
|
||||||
|
readonly property string groupLabel: {
|
||||||
|
const ipc = root.mine ? root.toplevel.lastIpcObject : null;
|
||||||
|
const members = ipc?.grouped ?? [];
|
||||||
|
if (members.length < 2) return "";
|
||||||
|
const bare = a => String(a).replace(/^0x/, "");
|
||||||
|
const at = members.findIndex(m => bare(m) === bare(root.toplevel.address));
|
||||||
|
return (at < 0 ? "?" : at + 1) + "/" + members.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lastIpcObject is a snapshot, refreshed only on request. Ask again
|
||||||
|
// whenever focus or group membership may have changed.
|
||||||
|
Connections {
|
||||||
|
target: Hyprland
|
||||||
|
function onRawEvent(event) {
|
||||||
|
const n = event.name;
|
||||||
|
if (n === "activewindowv2" || n === "togglegroup"
|
||||||
|
|| n === "moveintogroup" || n === "moveoutofgroup"
|
||||||
|
|| n === "closewindow" || n === "openwindow")
|
||||||
|
Hyprland.refreshToplevels();
|
||||||
|
}
|
||||||
|
}
|
||||||
property string displayedTitle: "—"
|
property string displayedTitle: "—"
|
||||||
|
|
||||||
// Which toplevel the landing transition last played for. The landing is a
|
// Which toplevel the landing transition last played for. The landing is a
|
||||||
@@ -30,7 +55,8 @@ Item {
|
|||||||
// The bar shrinks this when the three clusters would otherwise collide.
|
// The bar shrinks this when the three clusters would otherwise collide.
|
||||||
property real maxWidth: 240
|
property real maxWidth: 240
|
||||||
|
|
||||||
implicitWidth: Math.min(maxWidth, Math.max(70, label.implicitWidth + 4))
|
implicitWidth: Math.min(maxWidth,
|
||||||
|
Math.max(70, label.implicitWidth + 4 + (groupTag.visible ? groupTag.width + Theme.padS : 0)))
|
||||||
implicitHeight: 20
|
implicitHeight: 20
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
Behavior on implicitWidth {
|
||||||
@@ -45,7 +71,7 @@ Item {
|
|||||||
Text {
|
Text {
|
||||||
id: label
|
id: label
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: parent.width
|
width: parent.width - (groupTag.visible ? groupTag.width + Theme.padS : 0)
|
||||||
text: root.displayedTitle
|
text: root.displayedTitle
|
||||||
color: root.mine ? Theme.subtext : Theme.muted
|
color: root.mine ? Theme.subtext : Theme.muted
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
@@ -61,7 +87,7 @@ Item {
|
|||||||
Text {
|
Text {
|
||||||
id: ghost
|
id: ghost
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: parent.width
|
width: label.width
|
||||||
text: root.displayedTitle
|
text: root.displayedTitle
|
||||||
color: Theme.accent
|
color: Theme.accent
|
||||||
opacity: 0
|
opacity: 0
|
||||||
@@ -69,6 +95,18 @@ Item {
|
|||||||
font: label.font
|
font: label.font
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: groupTag
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: root.groupLabel !== ""
|
||||||
|
text: root.groupLabel
|
||||||
|
color: Theme.muted
|
||||||
|
font.family: Theme.fontMono
|
||||||
|
font.pixelSize: Theme.fsMicro
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adopt the settled caption, and stamp it only when focus actually moved.
|
// Adopt the settled caption, and stamp it only when focus actually moved.
|
||||||
|
|||||||
@@ -137,6 +137,19 @@ PanelWindow {
|
|||||||
|
|
||||||
Divider { visible: tray.visible }
|
Divider { visible: tray.visible }
|
||||||
|
|
||||||
|
// Only there while the idle chain is held off by hand, so it is
|
||||||
|
// obvious why the screen never locked.
|
||||||
|
RailIcon {
|
||||||
|
id: awakeIcon
|
||||||
|
visible: Idle.stayAwake
|
||||||
|
icon: ""
|
||||||
|
label: "Stay awake"
|
||||||
|
statusText: "Screen will not dim or lock"
|
||||||
|
hint: "Click to allow sleep"
|
||||||
|
live: true
|
||||||
|
onClicked: Idle.toggleStayAwake()
|
||||||
|
}
|
||||||
|
|
||||||
RailIcon {
|
RailIcon {
|
||||||
id: bellIcon
|
id: bellIcon
|
||||||
icon: Notifs.icon
|
icon: Notifs.icon
|
||||||
|
|||||||
@@ -131,6 +131,18 @@ Item {
|
|||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The one line the face says to you. Nothing here is in a hurry.
|
||||||
|
Text {
|
||||||
|
topPadding: Math.round(Theme.padL * surface.uiScale)
|
||||||
|
leftPadding: Math.round(4 * surface.uiScale)
|
||||||
|
text: "Take your time."
|
||||||
|
color: Theme.subtext
|
||||||
|
font.family: Theme.fontDisplay
|
||||||
|
font.pixelSize: Math.round(Theme.fsLarge * surface.uiScale)
|
||||||
|
font.weight: Font.Light
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
}
|
||||||
|
|
||||||
Item { width: 1; height: Math.round(Theme.padXL * surface.uiScale) }
|
Item { width: 1; height: Math.round(Theme.padXL * surface.uiScale) }
|
||||||
|
|
||||||
// ------------------------------------------------------ status log
|
// ------------------------------------------------------ status log
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import "root:/config"
|
||||||
|
import "root:/services"
|
||||||
|
|
||||||
|
// The first stage of idle (services/Idle.qml): the screen dims the way a room
|
||||||
|
// does when the lights go down, slowly enough that you notice it before the
|
||||||
|
// lock does. Any input lifts it at once. Input passes straight through.
|
||||||
|
PanelWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
screen: modelData
|
||||||
|
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.namespace: "takemi-dim"
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||||
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
anchors { top: true; bottom: true; left: true; right: true }
|
||||||
|
color: "transparent"
|
||||||
|
mask: Region {}
|
||||||
|
|
||||||
|
visible: Idle.dimmed || shade.opacity > 0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: shade
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Theme.ink
|
||||||
|
opacity: Idle.dimmed ? 0.6 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Idle.dimmed ? 8000 : Theme.durBase
|
||||||
|
easing.type: Idle.dimmed ? Easing.InOutSine : Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,19 +100,19 @@ PanelWindow {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
topPadding: Theme.padM
|
topPadding: Theme.padM
|
||||||
text: "GLORY TO MANKIND."
|
text: "Take your time."
|
||||||
color: Theme.accent
|
color: Theme.accent
|
||||||
font.family: Theme.fontDisplay
|
font.family: Theme.fontDisplay
|
||||||
font.pixelSize: Theme.fsHuge
|
font.pixelSize: Theme.fsHuge
|
||||||
font.weight: Font.Light
|
font.weight: Font.Light
|
||||||
font.letterSpacing: 6
|
font.letterSpacing: 1
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
topPadding: Theme.padS
|
topPadding: Theme.padS
|
||||||
leftPadding: 2
|
leftPadding: 2
|
||||||
text: ["YORHA", (Quickshell.env("USER") || "user") + "@" + hostFile.text().trim(),
|
text: [(Quickshell.env("USER") || "user") + "@" + hostFile.text().trim(),
|
||||||
Sys.uptime ? "UP " + Sys.uptime : ""].filter(t => t !== "").join(" · ")
|
Sys.uptime ? "UP " + Sys.uptime : ""].filter(t => t !== "").join(" · ")
|
||||||
color: Theme.muted
|
color: Theme.muted
|
||||||
font.family: Theme.fontMono
|
font.family: Theme.fontMono
|
||||||
|
|||||||
@@ -163,5 +163,7 @@ Singleton {
|
|||||||
function reloadConfig(): void { root.reloadShell(); }
|
function reloadConfig(): void { root.reloadShell(); }
|
||||||
function toggleDnd(): void { Notifs.toggleDnd(); }
|
function toggleDnd(): void { Notifs.toggleDnd(); }
|
||||||
function clearNotifications(): void { Notifs.clearAll(); }
|
function clearNotifications(): void { Notifs.clearAll(); }
|
||||||
|
function toggleStayAwake(): void { Idle.toggleStayAwake(); }
|
||||||
|
function wallpaper(path: string): void { Wallpaper.set(path); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import "root:/services"
|
||||||
|
|
||||||
|
// What happens when nobody is at the machine. There is no hypridle: the shell
|
||||||
|
// already owns the lock screen, so it owns the clock that leads up to it.
|
||||||
|
//
|
||||||
|
// dim the screen slowly darkens, so the lock does not arrive unannounced
|
||||||
|
// lock the session lock (lock/Lock.qml)
|
||||||
|
// off the displays power down; any input wakes them
|
||||||
|
// suspend only on battery, and only after a long while
|
||||||
|
//
|
||||||
|
// Every stage respects idle inhibitors, so a fullscreen video or a call that
|
||||||
|
// asks the compositor to stay awake holds all of them off. `stayAwake` is the
|
||||||
|
// same thing by hand (`qs ipc call shell toggleStayAwake`).
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// Seconds of no input before each stage.
|
||||||
|
readonly property int dimAfter: 240
|
||||||
|
readonly property int lockAfter: 300
|
||||||
|
readonly property int offAfter: 360
|
||||||
|
readonly property int suspendAfter: 900
|
||||||
|
|
||||||
|
property bool stayAwake: false
|
||||||
|
|
||||||
|
readonly property bool dimmed: dimMon.isIdle && !Actions.lockRequested
|
||||||
|
|
||||||
|
function toggleStayAwake() { root.stayAwake = !root.stayAwake; }
|
||||||
|
|
||||||
|
IdleMonitor {
|
||||||
|
id: dimMon
|
||||||
|
enabled: !root.stayAwake
|
||||||
|
respectInhibitors: true
|
||||||
|
timeout: root.dimAfter
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleMonitor {
|
||||||
|
id: lockMon
|
||||||
|
enabled: !root.stayAwake
|
||||||
|
respectInhibitors: true
|
||||||
|
timeout: root.lockAfter
|
||||||
|
onIsIdleChanged: if (isIdle) Actions.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleMonitor {
|
||||||
|
id: offMon
|
||||||
|
enabled: !root.stayAwake
|
||||||
|
respectInhibitors: true
|
||||||
|
timeout: root.offAfter
|
||||||
|
// Input ends the idle period, so the displays come back on the same
|
||||||
|
// event that would have woken them anyway.
|
||||||
|
onIsIdleChanged: Hyprland.dispatch(
|
||||||
|
"hl.dsp.dpms({ action = \"" + (isIdle ? "off" : "on") + "\" })")
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleMonitor {
|
||||||
|
id: suspendMon
|
||||||
|
enabled: !root.stayAwake && Battery.onBattery
|
||||||
|
respectInhibitors: true
|
||||||
|
timeout: root.suspendAfter
|
||||||
|
onIsIdleChanged: if (isIdle) Actions.suspend()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,9 @@ Singleton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string preferredId: ""
|
property string preferredId: ""
|
||||||
|
// The player that was playing most recently, so pausing it keeps it in
|
||||||
|
// the bar instead of handing the slot to whichever player is listed first.
|
||||||
|
property string lastPlayingId: ""
|
||||||
|
|
||||||
readonly property var players: Mpris.players?.values ?? []
|
readonly property var players: Mpris.players?.values ?? []
|
||||||
readonly property bool hasPlayer: active !== null
|
readonly property bool hasPlayer: active !== null
|
||||||
@@ -22,9 +25,23 @@ Singleton {
|
|||||||
for (const p of players) if (p.dbusName === root.preferredId) return p;
|
for (const p of players) if (p.dbusName === root.preferredId) return p;
|
||||||
}
|
}
|
||||||
for (const p of players) if (p.isPlaying) return p;
|
for (const p of players) if (p.isPlaying) return p;
|
||||||
|
if (root.lastPlayingId !== "") {
|
||||||
|
for (const p of players) if (p.dbusName === root.lastPlayingId) return p;
|
||||||
|
}
|
||||||
|
// Browsers register a player for every tab with a media element, most
|
||||||
|
// of them with no track at all. Prefer one that has something to show.
|
||||||
|
for (const p of players) if (p.trackTitle) return p;
|
||||||
return players[0];
|
return players[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remember whichever player was playing last. Bound through the active
|
||||||
|
// player, so it updates whenever playback starts anywhere.
|
||||||
|
readonly property string playingId: {
|
||||||
|
for (const p of players) if (p.isPlaying) return p.dbusName;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
onPlayingIdChanged: if (root.playingId !== "") root.lastPlayingId = root.playingId
|
||||||
|
|
||||||
readonly property string title: active?.trackTitle || ""
|
readonly property string title: active?.trackTitle || ""
|
||||||
readonly property string artist: active?.trackArtist || ""
|
readonly property string artist: active?.trackArtist || ""
|
||||||
readonly property string album: active?.trackAlbum || ""
|
readonly property string album: active?.trackAlbum || ""
|
||||||
|
|||||||
@@ -5,24 +5,17 @@ import Quickshell
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import "root:/config"
|
import "root:/config"
|
||||||
|
|
||||||
// The wallpaper currently on screen, per monitor.
|
// The wallpaper, owned by the shell. backdrop/Backdrop.qml draws it and the lock
|
||||||
|
// screen fades in from the same picture, so there is one answer to "what is
|
||||||
|
// on screen" and nothing to ask a separate daemon (this used to poll
|
||||||
|
// hyprpaper every ten seconds).
|
||||||
//
|
//
|
||||||
// The lock screen used to point at a hardcoded path in Theme.qml, which meant
|
// The choice lives in ~/.config/quickshell/wallpaper — one line, a path, `~`
|
||||||
// it showed whatever picture was correct on the day that line was written —
|
// allowed — so it survives restarts and can be edited by hand. Change it live
|
||||||
// takemi_2 while hyprpaper had been switched to takemi_1. Anything that puts
|
// with `qs ipc call shell wallpaper ~/.wallpapers/other.jpg`.
|
||||||
// the wallpaper on screen should ask hyprpaper what it is actually displaying,
|
|
||||||
// which is what this does.
|
|
||||||
//
|
|
||||||
// hyprpaper is the source of truth at runtime; hyprpaper.conf is the fallback
|
|
||||||
// for the window between the shell starting and hyprpaper answering, and for
|
|
||||||
// the case where hyprpaper is not running at all.
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// monitor name -> file path. Monitors hyprpaper set with a blank `monitor =`
|
|
||||||
// come back under the empty-string key.
|
|
||||||
property var byMonitor: ({})
|
|
||||||
|
|
||||||
// The wallpaper to use when no particular monitor is being asked about.
|
// The wallpaper to use when no particular monitor is being asked about.
|
||||||
property string path: ""
|
property string path: ""
|
||||||
|
|
||||||
@@ -30,18 +23,19 @@ Singleton {
|
|||||||
? Qt.resolvedUrl("file://" + root.path)
|
? Qt.resolvedUrl("file://" + root.path)
|
||||||
: Theme.fallbackWallpaper
|
: Theme.fallbackWallpaper
|
||||||
|
|
||||||
// Path set from hyprpaper.conf, used until (and unless) hyprctl answers.
|
|
||||||
property string configPath: ""
|
|
||||||
|
|
||||||
signal changed()
|
signal changed()
|
||||||
|
|
||||||
|
// Every monitor shows the same picture. Kept as a per-monitor lookup so
|
||||||
|
// callers do not have to change if that stops being true.
|
||||||
function forMonitor(name: string): url {
|
function forMonitor(name: string): url {
|
||||||
const p = root.byMonitor[name];
|
return root.source;
|
||||||
return p ? Qt.resolvedUrl("file://" + p) : root.source;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function refresh() {
|
function set(p: string) {
|
||||||
reader.running = true;
|
const next = root._expand(p);
|
||||||
|
if (next === "") return;
|
||||||
|
store.setText("# The wallpaper the shell draws (services/Wallpaper.qml). One path; ~ allowed.\n"
|
||||||
|
+ next + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
function _expand(p: string): string {
|
function _expand(p: string): string {
|
||||||
@@ -50,71 +44,19 @@ Singleton {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _adopt(map: var, fallback: string) {
|
FileView {
|
||||||
root.byMonitor = map;
|
id: store
|
||||||
|
path: Quickshell.env("HOME") + "/.config/quickshell/wallpaper"
|
||||||
// Prefer the focused monitor's wallpaper, then any monitor's, then the
|
watchChanges: true
|
||||||
// config. Object.values order is insertion order here, which is the
|
printErrors: false
|
||||||
// order hyprpaper listed them in.
|
onFileChanged: reload()
|
||||||
const vals = Object.keys(map).map(k => map[k]).filter(v => v !== "");
|
onLoaded: {
|
||||||
const next = vals.length > 0 ? vals[0] : fallback;
|
const line = text().split("\n").map(l => l.trim()).find(l => l !== "" && !l.startsWith("#"));
|
||||||
|
const next = line ? root._expand(line) : "";
|
||||||
if (next !== root.path) {
|
if (next !== root.path) {
|
||||||
root.path = next;
|
root.path = next;
|
||||||
root.changed();
|
root.changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
|
||||||
id: reader
|
|
||||||
command: ["hyprctl", "hyprpaper", "listactive"]
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
const map = {};
|
|
||||||
for (const line of text.split("\n")) {
|
|
||||||
// "eDP-1: /home/narl/.wallpapers/takemi_1.jpg". Split on the
|
|
||||||
// first colon only — the path may contain one.
|
|
||||||
const at = line.indexOf(":");
|
|
||||||
if (at === -1) continue;
|
|
||||||
const mon = line.slice(0, at).trim();
|
|
||||||
const file = line.slice(at + 1).trim();
|
|
||||||
if (file === "" || file.startsWith("invalid")) continue;
|
|
||||||
map[mon] = file;
|
|
||||||
}
|
|
||||||
root._adopt(map, root.configPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hyprpaper down, or hyprctl missing. Fall back to the config file.
|
|
||||||
onExited: code => {
|
|
||||||
if (code !== 0 && root.path === "") root._adopt({}, root.configPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hyprpaper has no change signal to subscribe to, so poll — but slowly. A
|
|
||||||
// wallpaper changes when a person decides to change it, not continuously.
|
|
||||||
Timer {
|
|
||||||
interval: 10000
|
|
||||||
running: true
|
|
||||||
repeat: true
|
|
||||||
triggeredOnStart: true
|
|
||||||
onTriggered: root.refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Editing the config is the other way the wallpaper changes here, and that
|
|
||||||
// one we can watch properly.
|
|
||||||
FileView {
|
|
||||||
id: conf
|
|
||||||
path: Quickshell.env("HOME") + "/.config/hypr/hyprpaper.conf"
|
|
||||||
watchChanges: true
|
|
||||||
onFileChanged: reload()
|
|
||||||
onLoaded: {
|
|
||||||
const m = /^\s*path\s*=\s*(.+)$/m.exec(text());
|
|
||||||
if (m) root.configPath = root._expand(m[1]);
|
|
||||||
// A config edit is usually followed by a hyprpaper reload, so go
|
|
||||||
// ask what actually took effect rather than trusting the file.
|
|
||||||
root.refresh();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ import QtQuick
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import "root:/config"
|
import "root:/config"
|
||||||
import "root:/services"
|
import "root:/services"
|
||||||
|
import "root:/backdrop"
|
||||||
import "root:/bar"
|
import "root:/bar"
|
||||||
import "root:/launcher"
|
import "root:/launcher"
|
||||||
import "root:/dashboard"
|
import "root:/dashboard"
|
||||||
@@ -12,6 +13,7 @@ import "root:/lock"
|
|||||||
// Takemi — a YoRHa-dark Quickshell desktop: NieR:Automata's interface
|
// Takemi — a YoRHa-dark Quickshell desktop: NieR:Automata's interface
|
||||||
// language, lit like the wallpaper.
|
// language, lit like the wallpaper.
|
||||||
//
|
//
|
||||||
|
// backdrop/ the wallpaper, drifting with the workspace
|
||||||
// bar/ the hull, the top bar, the rail and their modules
|
// bar/ the hull, the top bar, the rail and their modules
|
||||||
// popouts/ hover panels hanging off bar modules
|
// popouts/ hover panels hanging off bar modules
|
||||||
// launcher/ the application launcher
|
// launcher/ the application launcher
|
||||||
@@ -36,6 +38,14 @@ ShellRoot {
|
|||||||
void Bt.available;
|
void Bt.available;
|
||||||
void Actions.powerMenuOpen;
|
void Actions.powerMenuOpen;
|
||||||
void Apps.index;
|
void Apps.index;
|
||||||
|
void Idle.stayAwake;
|
||||||
|
void Wallpaper.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
Backdrop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Variants {
|
Variants {
|
||||||
@@ -92,5 +102,11 @@ ShellRoot {
|
|||||||
Osd {}
|
Osd {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
IdleDim {}
|
||||||
|
}
|
||||||
|
|
||||||
Lock {}
|
Lock {}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# The wallpaper the shell draws (services/Wallpaper.qml). One path; ~ allowed.
|
||||||
|
~/.wallpapers/space-1.jpg
|
||||||
Reference in new issue
Block a user