Skip to content

Commit

Permalink
refactor(core): simplify usage of app event and window label types (#…
Browse files Browse the repository at this point in the history
…1623)

Co-authored-by: chip reed <chip@chip.sh>
  • Loading branch information
lucasfernog and chippers committed Apr 27, 2021
1 parent af6411d commit 181e132
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 101 deletions.
5 changes: 5 additions & 0 deletions .changes/simplify-tag-label-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": patch
---

Simplify usage of app event and window label types.
6 changes: 3 additions & 3 deletions core/tauri/src/endpoints/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ impl Cmd {
});

// dispatch the event to Rust listeners
window.trigger(e.clone(), payload.clone());
window.trigger(&e, payload.clone());

if let Some(target) = window_label {
window.emit_to(&target, e, payload)?;
window.emit_to(&target, &e, payload)?;
} else {
window.emit_all(e, payload)?;
window.emit_all(&e, payload)?;
}
Ok(().into())
}
Expand Down
10 changes: 6 additions & 4 deletions core/tauri/src/endpoints/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ struct WindowCreatedEvent {

impl Cmd {
#[allow(dead_code)]
pub async fn run<M: Params>(self, window: Window<M>) -> crate::Result<InvokeResponse> {
pub async fn run<P: Params>(self, window: Window<P>) -> crate::Result<InvokeResponse> {
if cfg!(not(window_all)) {
Err(crate::Error::ApiNotAllowlisted("window > all".to_string()))
} else {
Expand All @@ -114,7 +114,7 @@ impl Cmd {
Self::CreateWebview { options } => {
let mut window = window;
// Panic if the user's `Tag` type decided to return an error while parsing.
let label: M::Label = options.label.parse().unwrap_or_else(|_| {
let label: P::Label = options.label.parse().unwrap_or_else(|_| {
panic!(
"Window module received unknown window label: {}",
options.label
Expand All @@ -124,13 +124,15 @@ impl Cmd {
let url = options.url.clone();
let pending =
crate::runtime::window::PendingWindow::with_config(options, label.clone(), url);
window.create_window(pending)?.emit_others_internal(
"tauri://window-created".to_string(),

window.create_window(pending)?.emit_others(
&crate::runtime::manager::tauri_event::<P::Event>("tauri://window-created"),
Some(WindowCreatedEvent {
label: label.to_string(),
}),
)?;
}

Self::SetResizable { resizable } => window.set_resizable(resizable)?,
Self::SetTitle { title } => window.set_title(&title)?,
Self::Maximize => window.maximize()?,
Expand Down
17 changes: 11 additions & 6 deletions core/tauri/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use crate::runtime::tag::Tag;
use crate::runtime::tag::{Tag, TagRef};
use std::{
borrow::Borrow,
boxed::Box,
collections::HashMap,
fmt,
Expand Down Expand Up @@ -134,7 +135,7 @@ impl<Event: Tag, Window: Tag> Listeners<Event, Window> {
match action {
Pending::Unlisten(id) => self.unlisten(id),
Pending::Listen(id, event, handler) => self.listen_(id, event, handler),
Pending::Trigger(event, window, payload) => self.trigger(event, window, payload),
Pending::Trigger(ref event, window, payload) => self.trigger(event, window, payload),
}
}
}
Expand Down Expand Up @@ -191,12 +192,16 @@ impl<Event: Tag, Window: Tag> Listeners<Event, Window> {
}

/// Triggers the given global event with its payload.
pub(crate) fn trigger(&self, event: Event, window: Option<Window>, payload: Option<String>) {
pub(crate) fn trigger<E>(&self, event: &E, window: Option<Window>, payload: Option<String>)
where
E: TagRef<Event> + ?Sized,
Event: Borrow<E>,
{
let mut maybe_pending = false;
match self.inner.handlers.try_lock() {
Err(_) => self.insert_pending(Pending::Trigger(event, window, payload)),
Err(_) => self.insert_pending(Pending::Trigger(event.to_owned(), window, payload)),
Ok(lock) => {
if let Some(handlers) = lock.get(&event) {
if let Some(handlers) = lock.get(event) {
for (&id, handler) in handlers {
if window.is_none() || window == handler.window {
maybe_pending = true;
Expand Down Expand Up @@ -280,7 +285,7 @@ mod test {
// call listen with e and the event_fn dummy func
listeners.listen(e.clone(), None, event_fn);
// call on event with e and d.
listeners.trigger(e, None, Some(d));
listeners.trigger(&e, None, Some(d));

// lock the mutex
let l = listeners.inner.handlers.lock().unwrap();
Expand Down
50 changes: 34 additions & 16 deletions core/tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub type SyncTask = Box<dyn FnOnce() + Send>;
use crate::api::assets::Assets;
use crate::api::config::Config;
use crate::event::{Event, EventHandler};
use crate::runtime::tag::Tag;
use crate::runtime::tag::{Tag, TagRef};
use crate::runtime::window::PendingWindow;
use crate::runtime::{Dispatch, Runtime};
use serde::Serialize;
Expand All @@ -51,10 +51,12 @@ pub use {
api::config::WindowUrl,
hooks::{InvokeHandler, InvokeMessage, OnPageLoad, PageLoadPayload, SetupHook},
runtime::app::{App, Builder},
runtime::flavors::wry::Wry,
runtime::webview::Attributes,
runtime::window::export::Window,
};

use std::borrow::Borrow;
/// Reads the config file at compile time and generates a [`Context`] based on its content.
///
/// The default config file path is a `tauri.conf.json` file inside the Cargo manifest directory of
Expand Down Expand Up @@ -130,31 +132,39 @@ pub trait Params: sealed::ParamsBase {
/// Manages a running application.
///
/// TODO: expand these docs
pub trait Manager<M: Params>: sealed::ManagerBase<M> {
pub trait Manager<P: Params>: sealed::ManagerBase<P> {
/// The [`Config`] the manager was created with.
fn config(&self) -> &Config {
self.manager().config()
}

/// Emits a event to all windows.
fn emit_all<S: Serialize + Clone>(&self, event: M::Event, payload: Option<S>) -> Result<()> {
fn emit_all<E, S>(&self, event: &E, payload: Option<S>) -> Result<()>
where
E: TagRef<P::Event> + ?Sized,
S: Serialize + Clone,
{
self.manager().emit_filter(event, payload, |_| true)
}

/// Emits an event to a window with the specified label.
fn emit_to<S: Serialize + Clone>(
fn emit_to<E, L, S: Serialize + Clone>(
&self,
label: &M::Label,
event: M::Event,
label: &L,
event: &E,
payload: Option<S>,
) -> Result<()> {
) -> Result<()>
where
L: TagRef<P::Label> + ?Sized,
E: TagRef<P::Event> + ?Sized,
{
self
.manager()
.emit_filter(event, payload, |w| w.label() == label)
.emit_filter(event, payload, |w| label == w.label())
}

/// Creates a new [`Window`] on the [`Runtime`] and attaches it to the [`Manager`].
fn create_window(&mut self, pending: PendingWindow<M>) -> Result<Window<M>> {
fn create_window(&mut self, pending: PendingWindow<P>) -> Result<Window<P>> {
use sealed::RuntimeOrDispatch::*;

let labels = self.manager().labels().into_iter().collect::<Vec<_>>();
Expand All @@ -167,23 +177,27 @@ pub trait Manager<M: Params>: sealed::ManagerBase<M> {
}

/// Listen to a global event.
fn listen_global<F>(&self, event: M::Event, handler: F) -> EventHandler
fn listen_global<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
where
F: Fn(Event) + Send + 'static,
{
self.manager().listen(event, None, handler)
self.manager().listen(event.into(), None, handler)
}

/// Listen to a global event only once.
fn once_global<F>(&self, event: M::Event, handler: F) -> EventHandler
fn once_global<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
where
F: Fn(Event) + Send + 'static,
{
self.manager().once(event, None, handler)
self.manager().once(event.into(), None, handler)
}

/// Trigger a global event.
fn trigger_global(&self, event: M::Event, data: Option<String>) {
fn trigger_global<E>(&self, event: &E, data: Option<String>)
where
E: TagRef<P::Event> + ?Sized,
P::Event: Borrow<E>,
{
self.manager().trigger(event, None, data)
}

Expand All @@ -193,12 +207,16 @@ pub trait Manager<M: Params>: sealed::ManagerBase<M> {
}

/// Fetch a single window from the manager.
fn get_window(&self, label: &M::Label) -> Option<Window<M>> {
fn get_window<L>(&self, label: &L) -> Option<Window<P>>
where
L: TagRef<P::Label> + ?Sized,
P::Label: Borrow<L>,
{
self.manager().get_window(label)
}

/// Fetch all managed windows.
fn windows(&self) -> HashMap<M::Label, Window<M>> {
fn windows(&self) -> HashMap<P::Label, Window<P>> {
self.manager().windows()
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/runtime/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl<M: Params> App<M> {
// invoke the Event `tauri://update` from JS or rust side.
main_window.listen(
updater::EVENT_CHECK_UPDATE
.parse()
.parse::<M::Event>()
.unwrap_or_else(|_| panic!("bad label")),
move |_msg| {
let window = event_window.clone();
Expand Down
80 changes: 50 additions & 30 deletions core/tauri/src/runtime/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use crate::runtime::tag::TagRef;
use crate::{
api::{
assets::Assets,
Expand All @@ -13,7 +14,7 @@ use crate::{
hooks::{InvokeHandler, InvokeMessage, InvokePayload, OnPageLoad, PageLoadPayload},
plugin::PluginStore,
runtime::{
tag::{tags_to_javascript_array, Tag, ToJavascript},
tag::{tags_to_javascript_array, Tag, ToJsString},
webview::{Attributes, CustomProtocol, FileDropEvent, FileDropHandler, WebviewRpcHandler},
window::{DetachedWindow, PendingWindow},
Dispatch, Icon, Runtime,
Expand All @@ -23,6 +24,7 @@ use crate::{
};
use serde::Serialize;
use serde_json::Value as JsonValue;
use std::borrow::Borrow;
use std::marker::PhantomData;
use std::{
borrow::Cow,
Expand All @@ -33,6 +35,20 @@ use std::{
};
use uuid::Uuid;

/// Parse a string representing an internal tauri event into [`Params::Event`]
///
/// # Panics
///
/// This will panic if the `FromStr` implementation of [`Params::Event`] returns an error.
pub(crate) fn tauri_event<Event: Tag>(tauri_event: &str) -> Event {
tauri_event.parse().unwrap_or_else(|_| {
panic!(
"failed to parse internal tauri event into Params::Event: {}",
tauri_event
)
})
}

pub struct InnerWindowManager<P: Params> {
windows: Mutex<HashMap<P::Label, Window<P>>>,
plugins: Mutex<PluginStore<P>>,
Expand Down Expand Up @@ -168,7 +184,7 @@ impl<P: Params> WindowManager<P> {
window.__TAURI__.__currentWindow = {{ label: {current_window_label} }}
"#,
window_labels_array = tags_to_javascript_array(pending_labels)?,
current_window_label = label.to_javascript()?,
current_window_label = label.to_js_string()?,
));

if !attributes.has_icon() {
Expand Down Expand Up @@ -281,14 +297,16 @@ impl<P: Params> WindowManager<P> {
let window = manager.attach_window(window);
let _ = match event {
FileDropEvent::Hovered(paths) => {
window.emit_internal("tauri://file-drop".to_string(), Some(paths))
}
FileDropEvent::Dropped(paths) => {
window.emit_internal("tauri://file-drop-hover".to_string(), Some(paths))
}
FileDropEvent::Cancelled => {
window.emit_internal("tauri://file-drop-cancelled".to_string(), Some(()))
window.emit_internal(&tauri_event::<P::Event>("tauri://file-drop"), Some(paths))
}
FileDropEvent::Dropped(paths) => window.emit_internal(
&tauri_event::<P::Event>("tauri://file-drop-hover"),
Some(paths),
),
FileDropEvent::Cancelled => window.emit_internal(
&tauri_event::<P::Event>("tauri://file-drop-cancelled"),
Some(()),
),
};
});
true
Expand Down Expand Up @@ -474,30 +492,20 @@ impl<P: Params> WindowManager<P> {

window
}
pub fn emit_filter_internal<S: Serialize + Clone, F: Fn(&Window<P>) -> bool>(
&self,
event: String,
payload: Option<S>,
filter: F,
) -> crate::Result<()> {
self
.windows_lock()
.values()
.filter(|&w| filter(w))
.try_for_each(|window| window.emit_internal(event.clone(), payload.clone()))
}
pub fn emit_filter<S: Serialize + Clone, F: Fn(&Window<P>) -> bool>(
&self,
event: P::Event,
payload: Option<S>,
filter: F,
) -> crate::Result<()> {

pub fn emit_filter<E, S, F>(&self, event: &E, payload: Option<S>, filter: F) -> crate::Result<()>
where
E: TagRef<P::Event> + ?Sized,
S: Serialize + Clone,
F: Fn(&Window<P>) -> bool,
{
self
.windows_lock()
.values()
.filter(|&w| filter(w))
.try_for_each(|window| window.emit(&event, payload.clone()))
.try_for_each(|window| window.emit(event, payload.clone()))
}

pub fn labels(&self) -> HashSet<P::Label> {
self.windows_lock().keys().cloned().collect()
}
Expand All @@ -510,9 +518,15 @@ impl<P: Params> WindowManager<P> {
pub fn unlisten(&self, handler_id: EventHandler) {
self.inner.listeners.unlisten(handler_id)
}
pub fn trigger(&self, event: P::Event, window: Option<P::Label>, data: Option<String>) {

pub fn trigger<E>(&self, event: &E, window: Option<P::Label>, data: Option<String>)
where
E: TagRef<P::Event> + ?Sized,
P::Event: Borrow<E>,
{
self.inner.listeners.trigger(event, window, data)
}

pub fn listen<F: Fn(Event) + Send + 'static>(
&self,
event: P::Event,
Expand Down Expand Up @@ -563,9 +577,15 @@ impl<P: Params> WindowManager<P> {
.expect("poisoned salt mutex")
.remove(&uuid)
}
pub fn get_window(&self, label: &P::Label) -> Option<Window<P>> {

pub fn get_window<L>(&self, label: &L) -> Option<Window<P>>
where
L: TagRef<P::Label> + ?Sized,
P::Label: Borrow<L>,
{
self.windows_lock().get(label).cloned()
}

pub fn windows(&self) -> HashMap<P::Label, Window<P>> {
self.windows_lock().clone()
}
Expand Down
Loading

0 comments on commit 181e132

Please sign in to comment.