Fix timer requests in update and lifecycle.#964
Conversation
cmyr
left a comment
There was a problem hiding this comment.
Overall this looks totally reasonable, but I'm curious about processing events after anim_frame. In particular, I don't think we should be sending any events between anim_frame and paint?
|
|
||
| /// Makes the scrollbars visible, and resets the fade timer. | ||
| pub fn reset_scrollbar_fade(&mut self, ctx: &mut EventCtx, env: &Env) { | ||
| pub fn reset_scrollbar_fade<F>(&mut self, request_timer: F, env: &Env) |
There was a problem hiding this comment.
Yea, this is annoying.
Something I've been wondering is whether we could have certain traits for behaviour that is common to (most?) contexts, and then for things like requesting a timer or sending a command you could have the argument be ctx: &mut dyn ContextCommon or something...
There was a problem hiding this comment.
Yeap, I was thinking of the same thing based on the amount of code duplication we have in context.rs. Then having to do this request_timer closure here really boosted that thinking. I have it in my notes to attempt to better the situation with traits. (Would be a separate PR.)
There was a problem hiding this comment.
I am accidentally working on this right now.
| K: Eq + Hash + Copy, | ||
| V: Copy, | ||
| { | ||
| fn extend_drain(&mut self, source: &mut Self) { |
There was a problem hiding this comment.
just an observation: this is the kind of thing I'm always curious to profile, or at least take a look at the asm; always room for funny surprises. I certainly suspect its an improvement, but it is a suspicion, it's not impossible the compiler generating code like this as an optimization already.
There was a problem hiding this comment.
There was a funny surprise alright. The empty target case is 0ns with this optimized function, which is a win. However unexpectedly even the slow path is faster! The slow path is faster only with drain though. If I bench extending with just iter vs iter, then the slow paths are equal. Some sort of non-generic code win I guess.
druid/src/window.rs
Outdated
| self.last_anim = Some(now); | ||
| } | ||
|
|
||
| self.post_event_processing(&mut base_state, queue, data, env, process_commands); |
There was a problem hiding this comment.
Is there a specific reason we think this is necessary? do_anim_frame is part of paint, and paint calls this already.
There was a problem hiding this comment.
- It's necessary because a widget might call
submit_commandorrequest_timerin response toAnimFrame. do_anim_frameis currently part oflifecyclenotpaintand so even ifpaintcalledpost_event_processingthat wouldn't be guaranteed for otherAnimFramecalls tolifecycle.paintdoesn't callpost_event_processing.AnimFramedoes not guaranteepaintin the future as discussed on zulip.
There was a problem hiding this comment.
in order:
-
to my mind,
AnimFrameshould only be used to update state in preparation for an imminent paint call. This is a weird case;AnimFrameis one of the bits of event flow that is really a poor fit to the current architecture, and when (like.... a year ago? 😬) I was playing around with a higher-level animation API, one of the changes was to just make aprepare_for_animationmethod onWidgetthat replacedAnimFrame.submit_commandandrequest_timershould be discouraged here, and it's annoying that this isn't enforced by the type system. -
do_anim_framesort of is part of paint;LifeCycle::AnimFrameshould only be sent fromWindow::do_paint, if it happens anywhere else that's a mistake. -
this checks out, I must've misread again. That said, it looks like we call
post_event_processingin Window::lifecycle, which is what callsdo_anim_frame`? -
I think this is false? it's not really that anim guarantees
paint, it's thatAnimFrameis only called from the painting code path.
There was a problem hiding this comment.
-
Yes we do call
post_event_processinginWindow::lifecycleright now, which means it also applies todo_anim_frame. However due to borrow checking limitations, in order to keep that functionality, I had to add it todo_anim_framebecause theWindow::lifecyclecall moved into anifblock. -
Yeah right now
AnimFrameis sent just beforepaint. However based on that zulip discussion this may change. @raphlinus said It's up to the handler of that lifecycle event to request painting - from which I derive that if the handler doesn't request painting, the painting might not happen at all. (This is for future behavior, today that's not true.)
More generally, moving AnimFrame out of lifecycle makes sense if it's supposed to have different limitations. However as long as it's part of lifecycle I think it should behave like a lifecycle event. That includes a working request_timer and submit_command.
There was a problem hiding this comment.
On the second point: I think there's a confusion about raph's comments. AnimFrame does mean you're going to paint; there's no short-circuiting. If you see it, it means a call to paint is next. To continue the animation, you do need to request another frame.
I'll take a look at the code you're talking about, I might've missed that.
druid/src/window.rs
Outdated
| }; | ||
|
|
||
| self.root.lifecycle(&mut ctx, event, data, env); | ||
| self.post_event_processing(&mut base_state, queue, data, env, process_commands); |
There was a problem hiding this comment.
we can move this out of the if branch if we move the base_state decl to above the block, this should solve our other little confusion?
cmyr
left a comment
There was a problem hiding this comment.
looks good. I'm wondering if, for future work, we can actually just get rid of do_anin_frame at some point? it just seems like more confusion than its worth maybe.
This PR fixes the handling of timer requests. Previously they were only collected in the window's
eventbut I moved the collection to the general post processing step. I also removed the legacyrequest_timerboolwhich no longer served a purpose and was never being reset.This also finally allowed to address #834. Scrollbars now briefly animate when the container is resized. This can be seen with e.g. the
scroll_colorsexample when you resize the window.Fixes #834.