fix workspace clicks and the island stuck after a hidden start

- workspace pill: clicks did nothing. amane's Workspaces::focus sends
  'dispatch workspace N', which hyprland 0.56 with a lua config turns into
  hl.dispatch(workspace N) and rejects. dispatch the lua form the user's
  keybinds use, hl.dsp.focus({ workspace = N }), through hyprctl on its own
  thread (named workspaces with negative ids are left out)
- island: 'magic-island has no child to draw' at startup without a player,
  and the island then never appeared. hyprland 0.56 configures a layer
  surface before its first commit (seen with WAYLAND_DEBUG), so a window
  that starts visible(false) gets a size, amane runs the empty view, logs,
  and waits for frame callbacks an undrawn surface never gets. with no
  player the island is now an empty click-through window instead
- verified on the desktop: 0 'no child' lines, island draws at startup and
  shows on all 4 monitors when a player starts
This commit is contained in:
server2
2026-10-08 11:38:16 +02:00
parent c749ca9d9d
commit 66bf25f7dd
2 changed files with 30 additions and 3 deletions
+8 -1
View File
@@ -267,8 +267,15 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
.space(Zone::Ignore) .space(Zone::Ignore)
.namespace("magic-island"); .namespace("magic-island");
/*
* no player: an empty window that lets every click through, never visible(false).
* hyprland 0.56 configures a layer surface before its first commit, so a window
* that starts hidden gets a size anyway: amane then logs "no child to draw" and,
* with nothing ever drawn, waits for frame callbacks that never come, and the
* island never showed up once a player started
*/
let Some(player) = shown(&media, island.selected.as_deref()) else { let Some(player) = shown(&media, island.selected.as_deref()) else {
return window.visible(false); return window.click_through().child(Rectangle::new().width(0.0).height(0.0));
}; };
let (grow, pill, reveal) = phases(if opened_here { island.open.value() } else { 0.0 }); let (grow, pill, reveal) = phases(if opened_here { island.open.value() } else { 0.0 });
+22 -2
View File
@@ -1,4 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::process::Command;
use std::thread;
use std::time::Duration; use std::time::Duration;
use amane::{ use amane::{
@@ -59,8 +61,9 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
.space(Zone::Ignore) .space(Zone::Ignore)
.namespace("magic-workspaces"); .namespace("magic-workspaces");
// empty and click-through rather than hidden: see the island's view for why
if here.is_empty() { if here.is_empty() {
return window.visible(false); return window.click_through().child(Rectangle::new().width(0.0).height(0.0));
} }
let mut slots: Vec<Box<dyn Widget>> = Vec::new(); let mut slots: Vec<Box<dyn Widget>> = Vec::new();
@@ -95,7 +98,7 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
.scale(1.0 + 0.08 * lit) .scale(1.0 + 0.08 * lit)
.cursor(Pointer) .cursor(Pointer)
.on_hover(move |inside| hovering(id, inside)) .on_hover(move |inside| hovering(id, inside))
.on_click(move |_| Workspaces::focus(id)) .on_click(move |_| focus(id))
.child(Text::new(label).size(12.0).weight(weight).color(color)), .child(Text::new(label).size(12.0).weight(weight).color(color)),
)); ));
} }
@@ -131,6 +134,23 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
) )
} }
/*
* switches to a workspace. amane's Workspaces::focus sends `dispatch workspace N`,
* which hyprland 0.56 with a lua config turns into hl.dispatch(workspace N) and
* rejects; this is the lua form the user's own keybinds use. on its own thread,
* so hyprctl never holds up drawing. named workspaces (negative ids) aren't
* switched: their lua form is unverified
*/
fn focus(id: i64) {
if id < 0 {
return;
}
thread::spawn(move || {
let _ = Command::new("hyprctl").arg("dispatch").arg(format!("hl.dsp.focus({{ workspace = {id} }})")).output();
});
}
/* /*
* one workspace lit at a time: amane matches hover targets by their place in the frame, * one workspace lit at a time: amane matches hover targets by their place in the frame,
* so a workspace that closes under the pointer never hears it leave * so a workspace that closes under the pointer never hears it leave