Cargo.lock 🔗
@@ -10626,6 +10626,7 @@ dependencies = [
"story",
"strum",
"theme",
+ "windows 0.53.0",
]
[[package]]
Ezekiel Warren created
screenshots and description incoming
## title bar when window is maximized
| before | after |
| --- | --- |
|

|

|
## ~~caption buttons at 200%~~
~~buttons are now properly responsive at different scales~~
~~closes #9438~~
~~proper scale factor handling in follow up PR (possibly #9440)~~
<details>
<summary>out of date image</summary>

</details>
should be fixed by https://github.com/zed-industries/zed/pull/9456
Release Notes:
- N/A
Cargo.lock | 1
crates/gpui/src/platform/windows/window.rs | 49 ++--
crates/ui/Cargo.toml | 3
crates/ui/src/components/title_bar/title_bar.rs | 48 +++-
crates/ui/src/components/title_bar/windows_window_controls.rs | 8
5 files changed, 67 insertions(+), 42 deletions(-)
@@ -10626,6 +10626,7 @@ dependencies = [
"story",
"strum",
"theme",
+ "windows 0.53.0",
]
[[package]]
@@ -134,33 +134,37 @@ impl WindowsWindowInner {
return false;
}
- fn get_titlebar_rect(&self) -> anyhow::Result<RECT> {
- let top_and_bottom_borders = 2;
- let scale_factor = self.scale_factor.get();
- let theme = unsafe { OpenThemeData(self.hwnd, w!("WINDOW")) };
- let title_bar_size = unsafe {
- GetThemePartSize(
- theme,
- HDC::default(),
- WP_CAPTION.0,
- CS_ACTIVE.0,
- None,
- TS_TRUE,
- )
- }?;
- unsafe { CloseThemeData(theme) }?;
-
- let mut height =
- (title_bar_size.cy as f32 * scale_factor).round() as i32 + top_and_bottom_borders;
+ pub(crate) fn title_bar_padding(&self) -> Pixels {
+ // using USER_DEFAULT_SCREEN_DPI because GPUI handles the scale with the scale factor
+ let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, USER_DEFAULT_SCREEN_DPI) };
+ px(padding as f32)
+ }
+ pub(crate) fn title_bar_top_offset(&self) -> Pixels {
if self.is_maximized() {
- let dpi = unsafe { GetDpiForWindow(self.hwnd) };
- height += unsafe { (GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) * 2) as i32 };
+ self.title_bar_padding() * 2
+ } else {
+ px(0.)
}
+ }
+
+ pub(crate) fn title_bar_height(&self) -> Pixels {
+ // todo(windows) this is hard set to match the ui title bar
+ // in the future the ui title bar component will report the size
+ px(32.) + self.title_bar_top_offset()
+ }
+ pub(crate) fn caption_button_width(&self) -> Pixels {
+ // todo(windows) this is hard set to match the ui title bar
+ // in the future the ui title bar component will report the size
+ px(36.)
+ }
+
+ fn get_titlebar_rect(&self) -> anyhow::Result<RECT> {
+ let height = self.title_bar_height();
let mut rect = RECT::default();
unsafe { GetClientRect(self.hwnd, &mut rect) }?;
- rect.bottom = rect.top + height;
+ rect.bottom = rect.top + ((height.0 as f32 * self.scale_factor.get()).round() as i32);
Ok(rect)
}
@@ -923,7 +927,8 @@ impl WindowsWindowInner {
let titlebar_rect = self.get_titlebar_rect();
if let Ok(titlebar_rect) = titlebar_rect {
if cursor_point.y < titlebar_rect.bottom {
- let caption_btn_width = unsafe { GetSystemMetricsForDpi(SM_CXSIZE, dpi) };
+ let caption_btn_width =
+ (self.caption_button_width().0 * self.scale_factor.get()) as i32;
if cursor_point.x >= titlebar_rect.right - caption_btn_width {
return LRESULT(HTCLOSE as _);
} else if cursor_point.x >= titlebar_rect.right - caption_btn_width * 2 {
@@ -23,6 +23,9 @@ story = { workspace = true, optional = true }
strum = { version = "0.25.0", features = ["derive"] }
theme.workspace = true
+[target.'cfg(windows)'.dependencies]
+windows.workspace = true
+
[features]
default = []
stories = ["dep:itertools", "dep:story"]
@@ -10,12 +10,40 @@ pub struct TitleBar {
content: Stateful<Div>,
children: SmallVec<[AnyElement; 2]>,
}
+#[cfg(not(target_os = "windows"))]
+fn title_bar_top_padding(_cx: &WindowContext) -> Pixels {
+ px(0.)
+}
+
+#[cfg(target_os = "windows")]
+fn title_bar_top_padding(cx: &WindowContext) -> Pixels {
+ use windows::Win32::UI::{
+ HiDpi::GetSystemMetricsForDpi,
+ WindowsAndMessaging::{SM_CXPADDEDBORDER, USER_DEFAULT_SCREEN_DPI},
+ };
+
+ // this top padding is not dependent on the title bar style and is instead a quirk of maximized windows on Windows
+ // https://devblogs.microsoft.com/oldnewthing/20150304-00/?p=44543
+ let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, USER_DEFAULT_SCREEN_DPI) };
+ if cx.is_maximized() {
+ px((padding * 2) as f32)
+ } else {
+ px(0.)
+ }
+}
impl TitleBar {
+ #[cfg(not(target_os = "windows"))]
pub fn height(cx: &mut WindowContext) -> Pixels {
(1.75 * cx.rem_size()).max(px(32.))
}
+ #[cfg(target_os = "windows")]
+ pub fn height(_cx: &mut WindowContext) -> Pixels {
+ // todo(windows) instead of hard coded size report the actual size to the Windows platform API
+ px(32.)
+ }
+
pub fn new(id: impl Into<ElementId>) -> Self {
Self {
platform_style: PlatformStyle::platform(),
@@ -29,16 +57,6 @@ impl TitleBar {
self.platform_style = style;
self
}
-
- fn top_padding(&self, cx: &WindowContext) -> Pixels {
- if self.platform_style == PlatformStyle::Windows && cx.is_maximized() {
- // todo(windows): get padding from win32 api, need HWND from window context somehow
- // should be GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) * 2
- px(8.)
- } else {
- px(0.)
- }
- }
}
impl InteractiveElement for TitleBar {
@@ -58,13 +76,11 @@ impl ParentElement for TitleBar {
impl RenderOnce for TitleBar {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let height = Self::height(cx);
- let top_padding = self.top_padding(cx);
-
h_flex()
.id("titlebar")
.w_full()
- .pt(top_padding)
- .h(height)
+ .pt(title_bar_top_padding(cx))
+ .h(height + title_bar_top_padding(cx))
.map(|this| {
if cx.is_fullscreen() {
this.pl_2()
@@ -88,9 +104,7 @@ impl RenderOnce for TitleBar {
.children(self.children),
)
.when(self.platform_style == PlatformStyle::Windows, |title_bar| {
- let button_height = Self::height(cx) - top_padding;
-
- title_bar.child(WindowsWindowControls::new(button_height))
+ title_bar.child(WindowsWindowControls::new(height))
})
}
}
@@ -98,9 +98,11 @@ impl WindowsCaptionButton {
impl RenderOnce for WindowsCaptionButton {
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
- // todo(windows): get padding from win32 api, need HWND from window context somehow
- // should be GetSystemMetricsForDpi(SM_CXSIZE, dpi)
- let width = px(36.0);
+ // todo(windows) report this width to the Windows platform API
+ // NOTE: this is intentionally hard coded. An option to use the 'native' size
+ // could be added when the width is reported to the Windows platform API
+ // as this could change between future Windows versions.
+ let width = px(36.);
h_flex()
.id(self.id)