Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions crates/tauri-runtime-cef/src/cef_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ use crate::{
};

mod cookie;
mod drag_window;
mod request_handler;

use cookie::{CollectAllCookiesVisitor, CollectUrlCookiesVisitor};

#[cfg(target_os = "linux")]
Expand Down Expand Up @@ -823,6 +825,11 @@ wrap_window_delegate! {
impl WindowDelegate {
fn on_window_created(&self, window: Option<&mut Window>) {
if let Some(window) = window {

// Setup necessary handling for `start_window_dragging` to work on Windows
#[cfg(windows)]
drag_window::windows::subclass_window_for_dragging(window);

let a = self.attributes.borrow();
if let Some(icon) = a.icon.clone() {
set_window_icon(window, icon);
Expand Down Expand Up @@ -1884,16 +1891,28 @@ fn start_window_dragging(window: &cef::Window) {

#[cfg(windows)]
fn start_window_dragging(window: &cef::Window) {
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::{SendMessageW, HTCAPTION, WM_NCLBUTTONDOWN};
use windows::Win32::Foundation::*;
use windows::Win32::UI::Input::KeyboardAndMouse::*;
use windows::Win32::UI::WindowsAndMessaging::*;

unsafe {
let hwnd = window.window_handle();
let _ = SendMessageW(
HWND(hwnd.0 as _),

let mut pos = std::mem::zeroed();
let _ = GetCursorPos(&mut pos);

let points = POINTS {
x: pos.x as i16,
y: pos.y as i16,
};

let _ = ReleaseCapture();

let _ = PostMessageW(
Some(HWND(hwnd.0 as _)),
WM_NCLBUTTONDOWN,
Some(windows::Win32::Foundation::WPARAM(HTCAPTION as usize)),
Some(windows::Win32::Foundation::LPARAM(0)),
WPARAM(HTCAPTION as usize),
LPARAM(&points as *const _ as isize),
);
}
}
Expand Down
71 changes: 71 additions & 0 deletions crates/tauri-runtime-cef/src/cef_impl/drag_window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

pub mod windows {
use cef::*;
use windows::core::{w, PCWSTR};
use windows::Win32::Foundation::*;
use windows::Win32::UI::WindowsAndMessaging::*;

/// Same as [WNDPROC] but without the Option wrapper.
type WindowProc = unsafe extern "system" fn(HWND, u32, WPARAM, LPARAM) -> LRESULT;

const ORIGINAL_WND_PROP: PCWSTR = w!("TAURI_CEF_ORIGINAL_WND_PROC");

/// Subclasses the given window to handle draggable regions
/// by replacing its window procedure with `root_window_proc`
/// and storing the original procedure as a property to be called later.
pub fn subclass_window_for_dragging(window: &mut cef::Window) {
let hwnd = window.window_handle();
let hwnd = HWND(hwnd.0 as _);
subclass_window(hwnd, root_window_proc);
}

/// Subclasses a window by replacing its window procedure with the given `proc`
/// and storing the original procedure as a property for later use.
fn subclass_window(hwnd: HWND, proc: WindowProc) {
// If already subclassed, return early
let orginial_wnd_proc = unsafe { GetPropW(hwnd, ORIGINAL_WND_PROP) };
if !orginial_wnd_proc.is_invalid() {
return;
}

// Reset last error
unsafe { SetLastError(ERROR_SUCCESS) };

// Set the new window procedure and get the orginal one
let original_wnd_proc = unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, proc as isize) };
if original_wnd_proc == 0 && unsafe { GetLastError() } != ERROR_SUCCESS {
return;
}

unsafe {
// Store the original window proc as a property for later use
let _ = SetPropW(
hwnd,
ORIGINAL_WND_PROP,
Some(HANDLE(original_wnd_proc as _)),
);
}
}

/// The root window procedure to handle WM_NCLBUTTONDOWN
/// by calling DefWindowProcW directly to allow dragging
/// and forwarding other messages to the original CEF window procedure.
unsafe extern "system" fn root_window_proc(
hwnd: HWND,
msg: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
if msg == WM_NCLBUTTONDOWN {
return unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) };
}

// For other messages, call the original CEF window procedure
let original_wnd_proc = GetPropW(hwnd, ORIGINAL_WND_PROP);
let original_wnd_proc = std::mem::transmute::<_, WindowProc>(original_wnd_proc.0);
CallWindowProcW(Some(original_wnd_proc), hwnd, msg, wparam, lparam)
}
}
Loading