diff --git a/src/Surface.zig b/src/Surface.zig index 737414594..c4c30f675 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1824,15 +1824,16 @@ pub fn focusCallback(self: *Surface, focused: bool) !void { // Schedule render which also drains our mailbox try self.queueRender(); - // Notify the app about focus in/out if it is requesting it + // Update the focus state and notify the terminal about the focus event if + // it is requesting it { 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) { - const seq = if (focused) "\x1b[I" else "\x1b[O"; - self.io.queueMessage(.{ .write_stable = seq }, .unlocked); + self.io.queueMessage(.{ .focused = focused }, .unlocked); } } } diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 12a056664..0f15845dd 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -116,6 +116,9 @@ flags: packed struct { /// if the configuration allows it. mouse_shift_capture: enum(u2) { null, false, true } = .null, + /// True if the window is focused. + focused: bool = true, + /// Dirty flags for the renderer. dirty: Dirty = .{}, } = .{}, diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig index ae38eb043..f209748df 100644 --- a/src/termio/Termio.zig +++ b/src/termio/Termio.zig @@ -521,6 +521,12 @@ pub fn childExitedAbnormally(self: *Termio, exit_code: u32, runtime_ms: u64) !vo try self.backend.childExitedAbnormally(self.alloc, t, exit_code, runtime_ms); } +/// Called when focus is gained or lost (when focus events are enabled) +pub fn focusGained(self: *Termio, td: *ThreadData, focused: bool) !void { + const seq = if (focused) "\x1b[I" else "\x1b[O"; + try self.queueWrite(td, seq, false); +} + /// Process output from the pty. This is the manual API that users can /// call with pty data but it is also called by the read thread when using /// an exec subprocess. diff --git a/src/termio/Thread.zig b/src/termio/Thread.zig index a62e0b8de..4c75b3b9e 100644 --- a/src/termio/Thread.zig +++ b/src/termio/Thread.zig @@ -283,6 +283,7 @@ fn drainMailbox( .start_synchronized_output => self.startSynchronizedOutput(cb), .linefeed_mode => |v| self.flags.linefeed_mode = v, .child_exited_abnormally => |v| try io.childExitedAbnormally(v.exit_code, v.runtime_ms), + .focused => |v| try io.focusGained(data, v), .write_small => |v| try io.queueWrite( data, v.data[0..v.len], diff --git a/src/termio/message.zig b/src/termio/message.zig index 6bdb7a2da..79b920ad7 100644 --- a/src/termio/message.zig +++ b/src/termio/message.zig @@ -80,6 +80,9 @@ pub const Message = union(enum) { runtime_ms: u64, }, + /// The surface gained or lost focus. + focused: bool, + /// Write where the data fits in the union. write_small: WriteReq.Small, diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 93ee3e780..90a33e8b7 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -637,6 +637,10 @@ pub const StreamHandler = struct { .size_report = .mode_2048, }), + .focus_event => if (enabled) self.messageWriter(.{ + .focused = self.terminal.flags.focused, + }), + .mouse_event_x10 => { if (enabled) { self.terminal.flags.mouse_event = .x10;