Skip to content

Commit ad8a81c

Browse files
Only produce animation frames when requested
Restore the FTXUI 6 behavior: animation frames are produced only when requested via animation::RequestAnimationFrame(), typically by an animation::Animator which arms it on construction and re-arms it from OnAnimation until the transition completes. Handling an event no longer implicitly grants an animation tick. That behavior was introduced accidentally by the v7 event loop rework (33a40ee) and is what made the #1302 feedback loop possible in the first place: internal terminal replies are events too.
1 parent 77c9a59 commit ad8a81c

3 files changed

Lines changed: 24 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ Next
88
- Bugfix: Fix high CPU usage (app and terminal emulator, e.g. tmux) caused by a
99
cursor position request/reply feedback loop redrawing the screen at ~60fps in
1010
the non-alternate-screen modes. See #1302.
11-
- Request the animation frame when an event is handled instead of when it is
12-
received. All internal terminal replies (not only cursor position reports)
13-
stop triggering animation frames.
11+
- Animation frames are now produced only when requested via
12+
`animation::RequestAnimationFrame()` (e.g. by `animation::Animator`), as in
13+
FTXUI 6. Receiving an event no longer implicitly triggers an animation
14+
frame.
1415

1516
### Dom
1617
- Performance: `text` computes its requirement once and renders only the

src/ftxui/component/animation_test.cpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ class AnimationCounter : public ComponentBase {
5252
private:
5353
Element OnRender() override { return text(""); }
5454
void OnAnimation(animation::Params& /*params*/) override { count++; }
55+
bool OnEvent(Event event) override {
56+
if (event == Event::Character('a')) {
57+
animation::RequestAnimationFrame();
58+
return true;
59+
}
60+
return false;
61+
}
5562
};
5663

5764
// Give the recurring AnimationTask (reposted every 15ms) time to become due,
@@ -63,31 +70,34 @@ void RunAnimationTask(Loop& loop) {
6370

6471
} // namespace
6572

66-
// OnAnimation must tick once per handled event, and not tick for the
67-
// terminal's replies to FTXUI's own internal requests. See #1302.
68-
TEST(AnimationTest, EventRequestsAnimationFrame) {
73+
// OnAnimation must tick only when a frame was requested with
74+
// animation::RequestAnimationFrame(), typically by an Animator. In particular,
75+
// handling an event must not implicitly produce a tick: internal terminal
76+
// replies are events too, and animating on them caused the #1302 feedback
77+
// loop.
78+
TEST(AnimationTest, TicksOnlyWhenRequested) {
6979
auto component = Make<AnimationCounter>();
7080
auto screen = App::FixedSize(10, 1);
7181
Loop loop(&screen, component);
7282
loop.RunOnce();
7383

74-
// No event: the recurring AnimationTask is a no-op.
84+
// No request: the recurring AnimationTask is a no-op.
7585
RunAnimationTask(loop);
7686
EXPECT_EQ(component->count, 0);
7787

78-
// A handled event grants exactly one animation tick.
88+
// An event alone doesn't produce a tick.
7989
screen.PostEvent(Event::Custom);
8090
loop.RunOnce();
8191
RunAnimationTask(loop);
82-
EXPECT_EQ(component->count, 1);
83-
RunAnimationTask(loop);
84-
EXPECT_EQ(component->count, 1);
92+
EXPECT_EQ(component->count, 0);
8593

86-
// An internal terminal reply must not grant one.
87-
screen.PostEvent(Event::CursorPosition("", 1, 1));
94+
// A component requesting a frame gets exactly one tick.
95+
screen.PostEvent(Event::Character('a'));
8896
loop.RunOnce();
8997
RunAnimationTask(loop);
9098
EXPECT_EQ(component->count, 1);
99+
RunAnimationTask(loop);
100+
EXPECT_EQ(component->count, 1);
91101
}
92102

93103
} // namespace ftxui

src/ftxui/component/app.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -918,13 +918,6 @@ void App::Internal::HandleTask(Component component, Task& task) {
918918
#endif
919919

920920
frame_valid_ = false;
921-
922-
// Give animated components one tick in response to the event. This must
923-
// stay below the early-returns above: requesting a frame for the
924-
// terminal's replies to our own requests creates a redraw -> request ->
925-
// reply -> redraw feedback loop.
926-
// See https://github.com/ArthurSonzogni/FTXUI/issues/1302.
927-
public_->RequestAnimationFrame();
928921
return;
929922
}
930923

0 commit comments

Comments
 (0)