diff --git a/.changes/config-tray-icon-tooltip.md b/.changes/config-tray-icon-tooltip.md
new file mode 100644
index 000000000000..b02a90d6eed7
--- /dev/null
+++ b/.changes/config-tray-icon-tooltip.md
@@ -0,0 +1,5 @@
+---
+'tauri-utils': 'minor:feat'
+---
+
+Add option to specify a tooltip text for the tray icon in the config.
diff --git a/.changes/config-tray-icon.md b/.changes/config-tray-icon.md
new file mode 100644
index 000000000000..86e36cbefd75
--- /dev/null
+++ b/.changes/config-tray-icon.md
@@ -0,0 +1,5 @@
+---
+'tauri-utils': 'major:breaking'
+---
+
+`systemTray` config option has been renamed to `trayIcon`.
diff --git a/.changes/runtime-create-window-handler.md b/.changes/runtime-create-window-handler.md
new file mode 100644
index 000000000000..ab624f8e4503
--- /dev/null
+++ b/.changes/runtime-create-window-handler.md
@@ -0,0 +1,6 @@
+---
+'tauri-runtime': 'minor:breaking'
+'tauri-runtime-wry': 'minor:breaking'
+---
+
+`Dispatch::create_window`, `Runtime::create_window` and `RuntimeHandle::create_window` has been changed to accept a 3rd parameter which is a closure that takes `RawWindow` and to be executed right after the window is created and before the webview is added to the window.
diff --git a/.changes/runtime-defaultvbox.md b/.changes/runtime-defaultvbox.md
new file mode 100644
index 000000000000..51c38df25354
--- /dev/null
+++ b/.changes/runtime-defaultvbox.md
@@ -0,0 +1,5 @@
+---
+'tauri-runtime-wry': 'minor:feat'
+---
+
+Add `Dispatch::default_vbox`
diff --git a/.changes/runtime-menu-system-tray.md b/.changes/runtime-menu-system-tray.md
new file mode 100644
index 000000000000..49102235610e
--- /dev/null
+++ b/.changes/runtime-menu-system-tray.md
@@ -0,0 +1,6 @@
+---
+'tauri-runtime': 'major:breaking'
+'tauri-runtime-wry': 'major:breaking'
+---
+
+System tray and menu related APIs and structs have all been removed and are now implemented in tauri outside of the runtime-space.
diff --git a/.changes/runtime-new-args.md b/.changes/runtime-new-args.md
new file mode 100644
index 000000000000..e5fc889aff35
--- /dev/null
+++ b/.changes/runtime-new-args.md
@@ -0,0 +1,6 @@
+---
+'tauri-runtime': 'minor:breaking'
+'tauri-runtime-wry': 'minor:breaking'
+---
+
+`Runtime::new` and `Runtime::new_any_thread` now accept a `RuntimeInitArgs`.
diff --git a/.changes/system-tray-feat.md b/.changes/system-tray-feat.md
new file mode 100644
index 000000000000..2516e4e432da
--- /dev/null
+++ b/.changes/system-tray-feat.md
@@ -0,0 +1,6 @@
+---
+'tauri-runtime': 'major:breaking'
+'tauri-runtime-wry': 'major:breaking'
+---
+
+Removed `system-tray` feature flag
diff --git a/.changes/tauri-app-handle-ref.md b/.changes/tauri-app-handle-ref.md
new file mode 100644
index 000000000000..7afc2171ea62
--- /dev/null
+++ b/.changes/tauri-app-handle-ref.md
@@ -0,0 +1,5 @@
+---
+'tauri': 'major:breaking'
+---
+
+Changed `App::handle` and `Manager::app_handle` to return a reference to an `AppHandle` instead of an owned value.
diff --git a/.changes/tauri-cleanup-before-exit.md b/.changes/tauri-cleanup-before-exit.md
new file mode 100644
index 000000000000..ff99c9215f4f
--- /dev/null
+++ b/.changes/tauri-cleanup-before-exit.md
@@ -0,0 +1,5 @@
+---
+'tauri': 'minor:feat'
+---
+
+Add `App::cleanup_before_exit` and `AppHandle::cleanup_before_exit` to manually call the cleanup logic. **You should always exit the tauri app immediately after this function returns and not use any tauri-related APIs.**
diff --git a/.changes/tauri-defaultvbox.md b/.changes/tauri-defaultvbox.md
new file mode 100644
index 000000000000..967fb66f440d
--- /dev/null
+++ b/.changes/tauri-defaultvbox.md
@@ -0,0 +1,5 @@
+---
+'tauri': 'minor:feat'
+---
+
+On Linux, add `Window::default_vbox` to get a reference to the `gtk::Box` that contains the menu bar and the webview.
diff --git a/.changes/tauri-libxdo-feat.md b/.changes/tauri-libxdo-feat.md
new file mode 100644
index 000000000000..648376946e65
--- /dev/null
+++ b/.changes/tauri-libxdo-feat.md
@@ -0,0 +1,5 @@
+---
+'tauri': 'minor:feat'
+---
+
+Add `linux-libxdo` feature flag (disabled by default) to enable linking to `libxdo` which is used to make `Cut`, `Copy`, `Paste` and `SelectAll` native menu items work on Linux.
diff --git a/.changes/tauri-menu-tray-refactor.md b/.changes/tauri-menu-tray-refactor.md
new file mode 100644
index 000000000000..7c21970ce12b
--- /dev/null
+++ b/.changes/tauri-menu-tray-refactor.md
@@ -0,0 +1,17 @@
+---
+'tauri': 'major:breaking'
+---
+
+The tray icon and menu have received a huge refactor with a lot of breaking changes in order to add new functionalities and improve the DX around using them and here is an overview of the changes:
+
+- All menu and tray types are now exported from `tauri::menu` and `tauri::tray` modules with new names so make sure to check the new types.
+- Removed `tauri::Builder::system_tray`, instead you should use `tauri::tray::TrayIconBuilder` inside `tauri::Builder::setup` hook to create your tray icons.
+- Changed `tauri::Builder::menu` to be a function to accomodate for new menu changes, you can passe `tauri::menu::Menu::default` to it to create a default menu.
+- Renamed `tauri::Context` methods `system_tray_icon`, `tauri::Context::system_tray_icon_mut` and `tauri::Context::set_system_tray_icon` to `tauri::Context::tray_icon`, `tauri::Context::tray_icon_mut` and `tauri::Context::set_tray_icon` to be consistent with new type names.
+- Added `RunEvent::MenuEvent` and `RunEvent::TrayIconEvent`.
+- Added `App/AppHandle::set_menu`, `App/AppHandle::remove_menu`, `App/AppHandle::show_menu`, `App/AppHandle::hide_menu` and `App/AppHandle::menu` to access, remove, hide or show the app-wide menu that is used as the global menu on macOS and on all windows that don't have a specific menu set for it on Windows and Linux.
+- Added `Window::set_menu`, `Window::remove_menu`, `Window::show_menu`, `Window::hide_menu`, `Window::is_menu_visible` and `Window::menu` to access, remove, hide or show the menu on this window.
+- Added `Window::popup_menu` and `Window::popup_menu_at` to show a context menu on the window at the cursor position or at a specific position. You can also popup a context menu using `popup` and `popup_at` methods from `ContextMenu` trait which is implemented for `Menu` and `Submenu` types.
+- Added `App/AppHandle::tray`, `App/AppHandle::tray_by_id`, `App/AppHandle::remove_tray` and `App/AppHandle::remove_tray_by_id` to access or remove a registered tray.
+- Added `WindowBuilder/App/AppHandle::on_menu_event` to register a new menu event handler.
+- Added `App/AppHandle::on_tray_icon_event` to register a new tray event handler.
diff --git a/.changes/tauri-nsview.md b/.changes/tauri-nsview.md
new file mode 100644
index 000000000000..e50bfb0b2ebc
--- /dev/null
+++ b/.changes/tauri-nsview.md
@@ -0,0 +1,5 @@
+---
+'tauri': 'minor:feat'
+---
+
+On macOS, add `Window::ns_view` to get a pointer to the NSWindow content view.
diff --git a/.changes/tauri-run_on_main_thread.md b/.changes/tauri-run_on_main_thread.md
new file mode 100644
index 000000000000..a9bbc7a296c8
--- /dev/null
+++ b/.changes/tauri-run_on_main_thread.md
@@ -0,0 +1,5 @@
+---
+'tauri': 'minor:feat'
+---
+
+Expose `run_on_main_thread` method on `App` that is similar to `AppHandle::run_on_main_thread`.
diff --git a/.changes/tauri-tray-icon-feat-flag.md b/.changes/tauri-tray-icon-feat-flag.md
new file mode 100644
index 000000000000..7bbad7a6594a
--- /dev/null
+++ b/.changes/tauri-tray-icon-feat-flag.md
@@ -0,0 +1,5 @@
+---
+'tauri': 'major:breaking'
+---
+
+Renamed `system-tray` feature flag to `tray-icon`.
diff --git a/.github/workflows/lint-core.yml b/.github/workflows/lint-core.yml
index 3729dff688d3..fb1251bb2ac1 100644
--- a/.github/workflows/lint-core.yml
+++ b/.github/workflows/lint-core.yml
@@ -50,7 +50,7 @@ jobs:
clippy:
- { args: '', key: 'empty' }
- {
- args: '--features compression,wry,isolation,custom-protocol,system-tray,test',
+ args: '--features compression,wry,linux-ipc-protocol,isolation,custom-protocol,tray-icon,test',
key: 'all'
}
- { args: '--features custom-protocol', key: 'custom-protocol' }
diff --git a/.github/workflows/test-core.yml b/.github/workflows/test-core.yml
index 6b604201cd88..3fe76186e770 100644
--- a/.github/workflows/test-core.yml
+++ b/.github/workflows/test-core.yml
@@ -72,7 +72,7 @@ jobs:
key: no-default
}
- {
- args: --features compression,wry,isolation,custom-protocol,system-tray,test,
+ args: --features compression,wry,linux-ipc-protocol,isolation,custom-protocol,tray-icon,test,
key: all
}
diff --git a/Cargo.toml b/Cargo.toml
index 369e7c461f08..63ee69bc15d5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,7 +18,6 @@ exclude = [
# examples that can be compiled with the tauri CLI
"examples/api/src-tauri",
"examples/resources/src-tauri",
- "examples/sidecar/src-tauri",
"examples/web/core",
"examples/file-associations/src-tauri",
"examples/workspace",
diff --git a/core/tauri-build/src/allowlist.rs b/core/tauri-build/src/allowlist.rs
index 34654f689c37..813a315339db 100644
--- a/core/tauri-build/src/allowlist.rs
+++ b/core/tauri-build/src/allowlist.rs
@@ -43,7 +43,12 @@ pub fn check(config: &Config, manifest: &mut Manifest) -> Result<()> {
name: "tauri".into(),
alias: None,
kind: DependencyKind::Normal,
- all_cli_managed_features: Some(TauriConfig::all_features()),
+ all_cli_managed_features: Some(
+ TauriConfig::all_features()
+ .into_iter()
+ .filter(|f| f != &"tray-icon")
+ .collect(),
+ ),
expected_features: config
.tauri
.features()
diff --git a/core/tauri-build/src/codegen/context.rs b/core/tauri-build/src/codegen/context.rs
index e17fe3b8f8d4..f702ce21205f 100644
--- a/core/tauri-build/src/codegen/context.rs
+++ b/core/tauri-build/src/codegen/context.rs
@@ -120,7 +120,7 @@ impl CodegenContext {
config_parent.join(icon).display()
);
}
- if let Some(tray_icon) = config.tauri.system_tray.as_ref().map(|t| &t.icon_path) {
+ if let Some(tray_icon) = config.tauri.tray_icon.as_ref().map(|t| &t.icon_path) {
println!(
"cargo:rerun-if-changed={}",
config_parent.join(tray_icon).display()
diff --git a/core/tauri-build/src/mobile.rs b/core/tauri-build/src/mobile.rs
index 1a29cbc771be..4f134ef78d80 100644
--- a/core/tauri-build/src/mobile.rs
+++ b/core/tauri-build/src/mobile.rs
@@ -222,7 +222,7 @@ fn insert_into_xml(xml: &str, block_identifier: &str, parent_tag: &str, contents
rewritten.push(line.to_string());
}
- rewritten.join("\n").to_string()
+ rewritten.join("\n")
}
pub fn update_android_manifest(block_identifier: &str, parent: &str, insert: String) -> Result<()> {
@@ -294,16 +294,14 @@ dependencies {"
mod tests {
#[test]
fn insert_into_xml() {
- let manifest = format!(
- r#"
+ let manifest = r#"
- "#
- );
+ "#;
let id = "tauritest";
- let new = super::insert_into_xml(&manifest, id, "application", " ");
+ let new = super::insert_into_xml(manifest, id, "application", " ");
let block_id_comment = super::xml_block_comment(id);
let expected = format!(
diff --git a/core/tauri-codegen/README.md b/core/tauri-codegen/README.md
index 3f3e15990f28..8d5518db7b76 100644
--- a/core/tauri-codegen/README.md
+++ b/core/tauri-codegen/README.md
@@ -24,7 +24,7 @@ Tauri apps can have custom menus and have tray-type interfaces. They can be upda
## This module
-- Embed, hash, and compress assets, including icons for the app as well as the system-tray.
+- Embed, hash, and compress assets, including icons for the app as well as the tray icon.
- Parse `tauri.conf.json` at compile time and generate the Config struct.
To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document.
diff --git a/core/tauri-codegen/src/context.rs b/core/tauri-codegen/src/context.rs
index cf556e5120cc..788db7db5d43 100644
--- a/core/tauri-codegen/src/context.rs
+++ b/core/tauri-codegen/src/context.rs
@@ -264,8 +264,8 @@ pub fn context_codegen(data: ContextData) -> Result Result Result Result bool + 'static;
-#[cfg(all(desktop, feature = "system-tray"))]
-pub use tauri_runtime::TrayId;
mod webview;
pub use webview::Webview;
-#[cfg(all(desktop, feature = "system-tray"))]
-mod system_tray;
-#[cfg(all(desktop, feature = "system-tray"))]
-use system_tray::*;
-
pub type WebContextStore = Arc, WebContext>>>;
// window
pub type WindowEventHandler = Box;
pub type WindowEventListeners = Arc>>;
-// menu
-pub type MenuEventHandler = Box;
-pub type WindowMenuEventListeners = Arc>>;
#[derive(Debug, Clone, Default)]
pub struct WebviewIdStore(Arc>>);
@@ -174,8 +154,6 @@ pub(crate) fn send_user_message(
UserMessageContext {
webview_id_map: context.webview_id_map.clone(),
windows: context.main_thread.windows.clone(),
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager: context.main_thread.system_tray_manager.clone(),
},
&context.main_thread.web_context,
);
@@ -211,9 +189,12 @@ impl Context {
}
impl Context {
- fn create_webview(&self, pending: PendingWindow>) -> Result>> {
+ fn create_webview(
+ &self,
+ pending: PendingWindow>,
+ before_webview_creation: Option,
+ ) -> Result>> {
let label = pending.label.clone();
- let menu_ids = pending.menu_ids.clone();
let context = self.clone();
let window_id = rand::random();
@@ -222,7 +203,14 @@ impl Context {
Message::CreateWebview(
window_id,
Box::new(move |event_loop, web_context| {
- create_webview(window_id, event_loop, web_context, context, pending)
+ create_webview(
+ window_id,
+ event_loop,
+ web_context,
+ context,
+ pending,
+ before_webview_creation,
+ )
}),
),
)?;
@@ -231,21 +219,25 @@ impl Context {
window_id,
context: self.clone(),
};
- Ok(DetachedWindow {
- label,
- dispatcher,
- menu_ids,
- })
+ Ok(DetachedWindow { label, dispatcher })
}
}
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub struct DispatcherMainThreadContext {
pub window_target: EventLoopWindowTarget>,
pub web_context: WebContextStore,
pub windows: Arc>>,
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager: SystemTrayManager,
+}
+
+impl std::fmt::Debug for DispatcherMainThreadContext {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("DispatcherMainThreadContext")
+ .field("window_target", &self.window_target)
+ .field("web_context", &self.web_context)
+ .field("windows", &self.windows)
+ .finish()
+ }
}
// SAFETY: we ensure this type is only used on the main thread.
@@ -299,67 +291,6 @@ impl From for HttpResponseWrapper {
}
}
-pub struct MenuItemAttributesWrapper<'a>(pub WryMenuItemAttributes<'a>);
-
-impl<'a> From<&'a CustomMenuItem> for MenuItemAttributesWrapper<'a> {
- fn from(item: &'a CustomMenuItem) -> Self {
- let mut attributes = WryMenuItemAttributes::new(&item.title)
- .with_enabled(item.enabled)
- .with_selected(item.selected)
- .with_id(WryMenuId(item.id));
- if let Some(accelerator) = item.keyboard_accelerator.as_ref() {
- attributes = attributes.with_accelerators(&accelerator.parse().expect("invalid accelerator"));
- }
- Self(attributes)
- }
-}
-
-pub struct AboutMetadataWrapper(pub WryAboutMetadata);
-
-impl From for AboutMetadataWrapper {
- fn from(metadata: AboutMetadata) -> Self {
- Self(WryAboutMetadata {
- version: metadata.version,
- authors: metadata.authors,
- comments: metadata.comments,
- copyright: metadata.copyright,
- license: metadata.license,
- website: metadata.website,
- website_label: metadata.website_label,
- })
- }
-}
-
-pub struct MenuItemWrapper(pub WryMenuItem);
-
-impl From for MenuItemWrapper {
- fn from(item: MenuItem) -> Self {
- match item {
- MenuItem::About(name, metadata) => Self(WryMenuItem::About(
- name,
- AboutMetadataWrapper::from(metadata).0,
- )),
- MenuItem::Hide => Self(WryMenuItem::Hide),
- MenuItem::Services => Self(WryMenuItem::Services),
- MenuItem::HideOthers => Self(WryMenuItem::HideOthers),
- MenuItem::ShowAll => Self(WryMenuItem::ShowAll),
- MenuItem::CloseWindow => Self(WryMenuItem::CloseWindow),
- MenuItem::Quit => Self(WryMenuItem::Quit),
- MenuItem::Copy => Self(WryMenuItem::Copy),
- MenuItem::Cut => Self(WryMenuItem::Cut),
- MenuItem::Undo => Self(WryMenuItem::Undo),
- MenuItem::Redo => Self(WryMenuItem::Redo),
- MenuItem::SelectAll => Self(WryMenuItem::SelectAll),
- MenuItem::Paste => Self(WryMenuItem::Paste),
- MenuItem::EnterFullScreen => Self(WryMenuItem::EnterFullScreen),
- MenuItem::Minimize => Self(WryMenuItem::Minimize),
- MenuItem::Zoom => Self(WryMenuItem::Zoom),
- MenuItem::Separator => Self(WryMenuItem::Separator),
- _ => unimplemented!(),
- }
- }
-}
-
pub struct DeviceEventFilterWrapper(pub WryDeviceEventFilter);
impl From for DeviceEventFilterWrapper {
@@ -372,82 +303,6 @@ impl From for DeviceEventFilterWrapper {
}
}
-#[cfg(target_os = "macos")]
-pub struct NativeImageWrapper(pub WryNativeImage);
-
-#[cfg(target_os = "macos")]
-impl std::fmt::Debug for NativeImageWrapper {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("NativeImageWrapper").finish()
- }
-}
-
-#[cfg(target_os = "macos")]
-impl From for NativeImageWrapper {
- fn from(image: NativeImage) -> NativeImageWrapper {
- let wry_image = match image {
- NativeImage::Add => WryNativeImage::Add,
- NativeImage::Advanced => WryNativeImage::Advanced,
- NativeImage::Bluetooth => WryNativeImage::Bluetooth,
- NativeImage::Bookmarks => WryNativeImage::Bookmarks,
- NativeImage::Caution => WryNativeImage::Caution,
- NativeImage::ColorPanel => WryNativeImage::ColorPanel,
- NativeImage::ColumnView => WryNativeImage::ColumnView,
- NativeImage::Computer => WryNativeImage::Computer,
- NativeImage::EnterFullScreen => WryNativeImage::EnterFullScreen,
- NativeImage::Everyone => WryNativeImage::Everyone,
- NativeImage::ExitFullScreen => WryNativeImage::ExitFullScreen,
- NativeImage::FlowView => WryNativeImage::FlowView,
- NativeImage::Folder => WryNativeImage::Folder,
- NativeImage::FolderBurnable => WryNativeImage::FolderBurnable,
- NativeImage::FolderSmart => WryNativeImage::FolderSmart,
- NativeImage::FollowLinkFreestanding => WryNativeImage::FollowLinkFreestanding,
- NativeImage::FontPanel => WryNativeImage::FontPanel,
- NativeImage::GoLeft => WryNativeImage::GoLeft,
- NativeImage::GoRight => WryNativeImage::GoRight,
- NativeImage::Home => WryNativeImage::Home,
- NativeImage::IChatTheater => WryNativeImage::IChatTheater,
- NativeImage::IconView => WryNativeImage::IconView,
- NativeImage::Info => WryNativeImage::Info,
- NativeImage::InvalidDataFreestanding => WryNativeImage::InvalidDataFreestanding,
- NativeImage::LeftFacingTriangle => WryNativeImage::LeftFacingTriangle,
- NativeImage::ListView => WryNativeImage::ListView,
- NativeImage::LockLocked => WryNativeImage::LockLocked,
- NativeImage::LockUnlocked => WryNativeImage::LockUnlocked,
- NativeImage::MenuMixedState => WryNativeImage::MenuMixedState,
- NativeImage::MenuOnState => WryNativeImage::MenuOnState,
- NativeImage::MobileMe => WryNativeImage::MobileMe,
- NativeImage::MultipleDocuments => WryNativeImage::MultipleDocuments,
- NativeImage::Network => WryNativeImage::Network,
- NativeImage::Path => WryNativeImage::Path,
- NativeImage::PreferencesGeneral => WryNativeImage::PreferencesGeneral,
- NativeImage::QuickLook => WryNativeImage::QuickLook,
- NativeImage::RefreshFreestanding => WryNativeImage::RefreshFreestanding,
- NativeImage::Refresh => WryNativeImage::Refresh,
- NativeImage::Remove => WryNativeImage::Remove,
- NativeImage::RevealFreestanding => WryNativeImage::RevealFreestanding,
- NativeImage::RightFacingTriangle => WryNativeImage::RightFacingTriangle,
- NativeImage::Share => WryNativeImage::Share,
- NativeImage::Slideshow => WryNativeImage::Slideshow,
- NativeImage::SmartBadge => WryNativeImage::SmartBadge,
- NativeImage::StatusAvailable => WryNativeImage::StatusAvailable,
- NativeImage::StatusNone => WryNativeImage::StatusNone,
- NativeImage::StatusPartiallyAvailable => WryNativeImage::StatusPartiallyAvailable,
- NativeImage::StatusUnavailable => WryNativeImage::StatusUnavailable,
- NativeImage::StopProgressFreestanding => WryNativeImage::StopProgressFreestanding,
- NativeImage::StopProgress => WryNativeImage::StopProgress,
-
- NativeImage::TrashEmpty => WryNativeImage::TrashEmpty,
- NativeImage::TrashFull => WryNativeImage::TrashFull,
- NativeImage::User => WryNativeImage::User,
- NativeImage::UserAccounts => WryNativeImage::UserAccounts,
- NativeImage::UserGroup => WryNativeImage::UserGroup,
- NativeImage::UserGuest => WryNativeImage::UserGuest,
- };
- Self(wry_image)
- }
-}
-
/// Wrapper around a [`wry::application::window::Icon`] that can be created from an [`Icon`].
pub struct WryIcon(pub WryWindowIcon);
@@ -684,13 +539,24 @@ impl From for CursorIconWrapper {
}
}
-#[derive(Debug, Clone, Default)]
+#[derive(Clone, Default)]
pub struct WindowBuilderWrapper {
inner: WryWindowBuilder,
center: bool,
#[cfg(target_os = "macos")]
tabbing_identifier: Option,
- menu: Option,
+}
+
+impl std::fmt::Debug for WindowBuilderWrapper {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut s = f.debug_struct("WindowBuilderWrapper");
+ s.field("inner", &self.inner).field("center", &self.center);
+ #[cfg(target_os = "macos")]
+ {
+ s.field("tabbing_identifier", &self.tabbing_identifier);
+ }
+ s.finish()
+ }
}
// SAFETY: this type is `Send` since `menu_items` are read only here
@@ -773,11 +639,6 @@ impl WindowBuilder for WindowBuilderWrapper {
window
}
- fn menu(mut self, menu: Menu) -> Self {
- self.menu.replace(menu);
- self
- }
-
fn center(mut self) -> Self {
self.center = true;
self
@@ -902,7 +763,7 @@ impl WindowBuilder for WindowBuilderWrapper {
#[cfg(windows)]
fn parent_window(mut self, parent: HWND) -> Self {
- self.inner = self.inner.with_parent_window(parent);
+ self.inner = self.inner.with_parent_window(parent.0);
self
}
@@ -914,7 +775,7 @@ impl WindowBuilder for WindowBuilderWrapper {
#[cfg(windows)]
fn owner_window(mut self, owner: HWND) -> Self {
- self.inner = self.inner.with_owner_window(owner);
+ self.inner = self.inner.with_owner_window(owner.0);
self
}
@@ -986,10 +847,6 @@ impl WindowBuilder for WindowBuilderWrapper {
fn has_icon(&self) -> bool {
self.inner.window.window_icon.is_some()
}
-
- fn get_menu(&self) -> Option<&Menu> {
- self.menu.as_ref()
- }
}
pub struct FileDropEventWrapper(WryFileDropEvent);
@@ -1055,6 +912,24 @@ pub struct GtkWindow(pub gtk::ApplicationWindow);
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl Send for GtkWindow {}
+#[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+pub struct GtkBox(pub gtk::Box);
+#[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+#[allow(clippy::non_send_fields_in_send_ty)]
+unsafe impl Send for GtkBox {}
+
pub struct RawWindowHandle(pub raw_window_handle::RawWindowHandle);
unsafe impl Send for RawWindowHandle {}
@@ -1068,7 +943,6 @@ pub enum ApplicationMessage {
pub enum WindowMessage {
WithWebview(Box),
AddEventListener(Uuid, Box),
- AddMenuEventListener(Uuid, Box),
// Devtools
#[cfg(any(debug_assertions, feature = "devtools"))]
OpenDevTools,
@@ -1094,7 +968,6 @@ pub enum WindowMessage {
IsClosable(Sender),
IsVisible(Sender),
Title(Sender),
- IsMenuVisible(Sender),
CurrentMonitor(Sender>),
PrimaryMonitor(Sender >),
AvailableMonitors(Sender>),
@@ -1106,6 +979,14 @@ pub enum WindowMessage {
target_os = "openbsd"
))]
GtkWindow(Sender),
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ GtkBox(Sender),
RawWindowHandle(Sender),
Theme(Sender),
// Setters
@@ -1121,8 +1002,6 @@ pub enum WindowMessage {
Unmaximize,
Minimize,
Unminimize,
- ShowMenu,
- HideMenu,
Show,
Hide,
Close,
@@ -1145,7 +1024,6 @@ pub enum WindowMessage {
SetCursorPosition(Position),
SetIgnoreCursorEvents(bool),
DragWindow,
- UpdateMenuItem(u16, MenuUpdate),
RequestRedraw,
}
@@ -1163,21 +1041,6 @@ pub enum WebviewEvent {
Focused(bool),
}
-#[cfg(all(desktop, feature = "system-tray"))]
-#[derive(Debug, Clone)]
-pub enum TrayMessage {
- UpdateItem(u16, MenuUpdate),
- UpdateMenu(SystemTrayMenu),
- UpdateIcon(Icon),
- #[cfg(target_os = "macos")]
- UpdateIconAsTemplate(bool),
- #[cfg(target_os = "macos")]
- UpdateTitle(String),
- UpdateTooltip(String),
- Create(SystemTray, Sender>),
- Destroy(Sender>),
-}
-
pub type CreateWebviewClosure = Box<
dyn FnOnce(&EventLoopWindowTarget>, &WebContextStore) -> Result + Send,
>;
@@ -1188,8 +1051,6 @@ pub enum Message {
Application(ApplicationMessage),
Window(WebviewId, WindowMessage),
Webview(WebviewId, WebviewMessage),
- #[cfg(all(desktop, feature = "system-tray"))]
- Tray(TrayId, TrayMessage),
CreateWebview(WebviewId, CreateWebviewClosure),
CreateWindow(
WebviewId,
@@ -1203,8 +1064,6 @@ impl Clone for Message {
fn clone(&self) -> Self {
match self {
Self::Webview(i, m) => Self::Webview(*i, m.clone()),
- #[cfg(all(desktop, feature = "system-tray"))]
- Self::Tray(i, m) => Self::Tray(*i, m.clone()),
Self::UserEvent(t) => Self::UserEvent(t.clone()),
_ => unimplemented!(),
}
@@ -1239,15 +1098,6 @@ impl Dispatch for WryDispatcher {
id
}
- fn on_menu_event(&self, f: F) -> Uuid {
- let id = Uuid::new_v4();
- let _ = self.context.proxy.send_event(Message::Window(
- self.window_id,
- WindowMessage::AddMenuEventListener(id, Box::new(f)),
- ));
- id
- }
-
fn with_webview) + Send + 'static>(&self, f: F) -> Result<()> {
send_user_message(
&self.context,
@@ -1355,10 +1205,6 @@ impl Dispatch for WryDispatcher {
window_getter!(self, WindowMessage::Title)
}
- fn is_menu_visible(&self) -> Result {
- window_getter!(self, WindowMessage::IsMenuVisible)
- }
-
fn current_monitor(&self) -> Result> {
Ok(window_getter!(self, WindowMessage::CurrentMonitor)?.map(|m| MonitorHandleWrapper(m).into()))
}
@@ -1380,7 +1226,6 @@ impl Dispatch for WryDispatcher {
window_getter!(self, WindowMessage::Theme)
}
- /// Returns the `ApplicationWindow` from gtk crate that is used by this window.
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
@@ -1392,6 +1237,17 @@ impl Dispatch for WryDispatcher {
window_getter!(self, WindowMessage::GtkWindow).map(|w| w.0)
}
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ fn default_vbox(&self) -> Result {
+ window_getter!(self, WindowMessage::GtkBox).map(|w| w.0)
+ }
+
fn raw_window_handle(&self) -> Result {
window_getter!(self, WindowMessage::RawWindowHandle).map(|w| w.0)
}
@@ -1424,11 +1280,14 @@ impl Dispatch for WryDispatcher {
// Creates a window by dispatching a message to the event loop.
// Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
- fn create_window(
+ fn create_window(
&mut self,
pending: PendingWindow,
+ before_webview_creation: Option,
) -> Result> {
- self.context.create_webview(pending)
+ self
+ .context
+ .create_webview(pending, before_webview_creation)
}
fn set_resizable(&self, resizable: bool) -> Result<()> {
@@ -1501,20 +1360,6 @@ impl Dispatch for WryDispatcher {
)
}
- fn show_menu(&self) -> Result<()> {
- send_user_message(
- &self.context,
- Message::Window(self.window_id, WindowMessage::ShowMenu),
- )
- }
-
- fn hide_menu(&self) -> Result<()> {
- send_user_message(
- &self.context,
- Message::Window(self.window_id, WindowMessage::HideMenu),
- )
- }
-
fn show(&self) -> Result<()> {
send_user_message(
&self.context,
@@ -1692,13 +1537,6 @@ impl Dispatch for WryDispatcher {
),
)
}
-
- fn update_menu_item(&self, id: u16, update: MenuUpdate) -> Result<()> {
- send_user_message(
- &self.context,
- Message::Window(self.window_id, WindowMessage::UpdateMenuItem(id, update)),
- )
- }
}
#[derive(Clone)]
@@ -1757,9 +1595,7 @@ impl WindowHandle {
pub struct WindowWrapper {
label: String,
inner: Option,
- menu_items: Option>,
window_event_listeners: WindowEventListeners,
- menu_event_listeners: WindowMenuEventListeners,
}
impl fmt::Debug for WindowWrapper {
@@ -1767,7 +1603,6 @@ impl fmt::Debug for WindowWrapper {
f.debug_struct("WindowWrapper")
.field("label", &self.label)
.field("inner", &self.inner)
- .field("menu_items", &self.menu_items)
.finish()
}
}
@@ -1813,19 +1648,12 @@ pub struct Wry {
impl fmt::Debug for Wry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut d = f.debug_struct("Wry");
- d.field("main_thread_id", &self.context.main_thread_id)
+ f.debug_struct("Wry")
+ .field("main_thread_id", &self.context.main_thread_id)
.field("event_loop", &self.event_loop)
.field("windows", &self.context.main_thread.windows)
- .field("web_context", &self.context.main_thread.web_context);
-
- #[cfg(all(desktop, feature = "system-tray"))]
- d.field(
- "system_tray_manager",
- &self.context.main_thread.system_tray_manager,
- );
-
- d.finish()
+ .field("web_context", &self.context.main_thread.web_context)
+ .finish()
}
}
@@ -1897,36 +1725,20 @@ impl RuntimeHandle for WryHandle {
// Creates a window by dispatching a message to the event loop.
// Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
- fn create_window(
+ fn create_window(
&self,
pending: PendingWindow,
+ before_webview_creation: Option,
) -> Result> {
- self.context.create_webview(pending)
+ self
+ .context
+ .create_webview(pending, before_webview_creation)
}
fn run_on_main_thread(&self, f: F) -> Result<()> {
send_user_message(&self.context, Message::Task(Box::new(f)))
}
- #[cfg(all(desktop, feature = "system-tray"))]
- fn system_tray(
- &self,
- system_tray: SystemTray,
- ) -> Result<>::TrayHandler> {
- let id = system_tray.id;
- let (tx, rx) = channel();
- send_user_message(
- &self.context,
- Message::Tray(id, TrayMessage::Create(system_tray, tx)),
- )?;
- rx.recv().unwrap()?;
- Ok(SystemTrayHandle {
- context: self.context.clone(),
- id,
- proxy: self.context.proxy.clone(),
- })
- }
-
fn raw_display_handle(&self) -> RawDisplayHandle {
self.context.main_thread.window_target.raw_display_handle()
}
@@ -1968,9 +1780,9 @@ impl RuntimeHandle for WryHandle {
#[cfg(target_os = "android")]
fn find_class<'a>(
- &'a self,
- env: jni::JNIEnv<'a>,
- activity: jni::objects::JObject<'a>,
+ &self,
+ env: &mut jni::JNIEnv<'a>,
+ activity: &jni::objects::JObject<'_>,
name: impl Into,
) -> std::result::Result, jni::errors::Error> {
find_class(env, activity, name.into())
@@ -1979,15 +1791,25 @@ impl RuntimeHandle for WryHandle {
#[cfg(target_os = "android")]
fn run_on_android_context(&self, f: F)
where
- F: FnOnce(jni::JNIEnv<'_>, jni::objects::JObject<'_>, jni::objects::JObject<'_>)
- + Send
- + 'static,
+ F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send + 'static,
{
dispatch(f)
}
}
impl Wry {
+ fn init_with_builder(
+ mut event_loop_builder: EventLoopBuilder>,
+ #[allow(unused_variables)] args: RuntimeInitArgs,
+ ) -> Result {
+ #[cfg(windows)]
+ if let Some(hook) = args.msg_hook {
+ use wry::application::platform::windows::EventLoopBuilderExtWindows;
+ event_loop_builder.with_msg_hook(hook);
+ }
+ Self::init(event_loop_builder.build())
+ }
+
fn init(event_loop: EventLoop>) -> Result {
let main_thread_id = current_thread().id();
let web_context = WebContextStore::default();
@@ -1995,9 +1817,6 @@ impl Wry {
let windows = Arc::new(RefCell::new(HashMap::default()));
let webview_id_map = WebviewIdStore::default();
- #[cfg(all(desktop, feature = "system-tray"))]
- let system_tray_manager = Default::default();
-
let context = Context {
webview_id_map,
main_thread_id,
@@ -2006,8 +1825,6 @@ impl Wry {
window_target: event_loop.deref().clone(),
web_context,
windows,
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager,
},
plugins: Default::default(),
};
@@ -2023,24 +1840,31 @@ impl Runtime for Wry {
type Dispatcher = WryDispatcher;
type Handle = WryHandle;
- #[cfg(all(desktop, feature = "system-tray"))]
- type TrayHandler = SystemTrayHandle;
-
type EventLoopProxy = EventProxy;
- fn new() -> Result {
- let event_loop = EventLoop::>::with_user_event();
- Self::init(event_loop)
+ fn new(args: RuntimeInitArgs) -> Result {
+ Self::init_with_builder(EventLoopBuilder::>::with_user_event(), args)
+ }
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ fn new_any_thread(args: RuntimeInitArgs) -> Result {
+ use wry::application::platform::unix::EventLoopBuilderExtUnix;
+ let mut event_loop_builder = EventLoopBuilder::>::with_user_event();
+ event_loop_builder.with_any_thread(true);
+ Self::init_with_builder(event_loop_builder, args)
}
- #[cfg(any(windows, target_os = "linux"))]
- fn new_any_thread() -> Result {
- #[cfg(target_os = "linux")]
- use wry::application::platform::unix::EventLoopExtUnix;
- #[cfg(windows)]
- use wry::application::platform::windows::EventLoopExtWindows;
- let event_loop = EventLoop::>::new_any_thread();
- Self::init(event_loop)
+ #[cfg(windows)]
+ fn new_any_thread(args: RuntimeInitArgs) -> Result {
+ use wry::application::platform::windows::EventLoopBuilderExtWindows;
+ let mut event_loop_builder = EventLoopBuilder::>::with_user_event();
+ event_loop_builder.with_any_thread(true);
+ Self::init_with_builder(event_loop_builder, args)
}
fn create_proxy(&self) -> EventProxy {
@@ -2053,9 +1877,12 @@ impl Runtime for Wry {
}
}
- fn create_window(&self, pending: PendingWindow) -> Result> {
+ fn create_window(
+ &self,
+ pending: PendingWindow,
+ before_webview_creation: Option,
+ ) -> Result> {
let label = pending.label.clone();
- let menu_ids = pending.menu_ids.clone();
let window_id = rand::random();
let webview = create_webview(
@@ -2064,6 +1891,7 @@ impl Runtime for Wry {
&self.context.main_thread.web_context,
self.context.clone(),
pending,
+ before_webview_creation,
)?;
let dispatcher = WryDispatcher {
@@ -2078,54 +1906,7 @@ impl Runtime for Wry {
.borrow_mut()
.insert(window_id, webview);
- Ok(DetachedWindow {
- label,
- dispatcher,
- menu_ids,
- })
- }
-
- #[cfg(all(desktop, feature = "system-tray"))]
- fn system_tray(&self, mut system_tray: SystemTray) -> Result {
- let id = system_tray.id;
- let mut listeners = Vec::new();
- if let Some(l) = system_tray.on_event.take() {
- listeners.push(Arc::new(l));
- }
- let (tray, items) = create_tray(WryTrayId(id), system_tray, &self.event_loop)?;
- self
- .context
- .main_thread
- .system_tray_manager
- .trays
- .lock()
- .unwrap()
- .insert(
- id,
- TrayContext {
- tray: Arc::new(Mutex::new(Some(tray))),
- listeners: Arc::new(Mutex::new(listeners)),
- items: Arc::new(Mutex::new(items)),
- },
- );
-
- Ok(SystemTrayHandle {
- context: self.context.clone(),
- id,
- proxy: self.event_loop.create_proxy(),
- })
- }
-
- #[cfg(all(desktop, feature = "system-tray"))]
- fn on_system_tray_event(&mut self, f: F) {
- self
- .context
- .main_thread
- .system_tray_manager
- .global_listeners
- .lock()
- .unwrap()
- .push(Arc::new(Box::new(f)));
+ Ok(DetachedWindow { label, dispatcher })
}
fn primary_monitor(&self) -> Option {
@@ -2182,8 +1963,6 @@ impl Runtime for Wry {
let webview_id_map = self.context.webview_id_map.clone();
let web_context = &self.context.main_thread.web_context;
let plugins = self.context.plugins.clone();
- #[cfg(all(desktop, feature = "system-tray"))]
- let system_tray_manager = self.context.main_thread.system_tray_manager.clone();
let mut iteration = RunIteration::default();
@@ -2207,8 +1986,6 @@ impl Runtime for Wry {
callback: &mut callback,
webview_id_map: webview_id_map.clone(),
windows: windows.clone(),
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager: system_tray_manager.clone(),
},
web_context,
);
@@ -2225,8 +2002,6 @@ impl Runtime for Wry {
callback: &mut callback,
windows: windows.clone(),
webview_id_map: webview_id_map.clone(),
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager: system_tray_manager.clone(),
},
web_context,
);
@@ -2241,9 +2016,6 @@ impl Runtime for Wry {
let web_context = self.context.main_thread.web_context;
let plugins = self.context.plugins.clone();
- #[cfg(all(desktop, feature = "system-tray"))]
- let system_tray_manager = self.context.main_thread.system_tray_manager;
-
let proxy = self.event_loop.create_proxy();
self.event_loop.run(move |event, event_loop, control_flow| {
@@ -2257,8 +2029,6 @@ impl Runtime for Wry {
callback: &mut callback,
webview_id_map: webview_id_map.clone(),
windows: windows.clone(),
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager: system_tray_manager.clone(),
},
&web_context,
);
@@ -2274,8 +2044,6 @@ impl Runtime for Wry {
callback: &mut callback,
webview_id_map: webview_id_map.clone(),
windows: windows.clone(),
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager: system_tray_manager.clone(),
},
&web_context,
);
@@ -2287,15 +2055,11 @@ pub struct EventLoopIterationContext<'a, T: UserEvent> {
pub callback: &'a mut (dyn FnMut(RunEvent) + 'static),
pub webview_id_map: WebviewIdStore,
pub windows: Arc>>,
- #[cfg(all(desktop, feature = "system-tray"))]
- pub system_tray_manager: SystemTrayManager,
}
struct UserMessageContext {
windows: Arc>>,
webview_id_map: WebviewIdStore,
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager: SystemTrayManager,
}
fn handle_user_message(
@@ -2307,8 +2071,6 @@ fn handle_user_message(
let UserMessageContext {
webview_id_map,
windows,
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager,
} = context;
match message {
Message::Task(task) => task(),
@@ -2322,263 +2084,240 @@ fn handle_user_message(
}
},
Message::Window(id, window_message) => {
- if let WindowMessage::UpdateMenuItem(item_id, update) = window_message {
- if let Some(menu_items) = windows.borrow_mut().get_mut(&id).map(|w| &mut w.menu_items) {
- if let Some(menu_items) = menu_items.as_mut() {
- let item = menu_items.get_mut(&item_id).expect("menu item not found");
- match update {
- MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled),
- MenuUpdate::SetTitle(title) => item.set_title(&title),
- MenuUpdate::SetSelected(selected) => item.set_selected(selected),
- #[cfg(target_os = "macos")]
- MenuUpdate::SetNativeImage(image) => {
- item.set_native_image(NativeImageWrapper::from(image).0)
+ let w = windows
+ .borrow()
+ .get(&id)
+ .map(|w| (w.inner.clone(), w.window_event_listeners.clone()));
+ if let Some((Some(window), window_event_listeners)) = w {
+ match window_message {
+ WindowMessage::WithWebview(f) => {
+ if let WindowHandle::Webview { inner: w, .. } = &window {
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ {
+ use wry::webview::WebviewExtUnix;
+ f(w.webview());
}
- }
- }
- }
- } else {
- let w = windows.borrow().get(&id).map(|w| {
- (
- w.inner.clone(),
- w.window_event_listeners.clone(),
- w.menu_event_listeners.clone(),
- )
- });
- if let Some((Some(window), window_event_listeners, menu_event_listeners)) = w {
- match window_message {
- WindowMessage::WithWebview(f) => {
- if let WindowHandle::Webview { inner: w, .. } = &window {
- #[cfg(any(
- target_os = "linux",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "netbsd",
- target_os = "openbsd"
- ))]
- {
- use wry::webview::WebviewExtUnix;
- f(w.webview());
- }
- #[cfg(target_os = "macos")]
- {
- use wry::webview::WebviewExtMacOS;
- f(Webview {
- webview: w.webview(),
- manager: w.manager(),
- ns_window: w.ns_window(),
- });
- }
- #[cfg(target_os = "ios")]
- {
- use wry::{application::platform::ios::WindowExtIOS, webview::WebviewExtIOS};
-
- f(Webview {
- webview: w.webview(),
- manager: w.manager(),
- view_controller: w.window().ui_view_controller() as cocoa::base::id,
- });
- }
- #[cfg(windows)]
- {
- f(Webview {
- controller: w.controller(),
- });
- }
- #[cfg(target_os = "android")]
- {
- f(w.handle())
- }
- }
- }
-
- WindowMessage::AddEventListener(id, listener) => {
- window_event_listeners.lock().unwrap().insert(id, listener);
- }
-
- WindowMessage::AddMenuEventListener(id, listener) => {
- menu_event_listeners.lock().unwrap().insert(id, listener);
- }
-
- #[cfg(any(debug_assertions, feature = "devtools"))]
- WindowMessage::OpenDevTools => {
- if let WindowHandle::Webview { inner: w, .. } = &window {
- w.open_devtools();
- }
- }
- #[cfg(any(debug_assertions, feature = "devtools"))]
- WindowMessage::CloseDevTools => {
- if let WindowHandle::Webview { inner: w, .. } = &window {
- w.close_devtools();
+ #[cfg(target_os = "macos")]
+ {
+ use wry::webview::WebviewExtMacOS;
+ f(Webview {
+ webview: w.webview(),
+ manager: w.manager(),
+ ns_window: w.ns_window(),
+ });
}
- }
- #[cfg(any(debug_assertions, feature = "devtools"))]
- WindowMessage::IsDevToolsOpen(tx) => {
- if let WindowHandle::Webview { inner: w, .. } = &window {
- tx.send(w.is_devtools_open()).unwrap();
- } else {
- tx.send(false).unwrap();
+ #[cfg(target_os = "ios")]
+ {
+ use wry::{application::platform::ios::WindowExtIOS, webview::WebviewExtIOS};
+
+ f(Webview {
+ webview: w.webview(),
+ manager: w.manager(),
+ view_controller: w.window().ui_view_controller() as cocoa::base::id,
+ });
}
- }
- // Getters
- WindowMessage::Url(tx) => {
- if let WindowHandle::Webview { inner: w, .. } = &window {
- tx.send(w.url()).unwrap();
- }
- }
- WindowMessage::ScaleFactor(tx) => tx.send(window.scale_factor()).unwrap(),
- WindowMessage::InnerPosition(tx) => tx
- .send(
- window
- .inner_position()
- .map(|p| PhysicalPositionWrapper(p).into())
- .map_err(|_| Error::FailedToSendMessage),
- )
- .unwrap(),
- WindowMessage::OuterPosition(tx) => tx
- .send(
- window
- .outer_position()
- .map(|p| PhysicalPositionWrapper(p).into())
- .map_err(|_| Error::FailedToSendMessage),
- )
- .unwrap(),
- WindowMessage::InnerSize(tx) => tx
- .send(PhysicalSizeWrapper(window.inner_size()).into())
- .unwrap(),
- WindowMessage::OuterSize(tx) => tx
- .send(PhysicalSizeWrapper(window.outer_size()).into())
- .unwrap(),
- WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(),
- WindowMessage::IsMinimized(tx) => tx.send(window.is_minimized()).unwrap(),
- WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(),
- WindowMessage::IsFocused(tx) => tx.send(window.is_focused()).unwrap(),
- WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(),
- WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(),
- WindowMessage::IsMaximizable(tx) => tx.send(window.is_maximizable()).unwrap(),
- WindowMessage::IsMinimizable(tx) => tx.send(window.is_minimizable()).unwrap(),
- WindowMessage::IsClosable(tx) => tx.send(window.is_closable()).unwrap(),
- WindowMessage::IsVisible(tx) => tx.send(window.is_visible()).unwrap(),
- WindowMessage::Title(tx) => tx.send(window.title()).unwrap(),
- WindowMessage::IsMenuVisible(tx) => tx.send(window.is_menu_visible()).unwrap(),
- WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(),
- WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(),
- WindowMessage::AvailableMonitors(tx) => {
- tx.send(window.available_monitors().collect()).unwrap()
- }
- #[cfg(any(
- target_os = "linux",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "netbsd",
- target_os = "openbsd"
- ))]
- WindowMessage::GtkWindow(tx) => {
- tx.send(GtkWindow(window.gtk_window().clone())).unwrap()
- }
- WindowMessage::RawWindowHandle(tx) => tx
- .send(RawWindowHandle(window.raw_window_handle()))
- .unwrap(),
- WindowMessage::Theme(tx) => {
- tx.send(map_theme(&window.theme())).unwrap();
- }
- // Setters
- WindowMessage::Center => {
- let _ = center_window(&window, window.inner_size());
- }
- WindowMessage::RequestUserAttention(request_type) => {
- window.request_user_attention(request_type.map(|r| r.0));
- }
- WindowMessage::SetResizable(resizable) => window.set_resizable(resizable),
- WindowMessage::SetMaximizable(maximizable) => window.set_maximizable(maximizable),
- WindowMessage::SetMinimizable(minimizable) => window.set_minimizable(minimizable),
- WindowMessage::SetClosable(closable) => window.set_closable(closable),
- WindowMessage::SetTitle(title) => window.set_title(&title),
- WindowMessage::Navigate(url) => {
- if let WindowHandle::Webview { inner: w, .. } = &window {
- w.load_url(url.as_str())
- }
- }
- WindowMessage::Maximize => window.set_maximized(true),
- WindowMessage::Unmaximize => window.set_maximized(false),
- WindowMessage::Minimize => window.set_minimized(true),
- WindowMessage::Unminimize => window.set_minimized(false),
- WindowMessage::ShowMenu => window.show_menu(),
- WindowMessage::HideMenu => window.hide_menu(),
- WindowMessage::Show => window.set_visible(true),
- WindowMessage::Hide => window.set_visible(false),
- WindowMessage::Close => {
- panic!("cannot handle `WindowMessage::Close` on the main thread")
- }
- WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations),
- WindowMessage::SetShadow(_enable) => {
#[cfg(windows)]
- window.set_undecorated_shadow(_enable);
- #[cfg(target_os = "macos")]
- window.set_has_shadow(_enable);
- }
- WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top),
- WindowMessage::SetVisibleOnAllWorkspaces(visible_on_all_workspaces) => {
- window.set_visible_on_all_workspaces(visible_on_all_workspaces)
- }
- WindowMessage::SetContentProtected(protected) => {
- window.set_content_protection(protected)
- }
- WindowMessage::SetSize(size) => {
- window.set_inner_size(SizeWrapper::from(size).0);
- }
- WindowMessage::SetMinSize(size) => {
- window.set_min_inner_size(size.map(|s| SizeWrapper::from(s).0));
- }
- WindowMessage::SetMaxSize(size) => {
- window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0));
- }
- WindowMessage::SetPosition(position) => {
- window.set_outer_position(PositionWrapper::from(position).0)
- }
- WindowMessage::SetFullscreen(fullscreen) => {
- if fullscreen {
- window.set_fullscreen(Some(Fullscreen::Borderless(None)))
- } else {
- window.set_fullscreen(None)
+ {
+ f(Webview {
+ controller: w.controller(),
+ });
+ }
+ #[cfg(target_os = "android")]
+ {
+ f(w.handle())
}
}
- WindowMessage::SetFocus => {
- window.set_focus();
- }
- WindowMessage::SetIcon(icon) => {
- window.set_window_icon(Some(icon));
- }
- #[allow(unused_variables)]
- WindowMessage::SetSkipTaskbar(skip) => {
- #[cfg(any(windows, target_os = "linux"))]
- window.set_skip_taskbar(skip);
- }
- WindowMessage::SetCursorGrab(grab) => {
- let _ = window.set_cursor_grab(grab);
- }
- WindowMessage::SetCursorVisible(visible) => {
- window.set_cursor_visible(visible);
- }
- WindowMessage::SetCursorIcon(icon) => {
- window.set_cursor_icon(CursorIconWrapper::from(icon).0);
+ }
+
+ WindowMessage::AddEventListener(id, listener) => {
+ window_event_listeners.lock().unwrap().insert(id, listener);
+ }
+
+ #[cfg(any(debug_assertions, feature = "devtools"))]
+ WindowMessage::OpenDevTools => {
+ if let WindowHandle::Webview { inner: w, .. } = &window {
+ w.open_devtools();
}
- WindowMessage::SetCursorPosition(position) => {
- let _ = window.set_cursor_position(PositionWrapper::from(position).0);
+ }
+ #[cfg(any(debug_assertions, feature = "devtools"))]
+ WindowMessage::CloseDevTools => {
+ if let WindowHandle::Webview { inner: w, .. } = &window {
+ w.close_devtools();
}
- WindowMessage::SetIgnoreCursorEvents(ignore) => {
- let _ = window.set_ignore_cursor_events(ignore);
+ }
+ #[cfg(any(debug_assertions, feature = "devtools"))]
+ WindowMessage::IsDevToolsOpen(tx) => {
+ if let WindowHandle::Webview { inner: w, .. } = &window {
+ tx.send(w.is_devtools_open()).unwrap();
+ } else {
+ tx.send(false).unwrap();
}
- WindowMessage::DragWindow => {
- let _ = window.drag_window();
+ }
+
+ // Getters
+ WindowMessage::Url(tx) => {
+ if let WindowHandle::Webview { inner: w, .. } = &window {
+ tx.send(w.url()).unwrap();
}
- WindowMessage::UpdateMenuItem(_id, _update) => {
- // already handled
+ }
+ WindowMessage::ScaleFactor(tx) => tx.send(window.scale_factor()).unwrap(),
+ WindowMessage::InnerPosition(tx) => tx
+ .send(
+ window
+ .inner_position()
+ .map(|p| PhysicalPositionWrapper(p).into())
+ .map_err(|_| Error::FailedToSendMessage),
+ )
+ .unwrap(),
+ WindowMessage::OuterPosition(tx) => tx
+ .send(
+ window
+ .outer_position()
+ .map(|p| PhysicalPositionWrapper(p).into())
+ .map_err(|_| Error::FailedToSendMessage),
+ )
+ .unwrap(),
+ WindowMessage::InnerSize(tx) => tx
+ .send(PhysicalSizeWrapper(window.inner_size()).into())
+ .unwrap(),
+ WindowMessage::OuterSize(tx) => tx
+ .send(PhysicalSizeWrapper(window.outer_size()).into())
+ .unwrap(),
+ WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(),
+ WindowMessage::IsMinimized(tx) => tx.send(window.is_minimized()).unwrap(),
+ WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(),
+ WindowMessage::IsFocused(tx) => tx.send(window.is_focused()).unwrap(),
+ WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(),
+ WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(),
+ WindowMessage::IsMaximizable(tx) => tx.send(window.is_maximizable()).unwrap(),
+ WindowMessage::IsMinimizable(tx) => tx.send(window.is_minimizable()).unwrap(),
+ WindowMessage::IsClosable(tx) => tx.send(window.is_closable()).unwrap(),
+ WindowMessage::IsVisible(tx) => tx.send(window.is_visible()).unwrap(),
+ WindowMessage::Title(tx) => tx.send(window.title()).unwrap(),
+ WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(),
+ WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(),
+ WindowMessage::AvailableMonitors(tx) => {
+ tx.send(window.available_monitors().collect()).unwrap()
+ }
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ WindowMessage::GtkWindow(tx) => tx.send(GtkWindow(window.gtk_window().clone())).unwrap(),
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ WindowMessage::GtkBox(tx) => tx
+ .send(GtkBox(window.default_vbox().unwrap().clone()))
+ .unwrap(),
+ WindowMessage::RawWindowHandle(tx) => tx
+ .send(RawWindowHandle(window.raw_window_handle()))
+ .unwrap(),
+ WindowMessage::Theme(tx) => {
+ tx.send(map_theme(&window.theme())).unwrap();
+ }
+ // Setters
+ WindowMessage::Center => {
+ let _ = center_window(&window, window.inner_size());
+ }
+ WindowMessage::RequestUserAttention(request_type) => {
+ window.request_user_attention(request_type.map(|r| r.0));
+ }
+ WindowMessage::SetResizable(resizable) => window.set_resizable(resizable),
+ WindowMessage::SetMaximizable(maximizable) => window.set_maximizable(maximizable),
+ WindowMessage::SetMinimizable(minimizable) => window.set_minimizable(minimizable),
+ WindowMessage::SetClosable(closable) => window.set_closable(closable),
+ WindowMessage::SetTitle(title) => window.set_title(&title),
+ WindowMessage::Navigate(url) => {
+ if let WindowHandle::Webview { inner: w, .. } = &window {
+ w.load_url(url.as_str())
}
- WindowMessage::RequestRedraw => {
- window.request_redraw();
+ }
+ WindowMessage::Maximize => window.set_maximized(true),
+ WindowMessage::Unmaximize => window.set_maximized(false),
+ WindowMessage::Minimize => window.set_minimized(true),
+ WindowMessage::Unminimize => window.set_minimized(false),
+ WindowMessage::Show => window.set_visible(true),
+ WindowMessage::Hide => window.set_visible(false),
+ WindowMessage::Close => {
+ panic!("cannot handle `WindowMessage::Close` on the main thread")
+ }
+ WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations),
+ WindowMessage::SetShadow(_enable) => {
+ #[cfg(windows)]
+ window.set_undecorated_shadow(_enable);
+ #[cfg(target_os = "macos")]
+ window.set_has_shadow(_enable);
+ }
+ WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top),
+ WindowMessage::SetVisibleOnAllWorkspaces(visible_on_all_workspaces) => {
+ window.set_visible_on_all_workspaces(visible_on_all_workspaces)
+ }
+ WindowMessage::SetContentProtected(protected) => window.set_content_protection(protected),
+ WindowMessage::SetSize(size) => {
+ window.set_inner_size(SizeWrapper::from(size).0);
+ }
+ WindowMessage::SetMinSize(size) => {
+ window.set_min_inner_size(size.map(|s| SizeWrapper::from(s).0));
+ }
+ WindowMessage::SetMaxSize(size) => {
+ window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0));
+ }
+ WindowMessage::SetPosition(position) => {
+ window.set_outer_position(PositionWrapper::from(position).0)
+ }
+ WindowMessage::SetFullscreen(fullscreen) => {
+ if fullscreen {
+ window.set_fullscreen(Some(Fullscreen::Borderless(None)))
+ } else {
+ window.set_fullscreen(None)
}
}
+ WindowMessage::SetFocus => {
+ window.set_focus();
+ }
+ WindowMessage::SetIcon(icon) => {
+ window.set_window_icon(Some(icon));
+ }
+ #[allow(unused_variables)]
+ WindowMessage::SetSkipTaskbar(skip) => {
+ #[cfg(any(windows, target_os = "linux"))]
+ window.set_skip_taskbar(skip);
+ }
+ WindowMessage::SetCursorGrab(grab) => {
+ let _ = window.set_cursor_grab(grab);
+ }
+ WindowMessage::SetCursorVisible(visible) => {
+ window.set_cursor_visible(visible);
+ }
+ WindowMessage::SetCursorIcon(icon) => {
+ window.set_cursor_icon(CursorIconWrapper::from(icon).0);
+ }
+ WindowMessage::SetCursorPosition(position) => {
+ let _ = window.set_cursor_position(PositionWrapper::from(position).0);
+ }
+ WindowMessage::SetIgnoreCursorEvents(ignore) => {
+ let _ = window.set_ignore_cursor_events(ignore);
+ }
+ WindowMessage::DragWindow => {
+ let _ = window.drag_window();
+ }
+ WindowMessage::RequestRedraw => {
+ window.request_redraw();
+ }
}
}
}
@@ -2621,9 +2360,7 @@ fn handle_user_message(
WindowWrapper {
label,
inner: Some(WindowHandle::Window(w.clone())),
- menu_items: Default::default(),
window_event_listeners: Default::default(),
- menu_event_listeners: Default::default(),
},
);
sender.send(Ok(Arc::downgrade(&w))).unwrap();
@@ -2632,91 +2369,6 @@ fn handle_user_message(
}
}
- #[cfg(all(desktop, feature = "system-tray"))]
- Message::Tray(tray_id, tray_message) => {
- let mut trays = system_tray_manager.trays.lock().unwrap();
-
- if let TrayMessage::Create(mut tray, tx) = tray_message {
- let mut listeners = Vec::new();
- if let Some(l) = tray.on_event.take() {
- listeners.push(Arc::new(l));
- }
- match create_tray(WryTrayId(tray_id), tray, event_loop) {
- Ok((tray, items)) => {
- trays.insert(
- tray_id,
- TrayContext {
- tray: Arc::new(Mutex::new(Some(tray))),
- listeners: Arc::new(Mutex::new(listeners)),
- items: Arc::new(Mutex::new(items)),
- },
- );
-
- tx.send(Ok(())).unwrap();
- }
-
- Err(e) => {
- tx.send(Err(e)).unwrap();
- }
- }
- } else if let Some(tray_context) = trays.get(&tray_id) {
- match tray_message {
- TrayMessage::UpdateItem(menu_id, update) => {
- let mut tray = tray_context.items.as_ref().lock().unwrap();
- let item = tray.get_mut(&menu_id).expect("menu item not found");
- match update {
- MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled),
- MenuUpdate::SetTitle(title) => item.set_title(&title),
- MenuUpdate::SetSelected(selected) => item.set_selected(selected),
- #[cfg(target_os = "macos")]
- MenuUpdate::SetNativeImage(image) => {
- item.set_native_image(NativeImageWrapper::from(image).0)
- }
- }
- }
- TrayMessage::UpdateMenu(menu) => {
- if let Some(tray) = &mut *tray_context.tray.lock().unwrap() {
- let mut items = HashMap::new();
- tray.set_menu(&to_wry_context_menu(&mut items, menu));
- *tray_context.items.lock().unwrap() = items;
- }
- }
- TrayMessage::UpdateIcon(icon) => {
- if let Some(tray) = &mut *tray_context.tray.lock().unwrap() {
- if let Ok(icon) = TrayIcon::try_from(icon) {
- tray.set_icon(icon.0);
- }
- }
- }
- #[cfg(target_os = "macos")]
- TrayMessage::UpdateIconAsTemplate(is_template) => {
- if let Some(tray) = &mut *tray_context.tray.lock().unwrap() {
- tray.set_icon_as_template(is_template);
- }
- }
- #[cfg(target_os = "macos")]
- TrayMessage::UpdateTitle(title) => {
- if let Some(tray) = &mut *tray_context.tray.lock().unwrap() {
- tray.set_title(&title);
- }
- }
- TrayMessage::UpdateTooltip(tooltip) => {
- if let Some(tray) = &mut *tray_context.tray.lock().unwrap() {
- tray.set_tooltip(&tooltip);
- }
- }
- TrayMessage::Create(_tray, _tx) => {
- // already handled
- }
- TrayMessage::Destroy(tx) => {
- *tray_context.tray.lock().unwrap() = None;
- tray_context.listeners.lock().unwrap().clear();
- tray_context.items.lock().unwrap().clear();
- tx.send(Ok(())).unwrap();
- }
- }
- }
- }
Message::UserEvent(_) => (),
}
@@ -2737,8 +2389,6 @@ fn handle_event_loop(
callback,
webview_id_map,
windows,
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager,
} = context;
if *control_flow != ControlFlow::Exit {
*control_flow = ControlFlow::Wait;
@@ -2761,118 +2411,6 @@ fn handle_event_loop(
callback(RunEvent::Exit);
}
- Event::MenuEvent {
- window_id,
- menu_id,
- origin: MenuType::MenuBar,
- ..
- } => {
- #[allow(unused_mut)]
- let mut window_id = window_id.unwrap(); // always Some on MenuBar event
-
- #[cfg(target_os = "macos")]
- {
- // safety: we're only checking to see if the window_id is 0
- // which is the value sent by macOS when the window is minimized (NSApplication::sharedApplication::mainWindow is null)
- if window_id == unsafe { WindowId::dummy() } {
- window_id = *webview_id_map.0.lock().unwrap().keys().next().unwrap();
- }
- }
-
- let event = MenuEvent {
- menu_item_id: menu_id.0,
- };
- let window_menu_event_listeners = {
- // on macOS the window id might be the inspector window if it is detached
- let window_id = if let Some(window_id) = webview_id_map.get(&window_id) {
- window_id
- } else {
- *webview_id_map.0.lock().unwrap().values().next().unwrap()
- };
- windows
- .borrow()
- .get(&window_id)
- .unwrap()
- .menu_event_listeners
- .clone()
- };
- let listeners = window_menu_event_listeners.lock().unwrap();
- let handlers = listeners.values();
- for handler in handlers {
- handler(&event);
- }
- }
- #[cfg(all(desktop, feature = "system-tray"))]
- Event::MenuEvent {
- window_id: _,
- menu_id,
- origin: MenuType::ContextMenu,
- ..
- } => {
- let event = SystemTrayEvent::MenuItemClick(menu_id.0);
-
- let trays = system_tray_manager.trays.lock().unwrap();
- let trays_iter = trays.iter();
-
- let (mut listeners, mut tray_id) = (None, 0);
- for (id, tray_context) in trays_iter {
- let has_menu = {
- let items = tray_context.items.lock().unwrap();
- items.contains_key(&menu_id.0)
- };
- if has_menu {
- listeners.replace(tray_context.listeners.lock().unwrap().clone());
- tray_id = *id;
- break;
- }
- }
- drop(trays);
- if let Some(listeners) = listeners {
- let handlers = listeners.iter();
- for handler in handlers {
- handler(&event);
- }
-
- let global_listeners = system_tray_manager.global_listeners.lock().unwrap();
- let global_listeners_iter = global_listeners.iter();
- for global_listener in global_listeners_iter {
- global_listener(tray_id, &event);
- }
- }
- }
- #[cfg(all(desktop, feature = "system-tray"))]
- Event::TrayEvent {
- id,
- bounds,
- event,
- position: _cursor_position,
- ..
- } => {
- let (position, size) = (
- PhysicalPositionWrapper(bounds.position).into(),
- PhysicalSizeWrapper(bounds.size).into(),
- );
- let event = match event {
- TrayEvent::RightClick => SystemTrayEvent::RightClick { position, size },
- TrayEvent::DoubleClick => SystemTrayEvent::DoubleClick { position, size },
- // default to left click
- _ => SystemTrayEvent::LeftClick { position, size },
- };
- let trays = system_tray_manager.trays.lock().unwrap();
- if let Some(tray_context) = trays.get(&id.0) {
- let listeners = tray_context.listeners.lock().unwrap();
- let iter = listeners.iter();
- for handler in iter {
- handler(&event);
- }
- }
-
- let global_listeners = system_tray_manager.global_listeners.lock().unwrap();
- let global_listeners_iter = global_listeners.iter();
- for global_listener in global_listeners_iter {
- global_listener(id.0, &event);
- }
- }
Event::UserEvent(Message::Webview(id, WebviewMessage::WebviewEvent(event))) => {
if let Some(event) = WindowEventWrapper::from(&event).0 {
let windows = windows.borrow();
@@ -2891,6 +2429,7 @@ fn handle_event_loop(
}
}
}
+
Event::WindowEvent {
event, window_id, ..
} => {
@@ -2967,8 +2506,6 @@ fn handle_event_loop(
UserMessageContext {
webview_id_map,
windows,
- #[cfg(all(desktop, feature = "system-tray"))]
- system_tray_manager,
},
web_context,
);
@@ -3040,45 +2577,13 @@ pub fn center_window(window: &Window, window_size: WryPhysicalSize) -> Resu
}
}
-fn to_wry_menu(
- custom_menu_items: &mut HashMap,
- menu: Menu,
-) -> MenuBar {
- let mut wry_menu = MenuBar::new();
- for item in menu.items {
- match item {
- MenuEntry::CustomItem(c) => {
- let mut attributes = MenuItemAttributesWrapper::from(&c).0;
- attributes = attributes.with_id(WryMenuId(c.id));
- #[allow(unused_mut)]
- let mut item = wry_menu.add_item(attributes);
- #[cfg(target_os = "macos")]
- if let Some(native_image) = c.native_image {
- item.set_native_image(NativeImageWrapper::from(native_image).0);
- }
- custom_menu_items.insert(c.id, item);
- }
- MenuEntry::NativeItem(i) => {
- wry_menu.add_native_item(MenuItemWrapper::from(i).0);
- }
- MenuEntry::Submenu(submenu) => {
- wry_menu.add_submenu(
- &submenu.title,
- submenu.enabled,
- to_wry_menu(custom_menu_items, submenu.inner),
- );
- }
- }
- }
- wry_menu
-}
-
-fn create_webview(
+fn create_webview(
window_id: WebviewId,
event_loop: &EventLoopWindowTarget>,
web_context_store: &WebContextStore,
context: Context,
pending: PendingWindow>,
+ before_webview_creation: Option,
) -> Result {
#[allow(unused_mut)]
let PendingWindow {
@@ -3088,7 +2593,6 @@ fn create_webview(
label,
ipc_handler,
url,
- menu_ids,
#[cfg(target_os = "android")]
on_webview_created,
..
@@ -3119,14 +2623,6 @@ fn create_webview(
}
let is_window_transparent = window_builder.inner.window.transparent;
- let menu_items = if let Some(menu) = window_builder.menu {
- let mut menu_items = HashMap::new();
- let menu = to_wry_menu(&mut menu_items, menu);
- window_builder.inner = window_builder.inner.with_menu(menu);
- Some(menu_items)
- } else {
- None
- };
let window = window_builder.inner.build(event_loop).unwrap();
context.webview_id_map.insert(window.id(), window_id);
@@ -3134,6 +2630,32 @@ fn create_webview(
if window_builder.center {
let _ = center_window(&window, window.inner_size());
}
+
+ if let Some(handler) = before_webview_creation {
+ let raw = RawWindow {
+ #[cfg(windows)]
+ hwnd: window.hwnd(),
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ gtk_window: window.gtk_window(),
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ default_vbox: window.default_vbox(),
+ _marker: &std::marker::PhantomData,
+ };
+ handler(raw);
+ }
+
let mut webview_builder = WebViewBuilder::new(window)
.map_err(|e| Error::CreateWebview(Box::new(e)))?
.with_url(&url)
@@ -3171,12 +2693,8 @@ fn create_webview(
}
if let Some(handler) = ipc_handler {
- webview_builder = webview_builder.with_ipc_handler(create_ipc_handler(
- context,
- label.clone(),
- menu_ids,
- handler,
- ));
+ webview_builder =
+ webview_builder.with_ipc_handler(create_ipc_handler(context, label.clone(), handler));
}
for (scheme, protocol) in uri_scheme_protocols {
@@ -3291,9 +2809,7 @@ fn create_webview(
web_context_key
},
}),
- menu_items,
window_event_listeners,
- menu_event_listeners: Default::default(),
})
}
@@ -3301,7 +2817,6 @@ fn create_webview(
fn create_ipc_handler(
context: Context,
label: String,
- menu_ids: Arc>>,
handler: WebviewIpcHandler>,
) -> Box {
Box::new(move |window, request| {
@@ -3313,7 +2828,6 @@ fn create_ipc_handler(
context: context.clone(),
},
label: label.clone(),
- menu_ids: menu_ids.clone(),
},
request,
);
diff --git a/core/tauri-runtime-wry/src/system_tray.rs b/core/tauri-runtime-wry/src/system_tray.rs
deleted file mode 100644
index 594e13cc4908..000000000000
--- a/core/tauri-runtime-wry/src/system_tray.rs
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
-// SPDX-License-Identifier: Apache-2.0
-// SPDX-License-Identifier: MIT
-
-pub use tauri_runtime::{
- menu::{
- Menu, MenuEntry, MenuItem, MenuUpdate, Submenu, SystemTrayMenu, SystemTrayMenuEntry,
- SystemTrayMenuItem, TrayHandle,
- },
- Icon, SystemTrayEvent,
-};
-use wry::application::event_loop::EventLoopWindowTarget;
-pub use wry::application::{
- event::TrayEvent,
- event_loop::EventLoopProxy,
- menu::{
- ContextMenu as WryContextMenu, CustomMenuItem as WryCustomMenuItem, MenuItem as WryMenuItem,
- },
- system_tray::Icon as WryTrayIcon,
- TrayId as WryTrayId,
-};
-
-#[cfg(target_os = "macos")]
-pub use wry::application::platform::macos::{
- CustomMenuItemExtMacOS, SystemTrayBuilderExtMacOS, SystemTrayExtMacOS,
-};
-
-use wry::application::system_tray::{SystemTray as WrySystemTray, SystemTrayBuilder};
-
-use crate::{send_user_message, Context, Error, Message, Result, TrayId, TrayMessage};
-
-use tauri_runtime::{menu::MenuHash, SystemTray, UserEvent};
-
-use std::{
- collections::HashMap,
- fmt,
- sync::{Arc, Mutex},
-};
-
-pub type GlobalSystemTrayEventHandler = Box;
-pub type GlobalSystemTrayEventListeners = Arc>>>;
-
-pub type SystemTrayEventHandler = Box;
-pub type SystemTrayEventListeners = Arc>>>;
-pub type SystemTrayItems = Arc>>;
-
-#[derive(Clone, Default)]
-pub struct TrayContext {
- pub tray: Arc>>,
- pub listeners: SystemTrayEventListeners,
- pub items: SystemTrayItems,
-}
-
-impl fmt::Debug for TrayContext {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("TrayContext")
- .field("items", &self.items)
- .finish()
- }
-}
-
-#[derive(Clone, Default)]
-pub struct SystemTrayManager {
- pub trays: Arc>>,
- pub global_listeners: GlobalSystemTrayEventListeners,
-}
-
-impl fmt::Debug for SystemTrayManager {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SystemTrayManager")
- .field("trays", &self.trays)
- .finish()
- }
-}
-
-/// Wrapper around a [`wry::application::system_tray::Icon`] that can be created from an [`WindowIcon`].
-pub struct TrayIcon(pub(crate) WryTrayIcon);
-
-impl TryFrom for TrayIcon {
- type Error = Error;
- fn try_from(icon: Icon) -> std::result::Result {
- WryTrayIcon::from_rgba(icon.rgba, icon.width, icon.height)
- .map(Self)
- .map_err(crate::icon_err)
- }
-}
-
-pub fn create_tray(
- id: WryTrayId,
- system_tray: SystemTray,
- event_loop: &EventLoopWindowTarget,
-) -> crate::Result<(WrySystemTray, HashMap)> {
- let icon = TrayIcon::try_from(system_tray.icon.expect("tray icon not set"))?;
-
- let mut items = HashMap::new();
-
- #[allow(unused_mut)]
- let mut builder = SystemTrayBuilder::new(
- icon.0,
- system_tray
- .menu
- .map(|menu| to_wry_context_menu(&mut items, menu)),
- )
- .with_id(id);
-
- #[cfg(target_os = "macos")]
- {
- builder = builder
- .with_icon_as_template(system_tray.icon_as_template)
- .with_menu_on_left_click(system_tray.menu_on_left_click);
-
- if let Some(title) = system_tray.title {
- builder = builder.with_title(&title);
- }
- }
-
- if let Some(tooltip) = system_tray.tooltip {
- builder = builder.with_tooltip(&tooltip);
- }
-
- let tray = builder
- .build(event_loop)
- .map_err(|e| Error::SystemTray(Box::new(e)))?;
-
- Ok((tray, items))
-}
-
-#[derive(Debug, Clone)]
-pub struct SystemTrayHandle {
- pub(crate) context: Context,
- pub(crate) id: TrayId,
- pub(crate) proxy: EventLoopProxy>,
-}
-
-impl TrayHandle for SystemTrayHandle {
- fn set_icon(&self, icon: Icon) -> Result<()> {
- self
- .proxy
- .send_event(Message::Tray(self.id, TrayMessage::UpdateIcon(icon)))
- .map_err(|_| Error::FailedToSendMessage)
- }
-
- fn set_menu(&self, menu: SystemTrayMenu) -> Result<()> {
- self
- .proxy
- .send_event(Message::Tray(self.id, TrayMessage::UpdateMenu(menu)))
- .map_err(|_| Error::FailedToSendMessage)
- }
-
- fn update_item(&self, id: u16, update: MenuUpdate) -> Result<()> {
- self
- .proxy
- .send_event(Message::Tray(self.id, TrayMessage::UpdateItem(id, update)))
- .map_err(|_| Error::FailedToSendMessage)
- }
-
- #[cfg(target_os = "macos")]
- fn set_icon_as_template(&self, is_template: bool) -> tauri_runtime::Result<()> {
- self
- .proxy
- .send_event(Message::Tray(
- self.id,
- TrayMessage::UpdateIconAsTemplate(is_template),
- ))
- .map_err(|_| Error::FailedToSendMessage)
- }
-
- #[cfg(target_os = "macos")]
- fn set_title(&self, title: &str) -> tauri_runtime::Result<()> {
- self
- .proxy
- .send_event(Message::Tray(
- self.id,
- TrayMessage::UpdateTitle(title.to_owned()),
- ))
- .map_err(|_| Error::FailedToSendMessage)
- }
-
- fn set_tooltip(&self, tooltip: &str) -> Result<()> {
- self
- .proxy
- .send_event(Message::Tray(
- self.id,
- TrayMessage::UpdateTooltip(tooltip.to_owned()),
- ))
- .map_err(|_| Error::FailedToSendMessage)
- }
-
- fn destroy(&self) -> Result<()> {
- let (tx, rx) = std::sync::mpsc::channel();
- send_user_message(
- &self.context,
- Message::Tray(self.id, TrayMessage::Destroy(tx)),
- )?;
- rx.recv().unwrap()?;
- Ok(())
- }
-}
-
-impl From for crate::MenuItemWrapper {
- fn from(item: SystemTrayMenuItem) -> Self {
- match item {
- SystemTrayMenuItem::Separator => Self(WryMenuItem::Separator),
- _ => unimplemented!(),
- }
- }
-}
-
-pub fn to_wry_context_menu(
- custom_menu_items: &mut HashMap,
- menu: SystemTrayMenu,
-) -> WryContextMenu {
- let mut tray_menu = WryContextMenu::new();
- for item in menu.items {
- match item {
- SystemTrayMenuEntry::CustomItem(c) => {
- #[allow(unused_mut)]
- let mut item = tray_menu.add_item(crate::MenuItemAttributesWrapper::from(&c).0);
- #[cfg(target_os = "macos")]
- if let Some(native_image) = c.native_image {
- item.set_native_image(crate::NativeImageWrapper::from(native_image).0);
- }
- custom_menu_items.insert(c.id, item);
- }
- SystemTrayMenuEntry::NativeItem(i) => {
- tray_menu.add_native_item(crate::MenuItemWrapper::from(i).0);
- }
- SystemTrayMenuEntry::Submenu(submenu) => {
- tray_menu.add_submenu(
- &submenu.title,
- submenu.enabled,
- to_wry_context_menu(custom_menu_items, submenu.inner),
- );
- }
- }
- }
- tray_menu
-}
diff --git a/core/tauri-runtime/Cargo.toml b/core/tauri-runtime/Cargo.toml
index ca1cd004967a..6c40c1c3c6a4 100644
--- a/core/tauri-runtime/Cargo.toml
+++ b/core/tauri-runtime/Cargo.toml
@@ -42,12 +42,12 @@ features = [ "Win32_Foundation" ]
gtk = { version = "0.16", features = [ "v3_24" ] }
[target."cfg(target_os = \"android\")".dependencies]
-jni = "0.20"
+jni = "0.21"
[target."cfg(target_os = \"macos\")".dependencies]
url = "2"
[features]
devtools = [ ]
-system-tray = [ ]
macos-private-api = [ ]
+
diff --git a/core/tauri-runtime/src/lib.rs b/core/tauri-runtime/src/lib.rs
index dca99d511553..25c743b8ae35 100644
--- a/core/tauri-runtime/src/lib.rs
+++ b/core/tauri-runtime/src/lib.rs
@@ -20,8 +20,6 @@ use url::Url;
use uuid::Uuid;
pub mod http;
-/// Create window and system tray menus.
-pub mod menu;
/// Types useful for interacting with a user's monitors.
pub mod monitor;
pub mod webview;
@@ -31,7 +29,7 @@ use monitor::Monitor;
use webview::WindowBuilder;
use window::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
- CursorIcon, DetachedWindow, PendingWindow, WindowEvent,
+ CursorIcon, DetachedWindow, PendingWindow, RawWindow, WindowEvent,
};
use crate::http::{
@@ -41,156 +39,6 @@ use crate::http::{
InvalidUri,
};
-#[cfg(all(desktop, feature = "system-tray"))]
-use std::fmt;
-
-pub type TrayId = u16;
-pub type TrayEventHandler = dyn Fn(&SystemTrayEvent) + Send + 'static;
-
-#[cfg(all(desktop, feature = "system-tray"))]
-#[non_exhaustive]
-pub struct SystemTray {
- pub id: TrayId,
- pub icon: Option,
- pub menu: Option,
- #[cfg(target_os = "macos")]
- pub icon_as_template: bool,
- #[cfg(target_os = "macos")]
- pub menu_on_left_click: bool,
- #[cfg(target_os = "macos")]
- pub title: Option,
- pub on_event: Option>,
- pub tooltip: Option,
-}
-
-#[cfg(all(desktop, feature = "system-tray"))]
-impl fmt::Debug for SystemTray {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut d = f.debug_struct("SystemTray");
- d.field("id", &self.id)
- .field("icon", &self.icon)
- .field("menu", &self.menu);
- #[cfg(target_os = "macos")]
- {
- d.field("icon_as_template", &self.icon_as_template)
- .field("menu_on_left_click", &self.menu_on_left_click)
- .field("title", &self.title);
- }
- d.finish()
- }
-}
-
-#[cfg(all(desktop, feature = "system-tray"))]
-impl Clone for SystemTray {
- fn clone(&self) -> Self {
- Self {
- id: self.id,
- icon: self.icon.clone(),
- menu: self.menu.clone(),
- on_event: None,
- #[cfg(target_os = "macos")]
- icon_as_template: self.icon_as_template,
- #[cfg(target_os = "macos")]
- menu_on_left_click: self.menu_on_left_click,
- #[cfg(target_os = "macos")]
- title: self.title.clone(),
- tooltip: self.tooltip.clone(),
- }
- }
-}
-
-#[cfg(all(desktop, feature = "system-tray"))]
-impl Default for SystemTray {
- fn default() -> Self {
- Self {
- id: rand::random(),
- icon: None,
- menu: None,
- #[cfg(target_os = "macos")]
- icon_as_template: false,
- #[cfg(target_os = "macos")]
- menu_on_left_click: false,
- #[cfg(target_os = "macos")]
- title: None,
- on_event: None,
- tooltip: None,
- }
- }
-}
-
-#[cfg(all(desktop, feature = "system-tray"))]
-impl SystemTray {
- /// Creates a new system tray that only renders an icon.
- pub fn new() -> Self {
- Default::default()
- }
-
- pub fn menu(&self) -> Option<&menu::SystemTrayMenu> {
- self.menu.as_ref()
- }
-
- /// Sets the tray id.
- #[must_use]
- pub fn with_id(mut self, id: TrayId) -> Self {
- self.id = id;
- self
- }
-
- /// Sets the tray icon.
- #[must_use]
- pub fn with_icon(mut self, icon: Icon) -> Self {
- self.icon.replace(icon);
- self
- }
-
- /// Sets the tray icon as template.
- #[cfg(target_os = "macos")]
- #[must_use]
- pub fn with_icon_as_template(mut self, is_template: bool) -> Self {
- self.icon_as_template = is_template;
- self
- }
-
- /// Sets whether the menu should appear when the tray receives a left click. Defaults to `true`.
- #[cfg(target_os = "macos")]
- #[must_use]
- pub fn with_menu_on_left_click(mut self, menu_on_left_click: bool) -> Self {
- self.menu_on_left_click = menu_on_left_click;
- self
- }
-
- #[cfg(target_os = "macos")]
- #[must_use]
- pub fn with_title(mut self, title: &str) -> Self {
- self.title = Some(title.to_owned());
- self
- }
-
- /// Sets the tray icon tooltip.
- ///
- /// ## Platform-specific:
- ///
- /// - **Linux:** Unsupported
- #[must_use]
- pub fn with_tooltip(mut self, tooltip: &str) -> Self {
- self.tooltip = Some(tooltip.to_owned());
- self
- }
-
- /// Sets the menu to show when the system tray is right clicked.
- #[must_use]
- pub fn with_menu(mut self, menu: menu::SystemTrayMenu) -> Self {
- self.menu.replace(menu);
- self
- }
-
- #[must_use]
- pub fn on_event(mut self, f: F) -> Self {
- self.on_event.replace(Box::new(f));
- self
- }
-}
-
/// Type of user attention requested on a window.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(tag = "type")]
@@ -243,11 +91,6 @@ pub enum Error {
/// Failed to serialize/deserialize.
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
- /// Encountered an error creating the app system tray.
- #[cfg(all(desktop, feature = "system-tray"))]
- #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
- #[error("error encountered during tray setup: {0}")]
- SystemTray(Box),
/// Failed to load window icon.
#[error("invalid icon: {0}")]
InvalidIcon(Box),
@@ -328,24 +171,6 @@ pub enum ExitRequestedEventAction {
Prevent,
}
-/// A system tray event.
-#[derive(Debug)]
-pub enum SystemTrayEvent {
- MenuItemClick(u16),
- LeftClick {
- position: PhysicalPosition,
- size: PhysicalSize,
- },
- RightClick {
- position: PhysicalPosition,
- size: PhysicalSize,
- },
- DoubleClick {
- position: PhysicalPosition,
- size: PhysicalSize,
- },
-}
-
/// Metadata for a runtime event loop iteration on `run_iteration`.
#[derive(Debug, Clone, Default)]
pub struct RunIteration {
@@ -373,22 +198,15 @@ pub trait RuntimeHandle: Debug + Clone + Send + Sync + Sized + 'st
fn create_proxy(&self) -> >::EventLoopProxy;
/// Create a new webview window.
- fn create_window(
+ fn create_window(
&self,
pending: PendingWindow,
+ before_webview_creation: Option,
) -> Result>;
/// Run a task on the main thread.
fn run_on_main_thread(&self, f: F) -> Result<()>;
- /// Adds an icon to the system tray with the specified menu items.
- #[cfg(all(desktop, feature = "system-tray"))]
- #[cfg_attr(doc_cfg, doc(cfg(all(desktop, feature = "system-tray"))))]
- fn system_tray(
- &self,
- system_tray: SystemTray,
- ) -> Result<>::TrayHandler>;
-
fn raw_display_handle(&self) -> RawDisplayHandle;
fn primary_monitor(&self) -> Option;
@@ -407,9 +225,9 @@ pub trait RuntimeHandle