refactor(macos): keep native window chrome behind the platform boundary
Preserve native geometry coverage and publish lifecycle fixture PID files atomically so the newly enabled native CI cannot read an empty PID.
This commit is contained in:
1 parent
7a26f9c380
commit
78927d3325
7 files changed
+61
-25
No files matched your search
@@ -64,7 +64,7 @@ jobs:
|
||||
- name: Test native titlebar alignment
|
||||
if: runner.os == 'macOS'
|
||||
run: >-
|
||||
cargo test --locked -p nebula --bin pebrel --features gpui-test-support gpui_shell::workspace::window_titlebar::macos::tests::
|
||||
cargo test --locked -p nebula --bin pebrel --features gpui-test-support platform::window_chrome::macos::tests::
|
||||
- name: Test all Python helpers
|
||||
if: ${{ !cancelled() }}
|
||||
run: python -m unittest discover -s scripts/tests -v
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
use super::*;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub(super) mod macos;
|
||||
|
||||
/// Prepaint records the actual pane column before any titlebar paint runs. Keep
|
||||
/// this cell for the workspace lifetime, so resizing and panel animations do not
|
||||
/// allocate a new shared slot or duplicate the body's layout calculations.
|
||||
@@ -90,6 +87,7 @@ impl NebulaWorkspace {
|
||||
cx: &mut Context<Self>,
|
||||
) -> gpui::Div {
|
||||
let top_tabs = self.tabs_position == nebula_settings::TabsPositionName::Top;
|
||||
let native_layout = crate::platform::window_chrome::layout(window);
|
||||
let bar = TitleBar::new()
|
||||
// Leave 8px above and below the existing 32px controls.
|
||||
.h(px(48.0))
|
||||
@@ -97,7 +95,7 @@ impl NebulaWorkspace {
|
||||
.when(settings_active, |bar| {
|
||||
bar.border_b_1().border_color(crate::gpui_shell::theme::settings_hairline(cx))
|
||||
})
|
||||
.when(top_tabs && !cfg!(target_os = "macos"), |bar| {
|
||||
.when(top_tabs && native_layout.is_none(), |bar| {
|
||||
bar.pl(px(top_tabs::TOP_TAB_LEFT_INSET))
|
||||
})
|
||||
.when(top_tabs, |bar| {
|
||||
@@ -120,10 +118,10 @@ impl NebulaWorkspace {
|
||||
|
||||
// AppKit owns both the control group and its geometry. Read the live
|
||||
// frames so system layout, resize and full-screen transitions agree.
|
||||
#[cfg(target_os = "macos")]
|
||||
let bar = {
|
||||
let (height, inset) = macos::layout(window);
|
||||
let bar = if let Some((height, inset)) = native_layout {
|
||||
bar.h(px(height)).pl(px(inset))
|
||||
} else {
|
||||
bar
|
||||
};
|
||||
|
||||
div()
|
||||
|
||||
@@ -310,25 +310,15 @@ fn workspace_window_options(cx: &mut App, focus: bool, role: WindowRole) -> Wind
|
||||
)
|
||||
},
|
||||
);
|
||||
WindowOptions {
|
||||
crate::platform::window_chrome::configure_options(WindowOptions {
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
||||
window_min_size: Some(size(px(760.0), px(540.0)).min(&bounds.size)),
|
||||
titlebar: Some(gpui::TitlebarOptions {
|
||||
// A manual traffic-light position makes GPUI rewrite AppKit's
|
||||
// titlebar container, breaking the system toolbar layout.
|
||||
traffic_light_position: if cfg!(target_os = "macos") {
|
||||
None
|
||||
} else {
|
||||
TitleBar::title_bar_options().traffic_light_position
|
||||
},
|
||||
..TitleBar::title_bar_options()
|
||||
}),
|
||||
app_owns_titlebar_drag: cfg!(target_os = "macos"),
|
||||
titlebar: Some(TitleBar::title_bar_options()),
|
||||
app_id: Some("pebrel".to_owned()),
|
||||
window_background: crate::gpui_shell::wallpaper::initial_background_appearance(),
|
||||
focus,
|
||||
..Default::default()
|
||||
}
|
||||
})
|
||||
},
|
||||
#[cfg(windows)]
|
||||
WindowRole::QuickTerminal => {
|
||||
@@ -392,8 +382,7 @@ fn open_workspace_window(
|
||||
let hwnd_out = hwnd_slot.clone();
|
||||
let handle = cx.open_window(options, move |window, cx| {
|
||||
window.set_window_title(crate::brand::NAME);
|
||||
#[cfg(target_os = "macos")]
|
||||
super::window_titlebar::macos::configure(window);
|
||||
crate::platform::window_chrome::configure(window);
|
||||
*hwnd_out.borrow_mut() = native_hwnd(window).unwrap_or_default();
|
||||
#[cfg(windows)]
|
||||
crate::gpui_shell::set_native_window_icon(window);
|
||||
|
||||
@@ -27,6 +27,8 @@ pub mod notifications;
|
||||
pub mod shell;
|
||||
pub mod shell_integration;
|
||||
pub mod startup;
|
||||
#[cfg(feature = "gpui-shell")]
|
||||
pub(crate) mod window_chrome;
|
||||
|
||||
pub use capabilities::CAPABILITIES;
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
//! Native window decoration belongs to the platform boundary. Workspace code
|
||||
//! supplies ordinary GPUI options and uses optional geometry without depending
|
||||
//! on AppKit types or duplicating platform detection.
|
||||
|
||||
use gpui::{Window, WindowOptions};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos;
|
||||
|
||||
pub(crate) fn configure_options(options: WindowOptions) -> WindowOptions {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let mut options = options;
|
||||
if let Some(titlebar) = options.titlebar.as_mut() {
|
||||
// A manual position makes GPUI rewrite AppKit's titlebar container,
|
||||
// breaking the native toolbar layout.
|
||||
titlebar.traffic_light_position = None;
|
||||
}
|
||||
options.app_owns_titlebar_drag = true;
|
||||
options
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
options
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn configure(_window: &Window) {
|
||||
#[cfg(target_os = "macos")]
|
||||
macos::configure(_window);
|
||||
}
|
||||
|
||||
/// Height and left inset when native controls determine the titlebar geometry.
|
||||
pub(crate) fn layout(_window: &Window) -> Option<(f32, f32)> {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
Some(macos::layout(_window))
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@ fn native_window(window: &Window) -> Option<Retained<NSWindow>> {
|
||||
view.window()
|
||||
}
|
||||
|
||||
pub(in super::super) fn configure(window: &Window) {
|
||||
pub(super) fn configure(window: &Window) {
|
||||
let Some(native) = native_window(window) else { return };
|
||||
let toolbar = NSToolbar::initWithIdentifier(
|
||||
NSToolbar::alloc(native.mtm()),
|
||||
@@ -29,7 +29,11 @@ role = sys.argv[2]
|
||||
if role != 'grandchild':
|
||||
next_role = 'child' if role == 'parent' else 'grandchild'
|
||||
subprocess.Popen([sys.executable, '-I', '-S', __file__, str(root), next_role])
|
||||
(root / (role + '.pid')).write_text(str(os.getpid()))
|
||||
# Publish the PID only after the contents are complete. The parent polls for
|
||||
# file existence, so creating the final path first exposes an empty file.
|
||||
pid_path = root / (role + '.pid.tmp')
|
||||
pid_path.write_text(str(os.getpid()))
|
||||
pid_path.replace(root / (role + '.pid'))
|
||||
while True:
|
||||
if role == 'parent' and (root / 'exit').exists():
|
||||
code = root / 'exit-code'
|
||||
|
||||
Reference in new issue
Block a user