Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions rust/limux-host-linux/src/pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2054,8 +2054,9 @@ fn show_tab_context_menu(tab_btn: &gtk::Box, tab_id: &str, context: &TabContextM
let menu_ref = menu.clone();
let callbacks = context.callbacks.clone();
rename_btn.connect_clicked(move |_| {
let hover_focus_guard = terminal::suspend_hover_focus();
menu_ref.popdown();
show_rename_dialog(&lbl, &state, &tid, &callbacks);
show_rename_dialog(&lbl, &state, &tid, &callbacks, hover_focus_guard);
});
}

Expand Down Expand Up @@ -2138,6 +2139,7 @@ fn show_rename_dialog(
tab_state: &Rc<RefCell<TabState>>,
tab_id: &str,
callbacks: &Rc<PaneCallbacks>,
hover_focus_guard: terminal::HoverFocusGuard,
) {
let current_name = label.label().to_string();

Expand All @@ -2161,13 +2163,14 @@ fn show_rename_dialog(
entry.grab_focus();
entry.select_region(0, -1);

// On activate (Enter) or focus-out, commit rename
// On activate (Enter) or blur, commit rename.
let lbl = label.clone();
let state = tab_state.clone();
let tid = tab_id.to_string();
let parent_for_cleanup = parent.clone();

let commit = Rc::new(std::cell::Cell::new(false));
let hover_focus_guard = Rc::new(RefCell::new(Some(hover_focus_guard)));

let do_rename = {
let commit = commit.clone();
Expand All @@ -2176,6 +2179,7 @@ fn show_rename_dialog(
let tid = tid.clone();
let parent = parent_for_cleanup.clone();
let callbacks = callbacks.clone();
let hover_focus_guard = hover_focus_guard.clone();
move |entry: &gtk::Entry| {
if commit.get() {
return;
Expand All @@ -2191,6 +2195,7 @@ fn show_rename_dialog(
}
lbl.set_visible(true);
parent.remove(entry);
hover_focus_guard.borrow_mut().take();
(callbacks.on_state_changed)();
}
};
Expand All @@ -2203,15 +2208,18 @@ fn show_rename_dialog(
}
{
let do_rename = do_rename.clone();
let focus_controller = gtk::EventControllerFocus::new();
focus_controller.connect_leave(move |ctrl| {
if let Some(widget) = ctrl.widget() {
if let Some(entry) = widget.downcast_ref::<gtk::Entry>() {
do_rename(entry);
}
entry.connect_notify_local(Some("has-focus"), move |entry, _| {
if entry.has_focus() {
return;
}
let do_rename = do_rename.clone();
let entry = entry.clone();
glib::idle_add_local_once(move || {
if !entry.has_focus() {
do_rename(&entry);
}
});
});
entry.add_controller(focus_controller);
}
}

Expand Down
16 changes: 15 additions & 1 deletion rust/limux-host-linux/src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ pub struct TerminalIdentity {
pub surface_id: String,
}

pub(crate) struct HoverFocusGuard;

impl Drop for HoverFocusGuard {
fn drop(&mut self) {
HOVER_FOCUS_SUPPRESS_DEPTH.with(|depth| depth.set(depth.get().saturating_sub(1)));
}
}

pub(crate) fn suspend_hover_focus() -> HoverFocusGuard {
HOVER_FOCUS_SUPPRESS_DEPTH.with(|depth| depth.set(depth.get().saturating_add(1)));
HoverFocusGuard
}

/// Per-surface state, stored in a global registry keyed by surface pointer.
struct SurfaceEntry {
gl_area: gtk::GLArea,
Expand Down Expand Up @@ -160,6 +173,7 @@ impl TerminalImeState {
}

thread_local! {
static HOVER_FOCUS_SUPPRESS_DEPTH: Cell<usize> = const { Cell::new(0) };
static SURFACE_MAP: RefCell<HashMap<usize, SurfaceEntry>> = RefCell::new(HashMap::new());
}

Expand Down Expand Up @@ -1684,7 +1698,7 @@ pub fn create_terminal(
let had_focus = had_focus.clone();
let motion = gtk::EventControllerMotion::new();
motion.connect_enter(move |ctrl, x, y| {
if (hover_focus)() {
if HOVER_FOCUS_SUPPRESS_DEPTH.with(|depth| depth.get() == 0) && (hover_focus)() {
// Match common Hyprland/Omarchy-style focus-follows-mouse behavior:
// as soon as the pointer enters a terminal, focus it so typing works
// immediately without an extra click.
Expand Down