Forráskód Böngészése

Clean up shared context in desktop

Jonathan Kelley 1 éve
szülő
commit
cbed09b95c

+ 10 - 8
packages/desktop/src/app.rs

@@ -12,7 +12,7 @@ use crate::{
 use crossbeam_channel::Receiver;
 use dioxus_core::{Component, ElementId, VirtualDom};
 use dioxus_html::{
-    native_bind::NativeFileEngine, FileEngine, FormData, HasFormData, HtmlEvent, MountedData,
+    native_bind::NativeFileEngine, FileEngine, HasFormData, HtmlEvent, MountedData,
     PlatformEventData, SerializedHtmlEventConverter,
 };
 use std::{
@@ -35,22 +35,24 @@ pub(crate) struct App<P> {
     pub(crate) cfg: Cell<Option<Config>>,
 
     // Stuff we need mutable access to
+    pub(crate) root: Component<P>,
     pub(crate) control_flow: ControlFlow,
     pub(crate) is_visible_before_start: bool,
-    pub(crate) root: Component<P>,
-    pub(crate) webviews: HashMap<WindowId, WebviewInstance>,
     pub(crate) window_behavior: WindowCloseBehaviour,
+    pub(crate) webviews: HashMap<WindowId, WebviewInstance>,
 
-    pub(crate) shared: SharedContext,
+    /// This single blob of state is shared between all the windows so they have access to the runtime state
+    ///
+    /// This includes stuff like the event handlers, shortcuts, etc as well as ways to modify *other* windows
+    pub(crate) shared: Rc<SharedContext>,
 }
 
 /// A bundle of state shared between all the windows, providing a way for us to communicate with running webview.
 ///
 /// Todo: everything in this struct is wrapped in Rc<>, but we really only need the one top-level refcell
-#[derive(Clone)]
 pub struct SharedContext {
     pub(crate) event_handlers: WindowEventHandlers,
-    pub(crate) pending_webviews: Rc<RefCell<Vec<WebviewInstance>>>,
+    pub(crate) pending_webviews: RefCell<Vec<WebviewInstance>>,
     pub(crate) shortcut_manager: ShortcutRegistry,
     pub(crate) global_hotkey_channel: Receiver<GlobalHotKeyEvent>,
     pub(crate) proxy: EventLoopProxy<UserWindowEvent>,
@@ -69,14 +71,14 @@ impl<P: 'static> App<P> {
             control_flow: ControlFlow::Wait,
             props: Cell::new(Some(props)),
             cfg: Cell::new(Some(cfg)),
-            shared: SharedContext {
+            shared: Rc::new(SharedContext {
                 event_handlers: WindowEventHandlers::default(),
                 pending_webviews: Default::default(),
                 shortcut_manager: ShortcutRegistry::new(),
                 global_hotkey_channel: GlobalHotKeyEvent::receiver().clone(),
                 proxy: event_loop.create_proxy(),
                 target: event_loop.clone(),
-            },
+            }),
         };
 
         // Copy over any assets we find

+ 2 - 2
packages/desktop/src/desktop_context.rs

@@ -54,7 +54,7 @@ pub struct DesktopService {
     /// The tao window itself
     pub window: Window,
 
-    pub(crate) shared: SharedContext,
+    pub(crate) shared: Rc<SharedContext>,
 
     /// The receiver for queries about the current window
     pub(super) query: QueryEngine,
@@ -81,7 +81,7 @@ impl DesktopService {
     pub(crate) fn new(
         window: Window,
         webview: WebView,
-        shared: SharedContext,
+        shared: Rc<SharedContext>,
         edit_queue: EditQueue,
         asset_handlers: AssetHandlerRegistry,
     ) -> Self {

+ 1 - 3
packages/desktop/src/events.rs

@@ -1,9 +1,7 @@
 //! Convert a serialized event to an event trigger
 
-use dioxus_html::*;
-use serde::{Deserialize, Serialize};
-
 use crate::element::DesktopElement;
+use dioxus_html::*;
 
 pub(crate) struct SerializedHtmlEventConverter;
 

+ 15 - 11
packages/desktop/src/protocol.rs

@@ -37,6 +37,7 @@ pub(super) async fn desktop_handler(
     }
 
     // If the user provided a custom asset handler, then call it and return the response if the request was handled.
+    // todo(jon): I dont want this function to be async - we can probably just use a drop handler on the responder
     if let Some(response) = asset_handlers.try_handlers(&request).await {
         return responder.respond(response);
     }
@@ -50,9 +51,7 @@ pub(super) async fn desktop_handler(
 
 fn serve_from_fs(request: AssetRequest) -> Result<AssetResponse> {
     // If the path is relative, we'll try to serve it from the assets directory.
-    let mut asset = get_asset_root()
-        .unwrap_or_else(|| Path::new(".").to_path_buf())
-        .join(&request.path);
+    let mut asset = get_asset_root_or_default().join(&request.path);
 
     // If we can't find it, make it absolute and try again
     if !asset.exists() {
@@ -87,7 +86,7 @@ fn build_index_file(
     custom_head: Option<String>,
     root_name: &str,
     headless: bool,
-) -> std::result::Result<Response<Cow<'static, [u8]>>, wry::http::Error> {
+) -> std::result::Result<Response<Vec<u8>>, wry::http::Error> {
     // Load a custom index file if provided
     let mut index = custom_index.unwrap_or_else(|| DEFAULT_INDEX.to_string());
 
@@ -97,7 +96,9 @@ fn build_index_file(
         index.insert_str(index.find("</head>").expect("Head element to exist"), &head);
     }
 
-    // Inject our module loader
+    // Inject our module loader by looking for a body tag
+    // A failure mode here, obviously, is if the user provided a custom index without a body tag
+    // Might want to document this
     index.insert_str(
         index.find("</body>").expect("Body element to exist"),
         &module_loader(root_name, headless),
@@ -106,7 +107,7 @@ fn build_index_file(
     Response::builder()
         .header("Content-Type", "text/html")
         .header("Access-Control-Allow-Origin", "*")
-        .body(Cow::from(index.into_bytes()))
+        .body(index.into_bytes().into())
 }
 
 /// Construct the inline script that boots up the page and bridges the webview with rust code.
@@ -135,6 +136,14 @@ fn module_loader(root_id: &str, headless: bool) -> String {
     )
 }
 
+//// Get the assset directory, following tauri/cargo-bundles directory discovery approach
+////
+//// Defaults to the current directory if no asset directory is found, which is useful for development when the app
+//// isn't bundled.
+fn get_asset_root_or_default() -> PathBuf {
+    get_asset_root().unwrap_or_else(|| Path::new(".").to_path_buf())
+}
+
 /// Get the asset directory, following tauri/cargo-bundles directory discovery approach
 ///
 /// Currently supports:
@@ -144,11 +153,6 @@ fn module_loader(root_id: &str, headless: bool) -> String {
 /// - [ ] Linux (deb)
 /// - [ ] iOS
 /// - [ ] Android
-#[allow(unreachable_code)]
-pub(crate) fn get_asset_root_or_default() -> PathBuf {
-    get_asset_root().unwrap_or_else(|| Path::new(".").to_path_buf())
-}
-
 #[allow(unreachable_code)]
 fn get_asset_root() -> Option<PathBuf> {
     // If running under cargo, there's no bundle!

+ 5 - 8
packages/desktop/src/shortcut.rs

@@ -1,4 +1,4 @@
-use std::{cell::RefCell, collections::HashMap, rc::Rc, str::FromStr};
+use std::{cell::RefCell, collections::HashMap, str::FromStr};
 
 use dioxus_html::input_data::keyboard_types::Modifiers;
 use slab::Slab;
@@ -23,14 +23,11 @@ pub use global_hotkey::{
 #[cfg(any(target_os = "ios", target_os = "android"))]
 pub use crate::mobile_shortcut::*;
 
-#[derive(Clone)]
 pub(crate) struct ShortcutRegistry {
-    manager: Rc<GlobalHotKeyManager>,
-    shortcuts: ShortcutMap,
+    manager: GlobalHotKeyManager,
+    shortcuts: RefCell<HashMap<u32, Shortcut>>,
 }
 
-type ShortcutMap = Rc<RefCell<HashMap<u32, Shortcut>>>;
-
 struct Shortcut {
     #[allow(unused)]
     shortcut: HotKey,
@@ -54,8 +51,8 @@ impl Shortcut {
 impl ShortcutRegistry {
     pub fn new() -> Self {
         Self {
-            manager: Rc::new(GlobalHotKeyManager::new().unwrap()),
-            shortcuts: Rc::new(RefCell::new(HashMap::new())),
+            manager: GlobalHotKeyManager::new().unwrap(),
+            shortcuts: RefCell::new(HashMap::new()),
         }
     }
 

+ 1 - 1
packages/desktop/src/webview.rs

@@ -24,7 +24,7 @@ pub struct WebviewInstance {
 }
 
 impl WebviewInstance {
-    pub fn new(mut cfg: Config, dom: VirtualDom, shared: SharedContext) -> WebviewInstance {
+    pub fn new(mut cfg: Config, dom: VirtualDom, shared: Rc<SharedContext>) -> WebviewInstance {
         let window = cfg.window.clone().build(&shared.target).unwrap();
 
         // TODO: allow users to specify their own menubars, again :/