Skroll-stegning i fönsterlistan + klick/launch-debugloggar
All checks were successful
check / check (push) Successful in 1m34s
All checks were successful
check / check (push) Successful in 1m34s
Med en grupps lista öppen stegar skroll (på gruppikonen eller över listan) markeringen mellan raderna — markerad rad får accentbakgrund och triggar samma förhandsvisning som hover (peek/fokus enligt list_hover). Funkar i både hover- och klickläge; utan öppen lista beter sig skroll som förut (cykla fönster). Watchdogen räknar stegning som aktivitet så listan inte stängs mitt i. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
19
src/dock.rs
19
src/dock.rs
@@ -47,6 +47,8 @@ pub struct Ctx {
|
||||
pub refresh_pending: Cell<bool>,
|
||||
/// den enda popover som får vara öppen åt gången
|
||||
pub current_popover: RefCell<Option<gtk::Popover>>,
|
||||
/// öppen fönsterlista (för skroll-stegning från gruppikonen)
|
||||
pub group_list: RefCell<Option<menu::GroupList>>,
|
||||
}
|
||||
|
||||
pub struct Dock {
|
||||
@@ -730,6 +732,17 @@ fn build_item_widget(ctx: &Rc<Ctx>, connector: &str, item: Rc<Item>) -> 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<Ctx>, connector: &str, item: Rc<Item>) -> gtk::But
|
||||
}
|
||||
|
||||
fn primary_action(ctx: &Rc<Ctx>, connector: &str, item: &Rc<Item>, 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);
|
||||
|
||||
@@ -88,8 +88,9 @@ pub fn lookup_pin(desktop_id: &str) -> Option<AppMeta> {
|
||||
/// 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);
|
||||
|
||||
@@ -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
|
||||
|
||||
166
src/menu.rs
166
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<dyn Fn(f64)>,
|
||||
}
|
||||
|
||||
/// 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<Ctx>, item: &Rc<Item>, anchor: >k::Button) {
|
||||
// fönster som tonats ner av peek — återställs vid radbyte/stängning
|
||||
let dimmed: Rc<std::cell::RefCell<Vec<i64>>> = 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<Vec<crate::toplevel::ToplevelInfo>> = 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<Ctx>, item: &Rc<Item>, 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<Vec<gtk::Button>> = Rc::new(rows_vec);
|
||||
|
||||
// markera rad idx: visuell markering + förhandsvisning (peek/fokus)
|
||||
let selected = Rc::new(std::cell::Cell::new(None::<usize>));
|
||||
let select: Rc<dyn Fn(usize)> = 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<dyn Fn(f64)> = 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<Ctx>, item: &Rc<Item>, 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<Ctx>, item: &Rc<Item>, 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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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};
|
||||
}}
|
||||
"#,
|
||||
|
||||
Reference in New Issue
Block a user