Skip to content

Commit

Permalink
fix(core): set parent window handle on dialogs, closes #1876 (#1889)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed May 21, 2021
1 parent 977b3a8 commit abf78c5
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changes/dialog-parent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": patch
---

Set the Tauri window as parent for dialogs.
7 changes: 7 additions & 0 deletions .changes/window-parent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"tauri": patch
"tauri-runtime": patch
"tauri-runtime-wry": patch
---

Adds window native handle getter (HWND on Windows).
17 changes: 17 additions & 0 deletions core/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ impl From<FileDropEventWrapper> for FileDropEvent {
}
}

#[cfg(windows)]
struct Hwnd(*mut std::ffi::c_void);
#[cfg(windows)]
unsafe impl Send for Hwnd {}

#[derive(Debug, Clone)]
enum WindowMessage {
// Getters
Expand All @@ -397,6 +402,8 @@ enum WindowMessage {
CurrentMonitor(Sender<Option<MonitorHandle>>),
PrimaryMonitor(Sender<Option<MonitorHandle>>),
AvailableMonitors(Sender<Vec<MonitorHandle>>),
#[cfg(windows)]
Hwnd(Sender<Hwnd>),
// Setters
SetResizable(bool),
SetTitle(String),
Expand Down Expand Up @@ -547,6 +554,11 @@ impl Dispatch for WryDispatcher {
)
}

#[cfg(windows)]
fn hwnd(&self) -> Result<*mut std::ffi::c_void> {
Ok(dispatcher_getter!(self, WindowMessage::Hwnd).0)
}

// Setters

fn print(&self) -> Result<()> {
Expand Down Expand Up @@ -1126,6 +1138,11 @@ fn handle_event_loop(
WindowMessage::AvailableMonitors(tx) => {
tx.send(window.available_monitors().collect()).unwrap()
}
#[cfg(windows)]
WindowMessage::Hwnd(tx) => {
use wry::application::platform::windows::WindowExtWindows;
tx.send(Hwnd(window.hwnd())).unwrap()
}
// Setters
WindowMessage::SetResizable(resizable) => window.set_resizable(resizable),
WindowMessage::SetTitle(title) => window.set_title(&title),
Expand Down
4 changes: 4 additions & 0 deletions core/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ pub trait Dispatch: Clone + Send + Sized + 'static {
/// Returns the list of all the monitors available on the system.
fn available_monitors(&self) -> crate::Result<Vec<Monitor>>;

/// Returns the native handle that is used by this window.
#[cfg(windows)]
fn hwnd(&self) -> crate::Result<*mut std::ffi::c_void>;

// SETTERS

/// Opens the dialog to prints the contents of the webview.
Expand Down
5 changes: 3 additions & 2 deletions core/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ os_pipe = { version = "0.9", optional = true }

# Dialogs
rfd = "0.4"
raw-window-handle = { version="0.3.3", optional = true }

# Updater
minisign-verify = { version = "0.1", optional = true }
Expand Down Expand Up @@ -126,8 +127,8 @@ shell-all = [ "shell-open", "shell-execute" ]
shell-execute = [ "shared_child", "os_pipe" ]
shell-open = [ "open" ]
dialog-all = [ "dialog-open", "dialog-save" ]
dialog-open = [ ]
dialog-save = [ ]
dialog-open = [ "raw-window-handle" ]
dialog-save = [ "raw-window-handle" ]
http-all = [ ]
http-request = [ ]
notification-all = [ "notify-rust" ]
Expand Down
7 changes: 7 additions & 0 deletions core/tauri/src/api/dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ impl FileDialogBuilder {
self
}

#[cfg(windows)]
/// Sets the parent window of the dialog.
pub fn set_parent<W: raw_window_handle::HasRawWindowHandle>(mut self, parent: &W) -> Self {
self.0 = self.0.set_parent(parent);
self
}

/// Pick one file.
pub fn pick_file(self) -> Option<PathBuf> {
self.0.pick_file()
Expand Down
19 changes: 14 additions & 5 deletions core/tauri/src/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,23 @@ impl Module {
// on macOS, the dialog must run on another thread: https://github.com/rust-windowing/winit/issues/1779
// we do the same on Windows just to stay consistent with `tao` (and it also improves UX because of the event loop)
#[cfg(not(target_os = "linux"))]
Self::Dialog(cmd) => resolver
.respond_async(async move { cmd.run().and_then(|r| r.json).map_err(InvokeError::from) }),
Self::Dialog(cmd) => resolver.respond_async(async move {
cmd
.run(window)
.and_then(|r| r.json)
.map_err(InvokeError::from)
}),
// on Linux, the dialog must run on the main thread.
#[cfg(target_os = "linux")]
Self::Dialog(cmd) => {
let _ = window.run_on_main_thread(|| {
resolver
.respond_closure(move || cmd.run().and_then(|r| r.json).map_err(InvokeError::from))
let window_ = window.clone();
let _ = window.run_on_main_thread(move || {
resolver.respond_closure(move || {
cmd
.run(window_)
.and_then(|r| r.json)
.map_err(InvokeError::from)
})
});
}
Self::Cli(cmd) => {
Expand Down
53 changes: 47 additions & 6 deletions core/tauri/src/endpoints/dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
use super::InvokeResponse;
#[cfg(any(dialog_open, dialog_save))]
use crate::api::dialog::FileDialogBuilder;
use crate::api::dialog::{ask as ask_dialog, message as message_dialog, AskResponse};
use crate::{
api::dialog::{ask as ask_dialog, message as message_dialog, AskResponse},
Params, Window,
};
use serde::Deserialize;

use std::path::PathBuf;
Expand Down Expand Up @@ -68,15 +71,16 @@ pub enum Cmd {
}

impl Cmd {
pub fn run(self) -> crate::Result<InvokeResponse> {
#[allow(unused_variables)]
pub fn run<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
match self {
#[cfg(dialog_open)]
Self::OpenDialog { options } => open(options),
Self::OpenDialog { options } => open(window, options),
#[cfg(not(dialog_open))]
Self::OpenDialog { .. } => Err(crate::Error::ApiNotAllowlisted("dialog > open".to_string())),

#[cfg(dialog_save)]
Self::SaveDialog { options } => save(options),
Self::SaveDialog { options } => save(window, options),
#[cfg(not(dialog_save))]
Self::SaveDialog { .. } => Err(crate::Error::ApiNotAllowlisted("dialog > save".to_string())),

Expand Down Expand Up @@ -139,10 +143,39 @@ fn set_default_path(
}
}

#[cfg(windows)]
struct WindowParent {
hwnd: *mut std::ffi::c_void,
}

#[cfg(windows)]
unsafe impl raw_window_handle::HasRawWindowHandle for WindowParent {
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
let mut handle = raw_window_handle::windows::WindowsHandle::empty();
handle.hwnd = self.hwnd;
raw_window_handle::RawWindowHandle::Windows(handle)
}
}

#[cfg(windows)]
fn parent<P: Params>(window: Window<P>) -> crate::Result<WindowParent> {
Ok(WindowParent {
hwnd: window.hwnd()?,
})
}

/// Shows an open dialog.
#[cfg(dialog_open)]
pub fn open(options: OpenDialogOptions) -> crate::Result<InvokeResponse> {
#[allow(unused_variables)]
pub fn open<P: Params>(
window: Window<P>,
options: OpenDialogOptions,
) -> crate::Result<InvokeResponse> {
let mut dialog_builder = FileDialogBuilder::new();
#[cfg(windows)]
{
dialog_builder = dialog_builder.set_parent(&parent(window)?);
}
if let Some(default_path) = options.default_path {
if !default_path.exists() {
return Err(crate::Error::DialogDefaultPathNotExists(default_path));
Expand All @@ -165,8 +198,16 @@ pub fn open(options: OpenDialogOptions) -> crate::Result<InvokeResponse> {

/// Shows a save dialog.
#[cfg(dialog_save)]
pub fn save(options: SaveDialogOptions) -> crate::Result<InvokeResponse> {
#[allow(unused_variables)]
pub fn save<P: Params>(
window: Window<P>,
options: SaveDialogOptions,
) -> crate::Result<InvokeResponse> {
let mut dialog_builder = FileDialogBuilder::new();
#[cfg(windows)]
{
dialog_builder = dialog_builder.set_parent(&parent(window)?);
}
if let Some(default_path) = options.default_path {
if !default_path.exists() {
return Err(crate::Error::DialogDefaultPathNotExists(default_path));
Expand Down
6 changes: 6 additions & 0 deletions core/tauri/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,12 @@ impl<P: Params> Window<P> {
.map_err(Into::into)
}

/// Returns the native handle that is used by this window.
#[cfg(windows)]
pub fn hwnd(&self) -> crate::Result<*mut std::ffi::c_void> {
self.window.dispatcher.hwnd().map_err(Into::into)
}

// Setters

/// Opens the dialog to prints the contents of the webview.
Expand Down

0 comments on commit abf78c5

Please sign in to comment.