Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to upstream winit #679

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
15259ed
in progress
dzhou121 Nov 8, 2024
40b25e7
in progress
dzhou121 Nov 9, 2024
8a2a2ce
in progress
dzhou121 Nov 9, 2024
2b2d3a7
in progress
dzhou121 Nov 11, 2024
298741b
in progress
dzhou121 Nov 12, 2024
474d8cb
rebase
dzhou121 Nov 28, 2024
4758683
Merge branch 'main' into upstream_winit
dzhou121 Dec 9, 2024
da24afe
fix touchpad
dzhou121 Dec 19, 2024
4c3eb36
Merge branch 'main' into upstream_winit
dzhou121 Dec 19, 2024
febc1c3
Fix build for iOS
maun Dec 29, 2024
7318354
Merge pull request #717 from maun/ios
dzhou121 Jan 2, 2025
6ed93a0
Merge branch 'main' into upstream_winit
dzhou121 Jan 2, 2025
f523067
fix context menu
dzhou121 Jan 2, 2025
32bc320
muda only for windows and macos
dzhou121 Jan 2, 2025
fa68a85
update menu
dzhou121 Jan 2, 2025
1bfdbe7
fix linux show_context_menu
dzhou121 Jan 2, 2025
5412e14
menu action fix
dzhou121 Jan 3, 2025
d27dc1b
clippy
dzhou121 Jan 3, 2025
2fae54c
Merge branch 'main' into upstream_winit
dzhou121 Jan 3, 2025
970a7d3
revert 'static
dzhou121 Jan 3, 2025
379b8b5
update
dzhou121 Jan 3, 2025
56833a3
update
dzhou121 Jan 3, 2025
85e6ada
fix wasm
dzhou121 Jan 3, 2025
268655c
update
dzhou121 Jan 3, 2025
05fe1b7
clippy
dzhou121 Jan 3, 2025
4827c14
update
dzhou121 Jan 3, 2025
f1cb5eb
update
dzhou121 Jan 3, 2025
78938cb
update
dzhou121 Jan 3, 2025
d8b97bf
update
dzhou121 Jan 3, 2025
4d20098
svg str function
dzhou121 Jan 4, 2025
7752993
make app update event back to original
dzhou121 Jan 5, 2025
cad3534
revert capture in arc to rc
dzhou121 Jan 5, 2025
519c6dd
more revert from arc to rc
dzhou121 Jan 5, 2025
8ffb11f
change pointer-events to be in style
dzhou121 Jan 6, 2025
9f45def
cleanup
dzhou121 Jan 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ raw-window-handle = "0.6.0"
wgpu = { version = "22.0.0" }
parking_lot = { version = "0.12.1" }
swash = { version = "0.1.17" }
muda = { version = "0.15.3" }
winit = { git = "https://github.com/rust-windowing/winit", rev = "5ea81efc74ebaa04a7cb4621ec522bce14d700e5" }

[dependencies]
slotmap = "1.0.7"
Expand Down Expand Up @@ -69,7 +71,6 @@ floem_vello_renderer = { path = "vello", version = "0.2.0", optional = true }
floem_vger_renderer = { path = "vger", version = "0.2.0", optional = true }
floem_tiny_skia_renderer = { path = "tiny_skia", version = "0.2.0" }
floem_reactive = { path = "reactive", version = "0.2.0" }
floem-winit = { version = "0.29.5", features = ["rwh_05"] }
floem-editor-core = { path = "editor-core", version = "0.2.0", optional = true }
copypasta = { version = "0.10.0", default-features = false, features = [
"wayland",
Expand All @@ -79,9 +80,13 @@ parking_lot = { workspace = true }
image = { workspace = true }
im = { workspace = true }
wgpu = { workspace = true }
winit = { workspace = true }
futures = { version = "0.3.30", optional = true }
crossbeam = "0.8"

[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
muda = { workspace = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen-futures = { version = "0.4" }
web-time = "1"
Expand All @@ -97,7 +102,7 @@ vger = ["dep:floem_vger_renderer"]

serde = [
"dep:serde",
"floem-winit/serde",
"winit/serde",
"peniko/serde",
"lapce-xi-rope/serde",
"smallvec/serde",
Expand Down
7 changes: 6 additions & 1 deletion reactive/src/derived.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ use crate::{read::SignalTrack, RwSignal, SignalGet, SignalUpdate, SignalWith};
/// This is useful when you want a single state variable and don't want to use effects to synchronize multiple signals.
///
/// This is also useful when you want a derived signal that implements the [SignalGet], [SignalWith], etc. traits.
pub struct DerivedRwSignal<T, O, GF: Fn(&T) -> O + Clone + 'static, UF: Fn(&O) -> T + 'static> {
pub struct DerivedRwSignal<
T: 'static,
O,
GF: Fn(&T) -> O + Clone + 'static,
UF: Fn(&O) -> T + 'static,
> {
signal: RwSignal<T>,
getter: RwSignal<Box<GF>>,
setter: RwSignal<Box<UF>>,
Expand Down
13 changes: 3 additions & 10 deletions reactive/src/id.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
use std::{marker::PhantomData, sync::atomic::AtomicU64};
use std::sync::atomic::AtomicU64;

use crate::{effect::observer_clean_up, runtime::RUNTIME, signal::Signal};

/// Marker type explaining why something can't be sent across threads
#[allow(dead_code)]
struct NotThreadSafe(*const ());

/// An internal id which can reference a Signal/Effect/Scope.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Hash)]
pub struct Id(u64, PhantomData<NotThreadSafe>);
pub struct Id(u64);

impl Id {
/// Create a new Id that's next in order
pub(crate) fn next() -> Id {
static COUNTER: AtomicU64 = AtomicU64::new(0);
Id(
COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
PhantomData,
)
Id(COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
}

/// Try to get the Signal that links with this Id
Expand Down
2 changes: 1 addition & 1 deletion renderer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ resvg = { workspace = true }
swash = { workspace = true }

cosmic-text = { version = "0.12.1", features = ["shape-run-cache"] }
floem-winit = { version = "0.29.5", features = ["rwh_05"] }

winit = { workspace = true }
wgpu = { workspace = true }
crossbeam = { version = "0.8" }
futures = "0.3.26"
Expand Down
4 changes: 2 additions & 2 deletions renderer/src/gpu_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::{future::Future, sync::Arc};
use crossbeam::channel::{self, Receiver};
use wgpu::Backends;

use floem_winit::window::{Window, WindowId};
use winit::window::{Window, WindowId};

/// The acquired GPU resources needed for rendering with wgpu.
pub struct GpuResources {
Expand Down Expand Up @@ -45,7 +45,7 @@ impl GpuResources {
/// - `window`: The window to associate with the created surface.
pub fn request<F: Fn(WindowId) + 'static>(
on_result: F,
window: Arc<Window>,
window: Arc<dyn Window>,
) -> Receiver<Result<Self, GpuResourceError>> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::util::backend_bits_from_env().unwrap_or(Backends::all()),
Expand Down
2 changes: 1 addition & 1 deletion src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
use std::sync::atomic::AtomicU64;

use floem_reactive::SignalWith;
use floem_winit::window::ResizeDirection;
use peniko::kurbo::{Point, Size, Vec2};
use winit::window::ResizeDirection;

#[cfg(not(target_arch = "wasm32"))]
use std::time::{Duration, Instant};
Expand Down
161 changes: 85 additions & 76 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
use std::{cell::RefCell, rc::Rc};

use crossbeam_channel::{Receiver, Sender};
use floem_reactive::WriteSignal;
use floem_winit::{
event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy},
monitor::MonitorHandle,
use parking_lot::Mutex;
use raw_window_handle::HasDisplayHandle;
use winit::{
application::ApplicationHandler,
event::WindowEvent,
event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy},
window::WindowId,
};
use parking_lot::Mutex;
#[allow(deprecated)]
use raw_window_handle::HasRawDisplayHandle;

use crate::{
action::{Timer, TimerToken},
app_handle::ApplicationHandle,
clipboard::Clipboard,
inspector::Capture,
profiler::Profile,
view::{IntoView, View},
window::WindowConfig,
view::IntoView,
window::{WindowConfig, WindowCreation},
};

type AppEventCallback = dyn Fn(AppEvent);

static EVENT_LOOP_PROXY: Mutex<Option<EventLoopProxy<UserEvent>>> = Mutex::new(None);
static EVENT_LOOP_PROXY: Mutex<Option<(EventLoopProxy, Sender<UserEvent>)>> = Mutex::new(None);

thread_local! {
pub(crate) static APP_UPDATE_EVENTS: RefCell<Vec<AppUpdateEvent>> = Default::default();
Expand All @@ -49,7 +50,6 @@ pub enum AppEvent {
Reopen { has_visible_windows: bool },
}

#[derive(Debug)]
pub(crate) enum UserEvent {
AppUpdate,
Idle,
Expand All @@ -59,8 +59,7 @@ pub(crate) enum UserEvent {

pub(crate) enum AppUpdateEvent {
NewWindow {
view_fn: Box<dyn FnOnce(WindowId) -> Box<dyn View>>,
config: Option<WindowConfig>,
window_creation: WindowCreation,
},
CloseWindow {
window_id: WindowId,
Expand All @@ -79,28 +78,26 @@ pub(crate) enum AppUpdateEvent {
CancelTimer {
timer: TimerToken,
},
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
MenuAction {
window_id: WindowId,
action_id: usize,
action_id: String,
},
}

pub(crate) fn add_app_update_event(event: AppUpdateEvent) {
APP_UPDATE_EVENTS.with(|events| {
events.borrow_mut().push(event);
});
Application::with_event_loop_proxy(|proxy| {
let _ = proxy.send_event(UserEvent::AppUpdate);
});
Application::send_proxy_event(UserEvent::AppUpdate);
}

/// Floem top level application
/// This is the entry point of the application.
pub struct Application {
handle: Option<ApplicationHandle>,
receiver: Receiver<UserEvent>,
handle: ApplicationHandle,
event_listener: Option<Box<AppEventCallback>>,
event_loop: EventLoop<UserEvent>,
event_loop: Option<EventLoop>,
initial_windows: Vec<WindowCreation>,
}

impl Default for Application {
Expand All @@ -109,22 +106,71 @@ impl Default for Application {
}
}

impl ApplicationHandler for Application {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
while let Some(window_creation) = self.initial_windows.pop() {
self.handle.new_window(
event_loop,
window_creation.view_fn,
window_creation.config.unwrap_or_default(),
);
}
}

fn window_event(
&mut self,
event_loop: &dyn ActiveEventLoop,
window_id: WindowId,
event: WindowEvent,
) {
self.handle.handle_timer(event_loop);
self.handle
.handle_window_event(window_id, event, event_loop);
}

fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
self.handle.handle_timer(event_loop);
for event in self.receiver.try_iter() {
self.handle.handle_user_event(event_loop, event);
}
self.handle.handle_updates_for_all_windows();
}

fn exiting(&mut self, _event_loop: &dyn ActiveEventLoop) {
if let Some(action) = self.event_listener.as_ref() {
action(AppEvent::WillTerminate);
}
}

fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
self.handle.handle_timer(event_loop);
}
}

impl Application {
pub fn new() -> Self {
let event_loop = EventLoopBuilder::with_user_event()
.build()
.expect("can't start the event loop");
let event_loop = EventLoop::new().expect("can't start the event loop");
let event_loop_proxy = event_loop.create_proxy();
*EVENT_LOOP_PROXY.lock() = Some(event_loop_proxy.clone());
let (sender, receiver) = crossbeam_channel::unbounded();
*EVENT_LOOP_PROXY.lock() = Some((event_loop_proxy.clone(), sender));
unsafe {
#[allow(deprecated)]
Clipboard::init(event_loop.raw_display_handle().unwrap());
Clipboard::init(event_loop.display_handle().unwrap().as_raw());
}
let handle = ApplicationHandle::new();

#[cfg(any(target_os = "windows", target_os = "macos"))]
muda::MenuEvent::set_event_handler(Some(move |event: muda::MenuEvent| {
add_app_update_event(AppUpdateEvent::MenuAction {
action_id: event.id.0,
});
}));

Self {
handle: Some(handle),
receiver,
handle,
event_listener: None,
event_loop,
event_loop: Some(event_loop),
initial_windows: Vec::new(),
}
}

Expand All @@ -145,67 +191,30 @@ impl Application {
app_view: impl FnOnce(WindowId) -> V + 'static,
config: Option<WindowConfig>,
) -> Self {
self.handle.as_mut().unwrap().new_window(
&self.event_loop,
self.event_loop.create_proxy(),
Box::new(|window_id| app_view(window_id).into_any()),
config.unwrap_or_default(),
);
self.initial_windows.push(WindowCreation {
view_fn: Box::new(move |window_id: WindowId| app_view(window_id).into_any()),
config,
});
self
}

pub fn run(mut self) {
let mut handle = self.handle.take().unwrap();
handle.idle();
let event_loop_proxy = self.event_loop.create_proxy();
let _ = self.event_loop.run(|event, event_loop| {
event_loop.set_control_flow(ControlFlow::Wait);
handle.handle_timer(event_loop);

match event {
floem_winit::event::Event::NewEvents(_) => {}
floem_winit::event::Event::WindowEvent { window_id, event } => {
handle.handle_window_event(window_id, event, event_loop);
}
floem_winit::event::Event::DeviceEvent { .. } => {}
floem_winit::event::Event::UserEvent(event) => {
handle.handle_user_event(event_loop, event_loop_proxy.clone(), event);
}
floem_winit::event::Event::Suspended => {}
floem_winit::event::Event::Resumed => {}
floem_winit::event::Event::AboutToWait => {}
floem_winit::event::Event::LoopExiting => {
if let Some(action) = self.event_listener.as_ref() {
action(AppEvent::WillTerminate);
}
}
floem_winit::event::Event::MemoryWarning => {}
floem_winit::event::Event::Reopen => {}
}
});
let event_loop = self.event_loop.take().unwrap();
let _ = event_loop.run_app(self);
}

pub(crate) fn with_event_loop_proxy(f: impl FnOnce(&EventLoopProxy<UserEvent>)) {
if let Some(proxy) = EVENT_LOOP_PROXY.lock().as_ref() {
f(proxy);
pub(crate) fn send_proxy_event(event: UserEvent) {
if let Some((proxy, sender)) = EVENT_LOOP_PROXY.lock().as_ref() {
let _ = sender.send(event);
proxy.wake_up();
}
}

pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
self.event_loop.available_monitors()
}

pub fn primary_monitor(&self) -> Option<MonitorHandle> {
self.event_loop.primary_monitor()
}
}

/// Initiates the application shutdown process.
///
/// This function sends a `QuitApp` event to the application's event loop,
/// triggering the application to close gracefully.
pub fn quit_app() {
Application::with_event_loop_proxy(|proxy| {
let _ = proxy.send_event(UserEvent::QuitApp);
});
Application::send_proxy_event(UserEvent::QuitApp);
}
Loading
Loading