Fixa omladdningsloopen + churn; CI/släpp flyttat till x64-byggnoden
Some checks failed
check / check (push) Failing after 1m4s
Some checks failed
check / check (push) Failing after 1m4s
- KRITISKT: notify-watchern reagerade på Access-events, så vår egen läsning av configen triggade ny omladdning i all oändlighet (var 155:e ms). Panelen revs och byggdes om konstant → blinkande hover, klick som aldrig landade. Nu filtreras eventen till riktiga skrivningar (Modify/Create/Remove/Close-Write). - Titeländringar (webbläsare/terminaler) bygger inte längre om UI:t; tooltips slås i stället upp färskt vid hover (query-tooltip), och klick/skroll/menyer agerar på färskt fönster-state vid eventtillfället. - hotspots::rebuild är idempotent (skippar om config+skärmar oförändrade). - Settings: markup-escape i rubriker (Kant & skugga-varningen). - CI: check + release körs på byggnoden brasse-linux01 (runs-on linux-amd64) — waydock byggs BARA för x86_64, aldrig på Pi5:ns arm-runner. Ny release.yaml: vX.Y.Z-tagg bygger x64-binären och laddar upp till Gitea-släppsidan + rullande latest. release.sh är nu bara tagga-och-pusha. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
69
src/dock.rs
69
src/dock.rs
@@ -415,6 +415,33 @@ pub fn recompute_dodge(ctx: &Rc<Ctx>) {
|
||||
update_autohide(ctx);
|
||||
}
|
||||
|
||||
/// Färska fönster för en ikon — slås upp vid klick-/tooltip-tillfället så
|
||||
/// att closures aldrig agerar på inaktuellt state.
|
||||
pub fn fresh_windows(ctx: &Ctx, connector: &str, key: &str) -> Vec<ToplevelInfo> {
|
||||
let service = ctx.service.borrow();
|
||||
let Some(service) = service.as_ref() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let only_here = ctx.cfg.borrow().only_this_output(connector);
|
||||
service
|
||||
.snapshot()
|
||||
.into_iter()
|
||||
.filter(|t| {
|
||||
(!only_here || t.outputs.iter().any(|o| o == connector))
|
||||
&& icons::lookup(&t.app_id).key == key
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Bygg en färsk kopia av en ikon vid interaktionstillfället.
|
||||
fn live_item(ctx: &Ctx, connector: &str, item: &Item) -> Rc<Item> {
|
||||
Rc::new(Item {
|
||||
meta: item.meta.clone(),
|
||||
windows: fresh_windows(ctx, connector, &item.meta.key),
|
||||
pinned: item.pinned,
|
||||
})
|
||||
}
|
||||
|
||||
/// Gruppera snapshot → ikonrad för en viss skärm.
|
||||
fn build_items(ctx: &Ctx, connector: &str, snapshot: &[ToplevelInfo]) -> Vec<Item> {
|
||||
let cfg = ctx.cfg.borrow();
|
||||
@@ -459,7 +486,7 @@ pub fn refresh_items(ctx: &Rc<Ctx>) {
|
||||
}
|
||||
add_special_buttons(ctx, dock);
|
||||
for item in build_items(ctx, &dock.connector, &snapshot) {
|
||||
let widget = build_item_widget(ctx, Rc::new(item));
|
||||
let widget = build_item_widget(ctx, &dock.connector, Rc::new(item));
|
||||
dock.panel.append(&widget);
|
||||
}
|
||||
}
|
||||
@@ -496,7 +523,7 @@ fn add_special_buttons(ctx: &Rc<Ctx>, dock: &Rc<Dock>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_item_widget(ctx: &Rc<Ctx>, item: Rc<Item>) -> gtk::Button {
|
||||
fn build_item_widget(ctx: &Rc<Ctx>, connector: &str, item: Rc<Item>) -> gtk::Button {
|
||||
let cfg = ctx.cfg.borrow();
|
||||
let icon_size = cfg.appearance.icon_size;
|
||||
let max_dots = cfg.appearance.indicator.max as usize;
|
||||
@@ -543,15 +570,23 @@ fn build_item_widget(ctx: &Rc<Ctx>, item: Rc<Item>) -> gtk::Button {
|
||||
btn.set_child(Some(&vbox));
|
||||
|
||||
if tooltips {
|
||||
let tip = match item.windows.len() {
|
||||
0 => item.meta.display_name.clone(),
|
||||
1 => {
|
||||
let t = &item.windows[0].title;
|
||||
if t.is_empty() { item.meta.display_name.clone() } else { t.clone() }
|
||||
}
|
||||
n => format!("{} — {n} fönster", item.meta.display_name),
|
||||
};
|
||||
btn.set_tooltip_text(Some(&tip));
|
||||
btn.set_has_tooltip(true);
|
||||
let ctx2 = ctx.clone();
|
||||
let item2 = item.clone();
|
||||
let conn2 = connector.to_string();
|
||||
btn.connect_query_tooltip(move |_, _, _, _, tooltip| {
|
||||
let windows = fresh_windows(&ctx2, &conn2, &item2.meta.key);
|
||||
let tip = match windows.len() {
|
||||
0 => item2.meta.display_name.clone(),
|
||||
1 => {
|
||||
let t = &windows[0].title;
|
||||
if t.is_empty() { item2.meta.display_name.clone() } else { t.clone() }
|
||||
}
|
||||
n => format!("{} — {n} fönster", item2.meta.display_name),
|
||||
};
|
||||
tooltip.set_text(Some(&tip));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
// klick: vänster/mitt/höger
|
||||
@@ -561,12 +596,14 @@ fn build_item_widget(ctx: &Rc<Ctx>, item: Rc<Item>) -> gtk::Button {
|
||||
let ctx = ctx.clone();
|
||||
let item = item.clone();
|
||||
let btn2 = btn.clone();
|
||||
let conn2 = connector.to_string();
|
||||
click.connect_released(move |gesture, _, _, _| {
|
||||
gesture.set_state(gtk::EventSequenceState::Claimed);
|
||||
let live = live_item(&ctx, &conn2, &item);
|
||||
match gesture.current_button() {
|
||||
1 => primary_action(&ctx, &item, &btn2),
|
||||
2 => middle_action(&ctx, &item),
|
||||
3 => menu::popup_item_menu(&ctx, &item, &btn2),
|
||||
1 => primary_action(&ctx, &live, &btn2),
|
||||
2 => middle_action(&ctx, &live),
|
||||
3 => menu::popup_item_menu(&ctx, &live, &btn2),
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
@@ -578,9 +615,11 @@ fn build_item_widget(ctx: &Rc<Ctx>, item: Rc<Item>) -> gtk::Button {
|
||||
{
|
||||
let ctx = ctx.clone();
|
||||
let item = item.clone();
|
||||
let conn2 = connector.to_string();
|
||||
scroll.connect_scroll(move |_, _, dy| {
|
||||
if ctx.cfg.borrow().behavior.scroll == ScrollAction::CycleWindows {
|
||||
cycle_windows(&ctx, &item, dy > 0.0);
|
||||
let live = live_item(&ctx, &conn2, &item);
|
||||
cycle_windows(&ctx, &live, dy > 0.0);
|
||||
glib::Propagation::Stop
|
||||
} else {
|
||||
glib::Propagation::Proceed
|
||||
|
||||
Reference in New Issue
Block a user