Freeze issue experimental fix due to mouse

This commit is contained in:
Andy Dixon
2026-10-20 13:27:39 +01:00
parent 1a1b58e9a8
commit 6d78be7aa2
2 changed files with 48 additions and 1 deletions
+22
View File
@@ -992,9 +992,31 @@ impl eframe::App for App {
self.screenshot.is_none() self.screenshot.is_none()
} }
fn raw_input_hook(&mut self, _ctx: &egui::Context, raw: &mut egui::RawInput) {
if raw.events.iter().any(|e| matches!(e, egui::Event::WindowFocused(false))) {
// winit can miss mouse-up events when macOS hides or minimizes the window.
// Release egui's pointer buttons too, so every widget remains interactive on return.
let pos = raw.screen_rect.map_or(egui::pos2(-1000.0, -1000.0), |r| r.max + egui::vec2(100.0, 100.0));
for button in [egui::PointerButton::Primary, egui::PointerButton::Secondary, egui::PointerButton::Middle] {
raw.events.push(egui::Event::PointerButton { pos, button, pressed: false, modifiers: egui::Modifiers::default() });
}
}
}
fn ui(&mut self, ui: &mut Ui, _frame: &mut eframe::Frame) { fn ui(&mut self, ui: &mut Ui, _frame: &mut eframe::Frame) {
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
let t = Tokens::get(&ctx); let t = Tokens::get(&ctx);
// If the window is hidden or minimized during a drag, macOS may not deliver the
// matching mouse-up. Clear terminal-side pointer capture on every pane, including
// panes that are currently hidden behind another tab.
let lost_focus = ctx.input(|i| i.events.iter().any(|e| matches!(e, egui::Event::WindowFocused(false))));
if lost_focus {
for pane in self.s.panes.values_mut() {
if let crate::views::View::Terminal(term) = &mut pane.view {
term.cancel_pointer_interaction();
}
}
}
self.s.now = ctx.input(|i| i.time); self.s.now = ctx.input(|i| i.time);
self.drain_events(); self.drain_events();
self.handle_requests(); self.handle_requests();
+26 -1
View File
@@ -396,6 +396,13 @@ impl TermView {
self.focus_requested = true; self.focus_requested = true;
} }
/// A window can lose its mouse-up event when it is hidden or minimized mid-drag.
/// Drop the transient pointer state while keeping any text already selected.
pub fn cancel_pointer_interaction(&mut self) {
self.drag = None;
self.mouse_down = None;
}
pub fn selection_text(&self) -> Option<String> { pub fn selection_text(&self) -> Option<String> {
self.term.selection_to_string().filter(|s| !s.is_empty()) self.term.selection_to_string().filter(|s| !s.is_empty())
} }
@@ -780,13 +787,31 @@ impl TermView {
self.term.scroll_display(Scroll::Delta(n)); self.term.scroll_display(Scroll::Delta(n));
} }
} }
Event::PointerButton { pos, button, pressed, modifiers } if resp.rect.contains(*pos) => { Event::PointerButton { pos, button, pressed, modifiers } => {
let b = match button { let b = match button {
PointerButton::Primary => 0, PointerButton::Primary => 0,
PointerButton::Middle => 1, PointerButton::Middle => 1,
PointerButton::Secondary => 2, PointerButton::Secondary => 2,
_ => continue, _ => continue,
}; };
// A mouse-up outside this widget still ends a drag that began here.
// Without this, the next pointer movement keeps extending the selection.
let was_mouse_down = self.mouse_down == Some(b);
if !*pressed {
if b == 0 {
self.drag = None;
}
if was_mouse_down {
self.mouse_down = None;
}
}
if !resp.rect.contains(*pos) {
if !*pressed && was_mouse_down {
let (c, r) = to_cell(*pos);
out.input.extend(mouse_report(b, c, r, false, mode));
}
continue;
}
if reporting && b != 2 || reporting && mode.contains(TermMode::MOUSE_MODE) && b == 2 && !*pressed { if reporting && b != 2 || reporting && mode.contains(TermMode::MOUSE_MODE) && b == 2 && !*pressed {
let (c, r) = to_cell(*pos); let (c, r) = to_cell(*pos);
out.input.extend(mouse_report(b, c, r, *pressed, mode)); out.input.extend(mouse_report(b, c, r, *pressed, mode));