mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-25 11:43:06 +03:00
fix(core/wry): implement resizing natively on Windows (#9862)
closes #7388 closes #9510 closes #9464 ref #9268 ref #9053 ref #8770 ref #8750 ref #4012
This commit is contained in:
parent
fafc238f72
commit
f29b788110
10
.changes/undecorated-resizing.md
Normal file
10
.changes/undecorated-resizing.md
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
"tauri": "patch:bug"
|
||||
"tauri-runtime-wry": "patch:bug"
|
||||
---
|
||||
|
||||
On Windows, handle resizing undecorated windows natively which improves performance and fixes a couple of annoyances with previous JS implementation:
|
||||
- No more cursor flickering when moving the cursor across an edge.
|
||||
- Can resize from top even when `data-tauri-drag-region` element exists there.
|
||||
- Upon starting rezing, clicks don't go through elements behind it so no longer accidental clicks.
|
||||
|
@ -1988,8 +1988,6 @@ pub struct WindowWrapper {
|
||||
webviews: Vec<WebviewWrapper>,
|
||||
window_event_listeners: WindowEventListeners,
|
||||
#[cfg(windows)]
|
||||
is_window_fullscreen: bool,
|
||||
#[cfg(windows)]
|
||||
is_window_transparent: bool,
|
||||
#[cfg(windows)]
|
||||
surface: Option<softbuffer::Surface<Arc<Window>, Arc<Window>>>,
|
||||
@ -2773,7 +2771,15 @@ fn handle_user_message<T: UserEvent>(
|
||||
WindowMessage::Destroy => {
|
||||
panic!("cannot handle `WindowMessage::Destroy` on the main thread")
|
||||
}
|
||||
WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations),
|
||||
WindowMessage::SetDecorations(decorations) => {
|
||||
window.set_decorations(decorations);
|
||||
#[cfg(windows)]
|
||||
if decorations {
|
||||
undecorated_resizing::detach_resize_handler(window.hwnd());
|
||||
} else {
|
||||
undecorated_resizing::attach_resize_handler(window.hwnd());
|
||||
}
|
||||
}
|
||||
WindowMessage::SetShadow(_enable) => {
|
||||
#[cfg(windows)]
|
||||
window.set_undecorated_shadow(_enable);
|
||||
@ -2806,10 +2812,6 @@ fn handle_user_message<T: UserEvent>(
|
||||
} else {
|
||||
window.set_fullscreen(None)
|
||||
}
|
||||
#[cfg(windows)]
|
||||
if let Some(w) = windows.0.borrow_mut().get_mut(&id) {
|
||||
w.is_window_fullscreen = fullscreen;
|
||||
}
|
||||
}
|
||||
WindowMessage::SetFocus => {
|
||||
window.set_focus();
|
||||
@ -3197,8 +3199,6 @@ fn handle_user_message<T: UserEvent>(
|
||||
Message::CreateRawWindow(window_id, handler, sender) => {
|
||||
let (label, builder) = handler();
|
||||
|
||||
#[cfg(windows)]
|
||||
let is_window_fullscreen = builder.window.fullscreen.is_some();
|
||||
#[cfg(windows)]
|
||||
let is_window_transparent = builder.window.transparent;
|
||||
|
||||
@ -3232,8 +3232,6 @@ fn handle_user_message<T: UserEvent>(
|
||||
window_event_listeners: Default::default(),
|
||||
webviews: Vec::new(),
|
||||
#[cfg(windows)]
|
||||
is_window_fullscreen,
|
||||
#[cfg(windows)]
|
||||
is_window_transparent,
|
||||
#[cfg(windows)]
|
||||
surface,
|
||||
@ -3577,8 +3575,6 @@ fn create_window<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
|
||||
|
||||
#[cfg(windows)]
|
||||
let is_window_transparent = window_builder.inner.window.transparent;
|
||||
#[cfg(windows)]
|
||||
let is_window_fullscreen = window_builder.inner.window.fullscreen.is_some();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
@ -3727,8 +3723,6 @@ fn create_window<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
|
||||
webviews,
|
||||
window_event_listeners,
|
||||
#[cfg(windows)]
|
||||
is_window_fullscreen,
|
||||
#[cfg(windows)]
|
||||
is_window_transparent,
|
||||
#[cfg(windows)]
|
||||
surface,
|
||||
@ -3818,11 +3812,6 @@ fn create_webview<T: UserEvent>(
|
||||
.with_accept_first_mouse(webview_attributes.accept_first_mouse)
|
||||
.with_hotkeys_zoom(webview_attributes.zoom_hotkeys_enabled);
|
||||
|
||||
#[cfg(windows)]
|
||||
if kind == WebviewKind::WindowContent {
|
||||
webview_builder = webview_builder.with_initialization_script(undecorated_resizing::SCRIPT);
|
||||
}
|
||||
|
||||
if webview_attributes.drag_drop_handler_enabled {
|
||||
let proxy = context.proxy.clone();
|
||||
let window_id_ = window_id.clone();
|
||||
@ -4054,15 +4043,19 @@ fn create_webview<T: UserEvent>(
|
||||
.build()
|
||||
.map_err(|e| Error::CreateWebview(Box::new(e)))?;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
if kind == WebviewKind::WindowContent {
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
undecorated_resizing::attach_resize_handler(&webview);
|
||||
#[cfg(windows)]
|
||||
if window.is_resizable() && !window.is_decorated() {
|
||||
undecorated_resizing::attach_resize_handler(window.hwnd());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@ -4127,13 +4120,6 @@ fn create_ipc_handler<T: UserEvent>(
|
||||
ipc_handler: Option<WebviewIpcHandler<T, Wry<T>>>,
|
||||
) -> Box<IpcHandler> {
|
||||
Box::new(move |request| {
|
||||
#[cfg(windows)]
|
||||
if _kind == WebviewKind::WindowContent
|
||||
&& undecorated_resizing::handle_request(context.clone(), *window_id.lock().unwrap(), &request)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(handler) = &ipc_handler {
|
||||
handler(
|
||||
DetachedWebview {
|
||||
|
@ -26,10 +26,6 @@ pub use self::gtk::*;
|
||||
#[cfg(windows)]
|
||||
pub use self::windows::*;
|
||||
|
||||
#[cfg(windows)]
|
||||
type WindowDimensions = u32;
|
||||
#[cfg(not(windows))]
|
||||
type WindowDimensions = i32;
|
||||
#[cfg(windows)]
|
||||
type WindowPositions = i32;
|
||||
#[cfg(not(windows))]
|
||||
@ -49,27 +45,22 @@ enum HitTestResult {
|
||||
NoWhere,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn hit_test(
|
||||
width: WindowDimensions,
|
||||
height: WindowDimensions,
|
||||
x: WindowPositions,
|
||||
y: WindowPositions,
|
||||
left: WindowPositions,
|
||||
top: WindowPositions,
|
||||
right: WindowPositions,
|
||||
bottom: WindowPositions,
|
||||
cx: WindowPositions,
|
||||
cy: WindowPositions,
|
||||
border_x: WindowPositions,
|
||||
border_y: WindowPositions,
|
||||
) -> HitTestResult {
|
||||
#[cfg(windows)]
|
||||
let (top, left) = (0, 0);
|
||||
#[cfg(not(windows))]
|
||||
let (top, left) = (0., 0.);
|
||||
|
||||
let bottom = top + height as WindowPositions;
|
||||
let right = left + width as WindowPositions;
|
||||
|
||||
#[rustfmt::skip]
|
||||
let result = (LEFT * (x < left + border_x) as isize)
|
||||
| (RIGHT * (x >= right - border_x) as isize)
|
||||
| (TOP * (y < top + border_y) as isize)
|
||||
| (BOTTOM * (y >= bottom - border_y) as isize);
|
||||
let result = (LEFT * (cx < left + border_x) as isize)
|
||||
| (RIGHT * (cx >= right - border_x) as isize)
|
||||
| (TOP * (cy < top + border_y) as isize)
|
||||
| (BOTTOM * (cy >= bottom - border_y) as isize);
|
||||
|
||||
match result {
|
||||
CLIENT => HitTestResult::Client,
|
||||
@ -89,117 +80,285 @@ fn hit_test(
|
||||
mod windows {
|
||||
use super::{hit_test, HitTestResult};
|
||||
|
||||
use tao::window::{CursorIcon, ResizeDirection, Window};
|
||||
use windows::Win32::UI::WindowsAndMessaging::{
|
||||
GetSystemMetrics, SM_CXFRAME, SM_CXPADDEDBORDER, SM_CYFRAME,
|
||||
};
|
||||
|
||||
const MESSAGE_MOUSEMOVE: &str = "__internal_on_mousemove__|";
|
||||
const MESSAGE_MOUSEDOWN: &str = "__internal_on_mousedown__|";
|
||||
pub const SCRIPT: &str = r#"
|
||||
;(function () {
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
window.ipc.postMessage(
|
||||
`__internal_on_mousemove__|${e.clientX},${e.clientY}`
|
||||
)
|
||||
})
|
||||
document.addEventListener('mousedown', (e) => {
|
||||
if (e.button === 0) {
|
||||
window.ipc.postMessage(
|
||||
`__internal_on_mousedown__|${e.clientX},${e.clientY}`
|
||||
)
|
||||
}
|
||||
})
|
||||
})()
|
||||
"#;
|
||||
use windows::core::*;
|
||||
use windows::Win32::System::LibraryLoader::*;
|
||||
use windows::Win32::UI::WindowsAndMessaging::*;
|
||||
use windows::Win32::{Foundation::*, UI::Shell::SetWindowSubclass};
|
||||
use windows::Win32::{Graphics::Gdi::*, UI::Shell::DefSubclassProc};
|
||||
|
||||
impl HitTestResult {
|
||||
fn drag_resize_window(&self, window: &Window) {
|
||||
self.change_cursor(window);
|
||||
let edge = match self {
|
||||
HitTestResult::Left => ResizeDirection::West,
|
||||
HitTestResult::Right => ResizeDirection::East,
|
||||
HitTestResult::Top => ResizeDirection::North,
|
||||
HitTestResult::Bottom => ResizeDirection::South,
|
||||
HitTestResult::TopLeft => ResizeDirection::NorthWest,
|
||||
HitTestResult::TopRight => ResizeDirection::NorthEast,
|
||||
HitTestResult::BottomLeft => ResizeDirection::SouthWest,
|
||||
HitTestResult::BottomRight => ResizeDirection::SouthEast,
|
||||
|
||||
// if not on an edge, don't start resizing
|
||||
_ => return,
|
||||
};
|
||||
let _ = window.drag_resize_window(edge);
|
||||
}
|
||||
|
||||
fn change_cursor(&self, window: &Window) {
|
||||
let cursor = match self {
|
||||
HitTestResult::Left => CursorIcon::WResize,
|
||||
HitTestResult::Right => CursorIcon::EResize,
|
||||
HitTestResult::Top => CursorIcon::NResize,
|
||||
HitTestResult::Bottom => CursorIcon::SResize,
|
||||
HitTestResult::TopLeft => CursorIcon::NwResize,
|
||||
HitTestResult::TopRight => CursorIcon::NeResize,
|
||||
HitTestResult::BottomLeft => CursorIcon::SwResize,
|
||||
HitTestResult::BottomRight => CursorIcon::SeResize,
|
||||
|
||||
// if not on an edge, don't change the cursor, otherwise we cause flickering
|
||||
_ => return,
|
||||
};
|
||||
window.set_cursor_icon(cursor);
|
||||
fn to_win32(self) -> i32 {
|
||||
match self {
|
||||
HitTestResult::Left => HTLEFT as _,
|
||||
HitTestResult::Right => HTRIGHT as _,
|
||||
HitTestResult::Top => HTTOP as _,
|
||||
HitTestResult::Bottom => HTBOTTOM as _,
|
||||
HitTestResult::TopLeft => HTTOPLEFT as _,
|
||||
HitTestResult::TopRight => HTTOPRIGHT as _,
|
||||
HitTestResult::BottomLeft => HTBOTTOMLEFT as _,
|
||||
HitTestResult::BottomRight => HTBOTTOMRIGHT as _,
|
||||
_ => HTTRANSPARENT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether handled or not
|
||||
pub fn handle_request<T: crate::UserEvent>(
|
||||
context: crate::Context<T>,
|
||||
window_id: crate::WindowId,
|
||||
request: &http::Request<String>,
|
||||
) -> bool {
|
||||
if let Some(args) = request.body().strip_prefix(MESSAGE_MOUSEMOVE) {
|
||||
if let Some(window) = context.main_thread.windows.0.borrow().get(&window_id) {
|
||||
if let Some(w) = window.inner.as_ref() {
|
||||
if !w.is_decorated()
|
||||
&& w.is_resizable()
|
||||
&& !w.is_maximized()
|
||||
&& !window.is_window_fullscreen
|
||||
{
|
||||
let (x, y) = args.split_once(',').unwrap();
|
||||
let (x, y) = (x.parse().unwrap(), y.parse().unwrap());
|
||||
let size = w.inner_size();
|
||||
let padded_border = unsafe { GetSystemMetrics(SM_CXPADDEDBORDER) };
|
||||
let border_x = unsafe { GetSystemMetrics(SM_CXFRAME) + padded_border };
|
||||
let border_y = unsafe { GetSystemMetrics(SM_CYFRAME) + padded_border };
|
||||
hit_test(size.width, size.height, x, y, border_x, border_y).change_cursor(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
const CLASS_NAME: PCWSTR = w!("TAURI_DRAG_RESIZE_BORDERS");
|
||||
const WINDOW_NAME: PCWSTR = w!("TAURI_DRAG_RESIZE_WINDOW");
|
||||
|
||||
return true;
|
||||
}
|
||||
if let Some(args) = request.body().strip_prefix(MESSAGE_MOUSEDOWN) {
|
||||
if let Some(window) = context.main_thread.windows.0.borrow().get(&window_id) {
|
||||
if let Some(w) = window.inner.as_ref() {
|
||||
if !w.is_decorated()
|
||||
&& w.is_resizable()
|
||||
&& !w.is_maximized()
|
||||
&& !window.is_window_fullscreen
|
||||
{
|
||||
let (x, y) = args.split_once(',').unwrap();
|
||||
let (x, y) = (x.parse().unwrap(), y.parse().unwrap());
|
||||
let size = w.inner_size();
|
||||
let padded_border = unsafe { GetSystemMetrics(SM_CXPADDEDBORDER) };
|
||||
let border_x = unsafe { GetSystemMetrics(SM_CXFRAME) + padded_border };
|
||||
let border_y = unsafe { GetSystemMetrics(SM_CYFRAME) + padded_border };
|
||||
hit_test(size.width, size.height, x, y, border_x, border_y).drag_resize_window(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn attach_resize_handler(hwnd: isize) {
|
||||
let parent = HWND(hwnd);
|
||||
|
||||
return true;
|
||||
let child = unsafe { FindWindowExW(parent, HWND::default(), CLASS_NAME, WINDOW_NAME) };
|
||||
if child != HWND::default() {
|
||||
return;
|
||||
}
|
||||
|
||||
false
|
||||
let class = WNDCLASSEXW {
|
||||
cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
|
||||
style: WNDCLASS_STYLES::default(),
|
||||
lpfnWndProc: Some(drag_resize_window_proc),
|
||||
cbClsExtra: 0,
|
||||
cbWndExtra: 0,
|
||||
hInstance: unsafe { HINSTANCE(GetModuleHandleW(PCWSTR::null()).unwrap_or_default().0) },
|
||||
hIcon: HICON::default(),
|
||||
hCursor: HCURSOR::default(),
|
||||
hbrBackground: HBRUSH::default(),
|
||||
lpszMenuName: PCWSTR::null(),
|
||||
lpszClassName: CLASS_NAME,
|
||||
hIconSm: HICON::default(),
|
||||
};
|
||||
|
||||
unsafe { RegisterClassExW(&class) };
|
||||
|
||||
let mut rect = RECT::default();
|
||||
unsafe { GetClientRect(parent, &mut rect).unwrap() };
|
||||
let width = rect.right - rect.left;
|
||||
let height = rect.bottom - rect.top;
|
||||
|
||||
let drag_window = unsafe {
|
||||
CreateWindowExW(
|
||||
WINDOW_EX_STYLE::default(),
|
||||
CLASS_NAME,
|
||||
WINDOW_NAME,
|
||||
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
parent,
|
||||
HMENU::default(),
|
||||
GetModuleHandleW(PCWSTR::null()).unwrap_or_default(),
|
||||
None,
|
||||
)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
set_drag_hwnd_rgn(drag_window, width, height);
|
||||
|
||||
let _ = SetWindowPos(
|
||||
drag_window,
|
||||
HWND_TOP,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE,
|
||||
);
|
||||
|
||||
let _ = SetWindowSubclass(
|
||||
parent,
|
||||
Some(subclass_parent),
|
||||
(WM_USER + 1) as _,
|
||||
drag_window.0 as _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn subclass_parent(
|
||||
parent: HWND,
|
||||
msg: u32,
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
_: usize,
|
||||
child: usize,
|
||||
) -> LRESULT {
|
||||
if msg == WM_SIZE {
|
||||
let child = HWND(child as _);
|
||||
|
||||
if is_maximized(parent).unwrap_or(false) {
|
||||
let _ = SetWindowPos(
|
||||
child,
|
||||
HWND_TOP,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE,
|
||||
);
|
||||
} else {
|
||||
let mut rect = RECT::default();
|
||||
if GetClientRect(parent, &mut rect).is_ok() {
|
||||
let width = rect.right - rect.left;
|
||||
let height = rect.bottom - rect.top;
|
||||
|
||||
let _ = SetWindowPos(
|
||||
child,
|
||||
HWND_TOP,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE,
|
||||
);
|
||||
|
||||
set_drag_hwnd_rgn(child, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefSubclassProc(parent, msg, wparam, lparam)
|
||||
}
|
||||
|
||||
unsafe extern "system" fn drag_resize_window_proc(
|
||||
child: HWND,
|
||||
msg: u32,
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> LRESULT {
|
||||
match msg {
|
||||
WM_NCHITTEST => {
|
||||
let parent = GetParent(child);
|
||||
let style = GetWindowLongPtrW(parent, GWL_STYLE);
|
||||
let style = WINDOW_STYLE(style as u32);
|
||||
|
||||
let is_resizable = (style & WS_SIZEBOX).0 != 0;
|
||||
if !is_resizable {
|
||||
return DefWindowProcW(child, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
let mut rect = RECT::default();
|
||||
if GetWindowRect(child, &mut rect).is_err() {
|
||||
return DefWindowProcW(child, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
let (cx, cy) = (GET_X_LPARAM(lparam) as i32, GET_Y_LPARAM(lparam) as i32);
|
||||
|
||||
let padded_border = GetSystemMetrics(SM_CXPADDEDBORDER);
|
||||
let border_x = GetSystemMetrics(SM_CXFRAME) + padded_border;
|
||||
let border_y = GetSystemMetrics(SM_CYFRAME) + padded_border;
|
||||
|
||||
let res = hit_test(
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.right,
|
||||
rect.bottom,
|
||||
cx,
|
||||
cy,
|
||||
border_x,
|
||||
border_y,
|
||||
);
|
||||
|
||||
return LRESULT(res.to_win32() as _);
|
||||
}
|
||||
|
||||
WM_NCLBUTTONDOWN => {
|
||||
let parent = GetParent(child);
|
||||
let style = GetWindowLongPtrW(parent, GWL_STYLE);
|
||||
let style = WINDOW_STYLE(style as u32);
|
||||
|
||||
let is_resizable = (style & WS_SIZEBOX).0 != 0;
|
||||
if !is_resizable {
|
||||
return DefWindowProcW(child, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
let mut rect = RECT::default();
|
||||
if GetWindowRect(child, &mut rect).is_err() {
|
||||
return DefWindowProcW(child, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
let (cx, cy) = (GET_X_LPARAM(lparam) as i32, GET_Y_LPARAM(lparam) as i32);
|
||||
|
||||
let padded_border = GetSystemMetrics(SM_CXPADDEDBORDER);
|
||||
let border_x = GetSystemMetrics(SM_CXFRAME) + padded_border;
|
||||
let border_y = GetSystemMetrics(SM_CYFRAME) + padded_border;
|
||||
|
||||
let res = hit_test(
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.right,
|
||||
rect.bottom,
|
||||
cx,
|
||||
cy,
|
||||
border_x,
|
||||
border_y,
|
||||
);
|
||||
|
||||
if res != HitTestResult::NoWhere {
|
||||
let points = POINTS {
|
||||
x: cx as i16,
|
||||
y: cy as i16,
|
||||
};
|
||||
|
||||
let _ = PostMessageW(
|
||||
parent,
|
||||
WM_NCLBUTTONDOWN,
|
||||
WPARAM(res.to_win32() as _),
|
||||
LPARAM(&points as *const _ as _),
|
||||
);
|
||||
}
|
||||
|
||||
return LRESULT(0);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
DefWindowProcW(child, msg, wparam, lparam)
|
||||
}
|
||||
|
||||
pub fn detach_resize_handler(hwnd: isize) {
|
||||
let hwnd = HWND(hwnd);
|
||||
|
||||
let child = unsafe { FindWindowExW(hwnd, HWND::default(), CLASS_NAME, WINDOW_NAME) };
|
||||
if child == HWND::default() {
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = unsafe { DestroyWindow(child) };
|
||||
}
|
||||
|
||||
unsafe fn set_drag_hwnd_rgn(hwnd: HWND, width: i32, height: i32) {
|
||||
let padded_border = GetSystemMetrics(SM_CXPADDEDBORDER);
|
||||
let border_x = GetSystemMetrics(SM_CXFRAME) + padded_border;
|
||||
let border_y = GetSystemMetrics(SM_CYFRAME) + padded_border;
|
||||
|
||||
let hrgn1 = CreateRectRgn(0, 0, width, height);
|
||||
let hrgn2 = CreateRectRgn(border_x, border_y, width - border_x, height - border_y);
|
||||
CombineRgn(hrgn1, hrgn1, hrgn2, RGN_DIFF);
|
||||
SetWindowRgn(hwnd, hrgn1, true);
|
||||
}
|
||||
|
||||
fn is_maximized(window: HWND) -> windows::core::Result<bool> {
|
||||
let mut placement = WINDOWPLACEMENT {
|
||||
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
|
||||
..WINDOWPLACEMENT::default()
|
||||
};
|
||||
unsafe { GetWindowPlacement(window, &mut placement)? };
|
||||
Ok(placement.showCmd == SW_MAXIMIZE.0 as u32)
|
||||
}
|
||||
|
||||
/// Implementation of the `GET_X_LPARAM` macro.
|
||||
#[allow(non_snake_case)]
|
||||
#[inline]
|
||||
fn GET_X_LPARAM(lparam: LPARAM) -> i16 {
|
||||
((lparam.0 as usize) & 0xFFFF) as u16 as i16
|
||||
}
|
||||
|
||||
/// Implementation of the `GET_Y_LPARAM` macro.
|
||||
#[allow(non_snake_case)]
|
||||
#[inline]
|
||||
fn GET_Y_LPARAM(lparam: LPARAM) -> i16 {
|
||||
(((lparam.0 as usize) & 0xFFFF_0000) >> 16) as u16 as i16
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,8 +414,10 @@ mod gtk {
|
||||
let (client_x, client_y) = (root_x - window_x as f64, root_y - window_y as f64);
|
||||
let border = window.scale_factor() * BORDERLESS_RESIZE_INSET;
|
||||
let edge = hit_test(
|
||||
window.width(),
|
||||
window.height(),
|
||||
0.0,
|
||||
0.0,
|
||||
window.width() as f64,
|
||||
window.height() as f64,
|
||||
client_x,
|
||||
client_y,
|
||||
border as _,
|
||||
@ -294,8 +455,10 @@ mod gtk {
|
||||
let (client_x, client_y) = (root_x - window_x as f64, root_y - window_y as f64);
|
||||
let border = window.scale_factor() * BORDERLESS_RESIZE_INSET;
|
||||
let edge = hit_test(
|
||||
window.width(),
|
||||
window.height(),
|
||||
0.0,
|
||||
0.0,
|
||||
window.width() as f64,
|
||||
window.height() as f64,
|
||||
client_x,
|
||||
client_y,
|
||||
border as _,
|
||||
|
Loading…
Reference in New Issue
Block a user