Skip to content

Commit e11878b

Browse files
authored
refactor(core): add global-shortcut Cargo feature, enhancing binary size (#3956)
1 parent c23f139 commit e11878b

11 files changed

Lines changed: 261 additions & 152 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tauri": patch
3+
"tauri-runtime": minor
4+
"tauri-runtime-wry": minor
5+
---
6+
7+
**Breaking change::* Added the `global-shortcut` Cargo feature.

core/tauri-codegen/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ fn map_core_assets(
5656
if path.extension() == Some(OsStr::new("html")) {
5757
let mut document = parse_html(String::from_utf8_lossy(input).into_owned());
5858

59+
#[allow(clippy::collapsible_if)]
5960
if csp {
6061
#[cfg(target_os = "linux")]
6162
::tauri_utils::html::inject_csp_token(&mut document);

core/tauri-runtime-wry/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@ macos-private-api = [
4141
objc-exception = [ "wry/objc-exception" ]
4242
gtk-tray = [ "wry/gtk-tray" ]
4343
ayatana-tray = [ "wry/ayatana-tray" ]
44+
global-shortcut = [ "tauri-runtime/global-shortcut" ]
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
2+
// SPDX-License-Identifier: Apache-2.0
3+
// SPDX-License-Identifier: MIT
4+
5+
//! Global shortcut implementation.
6+
7+
use std::{
8+
collections::HashMap,
9+
fmt,
10+
sync::{
11+
mpsc::{channel, Sender},
12+
Arc, Mutex,
13+
},
14+
};
15+
16+
use crate::{getter, Context, Message};
17+
18+
use tauri_runtime::{Error, GlobalShortcutManager, Result, UserEvent};
19+
pub use wry::application::global_shortcut::ShortcutManager as WryShortcutManager;
20+
use wry::application::{
21+
accelerator::{Accelerator, AcceleratorId},
22+
global_shortcut::GlobalShortcut,
23+
};
24+
25+
pub type GlobalShortcutListeners = Arc<Mutex<HashMap<AcceleratorId, Box<dyn Fn() + Send>>>>;
26+
27+
#[derive(Debug, Clone)]
28+
pub enum GlobalShortcutMessage {
29+
IsRegistered(Accelerator, Sender<bool>),
30+
Register(Accelerator, Sender<Result<GlobalShortcutWrapper>>),
31+
Unregister(GlobalShortcutWrapper, Sender<Result<()>>),
32+
UnregisterAll(Sender<Result<()>>),
33+
}
34+
35+
#[derive(Debug, Clone)]
36+
pub struct GlobalShortcutWrapper(GlobalShortcut);
37+
38+
// SAFETY: usage outside of main thread is guarded, we use the event loop on such cases.
39+
#[allow(clippy::non_send_fields_in_send_ty)]
40+
unsafe impl Send for GlobalShortcutWrapper {}
41+
42+
/// Wrapper around [`WryShortcutManager`].
43+
#[derive(Clone)]
44+
pub struct GlobalShortcutManagerHandle<T: UserEvent> {
45+
pub context: Context<T>,
46+
pub shortcuts: Arc<Mutex<HashMap<String, (AcceleratorId, GlobalShortcutWrapper)>>>,
47+
pub listeners: GlobalShortcutListeners,
48+
}
49+
50+
// SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`.
51+
#[allow(clippy::non_send_fields_in_send_ty)]
52+
unsafe impl<T: UserEvent> Sync for GlobalShortcutManagerHandle<T> {}
53+
54+
impl<T: UserEvent> fmt::Debug for GlobalShortcutManagerHandle<T> {
55+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56+
f.debug_struct("GlobalShortcutManagerHandle")
57+
.field("context", &self.context)
58+
.field("shortcuts", &self.shortcuts)
59+
.finish()
60+
}
61+
}
62+
63+
impl<T: UserEvent> GlobalShortcutManager for GlobalShortcutManagerHandle<T> {
64+
fn is_registered(&self, accelerator: &str) -> Result<bool> {
65+
let (tx, rx) = channel();
66+
getter!(
67+
self,
68+
rx,
69+
Message::GlobalShortcut(GlobalShortcutMessage::IsRegistered(
70+
accelerator.parse().expect("invalid accelerator"),
71+
tx
72+
))
73+
)
74+
}
75+
76+
fn register<F: Fn() + Send + 'static>(&mut self, accelerator: &str, handler: F) -> Result<()> {
77+
let wry_accelerator: Accelerator = accelerator.parse().expect("invalid accelerator");
78+
let id = wry_accelerator.clone().id();
79+
let (tx, rx) = channel();
80+
let shortcut = getter!(
81+
self,
82+
rx,
83+
Message::GlobalShortcut(GlobalShortcutMessage::Register(wry_accelerator, tx))
84+
)??;
85+
86+
self.listeners.lock().unwrap().insert(id, Box::new(handler));
87+
self
88+
.shortcuts
89+
.lock()
90+
.unwrap()
91+
.insert(accelerator.into(), (id, shortcut));
92+
93+
Ok(())
94+
}
95+
96+
fn unregister_all(&mut self) -> Result<()> {
97+
let (tx, rx) = channel();
98+
getter!(
99+
self,
100+
rx,
101+
Message::GlobalShortcut(GlobalShortcutMessage::UnregisterAll(tx))
102+
)??;
103+
self.listeners.lock().unwrap().clear();
104+
self.shortcuts.lock().unwrap().clear();
105+
Ok(())
106+
}
107+
108+
fn unregister(&mut self, accelerator: &str) -> Result<()> {
109+
if let Some((accelerator_id, shortcut)) = self.shortcuts.lock().unwrap().remove(accelerator) {
110+
let (tx, rx) = channel();
111+
getter!(
112+
self,
113+
rx,
114+
Message::GlobalShortcut(GlobalShortcutMessage::Unregister(shortcut, tx))
115+
)??;
116+
self.listeners.lock().unwrap().remove(&accelerator_id);
117+
}
118+
Ok(())
119+
}
120+
}
121+
122+
pub fn handle_global_shortcut_message(
123+
message: GlobalShortcutMessage,
124+
global_shortcut_manager: &Arc<Mutex<WryShortcutManager>>,
125+
) {
126+
match message {
127+
GlobalShortcutMessage::IsRegistered(accelerator, tx) => tx
128+
.send(
129+
global_shortcut_manager
130+
.lock()
131+
.unwrap()
132+
.is_registered(&accelerator),
133+
)
134+
.unwrap(),
135+
GlobalShortcutMessage::Register(accelerator, tx) => tx
136+
.send(
137+
global_shortcut_manager
138+
.lock()
139+
.unwrap()
140+
.register(accelerator)
141+
.map(GlobalShortcutWrapper)
142+
.map_err(|e| Error::GlobalShortcut(Box::new(e))),
143+
)
144+
.unwrap(),
145+
GlobalShortcutMessage::Unregister(shortcut, tx) => tx
146+
.send(
147+
global_shortcut_manager
148+
.lock()
149+
.unwrap()
150+
.unregister(shortcut.0)
151+
.map_err(|e| Error::GlobalShortcut(Box::new(e))),
152+
)
153+
.unwrap(),
154+
GlobalShortcutMessage::UnregisterAll(tx) => tx
155+
.send(
156+
global_shortcut_manager
157+
.lock()
158+
.unwrap()
159+
.unregister_all()
160+
.map_err(|e| Error::GlobalShortcut(Box::new(e))),
161+
)
162+
.unwrap(),
163+
}
164+
}

0 commit comments

Comments
 (0)