Clean up shared context in desktop
This commit is contained in:
6 files changed
+34
-33
No files matched your search
@@ -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
|
||||||
|
|||||||
@@ -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,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;
|
||||||
|
|
||||||
|
|||||||
@@ -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!
|
||||||
|
|||||||
@@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 :/
|
||||||
|
|||||||
Reference in new issue
Block a user