Checkpoint

Nathan Sobo created

Change summary

crates/collab_ui/src/collab_panel.rs               |   8 
crates/collab_ui/src/collab_titlebar_item.rs       |   9 
crates/collab_ui/src/face_pile.rs                  |  10 
crates/editor/src/element.rs                       | 365 +++++++--------
crates/editor/src/hover_popover.rs                 |   8 
crates/gpui/examples/corner_radii.rs               |  25 
crates/gpui/examples/text.rs                       |   6 
crates/gpui/src/app.rs                             |  11 
crates/gpui/src/app/window.rs                      |  13 
crates/gpui/src/elements.rs                        |  20 
crates/gpui/src/elements/align.rs                  |   5 
crates/gpui/src/elements/canvas.rs                 |   9 
crates/gpui/src/elements/clipped.rs                |  14 
crates/gpui/src/elements/component.rs              |   7 
crates/gpui/src/elements/constrained_box.rs        |  11 
crates/gpui/src/elements/container.rs              |  29 
crates/gpui/src/elements/empty.rs                  |   3 
crates/gpui/src/elements/expanded.rs               |   7 
crates/gpui/src/elements/flex.rs                   |  23 
crates/gpui/src/elements/hook.rs                   |   6 
crates/gpui/src/elements/image.rs                  |   8 
crates/gpui/src/elements/keystroke_label.rs        |   3 
crates/gpui/src/elements/label.rs                  |  11 
crates/gpui/src/elements/list.rs                   |  30 
crates/gpui/src/elements/mouse_event_handler.rs    |  31 
crates/gpui/src/elements/overlay.rs                |  39 
crates/gpui/src/elements/resizable.rs              | 111 ++--
crates/gpui/src/elements/stack.rs                  |   9 
crates/gpui/src/elements/svg.rs                    |   7 
crates/gpui/src/elements/text.rs                   |  20 
crates/gpui/src/elements/tooltip.rs                |  10 
crates/gpui/src/elements/uniform_list.rs           |  11 
crates/gpui/src/scene.rs                           |  65 +-
crates/gpui/src/text_layout.rs                     |  21 
crates/gpui2/src/adapter.rs                        |   3 
crates/gpui2/src/elements/div.rs                   |   6 
crates/gpui2/src/elements/img.rs                   |   2 
crates/gpui2/src/elements/svg.rs                   |   2 
crates/gpui2/src/elements/text.rs                  |   8 
crates/gpui2/src/paint_context.rs                  |  10 
crates/gpui2/src/style.rs                          |   4 
crates/gpui_macros/src/gpui_macros.rs              |   3 
crates/terminal_view/src/terminal_element.rs       |  44 -
crates/workspace/src/pane.rs                       |  16 
crates/workspace/src/pane/dragged_item_receiver.rs |  17 
crates/workspace/src/pane_group.rs                 |  17 
crates/workspace/src/shared_screen.rs              |   4 
crates/workspace/src/status_bar.rs                 |  11 
crates/workspace/src/workspace.rs                  |   4 
49 files changed, 490 insertions(+), 626 deletions(-)

Detailed changes

crates/collab_ui/src/collab_panel.rs 🔗

@@ -2434,14 +2434,14 @@ fn render_tree_branch(
     let cap_height = row_style.cap_height(font_cache);
     let baseline_offset = row_style.baseline_offset(font_cache) + (size.y() - line_height) / 2.;
 
-    Canvas::new(move |scene, bounds, _, _, _| {
-        scene.paint_layer(None, |scene| {
+    Canvas::new(move |bounds, _, _, cx| {
+        cx.paint_layer(None, |cx| {
             let start_x = bounds.min_x() + (bounds.width() / 2.) - (branch_style.width / 2.);
             let end_x = bounds.max_x();
             let start_y = bounds.min_y();
             let end_y = bounds.min_y() + baseline_offset - (cap_height / 2.);
 
-            scene.push_quad(gpui::Quad {
+            cx.scene().push_quad(gpui::Quad {
                 bounds: RectF::from_points(
                     vec2f(start_x, start_y),
                     vec2f(
@@ -2453,7 +2453,7 @@ fn render_tree_branch(
                 border: gpui::Border::default(),
                 corner_radii: (0.).into(),
             });
-            scene.push_quad(gpui::Quad {
+            cx.scene().push_quad(gpui::Quad {
                 bounds: RectF::from_points(
                     vec2f(start_x, end_y),
                     vec2f(end_x, end_y + branch_style.width),

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -13,8 +13,8 @@ use gpui::{
     geometry::{rect::RectF, vector::vec2f, PathBuilder},
     json::{self, ToJson},
     platform::{CursorStyle, MouseButton},
-    AppContext, Entity, ImageData, LayoutContext, ModelHandle, PaintContext, SceneBuilder,
-    Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
+    AppContext, Entity, ImageData, LayoutContext, ModelHandle, PaintContext, Subscription, View,
+    ViewContext, ViewHandle, WeakViewHandle,
 };
 use picker::PickerEvent;
 use project::{Project, RepositoryEntry};
@@ -1172,12 +1172,11 @@ impl Element<CollabTitlebarItem> for AvatarRibbon {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         _: RectF,
         _: &mut Self::LayoutState,
         _: &mut CollabTitlebarItem,
-        _: &mut PaintContext<CollabTitlebarItem>,
+        cx: &mut PaintContext<CollabTitlebarItem>,
     ) -> Self::PaintState {
         let mut path = PathBuilder::new();
         path.reset(bounds.lower_left());
@@ -1188,7 +1187,7 @@ impl Element<CollabTitlebarItem> for AvatarRibbon {
         path.line_to(bounds.upper_right() - vec2f(bounds.height(), 0.));
         path.curve_to(bounds.lower_right(), bounds.upper_right());
         path.line_to(bounds.lower_left());
-        scene.push_path(path.build(self.color, None));
+        cx.scene().push_path(path.build(self.color, None));
     }
 
     fn rect_for_text_range(

crates/collab_ui/src/face_pile.rs 🔗

@@ -7,7 +7,7 @@ use gpui::{
     },
     json::ToJson,
     serde_json::{self, json},
-    AnyElement, Axis, Element, LayoutContext, PaintContext, SceneBuilder, View, ViewContext,
+    AnyElement, Axis, Element, LayoutContext, PaintContext, View, ViewContext,
 };
 
 pub(crate) struct FacePile<V: View> {
@@ -53,7 +53,6 @@ impl<V: View> Element<V> for FacePile<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _layout: &mut Self::LayoutState,
@@ -69,9 +68,10 @@ impl<V: View> Element<V> for FacePile<V> {
             let size = face.size();
             origin_x -= size.x();
             let origin_y = origin_y + (bounds.height() - size.y()) / 2.0;
-            scene.paint_layer(None, |scene| {
-                face.paint(scene, vec2f(origin_x, origin_y), visible_bounds, view, cx);
-            });
+
+            cx.scene().push_layer(None);
+            face.paint(vec2f(origin_x, origin_y), visible_bounds, view, cx);
+            cx.scene().pop_layer();
             origin_x += self.overlap;
         }
 

crates/editor/src/element.rs 🔗

@@ -33,7 +33,7 @@ use gpui::{
     platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},
     text_layout::{self, Line, RunStyle, TextLayoutCache},
     AnyElement, Axis, CursorRegion, Element, EventContext, FontCache, LayoutContext, MouseRegion,
-    PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WindowContext,
+    PaintContext, Quad, SizeConstraint, ViewContext, WindowContext,
 };
 use itertools::Itertools;
 use json::json;
@@ -131,7 +131,6 @@ impl EditorElement {
     }
 
     fn attach_mouse_handlers(
-        scene: &mut SceneBuilder,
         position_map: &Arc<PositionMap>,
         has_popovers: bool,
         visible_bounds: RectF,
@@ -141,124 +140,124 @@ impl EditorElement {
         cx: &mut ViewContext<Editor>,
     ) {
         enum EditorElementMouseHandlers {}
-        scene.push_mouse_region(
-            MouseRegion::new::<EditorElementMouseHandlers>(
-                cx.view_id(),
-                cx.view_id(),
-                visible_bounds,
-            )
-            .on_down(MouseButton::Left, {
-                let position_map = position_map.clone();
-                move |event, editor, cx| {
-                    if !Self::mouse_down(
-                        editor,
-                        event.platform_event,
-                        position_map.as_ref(),
-                        text_bounds,
-                        gutter_bounds,
-                        cx,
-                    ) {
-                        cx.propagate_event();
-                    }
-                }
-            })
-            .on_down(MouseButton::Right, {
-                let position_map = position_map.clone();
-                move |event, editor, cx| {
-                    if !Self::mouse_right_down(
-                        editor,
-                        event.position,
-                        position_map.as_ref(),
-                        text_bounds,
-                        cx,
-                    ) {
-                        cx.propagate_event();
+        let view_id = cx.view_id();
+        cx.scene().push_mouse_region(
+            MouseRegion::new::<EditorElementMouseHandlers>(view_id, view_id, visible_bounds)
+                .on_down(MouseButton::Left, {
+                    let position_map = position_map.clone();
+                    move |event, editor, cx| {
+                        if !Self::mouse_down(
+                            editor,
+                            event.platform_event,
+                            position_map.as_ref(),
+                            text_bounds,
+                            gutter_bounds,
+                            cx,
+                        ) {
+                            cx.propagate_event();
+                        }
                     }
-                }
-            })
-            .on_up(MouseButton::Left, {
-                let position_map = position_map.clone();
-                move |event, editor, cx| {
-                    if !Self::mouse_up(
-                        editor,
-                        event.position,
-                        event.cmd,
-                        event.shift,
-                        event.alt,
-                        position_map.as_ref(),
-                        text_bounds,
-                        cx,
-                    ) {
-                        cx.propagate_event()
+                })
+                .on_down(MouseButton::Right, {
+                    let position_map = position_map.clone();
+                    move |event, editor, cx| {
+                        if !Self::mouse_right_down(
+                            editor,
+                            event.position,
+                            position_map.as_ref(),
+                            text_bounds,
+                            cx,
+                        ) {
+                            cx.propagate_event();
+                        }
                     }
-                }
-            })
-            .on_drag(MouseButton::Left, {
-                let position_map = position_map.clone();
-                move |event, editor, cx| {
-                    if event.end {
-                        return;
+                })
+                .on_up(MouseButton::Left, {
+                    let position_map = position_map.clone();
+                    move |event, editor, cx| {
+                        if !Self::mouse_up(
+                            editor,
+                            event.position,
+                            event.cmd,
+                            event.shift,
+                            event.alt,
+                            position_map.as_ref(),
+                            text_bounds,
+                            cx,
+                        ) {
+                            cx.propagate_event()
+                        }
                     }
+                })
+                .on_drag(MouseButton::Left, {
+                    let position_map = position_map.clone();
+                    move |event, editor, cx| {
+                        if event.end {
+                            return;
+                        }
 
-                    if !Self::mouse_dragged(
-                        editor,
-                        event.platform_event,
-                        position_map.as_ref(),
-                        text_bounds,
-                        cx,
-                    ) {
-                        cx.propagate_event()
+                        if !Self::mouse_dragged(
+                            editor,
+                            event.platform_event,
+                            position_map.as_ref(),
+                            text_bounds,
+                            cx,
+                        ) {
+                            cx.propagate_event()
+                        }
                     }
-                }
-            })
-            .on_move({
-                let position_map = position_map.clone();
-                move |event, editor, cx| {
-                    if !Self::mouse_moved(
-                        editor,
-                        event.platform_event,
-                        &position_map,
-                        text_bounds,
-                        cx,
-                    ) {
-                        cx.propagate_event()
+                })
+                .on_move({
+                    let position_map = position_map.clone();
+                    move |event, editor, cx| {
+                        if !Self::mouse_moved(
+                            editor,
+                            event.platform_event,
+                            &position_map,
+                            text_bounds,
+                            cx,
+                        ) {
+                            cx.propagate_event()
+                        }
                     }
-                }
-            })
-            .on_move_out(move |_, editor: &mut Editor, cx| {
-                if has_popovers {
-                    hide_hover(editor, cx);
-                }
-            })
-            .on_scroll({
-                let position_map = position_map.clone();
-                move |event, editor, cx| {
-                    if !Self::scroll(
-                        editor,
-                        event.position,
-                        *event.delta.raw(),
-                        event.delta.precise(),
-                        &position_map,
-                        bounds,
-                        cx,
-                    ) {
-                        cx.propagate_event()
+                })
+                .on_move_out(move |_, editor: &mut Editor, cx| {
+                    if has_popovers {
+                        hide_hover(editor, cx);
                     }
-                }
-            }),
+                })
+                .on_scroll({
+                    let position_map = position_map.clone();
+                    move |event, editor, cx| {
+                        if !Self::scroll(
+                            editor,
+                            event.position,
+                            *event.delta.raw(),
+                            event.delta.precise(),
+                            &position_map,
+                            bounds,
+                            cx,
+                        ) {
+                            cx.propagate_event()
+                        }
+                    }
+                }),
         );
 
         enum GutterHandlers {}
-        scene.push_mouse_region(
-            MouseRegion::new::<GutterHandlers>(cx.view_id(), cx.view_id() + 1, gutter_bounds)
-                .on_hover(|hover, editor: &mut Editor, cx| {
+        let view_id = cx.view_id();
+        let region_id = cx.view_id() + 1;
+        cx.scene().push_mouse_region(
+            MouseRegion::new::<GutterHandlers>(view_id, region_id, gutter_bounds).on_hover(
+                |hover, editor: &mut Editor, cx| {
                     editor.gutter_hover(
                         &GutterHover {
                             hovered: hover.started,
                         },
                         cx,
                     );
-                }),
+                },
+            ),
         )
     }
 
@@ -528,21 +527,21 @@ impl EditorElement {
 
     fn paint_background(
         &self,
-        scene: &mut SceneBuilder,
         gutter_bounds: RectF,
         text_bounds: RectF,
         layout: &LayoutState,
+        cx: &mut ViewContext<Editor>,
     ) {
         let bounds = gutter_bounds.union_rect(text_bounds);
         let scroll_top =
             layout.position_map.snapshot.scroll_position().y() * layout.position_map.line_height;
-        scene.push_quad(Quad {
+        cx.scene().push_quad(Quad {
             bounds: gutter_bounds,
             background: Some(self.style.gutter_background),
             border: Border::new(0., Color::transparent_black()).into(),
             corner_radii: Default::default(),
         });
-        scene.push_quad(Quad {
+        cx.scene().push_quad(Quad {
             bounds: text_bounds,
             background: Some(self.style.background),
             border: Border::new(0., Color::transparent_black()).into(),
@@ -570,7 +569,7 @@ impl EditorElement {
                         bounds.width(),
                         layout.position_map.line_height * (end_row - start_row + 1) as f32,
                     );
-                    scene.push_quad(Quad {
+                    cx.scene().push_quad(Quad {
                         bounds: RectF::new(origin, size),
                         background: Some(self.style.active_line_background),
                         border: Border::default().into(),
@@ -590,7 +589,7 @@ impl EditorElement {
                     bounds.width(),
                     layout.position_map.line_height * highlighted_rows.len() as f32,
                 );
-                scene.push_quad(Quad {
+                cx.scene().push_quad(Quad {
                     bounds: RectF::new(origin, size),
                     background: Some(self.style.highlighted_line_background),
                     border: Border::default().into(),
@@ -617,7 +616,7 @@ impl EditorElement {
                 } else {
                     self.style.wrap_guide
                 };
-                scene.push_quad(Quad {
+                cx.scene().push_quad(Quad {
                     bounds: RectF::new(
                         vec2f(x, text_bounds.origin_y()),
                         vec2f(1., text_bounds.height()),
@@ -632,7 +631,6 @@ impl EditorElement {
 
     fn paint_gutter(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut LayoutState,
@@ -650,7 +648,7 @@ impl EditorElement {
         );
 
         if show_gutter {
-            Self::paint_diff_hunks(scene, bounds, layout, cx);
+            Self::paint_diff_hunks(bounds, layout, cx);
         }
 
         for (ix, line) in layout.line_number_layouts.iter().enumerate() {
@@ -661,7 +659,7 @@ impl EditorElement {
                         ix as f32 * line_height - (scroll_top % line_height),
                     );
 
-                line.paint(scene, line_origin, visible_bounds, line_height, cx);
+                line.paint(line_origin, visible_bounds, line_height, cx);
             }
         }
 
@@ -678,7 +676,7 @@ impl EditorElement {
 
                 let indicator_origin = bounds.origin() + position + centering_offset;
 
-                indicator.paint(scene, indicator_origin, visible_bounds, editor, cx);
+                indicator.paint(indicator_origin, visible_bounds, editor, cx);
             }
         }
 
@@ -687,22 +685,11 @@ impl EditorElement {
             let mut y = *row as f32 * line_height - scroll_top;
             x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
             y += (line_height - indicator.size().y()) / 2.;
-            indicator.paint(
-                scene,
-                bounds.origin() + vec2f(x, y),
-                visible_bounds,
-                editor,
-                cx,
-            );
+            indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, editor, cx);
         }
     }
 
-    fn paint_diff_hunks(
-        scene: &mut SceneBuilder,
-        bounds: RectF,
-        layout: &mut LayoutState,
-        cx: &mut ViewContext<Editor>,
-    ) {
+    fn paint_diff_hunks(bounds: RectF, layout: &mut LayoutState, cx: &mut ViewContext<Editor>) {
         let diff_style = &theme::current(cx).editor.diff.clone();
         let line_height = layout.position_map.line_height;
 
@@ -721,7 +708,7 @@ impl EditorElement {
                     let highlight_size = vec2f(width * 2., end_y - start_y);
                     let highlight_bounds = RectF::new(highlight_origin, highlight_size);
 
-                    scene.push_quad(Quad {
+                    cx.scene().push_quad(Quad {
                         bounds: highlight_bounds,
                         background: Some(diff_style.modified),
                         border: Border::new(0., Color::transparent_black()).into(),
@@ -754,7 +741,7 @@ impl EditorElement {
                     let highlight_size = vec2f(width * 2., end_y - start_y);
                     let highlight_bounds = RectF::new(highlight_origin, highlight_size);
 
-                    scene.push_quad(Quad {
+                    cx.scene().push_quad(Quad {
                         bounds: highlight_bounds,
                         background: Some(diff_style.deleted),
                         border: Border::new(0., Color::transparent_black()).into(),
@@ -776,7 +763,7 @@ impl EditorElement {
             let highlight_size = vec2f(width * 2., end_y - start_y);
             let highlight_bounds = RectF::new(highlight_origin, highlight_size);
 
-            scene.push_quad(Quad {
+            cx.scene().push_quad(Quad {
                 bounds: highlight_bounds,
                 background: Some(color),
                 border: Border::new(0., Color::transparent_black()).into(),
@@ -787,7 +774,6 @@ impl EditorElement {
 
     fn paint_text(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut LayoutState,
@@ -804,9 +790,9 @@ impl EditorElement {
         let line_end_overshoot = 0.15 * layout.position_map.line_height;
         let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
 
-        scene.push_layer(Some(bounds));
+        cx.scene().push_layer(Some(bounds));
 
-        scene.push_cursor_region(CursorRegion {
+        cx.scene().push_cursor_region(CursorRegion {
             bounds,
             style: if !editor.link_go_to_definition_state.definitions.is_empty() {
                 CursorStyle::PointingHand
@@ -819,7 +805,6 @@ impl EditorElement {
             self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
         for (id, range, color) in layout.fold_ranges.iter() {
             self.paint_highlighted_range(
-                scene,
                 range.clone(),
                 *color,
                 fold_corner_radius,
@@ -829,6 +814,7 @@ impl EditorElement {
                 scroll_top,
                 scroll_left,
                 bounds,
+                cx,
             );
 
             for bound in range_to_bounds(
@@ -840,7 +826,7 @@ impl EditorElement {
                 line_end_overshoot,
                 &layout.position_map,
             ) {
-                scene.push_cursor_region(CursorRegion {
+                cx.scene().push_cursor_region(CursorRegion {
                     bounds: bound,
                     style: CursorStyle::PointingHand,
                 });
@@ -851,8 +837,9 @@ impl EditorElement {
                     .to_point(&layout.position_map.snapshot.display_snapshot)
                     .row;
 
-                scene.push_mouse_region(
-                    MouseRegion::new::<FoldMarkers>(cx.view_id(), *id as usize, bound)
+                let view_id = cx.view_id();
+                cx.scene().push_mouse_region(
+                    MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
                         .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
                             editor.unfold_at(&UnfoldAt { buffer_row }, cx)
                         })
@@ -864,7 +851,6 @@ impl EditorElement {
 
         for (range, color) in &layout.highlighted_ranges {
             self.paint_highlighted_range(
-                scene,
                 range.clone(),
                 *color,
                 0.,
@@ -874,6 +860,7 @@ impl EditorElement {
                 scroll_top,
                 scroll_left,
                 bounds,
+                cx,
             );
         }
 
@@ -891,7 +878,6 @@ impl EditorElement {
 
             for selection in selections {
                 self.paint_highlighted_range(
-                    scene,
                     selection.range.clone(),
                     selection_style.selection,
                     corner_radius,
@@ -901,6 +887,7 @@ impl EditorElement {
                     scroll_top,
                     scroll_left,
                     bounds,
+                    cx,
                 );
 
                 if selection.is_local && !selection.range.is_empty() {
@@ -980,7 +967,6 @@ impl EditorElement {
                     layout,
                     row,
                     scroll_top,
-                    scene,
                     content_origin,
                     scroll_left,
                     visible_text_bounds,
@@ -992,14 +978,14 @@ impl EditorElement {
             }
         }
 
-        scene.paint_layer(Some(bounds), |scene| {
-            for cursor in cursors {
-                cursor.paint(scene, content_origin, cx);
-            }
-        });
+        cx.scene().push_layer(Some(bounds));
+        for cursor in cursors {
+            cursor.paint(content_origin, cx);
+        }
+        cx.scene().pop_layer();
 
         if let Some((position, context_menu)) = layout.context_menu.as_mut() {
-            scene.push_stacking_context(None, None);
+            cx.scene().push_stacking_context(None, None);
             let cursor_row_layout =
                 &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
             let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
@@ -1019,18 +1005,17 @@ impl EditorElement {
             }
 
             context_menu.paint(
-                scene,
                 list_origin,
                 RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
                 editor,
                 cx,
             );
 
-            scene.pop_stacking_context();
+            cx.scene().pop_stacking_context();
         }
 
         if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
-            scene.push_stacking_context(None, None);
+            cx.scene().push_stacking_context(None, None);
 
             // This is safe because we check on layout whether the required row is available
             let hovered_row_layout =
@@ -1061,7 +1046,6 @@ impl EditorElement {
                     }
 
                     hover_popover.paint(
-                        scene,
                         popover_origin,
                         RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
                         editor,
@@ -1083,7 +1067,6 @@ impl EditorElement {
                     }
 
                     hover_popover.paint(
-                        scene,
                         popover_origin,
                         RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
                         editor,
@@ -1094,10 +1077,10 @@ impl EditorElement {
                 }
             }
 
-            scene.pop_stacking_context();
+            cx.scene().pop_stacking_context();
         }
 
-        scene.pop_layer();
+        cx.scene().pop_layer();
     }
 
     fn scrollbar_left(&self, bounds: &RectF) -> f32 {
@@ -1106,11 +1089,10 @@ impl EditorElement {
 
     fn paint_scrollbar(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         layout: &mut LayoutState,
-        cx: &mut ViewContext<Editor>,
         editor: &Editor,
+        cx: &mut ViewContext<Editor>,
     ) {
         enum ScrollbarMouseHandlers {}
         if layout.mode != EditorMode::Full {
@@ -1147,7 +1129,7 @@ impl EditorElement {
         let thumb_bounds = RectF::from_points(vec2f(left, thumb_top), vec2f(right, thumb_bottom));
 
         if layout.show_scrollbars {
-            scene.push_quad(Quad {
+            cx.scene().push_quad(Quad {
                 bounds: track_bounds,
                 border: style.track.border.into(),
                 background: style.track.background_color,
@@ -1177,7 +1159,7 @@ impl EditorElement {
                     }
                     let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y));
 
-                    scene.push_quad(Quad {
+                    cx.scene().push_quad(Quad {
                         bounds,
                         background: Some(color),
                         border: border.into(),
@@ -1237,7 +1219,7 @@ impl EditorElement {
                         left: true,
                     };
 
-                    scene.push_quad(Quad {
+                    cx.scene().push_quad(Quad {
                         bounds,
                         background: Some(color),
                         border: border.into(),
@@ -1246,7 +1228,7 @@ impl EditorElement {
                 }
             }
 
-            scene.push_quad(Quad {
+            cx.scene().push_quad(Quad {
                 bounds: thumb_bounds,
                 border: style.thumb.border.into(),
                 background: style.thumb.background_color,
@@ -1254,12 +1236,13 @@ impl EditorElement {
             });
         }
 
-        scene.push_cursor_region(CursorRegion {
+        cx.scene().push_cursor_region(CursorRegion {
             bounds: track_bounds,
             style: CursorStyle::Arrow,
         });
-        scene.push_mouse_region(
-            MouseRegion::new::<ScrollbarMouseHandlers>(cx.view_id(), cx.view_id(), track_bounds)
+        let region_id = cx.view_id();
+        cx.scene().push_mouse_region(
+            MouseRegion::new::<ScrollbarMouseHandlers>(region_id, region_id, track_bounds)
                 .on_move(move |event, editor: &mut Editor, cx| {
                     if event.pressed_button.is_none() {
                         editor.scroll_manager.show_scrollbar(cx);
@@ -1305,7 +1288,6 @@ impl EditorElement {
     #[allow(clippy::too_many_arguments)]
     fn paint_highlighted_range(
         &self,
-        scene: &mut SceneBuilder,
         range: Range<DisplayPoint>,
         color: Color,
         corner_radius: f32,
@@ -1315,6 +1297,7 @@ impl EditorElement {
         scroll_top: f32,
         scroll_left: f32,
         bounds: RectF,
+        cx: &mut ViewContext<Editor>,
     ) {
         let start_row = layout.visible_display_row_range.start;
         let end_row = layout.visible_display_row_range.end;
@@ -1358,13 +1341,12 @@ impl EditorElement {
                     .collect(),
             };
 
-            highlighted_range.paint(bounds, scene);
+            highlighted_range.paint(bounds, cx);
         }
     }
 
     fn paint_blocks(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut LayoutState,
@@ -1384,9 +1366,7 @@ impl EditorElement {
             if !matches!(block.style, BlockStyle::Sticky) {
                 origin += vec2f(-scroll_left, 0.);
             }
-            block
-                .element
-                .paint(scene, origin, visible_bounds, editor, cx);
+            block.element.paint(origin, visible_bounds, editor, cx);
         }
     }
 
@@ -2022,7 +2002,6 @@ impl LineWithInvisibles {
         layout: &LayoutState,
         row: u32,
         scroll_top: f32,
-        scene: &mut SceneBuilder,
         content_origin: Vector2F,
         scroll_left: f32,
         visible_text_bounds: RectF,
@@ -2035,7 +2014,6 @@ impl LineWithInvisibles {
         let line_y = row as f32 * line_height - scroll_top;
 
         self.line.paint(
-            scene,
             content_origin + vec2f(-scroll_left, line_y),
             visible_text_bounds,
             line_height,
@@ -2049,7 +2027,6 @@ impl LineWithInvisibles {
             scroll_left,
             line_y,
             row,
-            scene,
             visible_bounds,
             line_height,
             whitespace_setting,
@@ -2065,7 +2042,6 @@ impl LineWithInvisibles {
         scroll_left: f32,
         line_y: f32,
         row: u32,
-        scene: &mut SceneBuilder,
         visible_bounds: RectF,
         line_height: f32,
         whitespace_setting: ShowWhitespaceSetting,
@@ -2097,7 +2073,7 @@ impl LineWithInvisibles {
                     continue;
                 }
             }
-            invisible_symbol.paint(scene, origin, visible_bounds, line_height, cx);
+            invisible_symbol.paint(origin, visible_bounds, line_height, cx);
         }
     }
 }
@@ -2590,7 +2566,6 @@ impl Element<Editor> for EditorElement {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
@@ -2598,7 +2573,7 @@ impl Element<Editor> for EditorElement {
         cx: &mut PaintContext<Editor>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
-        scene.push_layer(Some(visible_bounds));
+        cx.scene().push_layer(Some(visible_bounds));
 
         let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size);
         let text_bounds = RectF::new(
@@ -2607,7 +2582,6 @@ impl Element<Editor> for EditorElement {
         );
 
         Self::attach_mouse_handlers(
-            scene,
             &layout.position_map,
             layout.hover_popovers.is_some(),
             visible_bounds,
@@ -2617,20 +2591,19 @@ impl Element<Editor> for EditorElement {
             cx,
         );
 
-        self.paint_background(scene, gutter_bounds, text_bounds, layout);
+        self.paint_background(gutter_bounds, text_bounds, layout, cx);
         if layout.gutter_size.x() > 0. {
-            self.paint_gutter(scene, gutter_bounds, visible_bounds, layout, editor, cx);
+            self.paint_gutter(gutter_bounds, visible_bounds, layout, editor, cx);
         }
-        self.paint_text(scene, text_bounds, visible_bounds, layout, editor, cx);
+        self.paint_text(text_bounds, visible_bounds, layout, editor, cx);
 
-        scene.push_layer(Some(bounds));
+        cx.scene().push_layer(Some(bounds));
         if !layout.blocks.is_empty() {
-            self.paint_blocks(scene, bounds, visible_bounds, layout, editor, cx);
+            self.paint_blocks(bounds, visible_bounds, layout, editor, cx);
         }
-        self.paint_scrollbar(scene, bounds, layout, cx, &editor);
-        scene.pop_layer();
-
-        scene.pop_layer();
+        self.paint_scrollbar(bounds, layout, &editor, cx);
+        cx.scene().pop_layer();
+        cx.scene().pop_layer();
     }
 
     fn rect_for_text_range(
@@ -2873,7 +2846,7 @@ impl Cursor {
         )
     }
 
-    pub fn paint(&self, scene: &mut SceneBuilder, origin: Vector2F, cx: &mut WindowContext) {
+    pub fn paint(&self, origin: Vector2F, cx: &mut WindowContext) {
         let bounds = match self.shape {
             CursorShape::Bar => RectF::new(self.origin + origin, vec2f(2.0, self.line_height)),
             CursorShape::Block | CursorShape::Hollow => RectF::new(
@@ -2888,14 +2861,14 @@ impl Cursor {
 
         //Draw background or border quad
         if matches!(self.shape, CursorShape::Hollow) {
-            scene.push_quad(Quad {
+            cx.scene().push_quad(Quad {
                 bounds,
                 background: None,
                 border: Border::all(1., self.color).into(),
                 corner_radii: Default::default(),
             });
         } else {
-            scene.push_quad(Quad {
+            cx.scene().push_quad(Quad {
                 bounds,
                 background: Some(self.color),
                 border: Default::default(),
@@ -2904,7 +2877,7 @@ impl Cursor {
         }
 
         if let Some(block_text) = &self.block_text {
-            block_text.paint(scene, self.origin + origin, bounds, self.line_height, cx);
+            block_text.paint(self.origin + origin, bounds, self.line_height, cx);
         }
     }
 
@@ -2929,17 +2902,17 @@ pub struct HighlightedRangeLine {
 }
 
 impl HighlightedRange {
-    pub fn paint(&self, bounds: RectF, scene: &mut SceneBuilder) {
+    pub fn paint(&self, bounds: RectF, cx: &mut WindowContext) {
         if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x {
-            self.paint_lines(self.start_y, &self.lines[0..1], bounds, scene);
+            self.paint_lines(self.start_y, &self.lines[0..1], bounds, cx);
             self.paint_lines(
                 self.start_y + self.line_height,
                 &self.lines[1..],
                 bounds,
-                scene,
+                cx,
             );
         } else {
-            self.paint_lines(self.start_y, &self.lines, bounds, scene);
+            self.paint_lines(self.start_y, &self.lines, bounds, cx);
         }
     }
 
@@ -2948,7 +2921,7 @@ impl HighlightedRange {
         start_y: f32,
         lines: &[HighlightedRangeLine],
         bounds: RectF,
-        scene: &mut SceneBuilder,
+        cx: &mut WindowContext,
     ) {
         if lines.is_empty() {
             return;
@@ -3046,7 +3019,7 @@ impl HighlightedRange {
         }
         path.line_to(first_top_right - top_curve_width);
 
-        scene.push_path(path.build(self.color, Some(bounds)));
+        cx.scene().push_path(path.build(self.color, Some(bounds)));
     }
 }
 
@@ -3368,11 +3341,9 @@ mod tests {
         );
 
         // Don't panic.
-        let mut scene = SceneBuilder::new(1.0);
         let bounds = RectF::new(Default::default(), size);
         editor.update(cx, |editor, cx| {
             element.paint(
-                &mut scene,
                 bounds,
                 bounds,
                 &mut state,

crates/editor/src/hover_popover.rs 🔗

@@ -691,15 +691,15 @@ impl InfoPopover {
                         .with_highlights(rendered_content.highlights.clone())
                         .with_custom_runs(
                             rendered_content.region_ranges.clone(),
-                            move |ix, bounds, scene, _| {
+                            move |ix, bounds, cx| {
                                 region_id += 1;
                                 let region = regions[ix].clone();
                                 if let Some(url) = region.link_url {
-                                    scene.push_cursor_region(CursorRegion {
+                                    cx.scene().push_cursor_region(CursorRegion {
                                         bounds,
                                         style: CursorStyle::PointingHand,
                                     });
-                                    scene.push_mouse_region(
+                                    cx.scene().push_mouse_region(
                                         MouseRegion::new::<Self>(view_id, region_id, bounds)
                                             .on_click::<Editor, _>(
                                                 MouseButton::Left,
@@ -708,7 +708,7 @@ impl InfoPopover {
                                     );
                                 }
                                 if region.code {
-                                    scene.push_quad(gpui::Quad {
+                                    cx.scene().push_quad(gpui::Quad {
                                         bounds,
                                         background: Some(code_span_background_color),
                                         border: Default::default(),

crates/gpui/examples/corner_radii.rs 🔗

@@ -49,22 +49,21 @@ impl<V: View> gpui::Element<V> for CornersElement {
 
     fn paint(
         &mut self,
-        scene: &mut gpui::SceneBuilder,
         bounds: pathfinder_geometry::rect::RectF,
         _: pathfinder_geometry::rect::RectF,
         _: &mut Self::LayoutState,
         _: &mut V,
-        _: &mut gpui::PaintContext<V>,
+        cx: &mut gpui::PaintContext<V>,
     ) -> Self::PaintState {
-        scene.push_quad(Quad {
+        cx.scene().push_quad(Quad {
             bounds,
             background: Some(Color::white()),
             ..Default::default()
         });
 
-        scene.push_layer(None);
+        cx.scene().push_layer(None);
 
-        scene.push_quad(Quad {
+        cx.scene().push_quad(Quad {
             bounds: RectF::new(vec2f(100., 100.), vec2f(100., 100.)),
             background: Some(Color::red()),
             border: Default::default(),
@@ -74,7 +73,7 @@ impl<V: View> gpui::Element<V> for CornersElement {
             },
         });
 
-        scene.push_quad(Quad {
+        cx.scene().push_quad(Quad {
             bounds: RectF::new(vec2f(200., 100.), vec2f(100., 100.)),
             background: Some(Color::green()),
             border: Default::default(),
@@ -84,7 +83,7 @@ impl<V: View> gpui::Element<V> for CornersElement {
             },
         });
 
-        scene.push_quad(Quad {
+        cx.scene().push_quad(Quad {
             bounds: RectF::new(vec2f(100., 200.), vec2f(100., 100.)),
             background: Some(Color::blue()),
             border: Default::default(),
@@ -94,7 +93,7 @@ impl<V: View> gpui::Element<V> for CornersElement {
             },
         });
 
-        scene.push_quad(Quad {
+        cx.scene().push_quad(Quad {
             bounds: RectF::new(vec2f(200., 200.), vec2f(100., 100.)),
             background: Some(Color::yellow()),
             border: Default::default(),
@@ -104,7 +103,7 @@ impl<V: View> gpui::Element<V> for CornersElement {
             },
         });
 
-        scene.push_shadow(Shadow {
+        cx.scene().push_shadow(Shadow {
             bounds: RectF::new(vec2f(400., 100.), vec2f(100., 100.)),
             corner_radii: gpui::scene::CornerRadii {
                 bottom_right: 20.,
@@ -114,8 +113,8 @@ impl<V: View> gpui::Element<V> for CornersElement {
             color: Color::black(),
         });
 
-        scene.push_layer(None);
-        scene.push_quad(Quad {
+        cx.scene().push_layer(None);
+        cx.scene().push_quad(Quad {
             bounds: RectF::new(vec2f(400., 100.), vec2f(100., 100.)),
             background: Some(Color::red()),
             border: Default::default(),
@@ -125,8 +124,8 @@ impl<V: View> gpui::Element<V> for CornersElement {
             },
         });
 
-        scene.pop_layer();
-        scene.pop_layer();
+        cx.scene().pop_layer();
+        cx.scene().pop_layer();
     }
 
     fn rect_for_text_range(

crates/gpui/examples/text.rs 🔗

@@ -62,12 +62,12 @@ impl gpui::View for TextView {
             },
         )
         .with_highlights(vec![(17..26, underline), (34..40, underline)])
-        .with_custom_runs(vec![(17..26), (34..40)], move |ix, bounds, scene, _| {
-            scene.push_cursor_region(CursorRegion {
+        .with_custom_runs(vec![(17..26), (34..40)], move |ix, bounds, cx| {
+            cx.scene().push_cursor_region(CursorRegion {
                 bounds,
                 style: CursorStyle::PointingHand,
             });
-            scene.push_mouse_region(
+            cx.scene().push_mouse_region(
                 MouseRegion::new::<Self>(view_id, ix, bounds).on_click::<Self, _>(
                     MouseButton::Left,
                     move |_, _, _| {

crates/gpui/src/app.rs 🔗

@@ -28,6 +28,7 @@ use collections::{hash_map::Entry, BTreeMap, HashMap, HashSet, VecDeque};
 use derive_more::Deref;
 pub use menu::*;
 use parking_lot::Mutex;
+use pathfinder_geometry::rect::RectF;
 use platform::Event;
 use postage::oneshot;
 #[cfg(any(test, feature = "test-support"))]
@@ -3571,6 +3572,16 @@ impl<'a, 'b, 'c, V> PaintContext<'a, 'b, 'c, V> {
     pub fn new(view_context: &'c mut ViewContext<'a, 'b, V>) -> Self {
         Self { view_context }
     }
+
+    pub fn paint_layer<F, R>(&mut self, clip_bounds: Option<RectF>, f: F) -> R
+    where
+        F: FnOnce(&mut Self) -> R,
+    {
+        self.scene().push_layer(clip_bounds);
+        let result = f(self);
+        self.scene().pop_layer();
+        result
+    }
 }
 
 impl<'a, 'b, 'c, V> Deref for PaintContext<'a, 'b, 'c, V> {

crates/gpui/src/app/window.rs 🔗

@@ -55,6 +55,7 @@ pub struct Window {
     pub(crate) invalidation: Option<WindowInvalidation>,
     pub(crate) platform_window: Box<dyn platform::Window>,
     pub(crate) rendered_views: HashMap<usize, Box<dyn AnyRootElement>>,
+    scene: SceneBuilder,
     pub(crate) text_style_stack: Vec<TextStyle>,
     pub(crate) theme_stack: Vec<Box<dyn Any>>,
     pub(crate) new_parents: HashMap<usize, usize>,
@@ -98,6 +99,7 @@ impl Window {
             inspector_enabled: false,
             platform_window,
             rendered_views: Default::default(),
+            scene: SceneBuilder::new(),
             text_style_stack: Vec::new(),
             theme_stack: Vec::new(),
             new_parents: HashMap::default(),
@@ -241,6 +243,10 @@ impl<'a> WindowContext<'a> {
             .push_back(Effect::RepaintWindow { window });
     }
 
+    pub fn scene(&mut self) -> &mut SceneBuilder {
+        &mut self.window.scene
+    }
+
     pub fn enable_inspector(&mut self) {
         self.window.inspector_enabled = true;
     }
@@ -1080,9 +1086,7 @@ impl<'a> WindowContext<'a> {
         let root_view_id = self.window.root_view().id();
         let mut rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap();
 
-        let mut scene_builder = SceneBuilder::new(scale_factor);
         rendered_root.paint(
-            &mut scene_builder,
             Vector2F::zero(),
             RectF::from_points(Vector2F::zero(), window_size),
             self,
@@ -1092,7 +1096,7 @@ impl<'a> WindowContext<'a> {
             .insert(root_view_id, rendered_root);
 
         self.window.text_layout_cache.finish_frame();
-        let mut scene = scene_builder.build();
+        let mut scene = self.window.scene.build(scale_factor);
         self.window.cursor_regions = scene.cursor_regions();
         self.window.mouse_regions = scene.mouse_regions();
         self.window.event_handlers = scene.take_event_handlers();
@@ -1696,7 +1700,6 @@ impl<V: 'static> Element<V> for ChildView {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
@@ -1705,7 +1708,7 @@ impl<V: 'static> Element<V> for ChildView {
     ) {
         if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) {
             rendered_view
-                .paint(scene, bounds.origin(), visible_bounds, cx)
+                .paint(bounds.origin(), visible_bounds, cx)
                 .log_err();
             cx.window.rendered_views.insert(self.view_id, rendered_view);
         } else {

crates/gpui/src/elements.rs 🔗

@@ -34,8 +34,8 @@ use crate::{
         rect::RectF,
         vector::{vec2f, Vector2F},
     },
-    json, Action, Entity, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, TypeTag, View,
-    ViewContext, WeakViewHandle, WindowContext,
+    json, Action, Entity, LayoutContext, PaintContext, SizeConstraint, TypeTag, View, ViewContext,
+    WeakViewHandle, WindowContext,
 };
 use anyhow::{anyhow, Result};
 use core::panic;
@@ -64,7 +64,6 @@ pub trait Element<V: 'static>: 'static {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
@@ -265,7 +264,6 @@ trait AnyElementState<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
@@ -346,7 +344,6 @@ impl<V, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
@@ -361,7 +358,6 @@ impl<V, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
             } => {
                 let bounds = RectF::new(origin, size);
                 let paint = element.paint(
-                    scene,
                     bounds,
                     visible_bounds,
                     &mut layout,
@@ -386,7 +382,6 @@ impl<V, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
             } => {
                 let bounds = RectF::new(origin, bounds.size());
                 let paint = element.paint(
-                    scene,
                     bounds,
                     visible_bounds,
                     &mut layout,
@@ -522,13 +517,12 @@ impl<V> AnyElement<V> {
 
     pub fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) {
-        self.state.paint(scene, origin, visible_bounds, view, cx);
+        self.state.paint(origin, visible_bounds, view, cx);
     }
 
     pub fn rect_for_text_range(
@@ -584,14 +578,13 @@ impl<V: 'static> Element<V> for AnyElement<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        self.paint(scene, bounds.origin(), visible_bounds, view, cx);
+        self.paint(bounds.origin(), visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(
@@ -647,7 +640,6 @@ pub trait AnyRootElement {
     fn layout(&mut self, constraint: SizeConstraint, cx: &mut WindowContext) -> Result<Vector2F>;
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         cx: &mut WindowContext,
@@ -675,7 +667,6 @@ impl<V: View> AnyRootElement for RootElement<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         cx: &mut WindowContext,
@@ -687,8 +678,7 @@ impl<V: View> AnyRootElement for RootElement<V> {
 
         view.update(cx, |view, cx| {
             let mut cx = PaintContext::new(cx);
-            self.element
-                .paint(scene, origin, visible_bounds, view, &mut cx);
+            self.element.paint(origin, visible_bounds, view, &mut cx);
             Ok(())
         })
     }

crates/gpui/src/elements/align.rs 🔗

@@ -1,7 +1,6 @@
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
-    ViewContext,
+    json, AnyElement, Element, LayoutContext, PaintContext, SizeConstraint, ViewContext,
 };
 use json::ToJson;
 
@@ -65,7 +64,6 @@ impl<V: 'static> Element<V> for Align<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
@@ -79,7 +77,6 @@ impl<V: 'static> Element<V> for Align<V> {
         let child_target = child_center + child_center * self.alignment;
 
         self.child.paint(
-            scene,
             bounds.origin() - (child_target - my_target),
             visible_bounds,
             view,

crates/gpui/src/elements/canvas.rs 🔗

@@ -3,7 +3,7 @@ use std::marker::PhantomData;
 use super::Element;
 use crate::{
     json::{self, json},
-    PaintContext, SceneBuilder, ViewContext,
+    PaintContext, ViewContext,
 };
 use json::ToJson;
 use pathfinder_geometry::{
@@ -15,7 +15,7 @@ pub struct Canvas<V, F>(F, PhantomData<V>);
 
 impl<V, F> Canvas<V, F>
 where
-    F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>),
+    F: FnMut(RectF, RectF, &mut V, &mut PaintContext<V>),
 {
     pub fn new(f: F) -> Self {
         Self(f, PhantomData)
@@ -24,7 +24,7 @@ where
 
 impl<V: 'static, F> Element<V> for Canvas<V, F>
 where
-    F: 'static + FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>),
+    F: 'static + FnMut(RectF, RectF, &mut V, &mut PaintContext<V>),
 {
     type LayoutState = ();
     type PaintState = ();
@@ -50,14 +50,13 @@ where
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        self.0(scene, bounds, visible_bounds, view, cx)
+        self.0(bounds, visible_bounds, view, cx)
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/clipped.rs 🔗

@@ -3,10 +3,7 @@ use std::ops::Range;
 use pathfinder_geometry::{rect::RectF, vector::Vector2F};
 use serde_json::json;
 
-use crate::{
-    json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
-    ViewContext,
-};
+use crate::{json, AnyElement, Element, LayoutContext, PaintContext, SizeConstraint, ViewContext};
 
 pub struct Clipped<V> {
     child: AnyElement<V>,
@@ -33,17 +30,16 @@ impl<V: 'static> Element<V> for Clipped<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        scene.paint_layer(Some(bounds), |scene| {
-            self.child
-                .paint(scene, bounds.origin(), visible_bounds, view, cx)
-        })
+        cx.scene().push_layer(Some(bounds));
+        let state = self.child.paint(bounds.origin(), visible_bounds, view, cx);
+        cx.scene().pop_layer();
+        state
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/component.rs 🔗

@@ -2,9 +2,7 @@ use std::{any::Any, marker::PhantomData};
 
 use pathfinder_geometry::{rect::RectF, vector::Vector2F};
 
-use crate::{
-    AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
-};
+use crate::{AnyElement, Element, LayoutContext, PaintContext, SizeConstraint, ViewContext};
 
 use super::Empty;
 
@@ -300,7 +298,6 @@ impl<V: 'static, C: StatefulComponent<V> + 'static> Element<V> for ComponentAdap
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
@@ -310,7 +307,7 @@ impl<V: 'static, C: StatefulComponent<V> + 'static> Element<V> for ComponentAdap
         self.element
             .as_mut()
             .expect("Layout should always be called before paint")
-            .paint(scene, bounds.origin(), visible_bounds, view, cx)
+            .paint(bounds.origin(), visible_bounds, view, cx)
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/constrained_box.rs 🔗

@@ -5,8 +5,7 @@ use serde_json::json;
 
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
-    ViewContext,
+    json, AnyElement, Element, LayoutContext, PaintContext, SizeConstraint, ViewContext,
 };
 
 pub struct ConstrainedBox<V> {
@@ -152,17 +151,15 @@ impl<V: 'static> Element<V> for ConstrainedBox<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        scene.paint_layer(Some(visible_bounds), |scene| {
-            self.child
-                .paint(scene, bounds.origin(), visible_bounds, view, cx);
-        })
+        cx.scene().push_layer(Some(visible_bounds));
+        self.child.paint(bounds.origin(), visible_bounds, view, cx);
+        cx.scene().pop_layer();
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/container.rs 🔗

@@ -10,7 +10,7 @@ use crate::{
     json::ToJson,
     platform::CursorStyle,
     scene::{self, CornerRadii, CursorRegion, Quad},
-    AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
+    AnyElement, Element, LayoutContext, PaintContext, SizeConstraint, ViewContext,
 };
 use schemars::JsonSchema;
 use serde::Deserialize;
@@ -387,7 +387,6 @@ impl<V: 'static> Element<V> for Container<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
@@ -400,7 +399,7 @@ impl<V: 'static> Element<V> for Container<V> {
         );
 
         if let Some(shadow) = self.style.shadow.as_ref() {
-            scene.push_shadow(scene::Shadow {
+            cx.scene().push_shadow(scene::Shadow {
                 bounds: quad_bounds + shadow.offset,
                 corner_radii: self.style.corner_radii,
                 sigma: shadow.blur,
@@ -410,7 +409,7 @@ impl<V: 'static> Element<V> for Container<V> {
 
         if let Some(hit_bounds) = quad_bounds.intersection(visible_bounds) {
             if let Some(style) = self.style.cursor {
-                scene.push_cursor_region(CursorRegion {
+                cx.scene().push_cursor_region(CursorRegion {
                     bounds: hit_bounds,
                     style,
                 });
@@ -421,26 +420,25 @@ impl<V: 'static> Element<V> for Container<V> {
             quad_bounds.origin() + vec2f(self.style.padding.left, self.style.padding.top);
 
         if self.style.border.overlay {
-            scene.push_quad(Quad {
+            cx.scene().push_quad(Quad {
                 bounds: quad_bounds,
                 background: self.style.background_color,
                 border: Default::default(),
                 corner_radii: self.style.corner_radii.into(),
             });
 
-            self.child
-                .paint(scene, child_origin, visible_bounds, view, cx);
+            self.child.paint(child_origin, visible_bounds, view, cx);
 
-            scene.push_layer(None);
-            scene.push_quad(Quad {
+            cx.scene().push_layer(None);
+            cx.scene().push_quad(Quad {
                 bounds: quad_bounds,
                 background: self.style.overlay_color,
                 border: self.style.border.into(),
                 corner_radii: self.style.corner_radii.into(),
             });
-            scene.pop_layer();
+            cx.scene().pop_layer();
         } else {
-            scene.push_quad(Quad {
+            cx.scene().push_quad(Quad {
                 bounds: quad_bounds,
                 background: self.style.background_color,
                 border: self.style.border.into(),
@@ -452,18 +450,17 @@ impl<V: 'static> Element<V> for Container<V> {
                     self.style.border.left_width(),
                     self.style.border.top_width(),
                 );
-            self.child
-                .paint(scene, child_origin, visible_bounds, view, cx);
+            self.child.paint(child_origin, visible_bounds, view, cx);
 
             if self.style.overlay_color.is_some() {
-                scene.push_layer(None);
-                scene.push_quad(Quad {
+                cx.scene().push_layer(None);
+                cx.scene().push_quad(Quad {
                     bounds: quad_bounds,
                     background: self.style.overlay_color,
                     border: Default::default(),
                     corner_radii: self.style.corner_radii.into(),
                 });
-                scene.pop_layer();
+                cx.scene().pop_layer();
             }
         }
     }

crates/gpui/src/elements/empty.rs 🔗

@@ -6,7 +6,7 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    LayoutContext, PaintContext, SceneBuilder, ViewContext,
+    LayoutContext, PaintContext, ViewContext,
 };
 use crate::{Element, SizeConstraint};
 
@@ -52,7 +52,6 @@ impl<V: 'static> Element<V> for Empty {
 
     fn paint(
         &mut self,
-        _: &mut SceneBuilder,
         _: RectF,
         _: RectF,
         _: &mut Self::LayoutState,

crates/gpui/src/elements/expanded.rs 🔗

@@ -2,8 +2,7 @@ use std::ops::Range;
 
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
-    ViewContext,
+    json, AnyElement, Element, LayoutContext, PaintContext, SizeConstraint, ViewContext,
 };
 use serde_json::json;
 
@@ -57,15 +56,13 @@ impl<V: 'static> Element<V> for Expanded<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        self.child
-            .paint(scene, bounds.origin(), visible_bounds, view, cx);
+        self.child.paint(bounds.origin(), visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/flex.rs 🔗

@@ -2,8 +2,8 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc};
 
 use crate::{
     json::{self, ToJson, Value},
-    AnyElement, Axis, Element, ElementStateHandle, LayoutContext, PaintContext, SceneBuilder,
-    SizeConstraint, Vector2FExt, ViewContext,
+    AnyElement, Axis, Element, ElementStateHandle, LayoutContext, PaintContext, SizeConstraint,
+    Vector2FExt, ViewContext,
 };
 use pathfinder_geometry::{
     rect::RectF,
@@ -260,7 +260,6 @@ impl<V: 'static> Element<V> for Flex<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         remaining_space: &mut Self::LayoutState,
@@ -272,14 +271,14 @@ impl<V: 'static> Element<V> for Flex<V> {
         let mut remaining_space = *remaining_space;
         let overflowing = remaining_space < 0.;
         if overflowing {
-            scene.push_layer(Some(visible_bounds));
+            cx.scene().push_layer(Some(visible_bounds));
         }
 
-        if let Some(scroll_state) = &self.scroll_state {
-            scene.push_mouse_region(
-                crate::MouseRegion::new::<Self>(scroll_state.1, 0, bounds)
+        if let Some((scroll_state, id)) = &self.scroll_state {
+            let scroll_state = scroll_state.read(cx).clone();
+            cx.scene().push_mouse_region(
+                crate::MouseRegion::new::<Self>(*id, 0, bounds)
                     .on_scroll({
-                        let scroll_state = scroll_state.0.read(cx).clone();
                         let axis = self.axis;
                         move |e, _: &mut V, cx| {
                             if remaining_space < 0. {
@@ -358,7 +357,7 @@ impl<V: 'static> Element<V> for Flex<V> {
                 aligned_child_origin
             };
 
-            child.paint(scene, aligned_child_origin, visible_bounds, view, cx);
+            child.paint(aligned_child_origin, visible_bounds, view, cx);
 
             match self.axis {
                 Axis::Horizontal => child_origin += vec2f(child.size().x() + self.spacing, 0.0),
@@ -367,7 +366,7 @@ impl<V: 'static> Element<V> for Flex<V> {
         }
 
         if overflowing {
-            scene.pop_layer();
+            cx.scene().pop_layer();
         }
     }
 
@@ -451,15 +450,13 @@ impl<V: 'static> Element<V> for FlexItem<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        self.child
-            .paint(scene, bounds.origin(), visible_bounds, view, cx)
+        self.child.paint(bounds.origin(), visible_bounds, view, cx)
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/hook.rs 🔗

@@ -3,7 +3,7 @@ use std::ops::Range;
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::json,
-    AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
+    AnyElement, Element, LayoutContext, PaintContext, SizeConstraint, ViewContext,
 };
 
 pub struct Hook<V> {
@@ -47,15 +47,13 @@ impl<V: 'static> Element<V> for Hook<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) {
-        self.child
-            .paint(scene, bounds.origin(), visible_bounds, view, cx);
+        self.child.paint(bounds.origin(), visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/image.rs 🔗

@@ -5,8 +5,7 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    scene, Element, ImageData, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
-    ViewContext,
+    scene, Element, ImageData, LayoutContext, PaintContext, SizeConstraint, ViewContext,
 };
 use schemars::JsonSchema;
 use serde::Deserialize;
@@ -92,15 +91,14 @@ impl<V: 'static> Element<V> for Image {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         _: RectF,
         layout: &mut Self::LayoutState,
         _: &mut V,
-        _: &mut PaintContext<V>,
+        cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
         if let Some(data) = layout {
-            scene.push_image(scene::Image {
+            cx.scene().push_image(scene::Image {
                 bounds,
                 border: self.style.border.into(),
                 corner_radii: self.style.corner_radius.into(),

crates/gpui/src/elements/keystroke_label.rs 🔗

@@ -61,14 +61,13 @@ impl<V: 'static> Element<V> for KeystrokeLabel {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         element: &mut AnyElement<V>,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) {
-        element.paint(scene, bounds.origin(), visible_bounds, view, cx);
+        element.paint(bounds.origin(), visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/label.rs 🔗

@@ -8,7 +8,7 @@ use crate::{
     },
     json::{ToJson, Value},
     text_layout::{Line, RunStyle},
-    Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
+    Element, LayoutContext, PaintContext, SizeConstraint, ViewContext,
 };
 use schemars::JsonSchema;
 use serde::Deserialize;
@@ -158,7 +158,6 @@ impl<V: 'static> Element<V> for Label {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         line: &mut Self::LayoutState,
@@ -166,13 +165,7 @@ impl<V: 'static> Element<V> for Label {
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
-        line.paint(
-            scene,
-            bounds.origin(),
-            visible_bounds,
-            bounds.size().y(),
-            cx,
-        )
+        line.paint(bounds.origin(), visible_bounds, bounds.size().y(), cx)
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/list.rs 🔗

@@ -4,8 +4,7 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     json::json,
-    AnyElement, Element, LayoutContext, MouseRegion, PaintContext, SceneBuilder, SizeConstraint,
-    ViewContext,
+    AnyElement, Element, LayoutContext, MouseRegion, PaintContext, SizeConstraint, ViewContext,
 };
 use std::{cell::RefCell, collections::VecDeque, fmt::Debug, ops::Range, rc::Rc};
 use sum_tree::{Bias, SumTree};
@@ -250,7 +249,6 @@ impl<V: 'static> Element<V> for List<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         scroll_top: &mut ListOffset,
@@ -258,9 +256,10 @@ impl<V: 'static> Element<V> for List<V> {
         cx: &mut PaintContext<V>,
     ) {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
-        scene.push_layer(Some(visible_bounds));
-        scene.push_mouse_region(
-            MouseRegion::new::<Self>(cx.view_id(), 0, bounds).on_scroll({
+        cx.scene().push_layer(Some(visible_bounds));
+        let view_id = cx.view_id();
+        cx.scene()
+            .push_mouse_region(MouseRegion::new::<Self>(view_id, 0, bounds).on_scroll({
                 let state = self.state.clone();
                 let height = bounds.height();
                 let scroll_top = scroll_top.clone();
@@ -274,17 +273,14 @@ impl<V: 'static> Element<V> for List<V> {
                         cx,
                     )
                 }
-            }),
-        );
+            }));
 
         let state = &mut *self.state.0.borrow_mut();
         for (element, origin) in state.visible_elements(bounds, scroll_top) {
-            element
-                .borrow_mut()
-                .paint(scene, origin, visible_bounds, view, cx);
+            element.borrow_mut().paint(origin, visible_bounds, view, cx);
         }
 
-        scene.pop_layer();
+        cx.scene().pop_layer();
     }
 
     fn rect_for_text_range(
@@ -957,15 +953,7 @@ mod tests {
             (self.size, ())
         }
 
-        fn paint(
-            &mut self,
-            _: &mut SceneBuilder,
-            _: RectF,
-            _: RectF,
-            _: &mut (),
-            _: &mut V,
-            _: &mut PaintContext<V>,
-        ) {
+        fn paint(&mut self, _: RectF, _: RectF, _: &mut (), _: &mut V, _: &mut PaintContext<V>) {
             unimplemented!()
         }
 

crates/gpui/src/elements/mouse_event_handler.rs 🔗

@@ -11,7 +11,7 @@ use crate::{
         MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
     },
     AnyElement, Element, EventContext, LayoutContext, MouseRegion, MouseState, PaintContext,
-    SceneBuilder, SizeConstraint, TypeTag, ViewContext,
+    SizeConstraint, TypeTag, ViewContext,
 };
 use serde_json::json;
 use std::ops::Range;
@@ -236,26 +236,21 @@ impl<V: 'static> MouseEventHandler<V> {
         .round_out()
     }
 
-    fn paint_regions(
-        &self,
-        scene: &mut SceneBuilder,
-        bounds: RectF,
-        visible_bounds: RectF,
-        cx: &mut ViewContext<V>,
-    ) {
+    fn paint_regions(&self, bounds: RectF, visible_bounds: RectF, cx: &mut ViewContext<V>) {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
         let hit_bounds = self.hit_bounds(visible_bounds);
 
         if let Some(style) = self.cursor_style {
-            scene.push_cursor_region(CursorRegion {
+            cx.scene().push_cursor_region(CursorRegion {
                 bounds: hit_bounds,
                 style,
             });
         }
-        scene.push_mouse_region(
+        let view_id = cx.view_id();
+        cx.scene().push_mouse_region(
             MouseRegion::from_handlers(
                 self.tag,
-                cx.view_id(),
+                view_id,
                 self.region_id,
                 hit_bounds,
                 self.handlers.clone(),
@@ -282,7 +277,6 @@ impl<V: 'static> Element<V> for MouseEventHandler<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
@@ -290,16 +284,13 @@ impl<V: 'static> Element<V> for MouseEventHandler<V> {
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
         if self.above {
-            self.child
-                .paint(scene, bounds.origin(), visible_bounds, view, cx);
-
-            scene.paint_layer(None, |scene| {
-                self.paint_regions(scene, bounds, visible_bounds, cx);
+            self.child.paint(bounds.origin(), visible_bounds, view, cx);
+            cx.paint_layer(None, |cx| {
+                self.paint_regions(bounds, visible_bounds, cx);
             });
         } else {
-            self.paint_regions(scene, bounds, visible_bounds, cx);
-            self.child
-                .paint(scene, bounds.origin(), visible_bounds, view, cx);
+            self.paint_regions(bounds, visible_bounds, cx);
+            self.child.paint(bounds.origin(), visible_bounds, view, cx);
         }
     }
 

crates/gpui/src/elements/overlay.rs 🔗

@@ -3,8 +3,8 @@ use std::ops::Range;
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::ToJson,
-    AnyElement, Axis, Element, LayoutContext, MouseRegion, PaintContext, SceneBuilder,
-    SizeConstraint, ViewContext,
+    AnyElement, Axis, Element, LayoutContext, MouseRegion, PaintContext, SizeConstraint,
+    ViewContext,
 };
 use serde_json::json;
 
@@ -138,7 +138,6 @@ impl<V: 'static> Element<V> for Overlay<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         _: RectF,
         size: &mut Self::LayoutState,
@@ -213,25 +212,23 @@ impl<V: 'static> Element<V> for Overlay<V> {
             OverlayFitMode::None => {}
         }
 
-        scene.paint_stacking_context(None, self.z_index, |scene| {
-            if self.hoverable {
-                enum OverlayHoverCapture {}
-                // Block hovers in lower stacking contexts
-                scene.push_mouse_region(MouseRegion::new::<OverlayHoverCapture>(
-                    cx.view_id(),
-                    cx.view_id(),
-                    bounds,
+        cx.scene().push_stacking_context(None, self.z_index);
+        if self.hoverable {
+            enum OverlayHoverCapture {}
+            // Block hovers in lower stacking contexts
+            let view_id = cx.view_id();
+            cx.scene()
+                .push_mouse_region(MouseRegion::new::<OverlayHoverCapture>(
+                    view_id, view_id, bounds,
                 ));
-            }
-
-            self.child.paint(
-                scene,
-                bounds.origin(),
-                RectF::new(Vector2F::zero(), cx.window_size()),
-                view,
-                cx,
-            );
-        });
+        }
+        self.child.paint(
+            bounds.origin(),
+            RectF::new(Vector2F::zero(), cx.window_size()),
+            view,
+            cx,
+        );
+        cx.scene().pop_stacking_context();
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/resizable.rs 🔗

@@ -7,7 +7,7 @@ use serde_json::json;
 use crate::{
     geometry::rect::RectF,
     platform::{CursorStyle, MouseButton},
-    AnyElement, AppContext, Axis, Element, LayoutContext, MouseRegion, PaintContext, SceneBuilder,
+    AnyElement, AppContext, Axis, Element, LayoutContext, MouseRegion, PaintContext,
     SizeConstraint, TypeTag, View, ViewContext,
 };
 
@@ -112,70 +112,70 @@ impl<V: 'static> Element<V> for Resizable<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: pathfinder_geometry::rect::RectF,
         visible_bounds: pathfinder_geometry::rect::RectF,
         constraint: &mut SizeConstraint,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        scene.push_stacking_context(None, None);
+        cx.scene().push_stacking_context(None, None);
 
         let handle_region = self.handle_side.of_rect(bounds, self.handle_size);
 
         enum ResizeHandle {}
-        scene.push_mouse_region(
-            MouseRegion::new::<ResizeHandle>(
-                cx.view_id(),
-                self.handle_side as usize,
-                handle_region,
-            )
-            .on_down(MouseButton::Left, |_, _: &mut V, _| {}) // This prevents the mouse down event from being propagated elsewhere
-            .on_click(MouseButton::Left, {
-                let on_resize = self.on_resize.clone();
-                move |click, v, cx| {
-                    if click.click_count == 2 {
-                        on_resize.borrow_mut()(v, None, cx);
+        let view_id = cx.view_id();
+        cx.scene().push_mouse_region(
+            MouseRegion::new::<ResizeHandle>(view_id, self.handle_side as usize, handle_region)
+                .on_down(MouseButton::Left, |_, _: &mut V, _| {}) // This prevents the mouse down event from being propagated elsewhere
+                .on_click(MouseButton::Left, {
+                    let on_resize = self.on_resize.clone();
+                    move |click, v, cx| {
+                        if click.click_count == 2 {
+                            on_resize.borrow_mut()(v, None, cx);
+                        }
                     }
-                }
-            })
-            .on_drag(MouseButton::Left, {
-                let bounds = bounds.clone();
-                let side = self.handle_side;
-                let prev_size = side.relevant_component(bounds.size());
-                let min_size = side.relevant_component(constraint.min);
-                let max_size = side.relevant_component(constraint.max);
-                let on_resize = self.on_resize.clone();
-                let tag = self.tag;
-                move |event, view: &mut V, cx| {
-                    if event.end {
-                        return;
+                })
+                .on_drag(MouseButton::Left, {
+                    let bounds = bounds.clone();
+                    let side = self.handle_side;
+                    let prev_size = side.relevant_component(bounds.size());
+                    let min_size = side.relevant_component(constraint.min);
+                    let max_size = side.relevant_component(constraint.max);
+                    let on_resize = self.on_resize.clone();
+                    let tag = self.tag;
+                    move |event, view: &mut V, cx| {
+                        if event.end {
+                            return;
+                        }
+
+                        let Some((bounds, _)) = get_bounds(tag, cx) else {
+                            return;
+                        };
+
+                        let new_size_raw = match side {
+                            // Handle on top side of element => Element is on bottom
+                            HandleSide::Top => {
+                                bounds.height() + bounds.origin_y() - event.position.y()
+                            }
+                            // Handle on right side of element => Element is on left
+                            HandleSide::Right => event.position.x() - bounds.lower_left().x(),
+                            // Handle on left side of element => Element is on the right
+                            HandleSide::Left => {
+                                bounds.width() + bounds.origin_x() - event.position.x()
+                            }
+                            // Handle on bottom side of element => Element is on the top
+                            HandleSide::Bottom => event.position.y() - bounds.lower_left().y(),
+                        };
+
+                        let new_size = min_size.max(new_size_raw).min(max_size).round();
+                        if new_size != prev_size {
+                            on_resize.borrow_mut()(view, Some(new_size), cx);
+                        }
                     }
-
-                    let Some((bounds, _)) = get_bounds(tag, cx) else {
-                        return;
-                    };
-
-                    let new_size_raw = match side {
-                        // Handle on top side of element => Element is on bottom
-                        HandleSide::Top => bounds.height() + bounds.origin_y() - event.position.y(),
-                        // Handle on right side of element => Element is on left
-                        HandleSide::Right => event.position.x() - bounds.lower_left().x(),
-                        // Handle on left side of element => Element is on the right
-                        HandleSide::Left => bounds.width() + bounds.origin_x() - event.position.x(),
-                        // Handle on bottom side of element => Element is on the top
-                        HandleSide::Bottom => event.position.y() - bounds.lower_left().y(),
-                    };
-
-                    let new_size = min_size.max(new_size_raw).min(max_size).round();
-                    if new_size != prev_size {
-                        on_resize.borrow_mut()(view, Some(new_size), cx);
-                    }
-                }
-            }),
+                }),
         );
 
-        scene.push_cursor_region(crate::CursorRegion {
+        cx.scene().push_cursor_region(crate::CursorRegion {
             bounds: handle_region,
             style: match self.handle_side.axis() {
                 Axis::Horizontal => CursorStyle::ResizeLeftRight,
@@ -183,10 +183,9 @@ impl<V: 'static> Element<V> for Resizable<V> {
             },
         });
 
-        scene.pop_stacking_context();
+        cx.scene().pop_stacking_context();
 
-        self.child
-            .paint(scene, bounds.origin(), visible_bounds, view, cx);
+        self.child.paint(bounds.origin(), visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(
@@ -249,7 +248,6 @@ impl<V: View, P: 'static> Element<V> for BoundsProvider<V, P> {
 
     fn paint(
         &mut self,
-        scene: &mut crate::SceneBuilder,
         bounds: pathfinder_geometry::rect::RectF,
         visible_bounds: pathfinder_geometry::rect::RectF,
         _: &mut Self::LayoutState,
@@ -260,8 +258,7 @@ impl<V: View, P: 'static> Element<V> for BoundsProvider<V, P> {
             map.0.insert(TypeTag::new::<P>(), (bounds, visible_bounds));
         });
 
-        self.child
-            .paint(scene, bounds.origin(), visible_bounds, view, cx)
+        self.child.paint(bounds.origin(), visible_bounds, view, cx)
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/stack.rs 🔗

@@ -3,7 +3,7 @@ use std::ops::Range;
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::{self, json, ToJson},
-    AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
+    AnyElement, Element, LayoutContext, PaintContext, SizeConstraint, ViewContext,
 };
 
 /// Element which renders it's children in a stack on top of each other.
@@ -52,7 +52,6 @@ impl<V: 'static> Element<V> for Stack<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
@@ -60,9 +59,9 @@ impl<V: 'static> Element<V> for Stack<V> {
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
         for child in &mut self.children {
-            scene.paint_layer(None, |scene| {
-                child.paint(scene, bounds.origin(), visible_bounds, view, cx);
-            });
+            cx.scene().push_layer(None);
+            child.paint(bounds.origin(), visible_bounds, view, cx);
+            cx.scene().pop_layer();
         }
     }
 

crates/gpui/src/elements/svg.rs 🔗

@@ -7,7 +7,7 @@ use crate::{
         rect::RectF,
         vector::{vec2f, Vector2F},
     },
-    scene, Element, LayoutContext, SceneBuilder, SizeConstraint, ViewContext,
+    scene, Element, LayoutContext, SizeConstraint, ViewContext,
 };
 use schemars::JsonSchema;
 use serde_derive::Deserialize;
@@ -69,15 +69,14 @@ impl<V: 'static> Element<V> for Svg {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         _visible_bounds: RectF,
         svg: &mut Self::LayoutState,
         _: &mut V,
-        _: &mut PaintContext<V>,
+        cx: &mut PaintContext<V>,
     ) {
         if let Some(svg) = svg.clone() {
-            scene.push_icon(scene::Icon {
+            cx.scene().push_icon(scene::Icon {
                 bounds,
                 svg,
                 path: self.path.clone(),

crates/gpui/src/elements/text.rs 🔗

@@ -7,8 +7,8 @@ use crate::{
     },
     json::{ToJson, Value},
     text_layout::{Line, RunStyle, ShapedBoundary},
-    AppContext, Element, FontCache, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
-    TextLayoutCache, ViewContext,
+    Element, FontCache, LayoutContext, PaintContext, SizeConstraint, TextLayoutCache, ViewContext,
+    WindowContext,
 };
 use log::warn;
 use serde_json::json;
@@ -21,7 +21,7 @@ pub struct Text {
     highlights: Option<Box<[(Range<usize>, HighlightStyle)]>>,
     custom_runs: Option<(
         Box<[Range<usize>]>,
-        Box<dyn FnMut(usize, RectF, &mut SceneBuilder, &mut AppContext)>,
+        Box<dyn FnMut(usize, RectF, &mut WindowContext)>,
     )>,
 }
 
@@ -58,7 +58,7 @@ impl Text {
     pub fn with_custom_runs(
         mut self,
         runs: impl Into<Box<[Range<usize>]>>,
-        callback: impl 'static + FnMut(usize, RectF, &mut SceneBuilder, &mut AppContext),
+        callback: impl 'static + FnMut(usize, RectF, &mut WindowContext),
     ) -> Self {
         self.custom_runs = Some((runs.into(), Box::new(callback)));
         self
@@ -166,7 +166,6 @@ impl<V: 'static> Element<V> for Text {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
@@ -175,7 +174,7 @@ impl<V: 'static> Element<V> for Text {
     ) -> Self::PaintState {
         let mut origin = bounds.origin();
         let empty = Vec::new();
-        let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {};
+        let mut callback = |_, _, _: &mut WindowContext| {};
 
         let mouse_runs;
         let custom_run_callback;
@@ -202,7 +201,6 @@ impl<V: 'static> Element<V> for Text {
             if boundaries.intersects(visible_bounds) {
                 if self.soft_wrap {
                     line.paint_wrapped(
-                        scene,
                         origin,
                         visible_bounds,
                         layout.line_height,
@@ -210,7 +208,7 @@ impl<V: 'static> Element<V> for Text {
                         cx,
                     );
                 } else {
-                    line.paint(scene, origin, visible_bounds, layout.line_height, cx);
+                    line.paint(origin, visible_bounds, layout.line_height, cx);
                 }
             }
 
@@ -248,7 +246,7 @@ impl<V: 'static> Element<V> for Text {
                                     *run_origin,
                                     glyph_origin + vec2f(0., layout.line_height),
                                 );
-                                custom_run_callback(*run_ix, bounds, scene, cx);
+                                custom_run_callback(*run_ix, bounds, cx);
                                 *run_origin =
                                     vec2f(origin.x(), glyph_origin.y() + layout.line_height);
                             }
@@ -264,7 +262,7 @@ impl<V: 'static> Element<V> for Text {
                                     run_origin,
                                     glyph_origin + vec2f(0., layout.line_height),
                                 );
-                                custom_run_callback(run_ix, bounds, scene, cx);
+                                custom_run_callback(run_ix, bounds, cx);
                                 custom_runs.next();
                             }
 
@@ -294,7 +292,7 @@ impl<V: 'static> Element<V> for Text {
                             run_origin,
                             line_end + vec2f(0., layout.line_height),
                         );
-                        custom_run_callback(run_ix, bounds, scene, cx);
+                        custom_run_callback(run_ix, bounds, cx);
                         if end_offset == run_end_offset {
                             custom_runs.next();
                         }

crates/gpui/src/elements/tooltip.rs 🔗

@@ -6,8 +6,8 @@ use crate::{
     fonts::TextStyle,
     geometry::{rect::RectF, vector::Vector2F},
     json::json,
-    Action, Axis, ElementStateHandle, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
-    Task, TypeTag, ViewContext,
+    Action, Axis, ElementStateHandle, LayoutContext, PaintContext, SizeConstraint, Task, TypeTag,
+    ViewContext,
 };
 use schemars::JsonSchema;
 use serde::Deserialize;
@@ -204,17 +204,15 @@ impl<V: 'static> Element<V> for Tooltip<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) {
-        self.child
-            .paint(scene, bounds.origin(), visible_bounds, view, cx);
+        self.child.paint(bounds.origin(), visible_bounds, view, cx);
         if let Some(tooltip) = self.tooltip.as_mut() {
-            tooltip.paint(scene, bounds.origin(), visible_bounds, view, cx);
+            tooltip.paint(bounds.origin(), visible_bounds, view, cx);
         }
     }
 

crates/gpui/src/elements/uniform_list.rs 🔗

@@ -6,7 +6,7 @@ use crate::{
     },
     json::{self, json},
     platform::ScrollWheelEvent,
-    AnyElement, LayoutContext, MouseRegion, PaintContext, SceneBuilder, ViewContext,
+    AnyElement, LayoutContext, MouseRegion, PaintContext, ViewContext,
 };
 use json::ToJson;
 use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
@@ -272,7 +272,6 @@ impl<V: 'static> Element<V> for UniformList<V> {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
@@ -281,9 +280,9 @@ impl<V: 'static> Element<V> for UniformList<V> {
     ) -> Self::PaintState {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
 
-        scene.push_layer(Some(visible_bounds));
+        cx.scene().push_layer(Some(visible_bounds));
 
-        scene.push_mouse_region(
+        cx.scene().push_mouse_region(
             MouseRegion::new::<Self>(self.view_id, 0, visible_bounds).on_scroll({
                 let scroll_max = layout.scroll_max;
                 let state = self.state.clone();
@@ -312,11 +311,11 @@ impl<V: 'static> Element<V> for UniformList<V> {
             );
 
         for item in &mut layout.items {
-            item.paint(scene, item_origin, visible_bounds, view, cx);
+            item.paint(item_origin, visible_bounds, view, cx);
             item_origin += vec2f(0.0, layout.item_height);
         }
 
-        scene.pop_layer();
+        cx.scene().pop_layer();
     }
 
     fn rect_for_text_range(

crates/gpui/src/scene.rs 🔗

@@ -26,7 +26,6 @@ pub use mouse_event::*;
 pub use mouse_region::*;
 
 pub struct SceneBuilder {
-    scale_factor: f32,
     stacking_contexts: Vec<StackingContext>,
     active_stacking_context_stack: Vec<usize>,
     /// Used by the gpui2 crate.
@@ -245,43 +244,38 @@ impl Scene {
 }
 
 impl SceneBuilder {
-    pub fn new(scale_factor: f32) -> Self {
-        let stacking_context = StackingContext::new(None, 0);
-        SceneBuilder {
-            scale_factor,
-            stacking_contexts: vec![stacking_context],
-            active_stacking_context_stack: vec![0],
+    pub fn new() -> Self {
+        let mut this = SceneBuilder {
+            stacking_contexts: Vec::new(),
+            active_stacking_context_stack: Vec::new(),
             #[cfg(debug_assertions)]
-            mouse_region_ids: Default::default(),
+            mouse_region_ids: HashSet::default(),
             event_handlers: Vec::new(),
-        }
+        };
+        this.clear();
+        this
     }
 
-    pub fn build(mut self) -> Scene {
-        self.stacking_contexts
-            .sort_by_key(|context| context.z_index);
-        Scene {
-            scale_factor: self.scale_factor,
-            stacking_contexts: self.stacking_contexts,
-            event_handlers: self.event_handlers,
-        }
+    pub fn clear(&mut self) {
+        self.stacking_contexts.clear();
+        self.stacking_contexts.push(StackingContext::new(None, 0));
+        self.active_stacking_context_stack.clear();
+        self.active_stacking_context_stack.push(0);
+        #[cfg(debug_assertions)]
+        self.mouse_region_ids.clear();
     }
 
-    pub fn scale_factor(&self) -> f32 {
-        self.scale_factor
-    }
+    pub fn build(&mut self, scale_factor: f32) -> Scene {
+        let mut stacking_contexts = std::mem::take(&mut self.stacking_contexts);
+        stacking_contexts.sort_by_key(|context| context.z_index);
+        let event_handlers = std::mem::take(&mut self.event_handlers);
+        self.clear();
 
-    pub fn paint_stacking_context<F>(
-        &mut self,
-        clip_bounds: Option<RectF>,
-        z_index: Option<usize>,
-        f: F,
-    ) where
-        F: FnOnce(&mut Self),
-    {
-        self.push_stacking_context(clip_bounds, z_index);
-        f(self);
-        self.pop_stacking_context();
+        Scene {
+            scale_factor,
+            stacking_contexts,
+            event_handlers,
+        }
     }
 
     pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>, z_index: Option<usize>) {
@@ -297,15 +291,6 @@ impl SceneBuilder {
         assert!(!self.active_stacking_context_stack.is_empty());
     }
 
-    pub fn paint_layer<F>(&mut self, clip_bounds: Option<RectF>, f: F)
-    where
-        F: FnOnce(&mut Self),
-    {
-        self.push_layer(clip_bounds);
-        f(self);
-        self.pop_layer();
-    }
-
     pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
         self.active_stacking_context().push_layer(clip_bounds);
     }

crates/gpui/src/text_layout.rs 🔗

@@ -9,7 +9,6 @@ use crate::{
     platform::FontSystem,
     scene,
     window::WindowContext,
-    SceneBuilder,
 };
 use ordered_float::OrderedFloat;
 use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
@@ -284,7 +283,6 @@ impl Line {
 
     pub fn paint(
         &self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         line_height: f32,
@@ -347,7 +345,7 @@ impl Line {
                 }
 
                 if let Some((underline_origin, underline_style)) = finished_underline {
-                    scene.push_underline(scene::Underline {
+                    cx.scene().push_underline(scene::Underline {
                         origin: underline_origin,
                         width: glyph_origin.x() - underline_origin.x(),
                         thickness: underline_style.thickness.into(),
@@ -357,14 +355,14 @@ impl Line {
                 }
 
                 if glyph.is_emoji {
-                    scene.push_image_glyph(scene::ImageGlyph {
+                    cx.scene().push_image_glyph(scene::ImageGlyph {
                         font_id: run.font_id,
                         font_size: self.layout.font_size,
                         id: glyph.id,
                         origin: glyph_origin,
                     });
                 } else {
-                    scene.push_glyph(scene::Glyph {
+                    cx.scene().push_glyph(scene::Glyph {
                         font_id: run.font_id,
                         font_size: self.layout.font_size,
                         id: glyph.id,
@@ -377,7 +375,7 @@ impl Line {
 
         if let Some((underline_start, underline_style)) = underline.take() {
             let line_end_x = origin.x() + self.layout.width;
-            scene.push_underline(scene::Underline {
+            cx.scene().push_underline(scene::Underline {
                 origin: underline_start,
                 width: line_end_x - underline_start.x(),
                 color: underline_style.color.unwrap(),
@@ -389,7 +387,6 @@ impl Line {
 
     pub fn paint_wrapped(
         &self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         line_height: f32,
@@ -417,7 +414,7 @@ impl Line {
                 {
                     boundaries.next();
                     if let Some((underline_origin, underline_style)) = underline {
-                        scene.push_underline(scene::Underline {
+                        cx.scene().push_underline(scene::Underline {
                             origin: underline_origin,
                             width: glyph_origin.x() - underline_origin.x(),
                             thickness: underline_style.thickness.into(),
@@ -461,7 +458,7 @@ impl Line {
                 }
 
                 if let Some((underline_origin, underline_style)) = finished_underline {
-                    scene.push_underline(scene::Underline {
+                    cx.scene().push_underline(scene::Underline {
                         origin: underline_origin,
                         width: glyph_origin.x() - underline_origin.x(),
                         thickness: underline_style.thickness.into(),
@@ -477,14 +474,14 @@ impl Line {
                 );
                 if glyph_bounds.intersects(visible_bounds) {
                     if glyph.is_emoji {
-                        scene.push_image_glyph(scene::ImageGlyph {
+                        cx.scene().push_image_glyph(scene::ImageGlyph {
                             font_id: run.font_id,
                             font_size: self.layout.font_size,
                             id: glyph.id,
                             origin: glyph_bounds.origin() + baseline_offset,
                         });
                     } else {
-                        scene.push_glyph(scene::Glyph {
+                        cx.scene().push_glyph(scene::Glyph {
                             font_id: run.font_id,
                             font_size: self.layout.font_size,
                             id: glyph.id,
@@ -498,7 +495,7 @@ impl Line {
 
         if let Some((underline_origin, underline_style)) = underline.take() {
             let line_end_x = glyph_origin.x() + self.layout.width - prev_position;
-            scene.push_underline(scene::Underline {
+            cx.scene().push_underline(scene::Underline {
                 origin: underline_origin,
                 width: line_end_x - underline_origin.x(),
                 thickness: underline_style.thickness.into(),

crates/gpui2/src/adapter.rs 🔗

@@ -36,7 +36,6 @@ impl<V: 'static> gpui::Element<V> for AdapterElement<V> {
 
     fn paint(
         &mut self,
-        scene: &mut gpui::SceneBuilder,
         bounds: RectF,
         _visible_bounds: RectF,
         layout_data: &mut Option<(LayoutEngine, LayoutId)>,
@@ -45,7 +44,7 @@ impl<V: 'static> gpui::Element<V> for AdapterElement<V> {
     ) -> Self::PaintState {
         let (layout_engine, layout_id) = layout_data.take().unwrap();
         legacy_cx.push_layout_engine(layout_engine);
-        let mut cx = PaintContext::new(legacy_cx, scene);
+        let mut cx = PaintContext::new(legacy_cx);
         self.0.paint(view, bounds.origin(), &mut cx);
         *layout_data = legacy_cx.pop_layout_engine().zip(Some(layout_id));
         debug_assert!(layout_data.is_some());

crates/gpui2/src/elements/div.rs 🔗

@@ -88,7 +88,7 @@ impl<V: 'static> Element<V> for Div<V> {
         // TODO: Support only one dimension being hidden
         let mut pop_layer = false;
         if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible {
-            cx.scene.push_layer(Some(bounds));
+            cx.scene().push_layer(Some(bounds));
             pop_layer = true;
         }
 
@@ -97,7 +97,7 @@ impl<V: 'static> Element<V> for Div<V> {
         }
 
         if pop_layer {
-            cx.scene.pop_layer();
+            cx.scene().pop_layer();
         }
 
         style.paint_foreground(bounds, cx);
@@ -221,7 +221,7 @@ impl<V: 'static> Div<V> {
         let hovered = bounds.contains_point(cx.mouse_position());
         if hovered {
             let rem_size = cx.rem_size();
-            cx.scene.push_quad(scene::Quad {
+            cx.scene().push_quad(scene::Quad {
                 bounds,
                 background: Some(hsla(0., 0., 1., 0.05).into()),
                 border: gpui::Border {

crates/gpui2/src/elements/img.rs 🔗

@@ -70,7 +70,7 @@ impl<V: 'static> Element<V> for Img {
                 .and_then(ResultExt::log_err)
             {
                 let rem_size = cx.rem_size();
-                cx.scene.push_image(scene::Image {
+                cx.scene().push_image(scene::Image {
                     bounds,
                     border: gpui::Border {
                         color: style.border_color.unwrap_or_default().into(),

crates/gpui2/src/elements/svg.rs 🔗

@@ -63,7 +63,7 @@ impl<V: 'static> Element<V> for Svg {
                     color: Rgba::from(fill_color).into(),
                 };
 
-                cx.scene.push_icon(icon);
+                cx.scene().push_icon(icon);
             }
         }
     }

crates/gpui2/src/elements/text.rs 🔗

@@ -92,13 +92,7 @@ impl<V: 'static> Element<V> for Text {
 
         // TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
         let visible_bounds = bounds;
-        line.paint(
-            cx.scene,
-            bounds.origin(),
-            visible_bounds,
-            line_height,
-            cx.legacy_cx,
-        );
+        line.paint(bounds.origin(), visible_bounds, line_height, cx.legacy_cx);
     }
 }
 

crates/gpui2/src/paint_context.rs 🔗

@@ -11,15 +11,11 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
     #[deref]
     #[deref_mut]
     pub(crate) legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
-    pub(crate) scene: &'d mut gpui::SceneBuilder,
 }
 
 impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
-    pub fn new(
-        legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
-        scene: &'d mut gpui::SceneBuilder,
-    ) -> Self {
-        Self { legacy_cx, scene }
+    pub fn new(legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>) -> Self {
+        Self { legacy_cx }
     }
 
     pub fn on_event<E: 'static>(
@@ -29,7 +25,7 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
     ) {
         let view = self.weak_handle();
 
-        self.scene.event_handlers.push(EventHandler {
+        self.scene().event_handlers.push(EventHandler {
             order,
             handler: Rc::new(move |event, window_cx| {
                 if let Some(view) = view.upgrade(window_cx) {

crates/gpui2/src/style.rs 🔗

@@ -167,7 +167,7 @@ impl Style {
     pub fn paint_background<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
         let rem_size = cx.rem_size();
         if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
-            cx.scene.push_quad(gpui::Quad {
+            cx.scene().push_quad(gpui::Quad {
                 bounds,
                 background: Some(color.into()),
                 corner_radii: self.corner_radii.to_gpui(bounds.size(), rem_size),
@@ -183,7 +183,7 @@ impl Style {
         if let Some(color) = self.border_color {
             let border = self.border_widths.to_pixels(rem_size);
             if !border.is_empty() {
-                cx.scene.push_quad(gpui::Quad {
+                cx.scene().push_quad(gpui::Quad {
                     bounds,
                     background: None,
                     corner_radii: self.corner_radii.to_gpui(bounds.size(), rem_size),

crates/gpui_macros/src/gpui_macros.rs 🔗

@@ -338,14 +338,13 @@ pub fn element_derive(input: TokenStream) -> TokenStream {
 
             fn paint(
                 &mut self,
-                scene: &mut gpui::SceneBuilder,
                 bounds: gpui::geometry::rect::RectF,
                 visible_bounds: gpui::geometry::rect::RectF,
                 element: &mut gpui::elements::AnyElement<V>,
                 view: &mut V,
                 cx: &mut gpui::PaintContext<V>,
             ) {
-                element.paint(scene, bounds.origin(), visible_bounds, view, cx);
+                element.paint(bounds.origin(), visible_bounds, view, cx);
             }
 
             fn rect_for_text_range(

crates/terminal_view/src/terminal_element.rs 🔗

@@ -11,8 +11,8 @@ use gpui::{
     serde_json::json,
     text_layout::{Line, RunStyle},
     AnyElement, Element, EventContext, FontCache, LayoutContext, ModelContext, MouseRegion,
-    PaintContext, Quad, SceneBuilder, SizeConstraint, TextLayoutCache, ViewContext,
-    WeakModelHandle,
+    PaintContext, Quad, SizeConstraint, TextLayoutCache, ViewContext, WeakModelHandle,
+    WindowContext,
 };
 use itertools::Itertools;
 use language::CursorShape;
@@ -86,12 +86,11 @@ impl LayoutCell {
 
     fn paint(
         &self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         layout: &LayoutState,
         visible_bounds: RectF,
         _view: &mut TerminalView,
-        cx: &mut ViewContext<TerminalView>,
+        cx: &mut WindowContext,
     ) {
         let pos = {
             let point = self.point;
@@ -102,7 +101,7 @@ impl LayoutCell {
         };
 
         self.text
-            .paint(scene, pos, visible_bounds, layout.size.line_height, cx);
+            .paint(pos, visible_bounds, layout.size.line_height, cx);
     }
 }
 
@@ -132,11 +131,10 @@ impl LayoutRect {
 
     fn paint(
         &self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         layout: &LayoutState,
         _view: &mut TerminalView,
-        _cx: &mut ViewContext<TerminalView>,
+        cx: &mut ViewContext<TerminalView>,
     ) {
         let position = {
             let point = self.point;
@@ -150,7 +148,7 @@ impl LayoutRect {
             layout.size.line_height,
         );
 
-        scene.push_quad(Quad {
+        cx.scene().push_quad(Quad {
             bounds: RectF::new(position, size),
             background: Some(self.color),
             border: Default::default(),
@@ -387,7 +385,6 @@ impl TerminalElement {
 
     fn attach_mouse_handlers(
         &self,
-        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         mode: TermMode,
@@ -518,7 +515,7 @@ impl TerminalElement {
                 )
         }
 
-        scene.push_mouse_region(region);
+        cx.scene().push_mouse_region(region);
     }
 }
 
@@ -733,7 +730,6 @@ impl Element<TerminalView> for TerminalElement {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
@@ -745,13 +741,13 @@ impl Element<TerminalView> for TerminalElement {
         //Setup element stuff
         let clip_bounds = Some(visible_bounds);
 
-        scene.paint_layer(clip_bounds, |scene| {
+        cx.paint_layer(clip_bounds, |cx| {
             let origin = bounds.origin() + vec2f(layout.gutter, 0.);
 
             // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
-            self.attach_mouse_handlers(scene, origin, visible_bounds, layout.mode, cx);
+            self.attach_mouse_handlers(origin, visible_bounds, layout.mode, cx);
 
-            scene.push_cursor_region(gpui::CursorRegion {
+            cx.scene().push_cursor_region(gpui::CursorRegion {
                 bounds,
                 style: if layout.hyperlink_tooltip.is_some() {
                     CursorStyle::PointingHand
@@ -760,9 +756,9 @@ impl Element<TerminalView> for TerminalElement {
                 },
             });
 
-            scene.paint_layer(clip_bounds, |scene| {
+            cx.paint_layer(clip_bounds, |cx| {
                 //Start with a background color
-                scene.push_quad(Quad {
+                cx.scene().push_quad(Quad {
                     bounds: RectF::new(bounds.origin(), bounds.size()),
                     background: Some(layout.background_color),
                     border: Default::default(),
@@ -770,12 +766,12 @@ impl Element<TerminalView> for TerminalElement {
                 });
 
                 for rect in &layout.rects {
-                    rect.paint(scene, origin, layout, view, cx)
+                    rect.paint(origin, layout, view, cx);
                 }
             });
 
             //Draw Highlighted Backgrounds
-            scene.paint_layer(clip_bounds, |scene| {
+            cx.paint_layer(clip_bounds, |cx| {
                 for (relative_highlighted_range, color) in layout.relative_highlighted_ranges.iter()
                 {
                     if let Some((start_y, highlighted_range_lines)) =
@@ -789,29 +785,29 @@ impl Element<TerminalView> for TerminalElement {
                             //Copied from editor. TODO: move to theme or something
                             corner_radius: 0.15 * layout.size.line_height,
                         };
-                        hr.paint(bounds, scene);
+                        hr.paint(bounds, cx);
                     }
                 }
             });
 
             //Draw the text cells
-            scene.paint_layer(clip_bounds, |scene| {
+            cx.paint_layer(clip_bounds, |cx| {
                 for cell in &layout.cells {
-                    cell.paint(scene, origin, layout, visible_bounds, view, cx);
+                    cell.paint(origin, layout, visible_bounds, view, cx);
                 }
             });
 
             //Draw cursor
             if self.cursor_visible {
                 if let Some(cursor) = &layout.cursor {
-                    scene.paint_layer(clip_bounds, |scene| {
-                        cursor.paint(scene, origin, cx);
+                    cx.paint_layer(clip_bounds, |cx| {
+                        cursor.paint(origin, cx);
                     })
                 }
             }
 
             if let Some(element) = &mut layout.hyperlink_tooltip {
-                element.paint(scene, origin, visible_bounds, view, cx)
+                element.paint(origin, visible_bounds, view, cx)
             }
         });
     }

crates/workspace/src/pane.rs 🔗

@@ -1440,10 +1440,10 @@ impl Pane {
                 None
             };
 
-            Canvas::new(move |scene, bounds, _, _, _| {
+            Canvas::new(move |bounds, _, _, cx| {
                 if let Some(color) = icon_color {
                     let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
-                    scene.push_quad(Quad {
+                    cx.scene().push_quad(Quad {
                         bounds: square,
                         background: Some(color),
                         border: Default::default(),
@@ -2007,7 +2007,6 @@ impl<V: 'static> Element<V> for PaneBackdrop<V> {
 
     fn paint(
         &mut self,
-        scene: &mut gpui::SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
@@ -2018,14 +2017,14 @@ impl<V: 'static> Element<V> for PaneBackdrop<V> {
 
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
-        scene.push_quad(gpui::Quad {
+        cx.scene().push_quad(gpui::Quad {
             bounds: RectF::new(bounds.origin(), bounds.size()),
             background: Some(background),
             ..Default::default()
         });
 
         let child_view_id = self.child_view;
-        scene.push_mouse_region(
+        cx.scene().push_mouse_region(
             MouseRegion::new::<Self>(child_view_id, 0, visible_bounds).on_down(
                 gpui::platform::MouseButton::Left,
                 move |_, _: &mut V, cx| {
@@ -2035,10 +2034,9 @@ impl<V: 'static> Element<V> for PaneBackdrop<V> {
             ),
         );
 
-        scene.paint_layer(Some(bounds), |scene| {
-            self.child
-                .paint(scene, bounds.origin(), visible_bounds, view, cx)
-        })
+        cx.scene().push_layer(Some(bounds));
+        self.child.paint(bounds.origin(), visible_bounds, view, cx);
+        cx.scene().pop_layer();
     }
 
     fn rect_for_text_range(

crates/workspace/src/pane/dragged_item_receiver.rs 🔗

@@ -50,7 +50,7 @@ where
         Stack::new()
             .with_child(render_child(state, cx))
             .with_children(drag_position.map(|drag_position| {
-                Canvas::new(move |scene, bounds, _, _, cx| {
+                Canvas::new(move |bounds, _, _, cx| {
                     if bounds.contains_point(drag_position) {
                         let overlay_region = split_margin
                             .and_then(|split_margin| {
@@ -60,14 +60,15 @@ where
                             .map(|(dir, margin)| dir.along_edge(bounds, margin))
                             .unwrap_or(bounds);
 
-                        scene.paint_stacking_context(None, None, |scene| {
-                            scene.push_quad(Quad {
-                                bounds: overlay_region,
-                                background: Some(overlay_color(cx)),
-                                border: Default::default(),
-                                corner_radii: Default::default(),
-                            });
+                        cx.scene().push_stacking_context(None, None);
+                        let background = overlay_color(cx);
+                        cx.scene().push_quad(Quad {
+                            bounds: overlay_region,
+                            background: Some(background),
+                            border: Default::default(),
+                            corner_radii: Default::default(),
                         });
+                        cx.scene().pop_stacking_context();
                     }
                 })
             }))

crates/workspace/src/pane_group.rs 🔗

@@ -595,7 +595,7 @@ mod element {
         platform::{CursorStyle, MouseButton},
         scene::MouseDrag,
         AnyElement, Axis, CursorRegion, Element, EventContext, LayoutContext, MouseRegion,
-        PaintContext, RectFExt, SceneBuilder, SizeConstraint, Vector2FExt, ViewContext,
+        PaintContext, RectFExt, SizeConstraint, Vector2FExt, ViewContext,
     };
 
     use crate::{
@@ -851,7 +851,6 @@ mod element {
 
         fn paint(
             &mut self,
-            scene: &mut SceneBuilder,
             bounds: RectF,
             visible_bounds: RectF,
             remaining_space: &mut Self::LayoutState,
@@ -863,7 +862,7 @@ mod element {
 
             let overflowing = *remaining_space < 0.;
             if overflowing {
-                scene.push_layer(Some(visible_bounds));
+                cx.scene().push_layer(Some(visible_bounds));
             }
 
             let mut child_origin = bounds.origin();
@@ -874,7 +873,7 @@ mod element {
             let mut children_iter = self.children.iter_mut().enumerate().peekable();
             while let Some((ix, child)) = children_iter.next() {
                 let child_start = child_origin.clone();
-                child.paint(scene, child_origin, visible_bounds, view, cx);
+                child.paint(child_origin, visible_bounds, view, cx);
 
                 bounding_boxes.push(Some(RectF::new(child_origin, child.size())));
 
@@ -884,7 +883,7 @@ mod element {
                 }
 
                 if can_resize && children_iter.peek().is_some() {
-                    scene.push_stacking_context(None, None);
+                    cx.scene().push_stacking_context(None, None);
 
                     let handle_origin = match self.axis {
                         Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0),
@@ -907,7 +906,7 @@ mod element {
                         Axis::Vertical => CursorStyle::ResizeUpDown,
                     };
 
-                    scene.push_cursor_region(CursorRegion {
+                    cx.scene().push_cursor_region(CursorRegion {
                         bounds: handle_bounds,
                         style,
                     });
@@ -940,14 +939,14 @@ mod element {
                                 }
                             }
                         });
-                    scene.push_mouse_region(mouse_region);
+                    cx.scene().push_mouse_region(mouse_region);
 
-                    scene.pop_stacking_context();
+                    cx.scene().pop_stacking_context();
                 }
             }
 
             if overflowing {
-                scene.pop_layer();
+                cx.scene().pop_layer();
             }
         }
 

crates/workspace/src/shared_screen.rs 🔗

@@ -73,14 +73,14 @@ impl View for SharedScreen {
 
         let frame = self.frame.clone();
         MouseEventHandler::new::<Focus, _>(0, cx, |_, cx| {
-            Canvas::new(move |scene, bounds, _, _, _| {
+            Canvas::new(move |bounds, _, _, cx| {
                 if let Some(frame) = frame.clone() {
                     let size = constrain_size_preserving_aspect_ratio(
                         bounds.size(),
                         vec2f(frame.width() as f32, frame.height() as f32),
                     );
                     let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.;
-                    scene.push_surface(gpui::platform::mac::Surface {
+                    cx.scene().push_surface(gpui::platform::mac::Surface {
                         bounds: RectF::new(origin, size),
                         image_buffer: frame.image(),
                     });

crates/workspace/src/status_bar.rs 🔗

@@ -8,8 +8,8 @@ use gpui::{
         vector::{vec2f, Vector2F},
     },
     json::{json, ToJson},
-    AnyElement, AnyViewHandle, Entity, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
-    Subscription, View, ViewContext, ViewHandle, WindowContext,
+    AnyElement, AnyViewHandle, Entity, LayoutContext, PaintContext, SizeConstraint, Subscription,
+    View, ViewContext, ViewHandle, WindowContext,
 };
 
 pub trait StatusItemView: View {
@@ -226,7 +226,6 @@ impl Element<StatusBar> for StatusBarElement {
 
     fn paint(
         &mut self,
-        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
@@ -237,12 +236,10 @@ impl Element<StatusBar> for StatusBarElement {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
         let left_origin = vec2f(bounds.lower_left().x(), origin_y);
-        self.left
-            .paint(scene, left_origin, visible_bounds, view, cx);
+        self.left.paint(left_origin, visible_bounds, view, cx);
 
         let right_origin = vec2f(bounds.upper_right().x() - self.right.size().x(), origin_y);
-        self.right
-            .paint(scene, right_origin, visible_bounds, view, cx);
+        self.right.paint(right_origin, visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(

crates/workspace/src/workspace.rs 🔗

@@ -3626,13 +3626,13 @@ fn notify_of_new_dock(workspace: &WeakViewHandle<Workspace>, cx: &mut AsyncAppCo
                             "Looking for the dock? Try ctrl-`!\nshift-escape now zooms your pane.",
                             text,
                         )
-                        .with_custom_runs(vec![26..32, 34..46], |_, bounds, scene, cx| {
+                        .with_custom_runs(vec![26..32, 34..46], |_, bounds, cx| {
                             let code_span_background_color = settings::get::<ThemeSettings>(cx)
                                 .theme
                                 .editor
                                 .document_highlight_read_background;
 
-                            scene.push_quad(gpui::Quad {
+                            cx.scene().push_quad(gpui::Quad {
                                 bounds,
                                 background: Some(code_span_background_color),
                                 border: Default::default(),