aboutsummaryrefslogtreecommitdiff
path: root/src/server/headless/retained_surface.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/headless/retained_surface.rs')
-rw-r--r--src/server/headless/retained_surface.rs110
1 files changed, 53 insertions, 57 deletions
diff --git a/src/server/headless/retained_surface.rs b/src/server/headless/retained_surface.rs
index a62a43f6..259714a3 100644
--- a/src/server/headless/retained_surface.rs
+++ b/src/server/headless/retained_surface.rs
@@ -28,7 +28,7 @@ fn patch_intersects_hyperlinks(
})
}
-fn apply_patch_row(frame: &mut FrameData, row: &protocol::PaneSurfacePatchRow) -> Option<bool> {
+fn patch_row_changed(frame: &FrameData, row: &protocol::PaneSurfacePatchRow) -> Option<bool> {
if row.y >= frame.height
|| row.x.saturating_add(u16::try_from(row.cells.len()).ok()?) > frame.width
{
@@ -39,13 +39,11 @@ fn apply_patch_row(frame: &mut FrameData, row: &protocol::PaneSurfacePatchRow) -
if end > frame.cells.len() {
return None;
}
- let changed = frame.cells[start..end] != row.cells;
- frame.cells[start..end].clone_from_slice(&row.cells);
- Some(changed)
+ Some(frame.cells[start..end] != row.cells)
}
-fn apply_rows(
- frame: &mut FrameData,
+fn changed_rows(
+ frame: &FrameData,
area: protocol::SurfaceRect,
patch: &crate::pane::TerminalDirtyPatch,
) -> Option<Vec<protocol::PaneSurfacePatchRow>> {
@@ -89,15 +87,12 @@ fn apply_rows(
offset = end;
}
}
- for row in &rows {
- apply_patch_row(frame, row)?;
- }
Some(rows)
}
fn retained_scrollbar_patch(
app: &app::App,
- frame: &mut FrameData,
+ frame: &FrameData,
pane: &mut protocol::PaneSurfacePane,
alternate_screen_active: bool,
metrics: Option<crate::pane::ScrollMetrics>,
@@ -146,7 +141,7 @@ fn retained_scrollbar_patch(
y: rect.y.checked_add(u16::try_from(offset).ok()?)?,
cells: vec![cell],
};
- if apply_patch_row(frame, &row)? {
+ if patch_row_changed(frame, &row)? {
rows.push(row);
}
}
@@ -186,9 +181,9 @@ fn retained_cursor(
})
}
-struct RetainedRecipient {
+struct RetainedRecipient<'a> {
client_id: u64,
- surface: protocol::PaneSurfaceFrame,
+ surface: &'a protocol::PaneSurfaceFrame,
}
struct CollectedPanePatch {
@@ -204,9 +199,11 @@ struct CollectedPanePatch {
struct RetainedRecipientUpdate {
client_id: u64,
- surface: protocol::PaneSurfaceFrame,
patch: protocol::PaneSurfacePatch,
- graphics_delivery: Option<crate::kitty_graphics::surface::DeliveryCache>,
+ graphics: Option<(
+ protocol::PaneSurfaceFrame,
+ crate::kitty_graphics::surface::DeliveryCache,
+ )>,
}
impl HeadlessServer {
@@ -283,7 +280,7 @@ impl HeadlessServer {
}
recipients.push(RetainedRecipient {
client_id: *client_id,
- surface: surface.clone(),
+ surface,
});
}
if recipients.is_empty() {
@@ -355,7 +352,8 @@ impl HeadlessServer {
let mut updates = Vec::with_capacity(recipients.len());
for recipient in recipients {
let client_id = recipient.client_id;
- let mut surface = recipient.surface;
+ let surface = recipient.surface;
+ let mut panes = surface.panes.clone();
let projection_revision = surface.projection_revision;
let base_surface_revision = surface.surface_revision;
let mut changed_panes = Vec::with_capacity(collected.len());
@@ -364,8 +362,7 @@ impl HeadlessServer {
let mut refresh_graphics = !surface.graphics.placements.is_empty()
|| !surface.graphics.retained_assets.is_empty();
for collected_pane in &collected {
- let Some(pane) = surface
- .panes
+ let Some(pane) = panes
.iter_mut()
.find(|pane| pane.pane_id == collected_pane.pane_id)
else {
@@ -387,14 +384,14 @@ impl HeadlessServer {
refresh_graphics |= collected_pane.graphics_may_have_placements;
let previous_pane = pane.clone();
let Some(rows) =
- apply_rows(&mut surface.frame, pane.inner_rect, &collected_pane.patch)
+ changed_rows(&surface.frame, pane.inner_rect, &collected_pane.patch)
else {
fallback!("invalid_patch");
};
patch_rows.extend(rows);
let Some(scrollbar_rows) = retained_scrollbar_patch(
&self.app,
- &mut surface.frame,
+ &surface.frame,
pane,
collected_pane.alternate_screen_active,
collected_pane.scroll_metrics,
@@ -417,19 +414,29 @@ impl HeadlessServer {
changed_panes.push(pane.clone());
}
- let cursor = retained_cursor(&self.app, &surface.panes);
+ let cursor = retained_cursor(&self.app, &panes);
let cursor_changed = cursor != surface.frame.cursor;
- surface.frame.cursor = cursor.clone();
+ let patch = protocol::PaneSurfacePatch {
+ boot_id: self.client_shell_boot_id.clone(),
+ projection_revision,
+ base_surface_revision,
+ surface_revision: 0,
+ rows: patch_rows,
+ panes: changed_panes,
+ cursor,
+ };
let mut graphics_changed = false;
- let graphics_delivery = if refresh_graphics {
+ let graphics = if refresh_graphics {
let Some(target) = self.shell_target_for_client(client_id) else {
fallback!("graphics_target");
};
let client = &self.clients[&client_id];
+ let mut next_surface = surface.clone();
+ crate::server::render_stream::apply_pane_surface_patch(&mut next_surface, &patch);
let Some((graphics, delivery)) =
crate::server::client_shell_graphics::collect_retained(
&self.app,
- &surface,
+ &next_surface,
target,
client.cell_size,
&client.shell_graphics_delivery,
@@ -439,28 +446,18 @@ impl HeadlessServer {
fallback!("graphics_geometry");
};
graphics_changed = graphics != surface.graphics;
- surface.graphics = graphics;
- Some(delivery)
+ next_surface.graphics = graphics;
+ Some((next_surface, delivery))
} else {
None
};
- if patch_rows.is_empty() && !cursor_changed && !metadata_changed && !graphics_changed {
+ if patch.rows.is_empty() && !cursor_changed && !metadata_changed && !graphics_changed {
continue;
}
- let patch = protocol::PaneSurfacePatch {
- boot_id: self.client_shell_boot_id.clone(),
- projection_revision,
- base_surface_revision,
- surface_revision: 0,
- rows: patch_rows,
- panes: changed_panes,
- cursor,
- };
updates.push(RetainedRecipientUpdate {
client_id,
- surface,
patch,
- graphics_delivery,
+ graphics,
});
}
if updates.is_empty() {
@@ -473,9 +470,8 @@ impl HeadlessServer {
for update in updates {
let RetainedRecipientUpdate {
client_id,
- surface,
patch,
- graphics_delivery,
+ graphics,
} = update;
let Some(client) = self.clients.get_mut(&client_id) else {
continue;
@@ -487,12 +483,13 @@ impl HeadlessServer {
};
// The published row patch cannot carry images. Reuse the retained text/layout
// in a graphics-capable surface message rather than invoking the full renderer.
- let prepared = if graphics_delivery.is_some() {
- client.render_state.prepare_pane_surface(surface)
+ let (prepared, graphics_delivery) = if let Some((surface, delivery)) = graphics {
+ (
+ client.render_state.prepare_pane_surface(surface),
+ Some(delivery),
+ )
} else {
- client
- .render_state
- .prepare_pane_surface_patch(patch, surface)
+ (client.render_state.prepare_pane_surface_patch(patch), None)
};
let Some(prepared) = prepared else {
client.defer_full_render();
@@ -573,7 +570,7 @@ mod tests {
#[test]
fn retained_rows_send_only_changed_cell_spans() {
- let mut frame = FrameData {
+ let frame = FrameData {
width: 6,
height: 2,
cells: vec![cell(" "); 12],
@@ -585,8 +582,8 @@ mod tests {
rows: vec![(0, vec![cell(" "), cell("x"), cell("y"), cell(" ")])],
};
- let rows = apply_rows(
- &mut frame,
+ let rows = changed_rows(
+ &frame,
protocol::SurfaceRect {
x: 1,
y: 1,
@@ -605,13 +602,12 @@ mod tests {
cells: vec![cell("x"), cell("y"), cell(" ")],
}]
);
- assert_eq!(frame.cells[8], cell("x"));
- assert_eq!(frame.cells[9], cell("y"));
+ assert_eq!(frame.cells, vec![cell(" "); 12], "planning must not commit");
}
#[test]
fn retained_rows_include_the_cell_after_a_width_transition() {
- let mut frame = FrameData {
+ let frame = FrameData {
width: 3,
height: 1,
cells: vec![cell("界"), cell("z"), cell("q")],
@@ -623,8 +619,8 @@ mod tests {
rows: vec![(0, vec![cell("x"), cell("z"), cell("q")])],
};
- let rows = apply_rows(
- &mut frame,
+ let rows = changed_rows(
+ &frame,
protocol::SurfaceRect {
x: 0,
y: 0,
@@ -647,7 +643,7 @@ mod tests {
#[test]
fn retained_rows_omit_unchanged_full_dirty_rows() {
- let mut frame = FrameData {
+ let frame = FrameData {
width: 4,
height: 2,
cells: vec![cell(" "); 8],
@@ -659,8 +655,8 @@ mod tests {
rows: vec![(0, vec![cell(" "); 4]), (1, vec![cell(" "); 4])],
};
- let rows = apply_rows(
- &mut frame,
+ let rows = changed_rows(
+ &frame,
protocol::SurfaceRect {
x: 0,
y: 0,