AsApplication + impl Application for App

This commit is contained in:
Jonathan Johnson 2023-12-21 14:17:35 -08:00
parent a10c250683
commit 1e162ed8df
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
3 changed files with 93 additions and 10 deletions

View file

@ -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

View file

@ -174,6 +174,27 @@ where
fn send(&mut self, message: AppMessage) -> Option<AppMessage::Response>;
}
/// A type that contains a reference to an [`Application`] implementor.
pub trait AsApplication<AppMessage> {
/// Returns this type's application.
fn as_application(&self) -> &dyn Application<AppMessage>
where
AppMessage: Message;
}
impl<T, AppMessage> AsApplication<AppMessage> for T
where
T: Application<AppMessage>,
AppMessage: Message,
{
fn as_application(&self) -> &dyn Application<AppMessage>
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<AppMessage> Application<AppMessage> for App<AppMessage>
where
AppMessage: Message,
{
fn app(&self) -> App<AppMessage> {
self.clone()
}
fn send(&mut self, message: AppMessage) -> Option<<AppMessage as Message>::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<AppMessage> private::ApplicationSealed<AppMessage> for App<AppMessage>
where
AppMessage: Message,
{
fn open(
&self,
attrs: WindowAttributes,
sender: mpsc::SyncSender<WindowMessage<AppMessage::Window>>,
) -> Result<Option<Arc<winit::window::Window>>, 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<Message> {
data: Arc<Mutex<HashMap<WindowId, OpenWindow<Message>>>>,
@ -282,8 +349,9 @@ impl<Message> Windows<Message> {
}
#[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,
);
}
}

View file

@ -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<AppMessage>,
Application: crate::Application<AppMessage>,
Application: crate::AsApplication<AppMessage>,
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: &App) -> WindowBuilder<'_, Self, App, AppMessage>
where
App: Application<AppMessage>,
App: AsApplication<AppMessage>,
Self::Context: Default,
{
Self::build_with(app, <Self::Context as Default>::default())
@ -774,7 +780,7 @@ where
context: Self::Context,
) -> WindowBuilder<'_, Self, App, AppMessage>
where
App: Application<AppMessage>,
App: AsApplication<AppMessage>,
{
WindowBuilder::new(app, context)
}
@ -840,7 +846,7 @@ where
/// [`winit::window::WindowBuilder::build`].
fn open<App>(app: &App) -> Result<Option<Window<AppMessage::Window>>, OsError>
where
App: Application<AppMessage>,
App: AsApplication<AppMessage>,
Self::Context: Default,
{
Self::build(app).open()
@ -861,7 +867,7 @@ where
context: Self::Context,
) -> Result<Option<Window<AppMessage::Window>>, OsError>
where
App: Application<AppMessage>,
App: AsApplication<AppMessage>,
{
Self::build_with(app, context).open()
}