From 1e162ed8df4470522d6dbfb1567b54df74ba911f Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Thu, 21 Dec 2023 14:17:35 -0800 Subject: [PATCH] AsApplication + impl Application for App --- CHANGELOG.md | 9 +++++++ src/lib.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/window.rs | 22 ++++++++++------ 3 files changed, 93 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9b6000..bc12e1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - This crate's default features now include `wayland-csd-adwaita`. This enables winit's built-in decoration drawing on Wayland. +### Fixed + +- `App` now implements `Application`. + +### Added + +- `AsApplication` is a new trait that can be implemented to resolve to the `App` + type. This allows wrapper types to be written that hide the appit types. + ## v0.1.1 (2023-12-18) ### Fixed diff --git a/src/lib.rs b/src/lib.rs index ae562b9..746ed6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -174,6 +174,27 @@ where fn send(&mut self, message: AppMessage) -> Option; } +/// A type that contains a reference to an [`Application`] implementor. +pub trait AsApplication { + /// Returns this type's application. + fn as_application(&self) -> &dyn Application + where + AppMessage: Message; +} + +impl AsApplication for T +where + T: Application, + AppMessage: Message, +{ + fn as_application(&self) -> &dyn Application + where + AppMessage: Message, + { + self + } +} + /// A message with an associated response type. pub trait Message: Send + 'static { /// The message type that is able to be sent to individual windows. @@ -216,6 +237,52 @@ where } } +impl Application for App +where + AppMessage: Message, +{ + fn app(&self) -> App { + self.clone() + } + + fn send(&mut self, message: AppMessage) -> Option<::Response> { + let (response_sender, response_receiver) = mpsc::sync_channel(1); + self.proxy + .send_event(EventLoopMessage::User { + message, + response_sender, + }) + .ok()?; + response_receiver.recv().ok() + } +} + +impl private::ApplicationSealed for App +where + AppMessage: Message, +{ + fn open( + &self, + attrs: WindowAttributes, + sender: mpsc::SyncSender>, + ) -> Result>, OsError> { + let (open_sender, open_receiver) = mpsc::sync_channel(1); + if self + .proxy + .send_event(EventLoopMessage::OpenWindow { + attrs, + sender, + open_sender, + }) + .is_err() + { + return Ok(None); + } + + open_receiver.recv().map_or(Ok(None), |opt| opt.map(Some)) + } +} + /// A collection of open windows. pub struct Windows { data: Arc>>>, @@ -282,8 +349,9 @@ impl Windows { } #[cfg(target_os = "windows")] { - builder = - winit::platform::windows::WindowBuilderExtWindows::with_class_name(builder, app_name); + builder = winit::platform::windows::WindowBuilderExtWindows::with_class_name( + builder, app_name, + ); } } diff --git a/src/window.rs b/src/window.rs index bafed13..dd7b37b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -16,7 +16,9 @@ use winit::keyboard::PhysicalKey; use winit::window::{Fullscreen, Icon, Theme, WindowButtons, WindowId, WindowLevel}; use crate::private::{self, WindowEvent}; -use crate::{App, Application, EventLoopMessage, Message, PendingApp, WindowMessage, Windows}; +use crate::{ + App, Application, AsApplication, EventLoopMessage, Message, PendingApp, WindowMessage, Windows, +}; /// A weak reference to a running window. #[derive(Debug, Clone)] @@ -175,7 +177,7 @@ impl Default for WindowAttributes { impl<'a, Behavior, Application, AppMessage> WindowBuilder<'a, Behavior, Application, AppMessage> where Behavior: self::WindowBehavior, - Application: crate::Application, + Application: crate::AsApplication, AppMessage: Message, { pub(crate) fn new(owner: &'a Application, context: Behavior::Context) -> Self { @@ -202,7 +204,11 @@ where // a fixed-size channel and be cautious to not block the main event loop // by always using try_send. let (sender, receiver) = mpsc::sync_channel(65536); - let Some(winit) = self.owner.open(self.attributes, sender.clone())? else { + let Some(winit) = self + .owner + .as_application() + .open(self.attributes, sender.clone())? + else { return Ok(None); }; let window = Window { @@ -212,7 +218,7 @@ where let running_window = RunningWindow { messages: (sender, receiver), responses: mpsc::sync_channel(1), - app: self.owner.app(), + app: self.owner.as_application().app(), occluded: winit.is_visible().unwrap_or(false), focused: winit.has_focus(), inner_size: winit.inner_size(), @@ -761,7 +767,7 @@ where /// initialized, a default [`Context`](Self::Context) will be passed. fn build(app: &App) -> WindowBuilder<'_, Self, App, AppMessage> where - App: Application, + App: AsApplication, Self::Context: Default, { Self::build_with(app, ::default()) @@ -774,7 +780,7 @@ where context: Self::Context, ) -> WindowBuilder<'_, Self, App, AppMessage> where - App: Application, + App: AsApplication, { WindowBuilder::new(app, context) } @@ -840,7 +846,7 @@ where /// [`winit::window::WindowBuilder::build`]. fn open(app: &App) -> Result>, OsError> where - App: Application, + App: AsApplication, Self::Context: Default, { Self::build(app).open() @@ -861,7 +867,7 @@ where context: Self::Context, ) -> Result>, OsError> where - App: Application, + App: AsApplication, { Self::build_with(app, context).open() }