From bd3d62c11c8047471049b99f5b2ab91e7178667c Mon Sep 17 00:00:00 2001 From: claude Date: Sun, 30 Aug 2026 14:37:55 +0200 Subject: [PATCH] =?UTF-8?q?v0.1.2:=20reservera=20plats=20som=20faktiskt=20?= =?UTF-8?q?reserverar=20+=20kantv=C3=A4nlig=20reveal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Exclusive zone sätts explicit (uppmätt storlek + marginal) — gtk4- layer-shells auto-zon räknar bara för ytor som spänner kanten, och zonen ignoreras per spec för hörn-förankrade ytor. Därför spänner ytan nu alltid kanten när avoid_windows är på (transparenta flanker); ön ritas via panel-alignment och ser ut precis som förut. - Zonen fryses och ligger kvar när docken dodge-göms (fönstret hålls mappat) — maximerade fönster stannar alltid vid docklinjen. - Dodge-djupet använder senaste synliga storlek (ingen flapp). - Reveal via kant-sensorn: docken STANNAR medan pekaren är kvar vid kanten/i dockområdet; göm-fördröjningen börjar först när man lämnar området (sensor_hover räknas som hover). Co-Authored-By: Claude Fable 5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- install.sh | 6 +- src/dock.rs | 166 +++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 131 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ed4b37..c80314a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1042,7 +1042,7 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "waydock" -version = "0.1.1" +version = "0.1.2" dependencies = [ "async-channel", "gtk4", diff --git a/Cargo.toml b/Cargo.toml index bbd3890..bb9fb57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "waydock" -version = "0.1.1" +version = "0.1.2" edition = "2021" description = "Modern, resurssnål dock för Wayfire — transparent, JSON-konfigurerad, per-skärm" license = "MIT" diff --git a/install.sh b/install.sh index 8dbd2df..5b33bd1 100755 --- a/install.sh +++ b/install.sh @@ -13,9 +13,11 @@ command -v gtk4-launch >/dev/null 2>&1 || \ mkdir -p "$DEST" echo "Hämtar waydock (latest)…" -curl -fSL -o "$DEST/waydock" \ +# temp + mv: atomiskt byte som funkar även när waydock kör (ETXTBSY) +curl -fSL -o "$DEST/waydock.new" \ "$BASE/releases/download/latest/waydock-latest-linux-x64" -chmod +x "$DEST/waydock" +chmod +x "$DEST/waydock.new" +mv -f "$DEST/waydock.new" "$DEST/waydock" # ikon + .desktop-fil mkdir -p "$HOME/.local/share/icons/hicolor/scalable/apps" "$HOME/.local/share/applications" diff --git a/src/dock.rs b/src/dock.rs index 3da0ddc..7fb1d35 100644 --- a/src/dock.rs +++ b/src/dock.rs @@ -58,10 +58,15 @@ pub struct Dock { pub connector: String, /// pekaren är över dockan just nu pub hover: Cell, + /// pekaren är på väcknings-sensorn vid kanten + pub sensor_hover: Cell, /// dockan är undan-gömd av autohide pub hidden: Cell, /// något fönster överlappar dockans kantzon (dodge) pub dodge_overlap: Cell, + /// senaste synliga storlek längs huvudaxeln (px) — används för + /// exclusive zone och dodge-djup även när docken är gömd + pub main_size: Cell, /// generationsräknare för fördröjd göm-timer hide_generation: Cell, /// sensorremsan som väcker dockan när den är gömd @@ -113,14 +118,17 @@ fn configure_layer(win: >k::ApplicationWindow, cfg: &Config, monitor: &gdk::Mo let (side_start, side_end) = side_edges(&cfg.position); win.set_anchor(edge, true); win.set_margin(edge, cfg.margin); - if cfg.expand { - // täck hela kanten; start/slut-marginalerna drar in baren + // exclusive zone honoreras bara för ytor som är förankrade i EN kant + // eller spänner kanten (spec + Wayfires tolkning) — så med reservera + // plats spänner ytan alltid kanten; ön ritas ändå som en ö via + // panelens alignment (flankerna är transparenta) + if cfg.expand || cfg.avoid_windows { win.set_anchor(side_start, true); win.set_anchor(side_end, true); - win.set_margin(side_start, cfg.margin_start); - win.set_margin(side_end, cfg.margin_end); + win.set_margin(side_start, cfg.margin_start.max(0)); + win.set_margin(side_end, cfg.margin_end.max(0)); } else { - // ö: förankra bara i vald ände (ingen sidoförankring = centrerad) + // ö utan reservation: förankra bara i vald ände match cfg.alignment { Alignment::Center => {} Alignment::Start => { @@ -133,13 +141,35 @@ fn configure_layer(win: >k::ApplicationWindow, cfg: &Config, monitor: &gdk::Mo } } } - // reservera plats fungerar ihop med autohide: maximerade fönster - // stannar vid dockan (och triggar då aldrig dodge) — bara fönster - // man själv drar in i zonen gömmer den - if cfg.avoid_windows { - win.auto_exclusive_zone_enable(); + // exclusive zone sätts explicit efter map (auto-zonen i + // gtk4-layer-shell fungerar bara för ytor som spänner hela kanten) + win.set_exclusive_zone(0); +} + +/// Reservera plats: zon = dockans uppmätta storlek + marginal. Zonen +/// ligger kvar även när docken är dodge-gömd (fönstret hålls mappat), +/// så maximerade fönster alltid stannar vid docklinjen. +pub fn update_exclusive_zone(ctx: &Rc, dock: &Rc) { + let cfg = ctx.cfg.borrow().for_output(&dock.connector); + if !cfg.avoid_windows { + if !dock.hidden.get() { + dock.window.set_exclusive_zone(0); + } + return; + } + let horizontal = matches!(cfg.position, Position::Bottom | Position::Top); + let size = if horizontal { + dock.window.height() } else { - win.set_exclusive_zone(0); + dock.window.width() + }; + if size > 1 && !dock.hidden.get() { + dock.main_size.set(size); + } + if dock.main_size.get() > 1 { + let zone = dock.main_size.get() + cfg.margin.max(0); + debug!("{}: exclusive zone {}px", dock.connector, zone); + dock.window.set_exclusive_zone(zone); } } @@ -204,9 +234,17 @@ fn build_dock(ctx: &Rc, monitor: &gdk::Monitor, connector: String) -> Rc, monitor: &gdk::Monitor, connector: String) -> Rc, monitor: &gdk::Monitor, connector: String) -> Rc, dock: &Rc, monitor: &gdk::Monitor) { let ctx = ctx.clone(); let dock2 = dock.clone(); motion.connect_enter(move |_, _, _| { + dock2.sensor_hover.set(true); + dock2.hide_generation.set(dock2.hide_generation.get() + 1); if dock2.hidden.get() { - set_dock_hidden(&dock2, false); - // om pekaren aldrig når dockan: göm igen efter en stund - let ctx2 = ctx.clone(); - let dock3 = dock2.clone(); - glib::timeout_add_local_once(Duration::from_millis(1500), move || { - if !dock3.hover.get() { - update_autohide(&ctx2); - } - }); + set_dock_hidden(&ctx, &dock2, false); } }); } + { + let ctx = ctx.clone(); + let dock2 = dock.clone(); + motion.connect_leave(move |_| { + dock2.sensor_hover.set(false); + // göm-fördröjningen börjar först NÄR man lämnar kantområdet + schedule_hide(&ctx, &dock2); + }); + } strip.add_controller(motion); sensor.present(); *dock.sensor.borrow_mut() = Some(sensor); } -fn set_dock_hidden(dock: &Rc, hidden: bool) { +fn set_dock_hidden(ctx: &Ctx, dock: &Rc, hidden: bool) { if dock.hidden.get() == hidden { return; } + let cfg = ctx.cfg.borrow().for_output(&dock.connector); + let horizontal = matches!(cfg.position, Position::Bottom | Position::Top); + // kom ihåg synlig storlek innan vi gömmer + if hidden { + let size = if horizontal { dock.window.height() } else { dock.window.width() }; + if size > 1 { + dock.main_size.set(size); + } + } dock.hidden.set(hidden); if hidden { - let duration = dock.revealer.transition_duration(); dock.revealer.set_reveal_child(false); - let dock2 = dock.clone(); - glib::timeout_add_local_once(Duration::from_millis(duration as u64 + 30), move || { - if dock2.hidden.get() { - dock2.window.set_visible(false); - } - }); + if cfg.avoid_windows { + // reservera plats även gömd: håll fönstret mappat (kollapsat) + // med frusen zon — maximerade fönster stannar vid docklinjen + dock.window + .set_exclusive_zone(dock.main_size.get().max(1) + cfg.margin.max(0)); + } else { + let duration = dock.revealer.transition_duration(); + let dock2 = dock.clone(); + glib::timeout_add_local_once( + Duration::from_millis(duration as u64 + 30), + move || { + if dock2.hidden.get() { + dock2.window.set_visible(false); + } + }, + ); + } } else { dock.window.set_visible(true); dock.revealer.set_reveal_child(true); @@ -399,7 +461,7 @@ fn set_dock_hidden(dock: &Rc, hidden: bool) { fn should_hide(ctx: &Ctx, dock: &Dock) -> bool { let cfg = ctx.cfg.borrow().for_output(&dock.connector); - if !cfg.autohide.enabled || dock.hover.get() { + if !cfg.autohide.enabled || dock.hover.get() || dock.sensor_hover.get() { return false; } match cfg.autohide.mode { @@ -417,7 +479,7 @@ fn should_hide(ctx: &Ctx, dock: &Dock) -> bool { /// Applicera göm/visa-läget på alla dockor. pub fn update_autohide(ctx: &Rc) { for dock in ctx.docks.borrow().iter() { - set_dock_hidden(dock, should_hide(ctx, dock)); + set_dock_hidden(ctx, dock, should_hide(ctx, dock)); } } @@ -429,7 +491,7 @@ fn schedule_hide(ctx: &Rc, dock: &Rc) { let dock = dock.clone(); glib::timeout_add_local_once(Duration::from_millis(delay as u64), move || { if dock.hide_generation.get() == generation && should_hide(&ctx, &dock) { - set_dock_hidden(&dock, true); + set_dock_hidden(&ctx, &dock, true); } }); } @@ -462,11 +524,18 @@ pub fn recompute_dodge(ctx: &Rc) { }; let ow = output["geometry"]["width"].as_f64().unwrap_or(0.0); let oh = output["geometry"]["height"].as_f64().unwrap_or(0.0); - // zonen dockan upptar vid sin kant (fönstrets storlek + marginal) - let depth = match position { - Position::Bottom | Position::Top => dock.window.height().max(40) + margin, - _ => dock.window.width().max(40) + margin, - } as f64; + // zonen dockan upptar vid sin kant: senaste SYNLIGA storlek — + // den kollapsade storleken skulle få hidden/synlig att flappa + if !dock.hidden.get() { + let current = match position { + Position::Bottom | Position::Top => dock.window.height(), + _ => dock.window.width(), + }; + if current > 1 { + dock.main_size.set(current); + } + } + let depth = (dock.main_size.get().max(40) + margin) as f64; let overlap = views.iter().any(|v| { if v["role"].as_str() != Some("toplevel") @@ -579,6 +648,21 @@ pub fn refresh_items(ctx: &Rc) { let widget = build_item_widget(ctx, &dock.connector, Rc::new(item)); dock.items_box.append(&widget); } + let ctx2 = ctx.clone(); + let dock2 = dock.clone(); + // första configure-rundan är asynkron — mät tills storleken finns + let mut attempts = 0; + glib::timeout_add_local(Duration::from_millis(120), move | +| { + attempts += 1; + update_exclusive_zone(&ctx2, &dock2); + let done = dock2.main_size.get() > 1 || attempts > 20; + if done { + glib::ControlFlow::Break + } else { + glib::ControlFlow::Continue + } + }); } }