#![allow(clippy::disallowed_methods)]
use super::*;
use crate::windows::create::FrameWindow;
use windows::Win32::UI::HiDpi::GetDpiForWindow;
#[test]
fn prepared_overlay_geometry_matches_native_caption_client_after_attachment() {
let _bootstrap_lock = super::BOOTSTRAP_TEST_LOCK.lock().unwrap();
let _com = crate::windows::initialize_com().unwrap();
let runtime = Runtime::initialize().unwrap();
for titlebar in [
TitlebarStyle::Overlay { height: 48 },
TitlebarStyle::HiddenInset,
] {
for caption_button_size in [CaptionButtonSize::Standard, CaptionButtonSize::Tall] {
for (resizable, maximized) in [(true, false), (false, false), (true, true)] {
let options = WindowOptions {
titlebar: titlebar.clone(),
caption_button_size,
resizable,
maximized,
center: false,
..WindowOptions::default()
};
let frame = FrameWindow::new(&options, None).unwrap();
crate::windows::nonclient::prepare_overlay_startup(frame.hwnd).unwrap();
frame.show().unwrap();
let mut before = RECT::default();
unsafe { WindowsAndMessaging::GetClientRect(frame.hwnd, &mut before).unwrap() };
let sdk = WindowFrame::attach(&runtime, frame.hwnd, &options).unwrap();
crate::windows::nonclient::finish_overlay_startup(frame.hwnd).unwrap();
let mut after = RECT::default();
unsafe { WindowsAndMessaging::GetClientRect(frame.hwnd, &mut after).unwrap() };
assert_eq!(
before, after,
"{titlebar:?}, {caption_button_size:?}, {resizable}, {maximized}"
);
assert!(sdk
.overlay
.as_ref()
.unwrap()
.titlebar
.ExtendsContentIntoTitleBar()
.unwrap());
}
}
}
}
#[test]
fn caption_button_size_selects_supported_native_sizes() {
assert_eq!(
height_option(CaptionButtonSize::Standard),
TitleBarHeightOption::Standard
);
assert_eq!(
height_option(CaptionButtonSize::Tall),
TitleBarHeightOption::Tall
);
}
#[test]
fn native_sdk_attaches_hidden_tall_caption_and_restores_fullscreen() {
let _bootstrap_lock = super::BOOTSTRAP_TEST_LOCK.lock().unwrap();
let _com = crate::windows::initialize_com().unwrap();
let runtime = Runtime::initialize().unwrap();
let options = WindowOptions {
titlebar: TitlebarStyle::Overlay { height: 48 },
caption_button_size: CaptionButtonSize::Tall,
center: false,
width: 800,
height: 600,
..WindowOptions::default()
};
let frame = FrameWindow::new(&options, None).unwrap();
let sdk = WindowFrame::attach(&runtime, frame.hwnd, &options).unwrap();
let caption = sdk.overlay.as_ref().unwrap();
assert!(caption.titlebar.ExtendsContentIntoTitleBar().unwrap());
assert_eq!(
caption.titlebar.PreferredHeightOption().unwrap(),
TitleBarHeightOption::Tall
);
unsafe {
assert!(!WindowsAndMessaging::IsWindowVisible(frame.hwnd).as_bool());
let dpi = GetDpiForWindow(frame.hwnd);
assert_eq!(
caption.titlebar.Height().unwrap(),
i32::try_from(48 * dpi / 96).unwrap()
);
}
let size = sdk.window.Size().unwrap();
sdk.set_fullscreen(true).unwrap();
assert!(!unsafe { WindowsAndMessaging::IsWindowVisible(frame.hwnd) }.as_bool());
assert_eq!(
sdk.window.Presenter().unwrap().Kind().unwrap(),
AppWindowPresenterKind::FullScreen
);
sdk.set_fullscreen(false).unwrap();
assert_eq!(
sdk.window.Presenter().unwrap().Kind().unwrap(),
AppWindowPresenterKind::Overlapped
);
assert_eq!(sdk.window.Size().unwrap(), size);
}
#[test]
fn standard_buttons_keep_a_taller_application_bar() {
let _bootstrap_lock = super::BOOTSTRAP_TEST_LOCK.lock().unwrap();
let _com = crate::windows::initialize_com().unwrap();
let runtime = Runtime::initialize().unwrap();
let options = WindowOptions {
titlebar: TitlebarStyle::Overlay { height: 48 },
center: false,
..WindowOptions::default()
};
let frame = FrameWindow::new(&options, None).unwrap();
let sdk = WindowFrame::attach(&runtime, frame.hwnd, &options).unwrap();
let caption = sdk.overlay.as_ref().unwrap();
assert_eq!(
caption.titlebar.PreferredHeightOption().unwrap(),
TitleBarHeightOption::Standard
);
let dpi = unsafe { GetDpiForWindow(frame.hwnd) };
assert_eq!(
caption.titlebar.Height().unwrap(),
i32::try_from(32 * dpi / 96).unwrap()
);
assert_eq!(caption.metrics.get().unwrap().minimum_height, 48);
}
#[test]
fn sdk_native_controls_preserve_frame_capabilities_and_input_safe_areas() {
use windows::Win32::Foundation::{LPARAM, WPARAM};
let _bootstrap_lock = super::BOOTSTRAP_TEST_LOCK.lock().unwrap();
let _com = crate::windows::initialize_com().unwrap();
let runtime = Runtime::initialize().unwrap();
for titlebar in [
TitlebarStyle::Overlay { height: 48 },
TitlebarStyle::HiddenInset,
TitlebarStyle::None,
TitlebarStyle::Native,
] {
for resizable in [true, false] {
let options = WindowOptions {
titlebar: titlebar.clone(),
resizable,
center: false,
..WindowOptions::default()
};
let frame = FrameWindow::new(&options, None).unwrap();
let sdk = WindowFrame::attach(&runtime, frame.hwnd, &options).unwrap();
let mut outer = RECT::default();
let hit = unsafe {
WindowsAndMessaging::GetWindowRect(frame.hwnd, &mut outer).unwrap();
let x = outer.left.cast_unsigned() & 0xffff;
let y = outer.top.cast_unsigned() & 0xffff;
WindowsAndMessaging::SendMessageW(
frame.hwnd,
WindowsAndMessaging::WM_NCHITTEST,
Some(WPARAM(0)),
Some(LPARAM(
isize::try_from(((y << 16) | x).cast_signed()).unwrap(),
)),
)
.0
};
let is_resize = (isize::try_from(WindowsAndMessaging::HTLEFT).unwrap()
..=isize::try_from(WindowsAndMessaging::HTBOTTOMRIGHT).unwrap())
.contains(&hit);
assert_eq!(is_resize, resizable, "{titlebar:?}: hit {hit}");
if let Some(caption) = &sdk.overlay {
let metrics = caption.metrics.get().unwrap();
assert!(metrics.left + metrics.right > 0);
let regions = caption
.input
.GetRegionRects(NonClientRegionKind::Passthrough)
.unwrap();
assert_eq!(regions.len(), 1);
assert_eq!(regions[0].X, metrics.left);
assert_eq!(regions[0].Height, metrics.height);
assert_eq!(
regions[0].X + regions[0].Width + metrics.right,
sdk.window.ClientSize().unwrap().Width
);
}
let before = crate::windows::state::window_style_bits(
frame.hwnd,
WindowsAndMessaging::GWL_STYLE,
);
sdk.set_fullscreen(true).unwrap();
sdk.refresh(frame.hwnd).unwrap();
if let Some(caption) = &sdk.overlay {
assert_eq!(caption.metrics.get().unwrap().height, 0);
}
sdk.set_fullscreen(false).unwrap();
let after = crate::windows::state::window_style_bits(
frame.hwnd,
WindowsAndMessaging::GWL_STYLE,
);
let capabilities =
WindowsAndMessaging::WS_THICKFRAME.0 | WindowsAndMessaging::WS_MAXIMIZEBOX.0;
assert_eq!(before & capabilities, after & capabilities);
}
}
}
#[test]
fn overlay_keeps_all_eight_resize_hit_targets() {
use windows::Win32::Foundation::{LPARAM, WPARAM};
let _bootstrap_lock = super::BOOTSTRAP_TEST_LOCK.lock().unwrap();
let _com = crate::windows::initialize_com().unwrap();
let runtime = Runtime::initialize().unwrap();
let options = WindowOptions {
titlebar: TitlebarStyle::Overlay { height: 48 },
center: false,
width: 800,
height: 600,
..WindowOptions::default()
};
let frame = FrameWindow::new(&options, None).unwrap();
let _sdk = WindowFrame::attach(&runtime, frame.hwnd, &options).unwrap();
let mut rect = RECT::default();
unsafe { WindowsAndMessaging::GetWindowRect(frame.hwnd, &mut rect).unwrap() };
let mid_x = (rect.left + rect.right) / 2;
let mid_y = (rect.top + rect.bottom) / 2;
let hit = |x: i32, y: i32| {
let bits = ((y.cast_unsigned() & 0xffff) << 16) | (x.cast_unsigned() & 0xffff);
unsafe {
WindowsAndMessaging::SendMessageW(
frame.hwnd,
WindowsAndMessaging::WM_NCHITTEST,
Some(WPARAM(0)),
Some(LPARAM(isize::try_from(bits).unwrap())),
)
.0
}
};
for ((x, y), expected) in [
((rect.left, rect.top), WindowsAndMessaging::HTTOPLEFT),
((mid_x, rect.top), WindowsAndMessaging::HTTOP),
((rect.right - 1, rect.top), WindowsAndMessaging::HTTOPRIGHT),
((rect.left, mid_y), WindowsAndMessaging::HTLEFT),
((rect.right - 1, mid_y), WindowsAndMessaging::HTRIGHT),
(
(rect.left, rect.bottom - 1),
WindowsAndMessaging::HTBOTTOMLEFT,
),
((mid_x, rect.bottom - 1), WindowsAndMessaging::HTBOTTOM),
(
(rect.right - 1, rect.bottom - 1),
WindowsAndMessaging::HTBOTTOMRIGHT,
),
] {
assert_eq!(
hit(x, y),
isize::try_from(expected).unwrap(),
"at ({x}, {y})"
);
}
}