chore: improce performance (#9)

Reviewed-on: https://git.reya.su/reya/signed/pulls/9
This commit was merged in pull request #9.
This commit is contained in:
2026-09-01 02:05:24 +00:00
parent d2468545d6
commit 05ab543fa0
24 changed files with 729 additions and 555 deletions
+12 -19
View File
@@ -27,11 +27,7 @@ use crate::tiles::SignedTilesSkin;
use crate::{TAB_BAR_HEIGHT, panel_handle};
/// What every part of the skin reads, and the dock area it belongs to.
///
/// The renderer is the only skin-owned object in the picture, so the settings
/// the old `DockArea` carried live here. It is shared by reference with the
/// per-container renderers, which are built once each and outlive any one
/// frame.
/// Shared by reference with the per-container renderers.
pub(crate) struct SkinShared {
area: WeakEntity<DockArea>,
toggle_button_visible: Cell<bool>,
@@ -201,10 +197,9 @@ impl DockAreaRenderer for SignedDockSkin {
.into_any_element()
}
/// The "unknown panel" message the old `InvalidPanel` drew.
///
/// It answers `dump` with the state it was handed, so a layout written by
/// a build that knows the panel survives a load and save here.
/// The "unknown panel" message the old `InvalidPanel` drew. It answers
/// `dump` with the state it was handed, so a layout written by a build
/// that knows the panel survives a load and save here.
fn build_placeholder(
&self,
state: &PanelState,
@@ -246,12 +241,10 @@ impl SignedDockSkin {
}
}
/// Turns the window's mouse stream into dock resizing.
///
/// A resize is driven by pointer moves that land anywhere in the window, not
/// only on the handle, so it cannot be expressed as a listener on the handle
/// itself. This element paints nothing and exists for its `paint` hook, which
/// is the only place a window-level mouse listener can be registered.
/// Turns the window's mouse stream into dock resizing. A resize is driven
/// by pointer moves anywhere in the window, so this paints nothing and
/// exists for its `paint` hook — the only place a window-level mouse
/// listener can be registered.
struct DockResizeTracker {
dock: DockContext,
shared: Rc<SkinShared>,
@@ -317,10 +310,10 @@ impl Element for DockResizeTracker {
if !phase.bubble() || shared.resizing_dock().get() != Some(placement) {
return;
}
// Dragging a closed dock's handle reopens it, as the old dock
// did. The live state is read rather than the render-time
// snapshot in `dock`, which would still say closed for the
// rest of the frame and toggle it shut again on the next move.
// Dragging a closed dock's handle reopens it. The live
// state is read rather than the render-time snapshot in
// `dock`, which would still say closed for the rest of the
// frame and toggle it shut again on the next move.
let open = shared
.area()
.upgrade()
+4 -6
View File
@@ -7,12 +7,10 @@ use gpui_component::ActiveTheme as _;
use crate::Panel;
/// Stands in for a panel this build cannot construct — one whose `panel_name`
/// no [`PanelRegistry`](gpui_base::dock::PanelRegistry) builder answers to.
///
/// It reports the original [`PanelState`] from
/// [`dump`](gpui_base::dock::Panel::dump), so a layout written by a build that
/// knows the panel survives a load and a save here rather than losing it.
/// Stands in for a panel this build cannot construct. It reports the
/// original [`PanelState`] from [`dump`](gpui_base::dock::Panel::dump), so
/// a layout written by a build that knows the panel survives a load and
/// save here.
pub(crate) struct InvalidPanel {
name: SharedString,
focus_handle: FocusHandle,
+5 -7
View File
@@ -1,12 +1,10 @@
//! The Signed dock skin.
//!
//! The dock engine lives upstream: `gpui_base::dock` owns the layout tree,
//! the drags, the zoom and the persistence, and `gpui_component::dock`
//! supplies the default appearance. This crate is the appearance the app
//! used to vendor from gpui-component — a 44px tab bar that doubles as the
//! window title bar, with pill tabs, window controls, title-bar dragging and
//! previous/next tab buttons — re-implemented against upstream's renderer
//! traits.
//! The dock engine lives upstream (`gpui_base::dock` owns the layout tree,
//! drags, zoom and persistence); this crate is the appearance the app used
//! to vendor from gpui-component — a 44px tab bar that doubles as the
//! window title bar, with pill tabs, window controls, title-bar dragging
//! and previous/next tab buttons.
//!
//! Everything `gpui_component::dock` exports is re-exported here, so the app
//! keeps importing the dock from a single place.
+23 -37
View File
@@ -84,11 +84,9 @@ impl Render for DragPanelPreview {
}
/// Where the zoom affordance goes for the group's displayed panel, or `None`
/// when there is none to offer.
///
/// Two questions, and both have to be asked. [`Panel::zoom_control`] says
/// *where* the control appears; [`gpui_base::dock::Panel::zoomable`] says
/// whether zooming happens at all, and base refuses a zoom that fails it.
/// when there is none to offer. Both [`Panel::zoom_control`] (where) and
/// [`gpui_base::dock::Panel::zoomable`] (whether) must pass; base refuses a
/// zoom that fails the latter.
fn zoom_control(group: &TabGroupContext, cx: &App) -> Option<PanelControl> {
let panel = group.active_panel()?;
panel
@@ -122,11 +120,8 @@ fn right_top_group(node: &PaneNode) -> Option<NodeId> {
}
}
/// One tab group's appearance.
///
/// Built per group — `DockAreaRenderer::tab_group_renderer` is called once
/// per container — so the tab bar's scroll position and the measured
/// title-bar geometry belong to the group they describe.
/// One tab group's appearance. Built once per container, so the tab bar's
/// scroll position and measured title-bar geometry belong to the group.
pub(crate) struct SignedTabGroupSkin {
shared: Rc<SkinShared>,
scroll_handle: ScrollHandle,
@@ -177,9 +172,8 @@ impl SignedTabGroupSkin {
/// The bottom or right dock whose root tab group this group is, if any.
///
/// Base bars a dock's only group from being dragged or closed, so the
/// dock cannot be emptied. A bottom/right panel is supposed to be
/// closable and movable, though — the vendored dock allowed exactly that
/// — so the skin recognizes the group and routes around the bar.
/// dock cannot be emptied — but a bottom/right panel is supposed to be
/// closable, so the skin routes around the bar for these groups.
fn is_dock_root_group(&self, group: &TabGroupContext, cx: &App) -> Option<DockPlacement> {
let area = self.shared.area().upgrade()?;
let area = area.read(cx);
@@ -270,9 +264,7 @@ impl SignedTabGroupSkin {
}
/// The previous/next tab buttons shown in the tab bar's leading prefix.
///
/// Unlike the dock toggle button they always render, but are disabled at
/// the ends of the tab strip (or while the panel is collapsed).
/// Always rendered, disabled at the ends of the strip (or collapsed).
fn render_prev_next_tab_buttons(
&self,
group: &TabGroupContext,
@@ -405,10 +397,9 @@ impl SignedTabGroupSkin {
)
}
/// One tab of the pill strip.
///
/// While collapsed, tabs lose the active style and all interactions, and
/// the strip becomes the way a closed bottom dock is opened again.
/// One tab of the pill strip. While collapsed, tabs lose the active
/// style and all interactions, and the strip becomes the way a closed
/// bottom dock is opened again.
#[allow(clippy::too_many_arguments)]
fn render_tab(
&self,
@@ -578,10 +569,8 @@ impl TabGroupRenderer for SignedTabGroupSkin {
if group.panels().is_empty() {
return div().id("tab-panel");
}
// Closing the only panel of a bottom/right dock would leave an empty
// dock, which base refuses through the group. The skin removes the
// whole dock instead — the vendored dock's close took its split
// group away just the same.
// Closing the only panel of a bottom/right dock would leave an
// empty dock, which base refuses; the skin removes the dock instead.
let dock_to_remove = (group.panels().len() <= 1)
.then(|| self.is_dock_root_group(group, cx))
.flatten();
@@ -601,8 +590,8 @@ impl TabGroupRenderer for SignedTabGroupSkin {
this.on_action({
let group = group.clone();
move |_: &ToggleZoom, window, cx| {
// The affordance decides the control, so a panel that
// offers none is not zoomed *in* by the keybinding
// The affordance decides the control, so a panel
// offering none is not zoomed *in* by the keybinding
// either. Zooming out is never refused: a panel that
// stopped offering the control while zoomed would
// otherwise strand the user with no way back.
@@ -671,12 +660,10 @@ impl TabGroupRenderer for SignedTabGroupSkin {
let right_dock_button = self.dock_toggle_button(DockPlacement::Right, group, cx);
let is_bottom_dock = bottom_dock_button.is_some();
// macOS: the traffic lights overlay the window's top-left corner. Only
// the group whose tab bar actually sits under them must reserve the
// space: the left dock (sidebar) normally clears them, and when it is
// closed or absent it is the center's left-most, top-most tab group
// that is in the corner. A bottom or right dock is never there, and
// neither is the right panel of a center split.
// macOS: the traffic lights overlay the window's top-left corner.
// Only the group whose tab bar actually sits under them reserves the
// space the center's left-most, top-most group when the left dock
// is closed or absent.
let needs_traffic_light_padding = cfg!(target_os = "macos")
&& self.shared.area().upgrade().is_some_and(|area| {
let area = area.read(cx);
@@ -703,11 +690,10 @@ impl TabGroupRenderer for SignedTabGroupSkin {
self.scroll_handle.scroll_to_item(visible_ix);
}
// The tab strip lays out its scrollable content at content width, so
// the area after the last tab only spans `min_w_16` — the rest of the
// tab bar has no element at all. Cover that dead zone with a
// measured overlay so the whole non-interactive area can drag the
// window. Its span is [last tab's right edge, suffix's left edge].
// The tab strip lays out at content width, so the area after the
// last tab has no element. Cover that dead zone (last tab's right
// edge to suffix's left edge) with a measured overlay so the whole
// non-interactive area can drag the window.
let drag_overlay = match (
self.title_bar_bounds.get(),
self.title_bar_strip_bounds.get(),
+8 -13
View File
@@ -101,13 +101,11 @@ impl SignedTilesSkin {
})
}
/// The trailing controls of a tile's title bar.
///
/// A tile has no tab bar to hang a toolbar off, so this is where its zoom,
/// close and ellipsis menu live. The entries use click handlers rather
/// than the [`ToggleZoom`](crate::ToggleZoom) and
/// [`ClosePanel`](crate::ClosePanel) actions: those are dispatched to a
/// focused tab group, and a tile is not one.
/// The trailing controls of a tile's title bar: zoom, close and the
/// ellipsis menu. They use click handlers rather than the
/// [`ToggleZoom`](crate::ToggleZoom)/[`ClosePanel`](crate::ClosePanel)
/// actions, which are dispatched to a focused tab group — a tile is
/// not one.
fn render_tile_controls(
&self,
tile: &TileContext,
@@ -388,12 +386,9 @@ impl TilesRenderer for SignedTilesSkin {
.size_full()
}
/// The canvas scrollbar.
///
/// It has to be an overlay rather than one of the frame's own children:
/// the frame is the scroll container and base appends the tiles after
/// whatever the frame carries, so a scrollbar placed there would paint and
/// hit-test underneath every tile.
/// The canvas scrollbar. It must be an overlay: the frame is the scroll
/// container and base appends the tiles after it, so a scrollbar placed
/// inside would paint and hit-test underneath every tile.
fn render_overlay(
&self,
content: Size<Pixels>,