Clean up shared context in desktop

This commit is contained in:
Jonathan Kelley committed 2024-01-05 12:37:47 -08:00
1 parent 8e9984b4b5
commit cbed09b95c
6 files changed
+34 -33

No files matched your search

+10 -8
View File
@@ -12,7 +12,7 @@ use crate::{
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use dioxus_core::{Component, ElementId, VirtualDom}; use dioxus_core::{Component, ElementId, VirtualDom};
use dioxus_html::{ use dioxus_html::{
native_bind::NativeFileEngine, FileEngine, FormData, HasFormData, HtmlEvent, MountedData, native_bind::NativeFileEngine, FileEngine, HasFormData, HtmlEvent, MountedData,
PlatformEventData, SerializedHtmlEventConverter, PlatformEventData, SerializedHtmlEventConverter,
}; };
use std::{ use std::{
@@ -35,22 +35,24 @@ pub(crate) struct App<P> {
pub(crate) cfg: Cell<Option<Config>>, pub(crate) cfg: Cell<Option<Config>>,
// Stuff we need mutable access to // Stuff we need mutable access to
pub(crate) root: Component<P>,
pub(crate) control_flow: ControlFlow, pub(crate) control_flow: ControlFlow,
pub(crate) is_visible_before_start: bool, 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) 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. /// 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 /// 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 struct SharedContext {
pub(crate) event_handlers: WindowEventHandlers, 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) shortcut_manager: ShortcutRegistry,
pub(crate) global_hotkey_channel: Receiver<GlobalHotKeyEvent>, pub(crate) global_hotkey_channel: Receiver<GlobalHotKeyEvent>,
pub(crate) proxy: EventLoopProxy<UserWindowEvent>, pub(crate) proxy: EventLoopProxy<UserWindowEvent>,
@@ -69,14 +71,14 @@ impl<P: 'static> App<P> {
control_flow: ControlFlow::Wait, control_flow: ControlFlow::Wait,
props: Cell::new(Some(props)), props: Cell::new(Some(props)),
cfg: Cell::new(Some(cfg)), cfg: Cell::new(Some(cfg)),
shared: SharedContext { shared: Rc::new(SharedContext {
event_handlers: WindowEventHandlers::default(), event_handlers: WindowEventHandlers::default(),
pending_webviews: Default::default(), pending_webviews: Default::default(),
shortcut_manager: ShortcutRegistry::new(), shortcut_manager: ShortcutRegistry::new(),
global_hotkey_channel: GlobalHotKeyEvent::receiver().clone(), global_hotkey_channel: GlobalHotKeyEvent::receiver().clone(),
proxy: event_loop.create_proxy(), proxy: event_loop.create_proxy(),
target: event_loop.clone(), target: event_loop.clone(),
}, }),
}; };
// Copy over any assets we find // Copy over any assets we find
+2 -2
View File
@@ -54,7 +54,7 @@ pub struct DesktopService {
/// The tao window itself /// The tao window itself
pub window: Window, pub window: Window,
pub(crate) shared: SharedContext, pub(crate) shared: Rc<SharedContext>,
/// The receiver for queries about the current window /// The receiver for queries about the current window
pub(super) query: QueryEngine, pub(super) query: QueryEngine,
@@ -81,7 +81,7 @@ impl DesktopService {
pub(crate) fn new( pub(crate) fn new(
window: Window, window: Window,
webview: WebView, webview: WebView,
shared: SharedContext, shared: Rc<SharedContext>,
edit_queue: EditQueue, edit_queue: EditQueue,
asset_handlers: AssetHandlerRegistry, asset_handlers: AssetHandlerRegistry,
) -> Self { ) -> Self {
+1 -3
View File
@@ -1,9 +1,7 @@
//! Convert a serialized event to an event trigger //! Convert a serialized event to an event trigger
use dioxus_html::*;
use serde::{Deserialize, Serialize};
use crate::element::DesktopElement; use crate::element::DesktopElement;
use dioxus_html::*;
pub(crate) struct SerializedHtmlEventConverter; pub(crate) struct SerializedHtmlEventConverter;
+15 -11
View File
@@ -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. // 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 { if let Some(response) = asset_handlers.try_handlers(&request).await {
return responder.respond(response); return responder.respond(response);
} }
@@ -50,9 +51,7 @@ pub(super) async fn desktop_handler(
fn serve_from_fs(request: AssetRequest) -> Result<AssetResponse> { fn serve_from_fs(request: AssetRequest) -> Result<AssetResponse> {
// If the path is relative, we'll try to serve it from the assets directory. // If the path is relative, we'll try to serve it from the assets directory.
let mut asset = get_asset_root() let mut asset = get_asset_root_or_default().join(&request.path);
.unwrap_or_else(|| Path::new(".").to_path_buf())
.join(&request.path);
// If we can't find it, make it absolute and try again // If we can't find it, make it absolute and try again
if !asset.exists() { if !asset.exists() {
@@ -87,7 +86,7 @@ fn build_index_file(
custom_head: Option<String>, custom_head: Option<String>,
root_name: &str, root_name: &str,
headless: bool, 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 // Load a custom index file if provided
let mut index = custom_index.unwrap_or_else(|| DEFAULT_INDEX.to_string()); 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); 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.insert_str(
index.find("</body>").expect("Body element to exist"), index.find("</body>").expect("Body element to exist"),
&module_loader(root_name, headless), &module_loader(root_name, headless),
@@ -106,7 +107,7 @@ fn build_index_file(
Response::builder() Response::builder()
.header("Content-Type", "text/html") .header("Content-Type", "text/html")
.header("Access-Control-Allow-Origin", "*") .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. /// 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 /// Get the asset directory, following tauri/cargo-bundles directory discovery approach
/// ///
/// Currently supports: /// Currently supports:
@@ -144,11 +153,6 @@ fn module_loader(root_id: &str, headless: bool) -> String {
/// - [ ] Linux (deb) /// - [ ] Linux (deb)
/// - [ ] iOS /// - [ ] iOS
/// - [ ] Android /// - [ ] 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)] #[allow(unreachable_code)]
fn get_asset_root() -> Option<PathBuf> { fn get_asset_root() -> Option<PathBuf> {
// If running under cargo, there's no bundle! // If running under cargo, there's no bundle!
+5 -8
View File
@@ -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 dioxus_html::input_data::keyboard_types::Modifiers;
use slab::Slab; use slab::Slab;
@@ -23,14 +23,11 @@ pub use global_hotkey::{
#[cfg(any(target_os = "ios", target_os = "android"))] #[cfg(any(target_os = "ios", target_os = "android"))]
pub use crate::mobile_shortcut::*; pub use crate::mobile_shortcut::*;
#[derive(Clone)]
pub(crate) struct ShortcutRegistry { pub(crate) struct ShortcutRegistry {
manager: Rc<GlobalHotKeyManager>, manager: GlobalHotKeyManager,
shortcuts: ShortcutMap, shortcuts: RefCell<HashMap<u32, Shortcut>>,
} }
type ShortcutMap = Rc<RefCell<HashMap<u32, Shortcut>>>;
struct Shortcut { struct Shortcut {
#[allow(unused)] #[allow(unused)]
shortcut: HotKey, shortcut: HotKey,
@@ -54,8 +51,8 @@ impl Shortcut {
impl ShortcutRegistry { impl ShortcutRegistry {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
manager: Rc::new(GlobalHotKeyManager::new().unwrap()), manager: GlobalHotKeyManager::new().unwrap(),
shortcuts: Rc::new(RefCell::new(HashMap::new())), shortcuts: RefCell::new(HashMap::new()),
} }
} }
+1 -1
View File
@@ -24,7 +24,7 @@ pub struct WebviewInstance {
} }
impl 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(); let window = cfg.window.clone().build(&shared.target).unwrap();
// TODO: allow users to specify their own menubars, again :/ // TODO: allow users to specify their own menubars, again :/