diff --git a/packages/desktop/src/controller.rs b/packages/desktop/src/controller.rs index 8497a42e9..06dfd3e9c 100644 --- a/packages/desktop/src/controller.rs +++ b/packages/desktop/src/controller.rs @@ -1,5 +1,4 @@ -use crate::desktop_context::DesktopContext; -use crate::user_window_events::UserWindowEvent; +use crate::desktop_context::{DesktopContext, UserWindowEvent}; use dioxus_core::*; use std::{ collections::{HashMap, VecDeque}, diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index e1b726d73..1376110f1 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -3,14 +3,23 @@ use std::rc::Rc; use dioxus_core::ScopeState; use wry::application::event_loop::EventLoopProxy; -use crate::user_window_events::UserWindowEvent; use UserWindowEvent::*; -type ProxyType = EventLoopProxy; +pub type ProxyType = EventLoopProxy; -/// Desktop-Window handle api context +/// Get an imperative handle to the current window +pub fn use_window(cx: &ScopeState) -> &Rc { + cx.use_hook(|_| cx.consume_context::()) + .as_ref() + .unwrap() +} + +/// An imperative interface to the current window. /// -/// you can use this context control some window event +/// To get a handle to the current window, use the [`use_window`] hook. +/// +/// +/// # Example /// /// you can use `cx.consume_context::` to get this context /// @@ -19,7 +28,8 @@ type ProxyType = EventLoopProxy; /// ``` #[derive(Clone)] pub struct DesktopContext { - proxy: ProxyType, + /// The wry/tao proxy to the current window + pub proxy: ProxyType, } impl DesktopContext { @@ -84,12 +94,12 @@ impl DesktopContext { let _ = self.proxy.send_event(AlwaysOnTop(top)); } - // set cursor visible or not + /// set cursor visible or not pub fn set_cursor_visible(&self, visible: bool) { let _ = self.proxy.send_event(CursorVisible(visible)); } - // set cursor grab + /// set cursor grab pub fn set_cursor_grab(&self, grab: bool) { let _ = self.proxy.send_event(CursorGrab(grab)); } @@ -110,9 +120,73 @@ impl DesktopContext { } } -/// use this function can get the `DesktopContext` context. -pub fn use_window(cx: &ScopeState) -> &Rc { - cx.use_hook(|_| cx.consume_context::()) - .as_ref() - .unwrap() +use wry::application::event_loop::ControlFlow; +use wry::application::window::Fullscreen as WryFullscreen; + +use crate::controller::DesktopController; + +pub enum UserWindowEvent { + Update, + + CloseWindow, + DragWindow, + FocusWindow, + + Visible(bool), + Minimize(bool), + Maximize(bool), + MaximizeToggle, + Resizable(bool), + AlwaysOnTop(bool), + Fullscreen(bool), + + CursorVisible(bool), + CursorGrab(bool), + + SetTitle(String), + SetDecorations(bool), + + DevTool, +} + +pub(super) fn handler( + user_event: UserWindowEvent, + desktop: &mut DesktopController, + control_flow: &mut ControlFlow, +) { + // currently dioxus-desktop supports a single window only, + // so we can grab the only webview from the map; + let webview = desktop.webviews.values().next().unwrap(); + let window = webview.window(); + + match user_event { + Update => desktop.try_load_ready_webviews(), + CloseWindow => *control_flow = ControlFlow::Exit, + DragWindow => { + // if the drag_window has any errors, we don't do anything + window.fullscreen().is_none().then(|| window.drag_window()); + } + Visible(state) => window.set_visible(state), + Minimize(state) => window.set_minimized(state), + Maximize(state) => window.set_maximized(state), + MaximizeToggle => window.set_maximized(!window.is_maximized()), + Fullscreen(state) => { + if let Some(handle) = window.current_monitor() { + window.set_fullscreen(state.then(|| WryFullscreen::Borderless(Some(handle)))); + } + } + FocusWindow => window.set_focus(), + Resizable(state) => window.set_resizable(state), + AlwaysOnTop(state) => window.set_always_on_top(state), + + CursorVisible(state) => window.set_cursor_visible(state), + CursorGrab(state) => { + let _ = window.set_cursor_grab(state); + } + + SetTitle(content) => window.set_title(&content), + SetDecorations(state) => window.set_decorations(state), + + DevTool => webview.devtool(), + } } diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 4d204a378..cd8099e3c 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -1,18 +1,23 @@ #![doc = include_str!("readme.md")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] +#![deny(missing_docs)] -pub mod cfg; +mod cfg; mod controller; -pub mod desktop_context; -pub mod escape; -pub mod events; +mod desktop_context; +mod escape; +mod events; mod protocol; -mod user_window_events; +use desktop_context::UserWindowEvent; +pub use desktop_context::{use_window, DesktopContext}; +pub use wry; +pub use wry::application as tao; + +use crate::events::trigger_from_serialized; use cfg::DesktopConfig; use controller::DesktopController; -pub use desktop_context::use_window; use dioxus_core::*; use events::parse_ipc_message; use tao::{ @@ -20,12 +25,8 @@ use tao::{ event_loop::{ControlFlow, EventLoop}, window::Window, }; -pub use wry; -pub use wry::application as tao; use wry::webview::WebViewBuilder; -use crate::events::trigger_from_serialized; - /// Launch the WebView and run the event loop. /// /// This function will start a multithreaded Tokio runtime as well the WebView event loop. @@ -139,8 +140,7 @@ pub fn launch_with_props( } "initialize" => { is_ready.store(true, std::sync::atomic::Ordering::Relaxed); - let _ = proxy - .send_event(user_window_events::UserWindowEvent::Update); + let _ = proxy.send_event(UserWindowEvent::Update); } "browser_open" => { println!("browser_open"); @@ -214,7 +214,7 @@ pub fn launch_with_props( }, Event::UserEvent(user_event) => { - user_window_events::handler(user_event, &mut desktop, control_flow) + desktop_context::handler(user_event, &mut desktop, control_flow) } Event::MainEventsCleared => {} Event::Resumed => {} diff --git a/packages/desktop/src/user_window_events.rs b/packages/desktop/src/user_window_events.rs deleted file mode 100644 index aab14561b..000000000 --- a/packages/desktop/src/user_window_events.rs +++ /dev/null @@ -1,72 +0,0 @@ -use wry::application::event_loop::ControlFlow; -use wry::application::window::Fullscreen as WryFullscreen; - -use crate::controller::DesktopController; - -pub(crate) enum UserWindowEvent { - Update, - - CloseWindow, - DragWindow, - FocusWindow, - - Visible(bool), - Minimize(bool), - Maximize(bool), - MaximizeToggle, - Resizable(bool), - AlwaysOnTop(bool), - Fullscreen(bool), - - CursorVisible(bool), - CursorGrab(bool), - - SetTitle(String), - SetDecorations(bool), - - DevTool, -} - -use UserWindowEvent::*; - -pub(super) fn handler( - user_event: UserWindowEvent, - desktop: &mut DesktopController, - control_flow: &mut ControlFlow, -) { - // currently dioxus-desktop supports a single window only, - // so we can grab the only webview from the map; - let webview = desktop.webviews.values().next().unwrap(); - let window = webview.window(); - - match user_event { - Update => desktop.try_load_ready_webviews(), - CloseWindow => *control_flow = ControlFlow::Exit, - DragWindow => { - // if the drag_window has any errors, we don't do anything - window.fullscreen().is_none().then(|| window.drag_window()); - } - Visible(state) => window.set_visible(state), - Minimize(state) => window.set_minimized(state), - Maximize(state) => window.set_maximized(state), - MaximizeToggle => window.set_maximized(!window.is_maximized()), - Fullscreen(state) => { - if let Some(handle) = window.current_monitor() { - window.set_fullscreen(state.then(|| WryFullscreen::Borderless(Some(handle)))); - } - } - FocusWindow => window.set_focus(), - Resizable(state) => window.set_resizable(state), - AlwaysOnTop(state) => window.set_always_on_top(state), - - CursorVisible(state) => window.set_cursor_visible(state), - CursorGrab(state) => { - let _ = window.set_cursor_grab(state); - } - - SetTitle(content) => window.set_title(&content), - SetDecorations(state) => window.set_decorations(state), - - DevTool => webview.devtool(), - } -} diff --git a/packages/hooks/src/lib.rs b/packages/hooks/src/lib.rs index cb4afd297..2960832c6 100644 --- a/packages/hooks/src/lib.rs +++ b/packages/hooks/src/lib.rs @@ -1,3 +1,6 @@ +#![deny(missing_docs)] +//! Useful foundational hooks for Dioxus + mod usestate; pub use usestate::{use_state, UseState}; diff --git a/packages/hooks/src/usefuture.rs b/packages/hooks/src/usefuture.rs index 58f350124..32b359204 100644 --- a/packages/hooks/src/usefuture.rs +++ b/packages/hooks/src/usefuture.rs @@ -1,19 +1,30 @@ +#![allow(missing_docs)] use dioxus_core::{ScopeState, TaskId}; use std::{cell::Cell, future::Future, rc::Rc}; +/// A future that resolves to a value. +/// +/// This runs the future only once - though the future may be regenerated +/// through the [`UseFuture::restart`] method. +/// +/// This is commonly used for components that cannot be rendered until some +/// asynchronous operation has completed. +/// +/// +/// +/// +/// pub fn use_future<'a, T: 'static, F: Future + 'static>( cx: &'a ScopeState, new_fut: impl FnOnce() -> F, ) -> &'a UseFuture { - let state = cx.use_hook(move |_| { - // - UseFuture { - update: cx.schedule_update(), - needs_regen: Cell::new(true), - slot: Rc::new(Cell::new(None)), - value: None, - task: None, - } + let state = cx.use_hook(move |_| UseFuture { + update: cx.schedule_update(), + needs_regen: Cell::new(true), + slot: Rc::new(Cell::new(None)), + value: None, + task: None, + pending: true, }); if let Some(value) = state.slot.take() { @@ -24,6 +35,7 @@ pub fn use_future<'a, T: 'static, F: Future + 'static>( if state.needs_regen.get() { // We don't need regen anymore state.needs_regen.set(false); + state.pending = false; // Create the new future let fut = new_fut(); @@ -42,10 +54,17 @@ pub fn use_future<'a, T: 'static, F: Future + 'static>( state } +pub enum FutureState<'a, T> { + Pending, + Complete(&'a T), + Regenerating(&'a T), // the old value +} + pub struct UseFuture { update: Rc, needs_regen: Cell, value: Option, + pending: bool, slot: Rc>>, task: Option, } @@ -72,4 +91,9 @@ impl UseFuture { pub fn value(&self) -> Option<&T> { self.value.as_ref() } + + pub fn state(&self) -> FutureState { + // self.value.as_ref() + FutureState::Pending + } } diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index 90fe84d04..c82dc4975 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(missing_docs)] + //! Dioxus WebSys //! //! ## Overview