Skip to content

Commit 49b99f3

Browse files
authored
fix(cef): fix start_window_dragging on Windows (#14618)
1 parent a0b5d84 commit 49b99f3

File tree

2 files changed

+96
-6
lines changed

2 files changed

+96
-6
lines changed

crates/tauri-runtime-cef/src/cef_impl.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ use crate::{
3030
};
3131

3232
mod cookie;
33+
mod drag_window;
3334
mod request_handler;
35+
3436
use cookie::{CollectAllCookiesVisitor, CollectUrlCookiesVisitor};
3537

3638
#[cfg(target_os = "linux")]
@@ -823,6 +825,11 @@ wrap_window_delegate! {
823825
impl WindowDelegate {
824826
fn on_window_created(&self, window: Option<&mut Window>) {
825827
if let Some(window) = window {
828+
829+
// Setup necessary handling for `start_window_dragging` to work on Windows
830+
#[cfg(windows)]
831+
drag_window::windows::subclass_window_for_dragging(window);
832+
826833
let a = self.attributes.borrow();
827834
if let Some(icon) = a.icon.clone() {
828835
set_window_icon(window, icon);
@@ -1884,16 +1891,28 @@ fn start_window_dragging(window: &cef::Window) {
18841891

18851892
#[cfg(windows)]
18861893
fn start_window_dragging(window: &cef::Window) {
1887-
use windows::Win32::Foundation::HWND;
1888-
use windows::Win32::UI::WindowsAndMessaging::{SendMessageW, HTCAPTION, WM_NCLBUTTONDOWN};
1894+
use windows::Win32::Foundation::*;
1895+
use windows::Win32::UI::Input::KeyboardAndMouse::*;
1896+
use windows::Win32::UI::WindowsAndMessaging::*;
18891897

18901898
unsafe {
18911899
let hwnd = window.window_handle();
1892-
let _ = SendMessageW(
1893-
HWND(hwnd.0 as _),
1900+
1901+
let mut pos = std::mem::zeroed();
1902+
let _ = GetCursorPos(&mut pos);
1903+
1904+
let points = POINTS {
1905+
x: pos.x as i16,
1906+
y: pos.y as i16,
1907+
};
1908+
1909+
let _ = ReleaseCapture();
1910+
1911+
let _ = PostMessageW(
1912+
Some(HWND(hwnd.0 as _)),
18941913
WM_NCLBUTTONDOWN,
1895-
Some(windows::Win32::Foundation::WPARAM(HTCAPTION as usize)),
1896-
Some(windows::Win32::Foundation::LPARAM(0)),
1914+
WPARAM(HTCAPTION as usize),
1915+
LPARAM(&points as *const _ as isize),
18971916
);
18981917
}
18991918
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
2+
// SPDX-License-Identifier: Apache-2.0
3+
// SPDX-License-Identifier: MIT
4+
5+
pub mod windows {
6+
use cef::*;
7+
use windows::core::{w, PCWSTR};
8+
use windows::Win32::Foundation::*;
9+
use windows::Win32::UI::WindowsAndMessaging::*;
10+
11+
/// Same as [WNDPROC] but without the Option wrapper.
12+
type WindowProc = unsafe extern "system" fn(HWND, u32, WPARAM, LPARAM) -> LRESULT;
13+
14+
const ORIGINAL_WND_PROP: PCWSTR = w!("TAURI_CEF_ORIGINAL_WND_PROC");
15+
16+
/// Subclasses the given window to handle draggable regions
17+
/// by replacing its window procedure with `root_window_proc`
18+
/// and storing the original procedure as a property to be called later.
19+
pub fn subclass_window_for_dragging(window: &mut cef::Window) {
20+
let hwnd = window.window_handle();
21+
let hwnd = HWND(hwnd.0 as _);
22+
subclass_window(hwnd, root_window_proc);
23+
}
24+
25+
/// Subclasses a window by replacing its window procedure with the given `proc`
26+
/// and storing the original procedure as a property for later use.
27+
fn subclass_window(hwnd: HWND, proc: WindowProc) {
28+
// If already subclassed, return early
29+
let orginial_wnd_proc = unsafe { GetPropW(hwnd, ORIGINAL_WND_PROP) };
30+
if !orginial_wnd_proc.is_invalid() {
31+
return;
32+
}
33+
34+
// Reset last error
35+
unsafe { SetLastError(ERROR_SUCCESS) };
36+
37+
// Set the new window procedure and get the orginal one
38+
let original_wnd_proc = unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, proc as isize) };
39+
if original_wnd_proc == 0 && unsafe { GetLastError() } != ERROR_SUCCESS {
40+
return;
41+
}
42+
43+
unsafe {
44+
// Store the original window proc as a property for later use
45+
let _ = SetPropW(
46+
hwnd,
47+
ORIGINAL_WND_PROP,
48+
Some(HANDLE(original_wnd_proc as _)),
49+
);
50+
}
51+
}
52+
53+
/// The root window procedure to handle WM_NCLBUTTONDOWN
54+
/// by calling DefWindowProcW directly to allow dragging
55+
/// and forwarding other messages to the original CEF window procedure.
56+
unsafe extern "system" fn root_window_proc(
57+
hwnd: HWND,
58+
msg: u32,
59+
wparam: WPARAM,
60+
lparam: LPARAM,
61+
) -> LRESULT {
62+
if msg == WM_NCLBUTTONDOWN {
63+
return unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) };
64+
}
65+
66+
// For other messages, call the original CEF window procedure
67+
let original_wnd_proc = GetPropW(hwnd, ORIGINAL_WND_PROP);
68+
let original_wnd_proc = std::mem::transmute::<_, WindowProc>(original_wnd_proc.0);
69+
CallWindowProcW(Some(original_wnd_proc), hwnd, msg, wparam, lparam)
70+
}
71+
}

0 commit comments

Comments
 (0)