1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use super::*;
use crate::platform::PlatformError;
pub trait WindowHandler: 'static {
/// Requests the handler to draw a new frame immediately.
///
/// In order to reduce resource usage, this method is not called systematically at every frame
/// interval.
/// However, this method is automatically scheduled to be called in several situations:
///
/// * When the window is first opened and shown to the user;
/// * When the window is shown after being previously hidden (if the platform did not keep the window's content in memory);
/// * When the window is resized;
/// * When the platform explicitly requests a window redraw (such as redrawing what was previously obscured by another window).
///
/// In those situations, the [`draw`] call will be preceded by a [`damage`] call, specifying which
/// parts of the window need to be redrawn.
///
/// This method can also be scheduled to be called from a call to [`WindowContext::request_redraw`],
/// as a result of [polling] or any kind of event. In this case, no [`damage`] call will occur.
///
/// If this method itself calls [`WindowContext::request_redraw`], then a redraw will be
/// scheduled for the next frame interval.
/// This is useful for handling animations that need to run for successive frames in order to look smooth.
///
/// Platforms may wait until this method completes before performing operations, such as
/// presenting the parent window or updating window decorations.
///
/// Therefore, implementations should perform and complete all drawing inside this method
/// (or return an error), in order to minimize rendering artifacts.
///
/// # Errors
///
/// If this returns an error, the window will be considered unable to render its contents, and
/// will be subsequently closed.
///
/// [`draw`]: WindowHandler::draw
/// [`damage`]: WindowHandler::damage
/// [polling]: WindowHandler::poll
fn draw(&self) -> Result<(), HandlerError>;
/// Notifies the handler that a given [`area`] of the window has been damaged by the platform
/// and needs to be redrawn.
///
/// This is useful for renderers that support partial rendering, in order to not have to redraw
/// every single pixel on every frame.
///
/// For instance, this will occur on non-compositing window managers (such as on X11), when
/// another window that initially obscured this one gets moved away.
///
/// Additionally, this method will also be automatically called in the following situations:
/// * When the window is first opened and shown to the user;
/// * When the window is shown after being previously hidden (if the platform did not keep the window's content in memory);
/// * When the window is resized;
///
/// Note that `baseview` only tracks and notifies about "external" (i.e. platform-originating) damage.
/// This method will *not* be called for "internal" damage, e.g. if moving the mouse over a button should redraw it.
/// Implementations should track this kind of damage internally (most GUI frameworks already do).
///
/// Also note that depending on the platform, this method may be called multiple times with
/// different damage areas during a single frame interval.
/// Implementations should coalesce all the damaged areas received until the next [`draw`] call.
///
/// Implementing this method is optional, as it's only useful if the handler supports partial rendering.
/// The default implementation of this method does nothing.
///
/// [`area`]: DamageArea
/// [`draw`]: WindowHandler::draw
fn damage(&self, area: DamageArea) {
let _ = area;
}
/// Requests the handler to poll updates from external sources, in preparation for rendering a new frame.
///
/// This is useful when UIs need to check periodically on some sources (such as channels, queues, shared values, etc.)
/// to figure if they need updating.
///
/// If received updates must result in the window updating its contents, then this method should
/// call [`WindowContext::request_redraw`].
///
/// Implementing this method is optional, and not needed if the window does not need to update itself
/// from external events. The default implementation for this method does nothing.
///
/// # External update logic
///
/// The goal is for all external update logic to be contained within this method.
/// Therefore, this method will be called in various cases, including (but not limited to):
///
/// * As a result of calling [`Window::request_poll`] or [`WindowWaker::request_poll`], at the platform's earliest convenience;
/// * Whenever a new frame has been scheduled, right before actually calling [`WindowHandler::draw`].
///
/// This all means that this method will be invoked very regularly, possibly multiple times per frame interval.
/// Implementations should do their best to not block and finish their work as quick as possible.
fn poll(&self) {}
/// Informs the handler that the window has been resized.
///
/// # Errors
///
/// This operation can fail, in which case an [`HandlerError`] can be returned.
/// This can happen if e.g. an underlying buffer could not be resized, or some kind of driver error.
///
/// In case this `resized` operation fails, `baseview` will assume that it did not meaningfully
/// change anything, and that the window is still able to render and operate at the previous size.
///
/// It will also attempt to resize the underlying platform window and parent window back to the
/// previous size, but this is only a best-effort attempt since those operations can also fail.
fn resized(&self, new_size: WindowSize) -> Result<(), HandlerError>;
fn on_event(&self, event: Event) -> EventStatus;
}
type DynBuilderResult = Result<Box<dyn WindowHandler>, HandlerError>;
pub struct WindowHandlerBuilder {
inner: Box<dyn FnOnce(WindowContext) -> DynBuilderResult + Send + 'static>,
}
impl WindowHandlerBuilder {
pub fn new<H: WindowHandler>(
f: impl FnOnce(WindowContext) -> Result<H, HandlerError> + Send + 'static,
) -> WindowHandlerBuilder {
Self { inner: Box::new(|c| Ok(Box::new(f(c)?))) }
}
pub fn build(self, ctx: WindowContext) -> Result<Box<dyn WindowHandler>, PlatformError> {
match (self.inner)(ctx) {
Ok(handle) => Ok(handle),
Err(e) => Err(PlatformError::Handler(e)),
}
}
}