termio: stop the termios poller when not focused

This commit is contained in:
Mitchell Hashimoto
2024-09-18 11:43:15 -07:00
parent 5c469a0b44
commit e8bbc987e0
4 changed files with 63 additions and 17 deletions

View File

@ -1826,18 +1826,13 @@ pub fn focusCallback(self: *Surface, focused: bool) !void {
// Schedule render which also drains our mailbox
try self.queueRender();
// Update the focus state and notify the terminal about the focus event if
// it is requesting it
// Update the focus state and notify the terminal
{
self.renderer_state.mutex.lock();
self.io.terminal.flags.focused = focused;
const focus_event = self.io.terminal.modes.get(.focus_event);
self.renderer_state.mutex.unlock();
if (focus_event) {
self.io.queueMessage(.{ .focused = focused }, .unlocked);
}
}
}
pub fn refreshCallback(self: *Surface) !void {

View File

@ -196,6 +196,32 @@ pub fn threadExit(self: *Exec, td: *termio.Termio.ThreadData) void {
exec.read_thread.join();
}
pub fn focusGained(
self: *Exec,
td: *termio.Termio.ThreadData,
focused: bool,
) !void {
_ = self;
assert(td.backend == .exec);
const execdata = &td.backend.exec;
if (!focused) {
// Flag the timer to end on the next iteration. This is
// a lot cheaper than doing full timer cancellation.
execdata.termios_timer_running = false;
} else {
// If we're focused, we want to start our termios timer. We
// only do this if it isn't already running. We use the termios
// callback because that'll trigger an immediate state check AND
// start the timer.
if (execdata.termios_timer_c.state() != .active) {
execdata.termios_timer_running = true;
_ = termiosTimer(td, undefined, undefined, {});
}
}
}
pub fn resize(
self: *Exec,
grid_size: renderer.GridSize,
@ -391,6 +417,8 @@ fn termiosTimer(
_: *xev.Completion,
r: xev.Timer.RunError!void,
) xev.CallbackAction {
// log.debug("termios timer fired", .{});
// This should never happen because we guard starting our
// timer on windows but we want this assertion to fire if
// we ever do start the timer on windows.
@ -448,6 +476,7 @@ fn termiosTimer(
}
// Repeat the timer
if (exec.termios_timer_running) {
exec.termios_timer.run(
td.loop,
&exec.termios_timer_c,
@ -456,6 +485,7 @@ fn termiosTimer(
td,
termiosTimer,
);
}
return .disarm;
}
@ -604,6 +634,7 @@ pub const ThreadData = struct {
/// The timer to detect termios state changes.
termios_timer: xev.Timer,
termios_timer_c: xev.Completion = .{},
termios_timer_running: bool = true,
/// The last known termios mode. Used for change detection
/// to prevent unnecessary locking of expensive mutexes.

View File

@ -523,8 +523,18 @@ pub fn childExitedAbnormally(self: *Termio, exit_code: u32, runtime_ms: u64) !vo
/// Called when focus is gained or lost (when focus events are enabled)
pub fn focusGained(self: *Termio, td: *ThreadData, focused: bool) !void {
self.renderer_state.mutex.lock();
const focus_event = self.renderer_state.terminal.modes.get(.focus_event);
self.renderer_state.mutex.unlock();
// If we have focus events enabled, we send the focus event.
if (focus_event) {
const seq = if (focused) "\x1b[I" else "\x1b[O";
try self.queueWrite(td, seq, false);
}
// We always notify our backend of focus changes.
try self.backend.focusGained(td, focused);
}
/// Process output from the pty. This is the manual API that users can

View File

@ -62,6 +62,16 @@ pub const Backend = union(Kind) {
}
}
pub fn focusGained(
self: *Backend,
td: *termio.Termio.ThreadData,
focused: bool,
) !void {
switch (self.*) {
.exec => |*exec| try exec.focusGained(td, focused),
}
}
pub fn resize(
self: *Backend,
grid_size: renderer.GridSize,