diff --git a/src/dock.rs b/src/dock.rs index 45e18af..0bbe0a2 100644 --- a/src/dock.rs +++ b/src/dock.rs @@ -47,6 +47,8 @@ pub struct Ctx { pub refresh_pending: Cell, /// den enda popover som får vara öppen åt gången pub current_popover: RefCell>, + /// öppen fönsterlista (för skroll-stegning från gruppikonen) + pub group_list: RefCell>, } pub struct Dock { @@ -730,6 +732,17 @@ fn build_item_widget(ctx: &Rc, connector: &str, item: Rc) -> gtk::But let item = item.clone(); let conn2 = connector.to_string(); scroll.connect_scroll(move |_, _, dy| { + // om den här gruppens lista är öppen: stega markeringen i den + let step = ctx + .group_list + .borrow() + .as_ref() + .filter(|h| h.key == item.meta.key && h.connector == conn2) + .map(|h| h.step.clone()); + if let Some(step) = step { + step(dy); + return glib::Propagation::Stop; + } if ctx.cfg.borrow().for_output(&conn2).behavior.scroll == ScrollAction::CycleWindows { let live = live_item(&ctx, &conn2, &item); cycle_windows(&ctx, &live, dy > 0.0); @@ -745,6 +758,12 @@ fn build_item_widget(ctx: &Rc, connector: &str, item: Rc) -> gtk::But } fn primary_action(ctx: &Rc, connector: &str, item: &Rc, anchor: >k::Button) { + debug!( + "vänsterklick: {} ({} fönster, pinnad={})", + item.meta.display_name, + item.windows.len(), + item.pinned + ); let service = ctx.service.borrow(); let Some(service) = service.as_ref() else { icons::launch(&item.meta); diff --git a/src/icons.rs b/src/icons.rs index 22b5971..58c2ab9 100644 --- a/src/icons.rs +++ b/src/icons.rs @@ -88,8 +88,9 @@ pub fn lookup_pin(desktop_id: &str) -> Option { /// Starta en app (ny instans). pub fn launch(meta: &AppMeta) { if let Some(info) = &meta.app_info { - if let Err(e) = info.launch(&[], None::<&gio::AppLaunchContext>) { - log::warn!("kunde inte starta {}: {e}", meta.display_name); + match info.launch(&[], None::<&gio::AppLaunchContext>) { + Ok(_) => log::info!("startade {}", meta.display_name), + Err(e) => log::warn!("kunde inte starta {}: {e}", meta.display_name), } } else { log::warn!("ingen .desktop för {} — kan inte starta", meta.display_name); diff --git a/src/main.rs b/src/main.rs index 6c12996..d133e01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -158,6 +158,7 @@ fn activate(app: >k::Application, cfg_path: PathBuf) { open_popovers: Cell::new(0), refresh_pending: Cell::new(false), current_popover: RefCell::new(None), + group_list: RefCell::new(None), }); // CSS + rebuild/refresh-logik diff --git a/src/menu.rs b/src/menu.rs index 2367015..252d9ce 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -18,6 +18,13 @@ use crate::settings; use crate::toplevel::ToplevelInfo; use crate::wayfire_ipc; +/// Handle till en öppen fönsterlista: gruppikonen skroll-stegar via denna. +pub struct GroupList { + pub key: String, + pub connector: String, + pub step: Rc, +} + /// Målet för den senast öppnade ikon-menyn (actions läser härifrån). pub struct MenuTarget { pub key: String, @@ -343,7 +350,10 @@ pub fn popup_group_list(ctx: &Rc, item: &Rc, anchor: >k::Button) { // fönster som tonats ner av peek — återställs vid radbyte/stängning let dimmed: Rc>> = Rc::new(std::cell::RefCell::new(Vec::new())); - for w in &item.windows { + // bygg raderna först, koppla handlers efteråt (select behöver alla) + let windows: Rc> = Rc::new(item.windows.clone()); + let mut rows_vec = Vec::new(); + for w in windows.iter() { let row = gtk::Button::new(); row.add_css_class("flat"); let title = if w.title.is_empty() { item.meta.display_name.clone() } else { w.title.clone() }; @@ -352,6 +362,68 @@ pub fn popup_group_list(ctx: &Rc, item: &Rc, anchor: >k::Button) { label.set_max_width_chars(40); label.set_halign(gtk::Align::Start); row.set_child(Some(&label)); + list.append(&row); + rows_vec.push(row); + } + let rows: Rc> = Rc::new(rows_vec); + + // markera rad idx: visuell markering + förhandsvisning (peek/fokus) + let selected = Rc::new(std::cell::Cell::new(None::)); + let select: Rc = Rc::new({ + let rows = rows.clone(); + let windows = windows.clone(); + let dimmed = dimmed.clone(); + let selected = selected.clone(); + let list_hover = list_hover.clone(); + let ctx2 = ctx.clone(); + move |idx: usize| { + for (i, r) in rows.iter().enumerate() { + if i == idx { + r.add_css_class("selected"); + } else { + r.remove_css_class("selected"); + } + } + selected.set(Some(idx)); + let w = &windows[idx]; + match list_hover { + ListHover::Peek if peek_possible => { + peek_restore(&dimmed.borrow()); + *dimmed.borrow_mut() = peek_apply(w); + } + ListHover::Focus => { + if let Some(s) = ctx2.service.borrow().as_ref() { + s.activate(w); + } + } + _ => {} + } + } + }); + + // skroll-stegning (från gruppikonen eller över listan) + let step: Rc = Rc::new({ + let select = select.clone(); + let selected = selected.clone(); + let n = windows.len(); + move |dy: f64| { + if n == 0 { + return; + } + let next = match selected.get() { + None => { + if dy > 0.0 { 0 } else { n - 1 } + } + Some(i) => { + if dy > 0.0 { (i + 1) % n } else { (i + n - 1) % n } + } + }; + select(next); + } + }); + + // per rad: klick aktiverar; hover markerar (efter armering) + for (i, (row, w)) in rows.iter().zip(windows.iter()).enumerate() { let ctx2 = ctx.clone(); let w2 = w.clone(); let pop2 = popover.clone(); @@ -364,47 +436,47 @@ pub fn popup_group_list(ctx: &Rc, item: &Rc, anchor: >k::Button) { } pop2.popdown(); }); - - // hover-effekt per rad: peek eller fokus - match list_hover { - ListHover::Peek if peek_possible => { - let mc = gtk::EventControllerMotion::new(); - let w3 = w.clone(); - let dimmed3 = dimmed.clone(); - let armed3 = armed.clone(); - mc.connect_enter(move |_, _, _| { - if !armed3.get() { - return; - } - peek_restore(&dimmed3.borrow()); - *dimmed3.borrow_mut() = peek_apply(&w3); - }); - let dimmed4 = dimmed.clone(); - mc.connect_leave(move |_| { - peek_restore(&dimmed4.borrow()); - dimmed4.borrow_mut().clear(); - }); - row.add_controller(mc); - } - ListHover::Focus => { - let mc = gtk::EventControllerMotion::new(); - let ctx3 = ctx.clone(); - let w3 = w.clone(); - let armed3 = armed.clone(); - mc.connect_enter(move |_, _, _| { - if !armed3.get() { - return; - } - if let Some(s) = ctx3.service.borrow().as_ref() { - s.activate(&w3); - } - }); - row.add_controller(mc); - } - _ => {} + if list_hover != ListHover::None { + let mc = gtk::EventControllerMotion::new(); + let select2 = select.clone(); + let armed2 = armed.clone(); + mc.connect_enter(move |_, _, _| { + if armed2.get() { + select2(i); + } + }); + row.add_controller(mc); } - list.append(&row); } + + // skroll över själva listan stegar också + { + let sc = gtk::EventControllerScroll::new(gtk::EventControllerScrollFlags::VERTICAL); + let step2 = step.clone(); + sc.connect_scroll(move |_, _, dy| { + step2(dy); + glib::Propagation::Stop + }); + popover.add_controller(sc); + } + + // registrera handlet så gruppikonens skroll når stegningen + *ctx.group_list.borrow_mut() = Some(GroupList { + key: item.meta.key.clone(), + connector: connector.clone(), + step: step.clone(), + }); + { + let ctx2 = ctx.clone(); + let key = item.meta.key.clone(); + popover.connect_closed(move |_| { + let mut gl = ctx2.group_list.borrow_mut(); + if gl.as_ref().map(|h| h.key == key).unwrap_or(false) { + *gl = None; + } + }); + } + popover.set_child(Some(&list)); popover.set_parent(anchor); @@ -437,13 +509,19 @@ pub fn popup_group_list(ctx: &Rc, item: &Rc, anchor: >k::Button) { } popover.add_controller(mc.clone()); - // watchdog: om pekaren aldrig ens når listan, stäng efter en stund + // watchdog: om pekaren aldrig når listan OCH ingen skroll-stegning + // sker, stäng efter en stund (upprepas; aktivitet = markerad rad) { let pop3 = popover.clone(); - glib::timeout_add_local_once(std::time::Duration::from_millis(1500), move || { - if !mc.contains_pointer() { - pop3.popdown(); + let selected2 = selected.clone(); + let last_seen = std::cell::Cell::new(selected.get()); + glib::timeout_add_local(std::time::Duration::from_millis(1500), move || { + if mc.contains_pointer() || selected2.get() != last_seen.get() { + last_seen.set(selected2.get()); + return glib::ControlFlow::Continue; } + pop3.popdown(); + glib::ControlFlow::Break }); } diff --git a/src/style.rs b/src/style.rs index 98bd516..9368af5 100644 --- a/src/style.rs +++ b/src/style.rs @@ -141,7 +141,8 @@ fn css_body(cfg: &Config, p: &str) -> String { }} {p}popover.waydock-menu modelbutton:hover, -{p}popover.waydock-menu button.flat:hover {{ +{p}popover.waydock-menu button.flat:hover, +{p}popover.waydock-menu button.flat.selected {{ background-color: {accent_soft}; }} "#,