Skip to content

Commit e419ad1

Browse files
committed
wip: animations via frame event
1 parent 4bc6ff9 commit e419ad1

4 files changed

Lines changed: 163 additions & 40 deletions

File tree

examples/sctk_todos/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
publish = false
77

88
[dependencies]
9-
iced = { path = "../..", default-features=false, features = ["async-std", "wayland", "debug", "image"] }
9+
iced = { path = "../..", default-features=false, features = ["async-std", "wayland", "debug", "a11y"] }
1010
serde = { version = "1.0", features = ["derive"] }
1111
serde_json = "1.0"
1212
once_cell = "1.15"
@@ -29,3 +29,5 @@ assets = [
2929
["target/release-opt/todos", "usr/bin/iced-todos", "755"],
3030
["iced-todos.desktop", "usr/share/applications/", "644"],
3131
]
32+
[profile.release-opt]
33+
debug = true

examples/todos/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
publish = false
77

88
[dependencies]
9-
iced = { path = "../..", features = ["async-std", "debug"] }
9+
iced = { path = "../..", features = ["async-std", "debug", "a11y"] }
1010
serde = { version = "1.0", features = ["derive"] }
1111
serde_json = "1.0"
1212
once_cell = "1.15"

runtime/src/window.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,9 @@ use crate::futures::subscription::{self, Subscription};
1919
/// animations without missing any frames.
2020
pub fn frames() -> Subscription<(Id, Instant)> {
2121
subscription::raw_events(|event, _status| match event {
22-
iced_core::Event::Window(id, Event::RedrawRequested(at))
23-
| iced_core::Event::PlatformSpecific(
24-
iced_core::event::PlatformSpecific::Wayland(
25-
iced_core::event::wayland::Event::Frame(at, _, id),
26-
),
27-
) => Some((id, at)),
22+
iced_core::Event::Window(id, Event::RedrawRequested(at)) => {
23+
Some((id, at))
24+
}
2825
_ => None,
2926
})
3027
}

sctk/src/application.rs

Lines changed: 156 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ use crate::{
55
commands::{layer_surface::get_layer_surface, window::get_window},
66
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
77
error::{self, Error},
8-
event_loop::{control_flow::ControlFlow, proxy, SctkEventLoop},
8+
event_loop::{
9+
control_flow::ControlFlow, proxy, state::SctkState, SctkEventLoop,
10+
},
911
sctk_event::{
1012
DataSourceEvent, IcedSctkEvent, KeyboardEventVariant,
11-
LayerSurfaceEventVariant, PopupEventVariant, SctkEvent,
13+
LayerSurfaceEventVariant, PopupEventVariant, SctkEvent, StartCause,
1214
},
1315
settings,
1416
};
@@ -40,7 +42,7 @@ use iced_futures::{
4042
use tracing::error;
4143

4244
use sctk::{
43-
reexports::client::{protocol::wl_surface::WlSurface, Proxy},
45+
reexports::client::{protocol::wl_surface::WlSurface, Proxy, QueueHandle},
4446
seat::{keyboard::Modifiers, pointer::PointerEventKind},
4547
};
4648
use std::{collections::HashMap, ffi::c_void, hash::Hash, marker::PhantomData};
@@ -251,6 +253,7 @@ where
251253

252254
// let (display, context, config, surface) = init_egl(&wl_surface, 100, 100);
253255
let backend = event_loop.state.connection.backend();
256+
let qh = event_loop.state.queue_handle.clone();
254257
let wrapper = SurfaceDisplayWrapper::<C> {
255258
comp_surface: None,
256259
backend: backend.clone(),
@@ -266,6 +269,7 @@ where
266269
let surface_ids = Default::default();
267270

268271
let (mut sender, receiver) = mpsc::unbounded::<IcedSctkEvent<A::Message>>();
272+
let (control_sender, mut control_receiver) = mpsc::unbounded();
269273

270274
let compositor_surfaces = HashMap::new();
271275
let mut instance = Box::pin(run_instance::<A, E, C>(
@@ -276,6 +280,7 @@ where
276280
ev_proxy,
277281
debug,
278282
receiver,
283+
control_sender,
279284
compositor_surfaces,
280285
surface_ids,
281286
auto_size_surfaces,
@@ -285,6 +290,7 @@ where
285290
backend,
286291
init_command,
287292
exit_on_close_request,
293+
qh,
288294
));
289295

290296
let mut context = task::Context::from_waker(task::noop_waker_ref());
@@ -294,12 +300,18 @@ where
294300
return;
295301
}
296302

297-
sender.start_send(event).expect("Send event");
303+
sender.start_send(event).expect("Failed to send event");
298304

299305
let poll = instance.as_mut().poll(&mut context);
300306

301307
*control_flow = match poll {
302-
task::Poll::Pending => ControlFlow::Wait,
308+
task::Poll::Pending => {
309+
if let Ok(Some(flow)) = control_receiver.try_next() {
310+
flow
311+
} else {
312+
ControlFlow::Wait
313+
}
314+
}
303315
task::Poll::Ready(_) => ControlFlow::ExitWithCode(1),
304316
};
305317
});
@@ -326,12 +338,14 @@ async fn run_instance<A, E, C>(
326338
mut ev_proxy: proxy::Proxy<Event<A::Message>>,
327339
mut debug: Debug,
328340
mut receiver: mpsc::UnboundedReceiver<IcedSctkEvent<A::Message>>,
341+
mut control_sender: mpsc::UnboundedSender<ControlFlow>,
329342
mut compositor_surfaces: HashMap<SurfaceId, SurfaceDisplayWrapper<C>>,
330343
mut surface_ids: HashMap<ObjectId, SurfaceIdWrapper>,
331344
mut auto_size_surfaces: HashMap<SurfaceIdWrapper, (u32, u32, Limits, bool)>,
332345
backend: wayland_backend::client::Backend,
333346
init_command: Command<A::Message>,
334347
_exit_on_close_request: bool, // TODO Ashley
348+
queue_handle: QueueHandle<SctkState<<A as Program>::Message>>,
335349
) -> Result<(), Error>
336350
where
337351
A: Application + 'static,
@@ -381,6 +395,8 @@ where
381395
let mut messages: Vec<A::Message> = Vec::new();
382396
#[cfg(feature = "a11y")]
383397
let mut commands: Vec<Command<A::Message>> = Vec::new();
398+
let mut redraw_pending = false;
399+
384400
debug.startup_finished();
385401

386402
// let mut current_context_window = init_id_inner;
@@ -393,7 +409,14 @@ where
393409

394410
'main: while let Some(event) = receiver.next().await {
395411
match event {
396-
IcedSctkEvent::NewEvents(_) => {} // TODO Ashley: Seems to be ignored in iced_winit so i'll ignore for now
412+
IcedSctkEvent::NewEvents(start_cause) => {
413+
redraw_pending = matches!(
414+
start_cause,
415+
StartCause::Init
416+
| StartCause::Poll
417+
| StartCause::ResumeTimeReached { .. }
418+
);
419+
}
397420
IcedSctkEvent::UserEvent(message) => {
398421
messages.push(message);
399422
}
@@ -679,9 +702,10 @@ where
679702
}
680703
SctkEvent::Frame(surface) => {
681704
if let Some(id) = surface_ids.get(&surface.id()) {
682-
runtime.broadcast(CoreEvent::PlatformSpecific(
683-
PlatformSpecific::Wayland(WaylandEvent::Frame(Instant::now(), surface, id.inner()))
684-
), Status::Ignored);
705+
if let Some(state) = states.get_mut(&id.inner()) {
706+
// TODO set this to the callback?
707+
state.set_frame(Some(surface));
708+
}
685709
}
686710
},
687711
SctkEvent::ScaleFactorChanged { .. } => {}
@@ -873,16 +897,18 @@ where
873897
break 'main;
874898
}
875899
} else {
876-
// TODO ensure that the surface_ids are
877-
let mut needs_redraw = false;
878900
for (object_id, surface_id) in &surface_ids {
879901
if matches!(surface_id, SurfaceIdWrapper::Dnd(_)) {
880902
continue;
881903
}
904+
let state = match states.get_mut(&surface_id.inner()) {
905+
Some(s) => s,
906+
None => continue,
907+
};
882908
let mut filtered_sctk =
883909
Vec::with_capacity(sctk_events.len());
884-
885910
let mut i = 0;
911+
886912
while i < sctk_events.len() {
887913
let has_kbd_focus =
888914
kbd_surface_id.as_ref() == Some(object_id);
@@ -897,12 +923,7 @@ where
897923
}
898924
}
899925
let has_events = !sctk_events.is_empty();
900-
901-
let cursor_position =
902-
match states.get(&surface_id.inner()) {
903-
Some(s) => s.cursor(),
904-
None => continue,
905-
};
926+
let cursor_position = state.cursor();
906927
debug.event_processing_started();
907928
#[allow(unused_mut)]
908929
let mut native_events: Vec<_> = filtered_sctk
@@ -966,11 +987,6 @@ where
966987
auto_size_surfaces.remove(surface_id)
967988
{
968989
if dirty {
969-
let state =
970-
match states.get_mut(&surface_id.inner()) {
971-
Some(s) => s,
972-
None => continue,
973-
};
974990
state.set_logical_size(w as f64, h as f64);
975991
match surface_id {
976992
SurfaceIdWrapper::Window(id) => {
@@ -990,22 +1006,18 @@ where
9901006
}
9911007

9921008
// TODO ASHLEY if event is a configure which isn't a new size and has no other changes, don't redraw
993-
if has_events
1009+
if redraw_pending
1010+
|| has_events
9941011
|| !messages.is_empty()
9951012
|| matches!(
9961013
interface_state,
9971014
user_interface::State::Outdated
9981015
)
9991016
{
1000-
needs_redraw = true;
1001-
ev_proxy.send_event(Event::SctkEvent(
1002-
IcedSctkEvent::RedrawRequested(
1003-
object_id.clone(),
1004-
),
1005-
));
1017+
state.set_needs_redraw(true);
10061018
}
10071019
}
1008-
if needs_redraw {
1020+
if states.iter().any(|(_, s)| s.needs_redraw) {
10091021
let mut pure_states: HashMap<_, _> =
10101022
ManuallyDrop::into_inner(interfaces)
10111023
.drain()
@@ -1017,7 +1029,13 @@ where
10171029
for surface_id in surface_ids.values() {
10181030
let state =
10191031
match states.get_mut(&surface_id.inner()) {
1020-
Some(s) => s,
1032+
Some(s) => {
1033+
if !s.needs_redraw() {
1034+
continue;
1035+
} else {
1036+
s
1037+
}
1038+
}
10211039
None => continue,
10221040
};
10231041
let mut cache =
@@ -1058,6 +1076,84 @@ where
10581076
&mut auto_size_surfaces,
10591077
&mut ev_proxy,
10601078
));
1079+
1080+
for (object_id, surface_id) in &surface_ids {
1081+
let state = match states
1082+
.get_mut(&surface_id.inner())
1083+
{
1084+
Some(s) => {
1085+
if !s.needs_redraw() || s.frame().is_none()
1086+
{
1087+
continue;
1088+
} else {
1089+
s
1090+
}
1091+
}
1092+
None => continue,
1093+
};
1094+
let Some(user_interface) = interfaces
1095+
.get_mut(&surface_id.inner()) else {
1096+
continue;
1097+
};
1098+
let redraw_event = CoreEvent::Window(
1099+
surface_id.inner(),
1100+
crate::core::window::Event::RedrawRequested(
1101+
Instant::now(),
1102+
),
1103+
);
1104+
1105+
let (interface_state, _) = user_interface.update(
1106+
&[redraw_event.clone()],
1107+
state.cursor(),
1108+
&mut renderer,
1109+
&mut simple_clipboard,
1110+
&mut messages,
1111+
);
1112+
1113+
debug.draw_started();
1114+
let new_mouse_interaction = user_interface.draw(
1115+
&mut renderer,
1116+
state.theme(),
1117+
&Style {
1118+
text_color: state.text_color(),
1119+
},
1120+
state.cursor(),
1121+
);
1122+
debug.draw_finished();
1123+
1124+
if new_mouse_interaction != mouse_interaction {
1125+
mouse_interaction = new_mouse_interaction;
1126+
ev_proxy.send_event(Event::SetCursor(
1127+
mouse_interaction,
1128+
));
1129+
}
1130+
1131+
runtime.broadcast(redraw_event, Status::Ignored);
1132+
1133+
ev_proxy.send_event(Event::SctkEvent(
1134+
IcedSctkEvent::RedrawRequested(
1135+
object_id.clone(),
1136+
),
1137+
));
1138+
1139+
let _ =
1140+
control_sender
1141+
.start_send(match interface_state {
1142+
user_interface::State::Updated {
1143+
redraw_request: Some(redraw_request),
1144+
} => match redraw_request {
1145+
crate::core::window::RedrawRequest::NextFrame => {
1146+
ControlFlow::Poll
1147+
}
1148+
crate::core::window::RedrawRequest::At(at) => {
1149+
ControlFlow::WaitUntil(at)
1150+
}
1151+
},
1152+
_ => ControlFlow::Wait,
1153+
});
1154+
state.set_needs_redraw(false);
1155+
redraw_pending = false;
1156+
}
10611157
}
10621158
}
10631159
sctk_events.clear();
@@ -1079,6 +1175,14 @@ where
10791175
let state = states.get_mut(&id.inner());
10801176
Some((*id, surface, interface, state))
10811177
}) {
1178+
// request a new frame
1179+
// NOTE Ashley: this is done here only after a redraw
1180+
// to prevent more events from being produced after repeatedly requesting redraws
1181+
if let Some(surface) = state.frame.take() {
1182+
surface.frame(&queue_handle, surface.clone());
1183+
surface.commit();
1184+
}
1185+
10821186
debug.render_started();
10831187
#[cfg(feature = "a11y")]
10841188
if let Some(Some(adapter)) = a11y_enabled
@@ -1387,6 +1491,8 @@ where
13871491
theme: <A::Renderer as Renderer>::Theme,
13881492
appearance: application::Appearance,
13891493
application: PhantomData<A>,
1494+
frame: Option<WlSurface>,
1495+
needs_redraw: bool,
13901496
}
13911497

13921498
impl<A: Application> State<A>
@@ -1414,9 +1520,27 @@ where
14141520
theme,
14151521
appearance,
14161522
application: PhantomData,
1523+
frame: None,
1524+
needs_redraw: false,
14171525
}
14181526
}
14191527

1528+
pub(crate) fn set_needs_redraw(&mut self, needs_redraw: bool) {
1529+
self.needs_redraw = needs_redraw;
1530+
}
1531+
1532+
pub(crate) fn needs_redraw(&self) -> bool {
1533+
self.needs_redraw
1534+
}
1535+
1536+
pub(crate) fn set_frame(&mut self, frame: Option<WlSurface>) {
1537+
self.frame = frame;
1538+
}
1539+
1540+
pub(crate) fn frame(&self) -> Option<&WlSurface> {
1541+
self.frame.as_ref()
1542+
}
1543+
14201544
/// Returns the current [`Viewport`] of the [`State`].
14211545
pub fn viewport(&self) -> &Viewport {
14221546
&self.viewport

0 commit comments

Comments
 (0)