parent
1bcc55e47d
commit
169a4fd90c
|
|
@ -456,6 +456,26 @@ struct TerminalCallbackState {
|
|||
write_pty: Option<Box<WritePtyCallback>>,
|
||||
pwd_changes: Vec<Vec<u8>>,
|
||||
clipboard_writes: Vec<Vec<u8>>,
|
||||
size_report: ffi::GhosttySizeReportSize,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn size_trampoline(
|
||||
_terminal: ffi::GhosttyTerminal,
|
||||
userdata: *mut c_void,
|
||||
out_size: *mut ffi::GhosttySizeReportSize,
|
||||
) -> bool {
|
||||
if userdata.is_null() || out_size.is_null() {
|
||||
return false;
|
||||
}
|
||||
let state = unsafe { &*userdata.cast::<TerminalCallbackState>() };
|
||||
let size = state.size_report;
|
||||
if size.rows == 0 || size.columns == 0 || size.cell_width == 0 || size.cell_height == 0 {
|
||||
return false;
|
||||
}
|
||||
unsafe {
|
||||
out_size.write(size);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
unsafe extern "C" fn write_pty_trampoline(
|
||||
|
|
@ -734,7 +754,14 @@ impl Terminal {
|
|||
|
||||
let mut terminal = Self {
|
||||
raw,
|
||||
callback_state: Box::default(),
|
||||
callback_state: Box::new(TerminalCallbackState {
|
||||
size_report: ffi::GhosttySizeReportSize {
|
||||
rows,
|
||||
columns: cols,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
kitty_fingerprints: Mutex::new(HashMap::new()),
|
||||
kitty_empty_generation: Cell::new(None),
|
||||
};
|
||||
|
|
@ -747,6 +774,12 @@ impl Terminal {
|
|||
userdata,
|
||||
)
|
||||
.into_result()?;
|
||||
ffi::ghostty_terminal_set(
|
||||
terminal.raw,
|
||||
ffi::GhosttyTerminalOption_GHOSTTY_TERMINAL_OPT_SIZE,
|
||||
(size_trampoline as *const ()).cast(),
|
||||
)
|
||||
.into_result()?;
|
||||
ffi::ghostty_terminal_set(
|
||||
terminal.raw,
|
||||
ffi::GhosttyTerminalOption_GHOSTTY_TERMINAL_OPT_PWD_CHANGED,
|
||||
|
|
@ -799,13 +832,25 @@ impl Terminal {
|
|||
cell_width_px: u32,
|
||||
cell_height_px: u32,
|
||||
) -> Result<(), Error> {
|
||||
let cell_width_px = cell_width_px.max(1);
|
||||
let cell_height_px = cell_height_px.max(1);
|
||||
let size_report = ffi::GhosttySizeReportSize {
|
||||
rows,
|
||||
columns: cols,
|
||||
cell_width: cell_width_px,
|
||||
cell_height: cell_height_px,
|
||||
};
|
||||
// SAFETY: self.raw is valid and sizes are plain values.
|
||||
unsafe {
|
||||
ffi::ghostty_terminal_resize(self.raw, cols, rows, cell_width_px, cell_height_px)
|
||||
.into_result()
|
||||
ffi::ghostty_terminal_resize(
|
||||
self.raw,
|
||||
cols,
|
||||
rows,
|
||||
cell_width_px.max(1),
|
||||
cell_height_px.max(1),
|
||||
)
|
||||
.into_result()?;
|
||||
}
|
||||
self.callback_state.size_report = size_report;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enable_kitty_graphics(&mut self) -> Result<(), Error> {
|
||||
|
|
|
|||
|
|
@ -1716,6 +1716,9 @@ impl PaneRuntime {
|
|||
let (response_tx, _response_rx) = mpsc::channel::<Bytes>(1);
|
||||
let mut terminal = crate::ghostty::Terminal::new(cols, rows, scrollback_limit_bytes)
|
||||
.map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||
terminal
|
||||
.resize(cols, rows, cell_width_px, cell_height_px)
|
||||
.map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||
if crate::kitty_graphics::is_enabled() {
|
||||
terminal
|
||||
.enable_kitty_graphics()
|
||||
|
|
|
|||
|
|
@ -4483,6 +4483,60 @@ mod tests {
|
|||
assert!(pane.recent_text(3).trim().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pty_bytes_answers_xtwinops_size_queries() {
|
||||
let (tx, _rx) = mpsc::channel(4);
|
||||
let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap();
|
||||
let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap();
|
||||
let pane_id = PaneId::from_raw(1);
|
||||
pane.resize(24, 80, 9, 18);
|
||||
|
||||
let result = pane.process_pty_bytes(pane_id, 0, b"\x1b[14t\x1b[16t\x1b[18t", &tx);
|
||||
|
||||
assert_eq!(
|
||||
result.terminal_responses,
|
||||
vec![
|
||||
Bytes::from_static(b"\x1b[4;432;720t"),
|
||||
Bytes::from_static(b"\x1b[6;18;9t"),
|
||||
Bytes::from_static(b"\x1b[8;24;80t"),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xtwinops_size_queries_follow_successful_resize() {
|
||||
let (tx, _rx) = mpsc::channel(4);
|
||||
let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap();
|
||||
let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap();
|
||||
let pane_id = PaneId::from_raw(1);
|
||||
pane.resize(24, 80, 9, 18);
|
||||
pane.resize(30, 100, 10, 20);
|
||||
|
||||
let result = pane.process_pty_bytes(pane_id, 0, b"\x1b[14t\x1b[16t\x1b[18t", &tx);
|
||||
|
||||
assert_eq!(
|
||||
result.terminal_responses,
|
||||
vec![
|
||||
Bytes::from_static(b"\x1b[4;600;1000t"),
|
||||
Bytes::from_static(b"\x1b[6;20;10t"),
|
||||
Bytes::from_static(b"\x1b[8;30;100t"),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xtwinops_size_queries_stay_silent_without_pixel_geometry() {
|
||||
let (tx, _rx) = mpsc::channel(4);
|
||||
let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap();
|
||||
let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap();
|
||||
let pane_id = PaneId::from_raw(1);
|
||||
for (cell_width_px, cell_height_px) in [(0, 0), (0, 18), (9, 0)] {
|
||||
pane.resize(24, 80, cell_width_px, cell_height_px);
|
||||
let result = pane.process_pty_bytes(pane_id, 0, b"\x1b[14t\x1b[16t\x1b[18t", &tx);
|
||||
assert!(result.terminal_responses.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resize_returns_in_band_size_report_response() {
|
||||
let (tx, _rx) = mpsc::channel(4);
|
||||
|
|
|
|||
Loading…
Reference in New Issue