Functional parity with linux
This commit is contained in:
@@ -15,8 +15,8 @@ use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
|
||||
use ruin_reactivity::effect;
|
||||
use ruin_runtime::queue_future;
|
||||
use ruin_reactivity::{current as current_reactor, effect};
|
||||
use ruin_runtime::{queue_future, spawn_worker};
|
||||
use ruin_ui::{
|
||||
Border, Color, CursorIcon, DisplayItem, Edges, Element, ElementId, HitTarget, InteractionTree,
|
||||
KeyboardEvent, KeyboardEventKind, KeyboardKey, LayoutCache, LayoutSnapshot, PlatformEvent,
|
||||
@@ -26,7 +26,7 @@ use ruin_ui::{
|
||||
layout_snapshot_with_cache,
|
||||
};
|
||||
#[cfg(target_os = "macos")]
|
||||
use ruin_ui_platform_macos::start_macos_ui;
|
||||
use ruin_ui_platform_macos::{run_macos_app_event_loop, start_macos_ui};
|
||||
#[cfg(target_os = "linux")]
|
||||
use ruin_ui_platform_wayland::start_wayland_ui;
|
||||
|
||||
@@ -98,8 +98,7 @@ impl App {
|
||||
pub fn mount<M: Mountable>(self, root: M) -> MountedApp<M> {
|
||||
MountedApp {
|
||||
window: self.window,
|
||||
root: Rc::new(root),
|
||||
render_state: Rc::new(RenderState::default()),
|
||||
root,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,19 +149,18 @@ impl Mountable for Element {
|
||||
|
||||
pub struct MountedApp<M: Mountable> {
|
||||
window: Window,
|
||||
root: Rc<M>,
|
||||
render_state: Rc<RenderState>,
|
||||
root: M,
|
||||
}
|
||||
|
||||
impl<M: Mountable> MountedApp<M> {
|
||||
pub async fn run(self) -> Result<()> {
|
||||
let MountedApp {
|
||||
window: app_window,
|
||||
root,
|
||||
render_state,
|
||||
} = self;
|
||||
|
||||
let mut ui = start_platform_ui();
|
||||
async fn run_with_ui_runtime(
|
||||
window: Window,
|
||||
root: M,
|
||||
mut ui: ruin_ui::UiRuntime,
|
||||
) -> Result<()> {
|
||||
let root = Rc::new(root);
|
||||
let render_state = Rc::new(RenderState::default());
|
||||
let app_window = window;
|
||||
let window = ui.create_window(app_window.spec.clone())?;
|
||||
let initial_viewport = app_window
|
||||
.spec
|
||||
@@ -170,6 +168,7 @@ impl<M: Mountable> MountedApp<M> {
|
||||
.unwrap_or(UiSize::new(960.0, 640.0));
|
||||
|
||||
let viewport = ruin_reactivity::cell(initial_viewport);
|
||||
let configure_serial = ruin_reactivity::cell(0_u64);
|
||||
let scene_version = StdCell::new(0_u64);
|
||||
let text_system = Rc::new(RefCell::new(TextSystem::new()));
|
||||
let layout_cache = Rc::new(RefCell::new(LayoutCache::new()));
|
||||
@@ -183,6 +182,7 @@ impl<M: Mountable> MountedApp<M> {
|
||||
let _scene_effect = effect({
|
||||
let window = window.clone();
|
||||
let viewport = viewport.clone();
|
||||
let configure_serial = configure_serial.clone();
|
||||
let text_system = Rc::clone(&text_system);
|
||||
let layout_cache = Rc::clone(&layout_cache);
|
||||
let interaction_tree = Rc::clone(&interaction_tree);
|
||||
@@ -194,6 +194,7 @@ impl<M: Mountable> MountedApp<M> {
|
||||
let text_selection = Rc::clone(&input_state.text_selection);
|
||||
move || {
|
||||
let viewport = viewport.get();
|
||||
let _ = configure_serial.get();
|
||||
let version = scene_version.get().wrapping_add(1);
|
||||
scene_version.set(version);
|
||||
let _ = text_selection.version.get();
|
||||
@@ -266,6 +267,8 @@ impl<M: Mountable> MountedApp<M> {
|
||||
"app received Configured, queuing layout effect"
|
||||
);
|
||||
let _ = viewport.set(configuration.actual_inner_size);
|
||||
configure_serial.update(|value| *value = value.wrapping_add(1));
|
||||
current_reactor().flush_now();
|
||||
}
|
||||
PlatformEvent::Pointer { window_id, event } if window_id == window.id() => {
|
||||
Self::handle_pointer_event(
|
||||
@@ -276,6 +279,7 @@ impl<M: Mountable> MountedApp<M> {
|
||||
&mut input_state,
|
||||
event,
|
||||
)?;
|
||||
current_reactor().flush_now();
|
||||
}
|
||||
PlatformEvent::Keyboard { window_id, event } if window_id == window.id() => {
|
||||
Self::handle_keyboard_event(
|
||||
@@ -285,11 +289,22 @@ impl<M: Mountable> MountedApp<M> {
|
||||
&input_state,
|
||||
event,
|
||||
)?;
|
||||
current_reactor().flush_now();
|
||||
}
|
||||
PlatformEvent::CloseRequested { window_id } if window_id == window.id() => {
|
||||
tracing::debug!(
|
||||
target: "ruin_app::lifecycle",
|
||||
?window_id,
|
||||
"app received CloseRequested, issuing open(false)"
|
||||
);
|
||||
let _ = window.update(WindowUpdate::new().open(false));
|
||||
}
|
||||
PlatformEvent::Closed { window_id } if window_id == window.id() => {
|
||||
tracing::debug!(
|
||||
target: "ruin_app::lifecycle",
|
||||
?window_id,
|
||||
"app received Closed, shutting down ui runtime"
|
||||
);
|
||||
ui.shutdown()?;
|
||||
return Ok(());
|
||||
}
|
||||
@@ -301,6 +316,14 @@ impl<M: Mountable> MountedApp<M> {
|
||||
ui.shutdown()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Mountable> MountedApp<M> {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub async fn run(self) -> Result<()> {
|
||||
let ui = start_platform_ui();
|
||||
Self::run_with_ui_runtime(self.window, self.root, ui).await
|
||||
}
|
||||
|
||||
fn handle_pointer_event(
|
||||
window: &WindowController,
|
||||
@@ -453,13 +476,46 @@ impl<M: Mountable> MountedApp<M> {
|
||||
if selection_changed {
|
||||
text_selection.version.update(|value| *value += 1);
|
||||
#[cfg(target_os = "linux")]
|
||||
sync_primary_selection(_window, interaction_tree, *text_selection.selection.borrow())?;
|
||||
sync_primary_selection(
|
||||
_window,
|
||||
interaction_tree,
|
||||
*text_selection.selection.borrow(),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
impl<M: Mountable + Send + 'static> MountedApp<M> {
|
||||
pub async fn run(self) -> Result<()> {
|
||||
let ui = start_platform_ui();
|
||||
let (done_tx, done_rx) = std::sync::mpsc::channel::<std::result::Result<(), String>>();
|
||||
let window = self.window;
|
||||
let root = self.root;
|
||||
let _worker = spawn_worker(
|
||||
move || {
|
||||
queue_future(async move {
|
||||
let result = Self::run_with_ui_runtime(window, root, ui)
|
||||
.await
|
||||
.map_err(|err| err.to_string());
|
||||
let _ = done_tx.send(result);
|
||||
});
|
||||
},
|
||||
|| {},
|
||||
);
|
||||
|
||||
run_macos_app_event_loop();
|
||||
|
||||
match done_rx.recv() {
|
||||
Ok(Ok(())) => Ok(()),
|
||||
Ok(Err(err)) => Err(err.into()),
|
||||
Err(_) => Err("ui worker terminated before completion".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct View {
|
||||
element: Element,
|
||||
@@ -1307,6 +1363,10 @@ pub fn use_effect(effect: impl Fn() + 'static) {
|
||||
with_hook_slot(|| ruin_reactivity::effect(effect), |_| ());
|
||||
}
|
||||
|
||||
pub fn flush_reactive_updates() {
|
||||
current_reactor().flush_now();
|
||||
}
|
||||
|
||||
pub fn use_window_title(compute: impl FnOnce() -> String) {
|
||||
with_render_context_state(|context| {
|
||||
context.side_effects.borrow_mut().window_title = Some(compute());
|
||||
@@ -1520,6 +1580,7 @@ where
|
||||
let result = future.await;
|
||||
if generation.get() == next_generation {
|
||||
let _ = resource.state.replace(ResourceState::Ready(result));
|
||||
current_reactor().flush_now();
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -1997,10 +2058,10 @@ pub mod prelude {
|
||||
ContextKey, FocusScope, FontWeight, IntoBorder, IntoEdges, IntoView, Key, Memo, Mountable,
|
||||
Pending, Ready, Resource, ResourceState, Result, ScrollBoxBuilder, ScrollBoxWidget,
|
||||
Shortcut, ShortcutScope, Signal, TextBuilder, TextChildren, TextRole, TextValue, View,
|
||||
WidgetRef, Window, block, button, colors, column, component, context_provider, provide,
|
||||
row, scroll_box, surfaces, text, use_context, use_effect, use_memo, use_resource,
|
||||
use_shortcut, use_shortcut_with_context, use_signal, use_widget_ref, use_window_title,
|
||||
view,
|
||||
WidgetRef, Window, block, button, colors, column, component, context_provider,
|
||||
flush_reactive_updates, provide, row, scroll_box, surfaces, text, use_context, use_effect,
|
||||
use_memo, use_resource, use_shortcut, use_shortcut_with_context, use_signal,
|
||||
use_widget_ref, use_window_title, view,
|
||||
};
|
||||
pub use ruin_ui::{
|
||||
Border, Color, CursorIcon, Edges, Element, ElementId, InteractionTree, PointerButton,
|
||||
|
||||
Reference in New Issue
Block a user