summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index 04854a37..402b3cd8 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -3482,6 +3482,9 @@ pub const Mouse = struct {
col: u16,
row: u16,
ctrl: bool = false,
+ shift: bool = false,
+ /// Alt, which xterm's mouse reports call meta.
+ alt: bool = false,
body_hit: ?BodyHit = null,
tag_hit: ?TagHit = null,
/// A pixel frontend's press on the rule it draws at the top of this row,
@@ -3575,6 +3578,8 @@ pub const Event = union(enum) {
/// The host pointer left the drawable area. Unlike an out-of-range motion,
/// this must not clamp onto and preview the final grid cell.
pointer_leave,
+ /// The window gained (true) or lost the host's keyboard focus.
+ focus: bool,
tick,
};
@@ -4346,6 +4351,13 @@ pub const Pardes = struct {
unattended: bool = false,
haptic: HapticSlot = if (platform == .macos) .none else {},
drag: mouse.Drag = .none,
+ /// A press a terminal's program took (mouse.programMouse): its drags
+ /// and release are the program's too, wherever the pointer goes.
+ mouse_grab: ?mouse.Grab = null,
+ /// Whether the host window has the keyboard (Event.focus), and the pane
+ /// whose program was last told it has it (reportFocus).
+ window_focused: bool = true,
+ focus_told: ?struct { id: usize, serial: u32 } = null,
hover_col: u16 = 0,
hover_row: u16 = 0,
pointer_raw_col: u16 = 0,
@@ -5047,6 +5059,25 @@ pub const Pardes = struct {
}
/// The column the keyboard is in: its tag's, or its pane's.
+ /// DECSET 1004: a program that asked is told `CSI I` when its pane
+ /// takes the keyboard (the active pane, its body, the window focused)
+ /// and `CSI O` when it gives it up, to another pane, a tag or header,
+ /// or another window.
+ fn reportFocus(p: *Pardes) void {
+ const want: @FieldType(Pardes, "focus_told") = blk: {
+ if (!p.window_focused or p.header_focus) break :blk null;
+ const pane = p.panes[p.active] orelse break :blk null;
+ if (pane.focus != .body) break :blk null;
+ break :blk .{ .id = p.active, .serial = pane.serial };
+ };
+ if (std.meta.eql(want, p.focus_told)) return;
+ if (p.focus_told) |old| if (p.panes[old.id]) |pane| {
+ if (pane.serial == old.serial and panes.terminal.reportsFocus(pane)) p.emitWrite(old.id, "\x1b[O");
+ };
+ if (want) |new| if (panes.terminal.reportsFocus(p.panes[new.id].?)) p.emitWrite(new.id, "\x1b[I");
+ p.focus_told = want;
+ }
+
pub fn noteTyped(p: *Pardes) void {
if (p.header_focus) {
if (p.header_column) |c| p.setActiveColumn(c);
@@ -5707,6 +5738,7 @@ pub const Pardes = struct {
}
pub fn update(p: *Pardes, ev: Event) void {
+ defer p.reportFocus();
// A tick with nothing animating is the one event that cannot change
// the screen.
p.needs_frame = p.needs_frame or ev != .tick;
@@ -5839,6 +5871,7 @@ pub const Pardes = struct {
.command => |line| _ = p.executeBuiltinLine(p.active, line),
.pinch => |scale| p.ov_pinch_scale = scale,
.touch_scroll => |delta| p.ov_touch_scroll_delta = delta,
+ .focus => |focused| p.window_focused = focused,
.pointer_leave => {
p.pointer_inside = false;
p.pointer_body_hit = null;