Reserve the top of every monitor for the bar
edge::spacer: a full-width, empty, click-through Background layer as tall as the pills reach (TOP_GAP + COMPACT_H = 44 px) with Zone::Reserve. Hyprland keeps tiled and maximised windows below it and lets fullscreen windows cover it, so space is reserved exactly where the bar stays. Verified: reserved 0 44 0 0 on all monitors, a tiled window moved from y=636 to 680, a fullscreen one still covers 1920x1080, idle 0 frames.
This commit is contained in:
@@ -15,6 +15,7 @@ A Dynamic-Island-style media widget for Amane (Rust Wayland shell library), runn
|
|||||||
- **System tray:** right of the workspace pill, a pill with every tray app's icon (StatusNotifierItem). Left click activates the app (or opens its menu if that's all it offers), right click opens its menu, drawn in the island's look (checkmarks, separators, submenus with a way back, disabled entries dim), middle click is the app's secondary action, scrolling its scroll. Nothing on this desktop ran a tray watcher, so the shell owns `org.kde.StatusNotifierWatcher` on the session bus and serves it (if another bar already does, the shell shows no tray). Icons come from the app's icon name (its own theme folder, gtk's icon theme, hicolor, AdwaitaLegacy, Adwaita, `/usr/share/pixmaps`) or from the pixels it sends, written as PNGs to `$XDG_RUNTIME_DIR/amane-tray/`. An app that quits takes its icon with it (`src/tray.rs`).
|
- **System tray:** right of the workspace pill, a pill with every tray app's icon (StatusNotifierItem). Left click activates the app (or opens its menu if that's all it offers), right click opens its menu, drawn in the island's look (checkmarks, separators, submenus with a way back, disabled entries dim), middle click is the app's secondary action, scrolling its scroll. Nothing on this desktop ran a tray watcher, so the shell owns `org.kde.StatusNotifierWatcher` on the session bus and serves it (if another bar already does, the shell shows no tray). Icons come from the app's icon name (its own theme folder, gtk's icon theme, hicolor, AdwaitaLegacy, Adwaita, `/usr/share/pixmaps`) or from the pixels it sends, written as PNGs to `$XDG_RUNTIME_DIR/amane-tray/`. An app that quits takes its icon with it (`src/tray.rs`).
|
||||||
- **Control centre:** top right on every monitor, a pill with Ethernet, Wi-Fi (or the hotspot), VPN, Bluetooth and the battery. Click it and it opens, in the island's way, into a panel like macOS's Control Center. See [Control centre](#control-centre).
|
- **Control centre:** top right on every monitor, a pill with Ethernet, Wi-Fi (or the hotspot), VPN, Bluetooth and the battery. Click it and it opens, in the island's way, into a panel like macOS's Control Center. See [Control centre](#control-centre).
|
||||||
- **Out of the way of fullscreen windows:** on a monitor whose workspace shows a fullscreen window (Hyprland fullscreen 2 or 3; only maximised keeps the bar), the island, the workspace pill (with the tray) and the control centre's pill slide out of sight. Resting the pointer on that monitor's top edge for 0.3 s brings them back until it has been off them and the edge for 0.7 s; an open card or panel stays. Everywhere else the bar is always there. Hyprland's event socket says when windows go fullscreen or workspaces change, and its command socket answers `monitors` and `clients`; nothing polls. The edge strip is a one-pixel Overlay layer, there only on fullscreen monitors (it takes their top pixel row). While hidden the bar draws nothing at all, a playing player included (`src/edge.rs`).
|
- **Out of the way of fullscreen windows:** on a monitor whose workspace shows a fullscreen window (Hyprland fullscreen 2 or 3; only maximised keeps the bar), the island, the workspace pill (with the tray) and the control centre's pill slide out of sight. Resting the pointer on that monitor's top edge for 0.3 s brings them back until it has been off them and the edge for 0.7 s; an open card or panel stays. Everywhere else the bar is always there. Hyprland's event socket says when windows go fullscreen or workspaces change, and its command socket answers `monitors` and `clients`; nothing polls. The edge strip is a one-pixel Overlay layer, there only on fullscreen monitors (it takes their top pixel row). While hidden the bar draws nothing at all, a playing player included (`src/edge.rs`).
|
||||||
|
- **Room for the bar:** windows that aren't fullscreen stay below the bar. An empty, click-through strip as tall as the pills reach (44 px) reserves the top of every monitor (a layer-shell exclusive zone, namespace `magic-reserve`); Hyprland keeps tiled and maximised windows out of it, plus `gaps_out`, while fullscreen windows cover it, just where the bar hides. The reservation goes away with the shell. The bar's own windows ignore it, so they stay at the top edge.
|
||||||
- **Peeks:** some events bring one part in for a moment over a fullscreen window: the workspace pill alone (without the tray) for 1.6 s when the workspace changes (with the disc sliding over), the island for 3.5 s when the song changes or a player appears, on the focused monitor. The island also pops (it widens and glows, then lets go) on those events when it's visible anyway. The control centre never peeks.
|
- **Peeks:** some events bring one part in for a moment over a fullscreen window: the workspace pill alone (without the tray) for 1.6 s when the workspace changes (with the disc sliding over), the island for 3.5 s when the song changes or a player appears, on the focused monitor. The island also pops (it widens and glows, then lets go) on those events when it's visible anyway. The control centre never peeks.
|
||||||
|
|
||||||
## Control centre
|
## Control centre
|
||||||
@@ -131,7 +132,7 @@ src/workspaces.rs the workspace pill, top left on every monitor
|
|||||||
src/control.rs the control centre: status pill top right, its panel and menus, `control` IPC
|
src/control.rs the control centre: status pill top right, its panel and menus, `control` IPC
|
||||||
src/map.rs the Wi-Fi and Bluetooth menus' map: this desktop in the middle, what it can connect to around it
|
src/map.rs the Wi-Fi and Bluetooth menus' map: this desktop in the middle, what it can connect to around it
|
||||||
src/prompt.rs the control centre's popup: passwords, PINs, codes, saved passwords, why a connection failed; joins through iwctl, pairs through bluetoothctl
|
src/prompt.rs the control centre's popup: passwords, PINs, codes, saved passwords, why a connection failed; joins through iwctl, pairs through bluetoothctl
|
||||||
src/edge.rs hides the bar over fullscreen windows (Hyprland's sockets), the edge strip, peeks, the workspace slide
|
src/edge.rs hides the bar over fullscreen windows (Hyprland's sockets), the edge strip, peeks, the workspace slide, the space reserved for the bar
|
||||||
src/tray.rs the system tray: StatusNotifierWatcher and host, icon lookup, dbusmenu menus
|
src/tray.rs the system tray: StatusNotifierWatcher and host, icon lookup, dbusmenu menus
|
||||||
src/png.rs a stdlib png writer, for tray icons sent as pixels
|
src/png.rs a stdlib png writer, for tray icons sent as pixels
|
||||||
src/system.rs what the control centre shows: iwd, wired cards, openvpn, power, the external GPU
|
src/system.rs what the control centre shows: iwd, wired cards, openvpn, power, the external GPU
|
||||||
|
|||||||
+19
@@ -410,3 +410,22 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
|
|||||||
|
|
||||||
window.child(Rectangle::new().width(Parent).height(Parent).on_hover(at_edge(monitor.name.clone())))
|
window.child(Rectangle::new().width(Parent).height(Parent).on_hover(at_edge(monitor.name.clone())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* keeps windows out from under the bar: an empty strip as tall as the pills reach,
|
||||||
|
* reserving its height on every monitor. Hyprland lets tiled and maximised windows
|
||||||
|
* respect it and fullscreen ones cover it, which is just when the bar stays and when
|
||||||
|
* it hides; it goes with the shell. the bar's own windows ignore what's reserved, so
|
||||||
|
* they stay at the top edge. reads nothing, so it never redraws
|
||||||
|
*/
|
||||||
|
pub fn spacer(_: &Monitor) -> LayerWindow {
|
||||||
|
LayerWindow::new()
|
||||||
|
.width(Full)
|
||||||
|
.height(TOP_GAP + COMPACT_H)
|
||||||
|
.anchor_vertical(Vertical::Top)
|
||||||
|
.layer(Layer::Background)
|
||||||
|
.space(Zone::Reserve)
|
||||||
|
.namespace("magic-reserve")
|
||||||
|
.click_through()
|
||||||
|
.child(Rectangle::new().width(0.0).height(0.0))
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ fn main() {
|
|||||||
.ipc("island", island::command)
|
.ipc("island", island::command)
|
||||||
.ipc("control", control::command)
|
.ipc("control", control::command)
|
||||||
.ipc("tray", tray::command)
|
.ipc("tray", tray::command)
|
||||||
|
.window_per_monitor(edge::spacer)
|
||||||
.window_per_monitor(edge::view)
|
.window_per_monitor(edge::view)
|
||||||
.window_per_monitor(island::view)
|
.window_per_monitor(island::view)
|
||||||
.window_per_monitor(workspaces::view)
|
.window_per_monitor(workspaces::view)
|
||||||
|
|||||||
Reference in New Issue
Block a user