emilk / emilk/egui

Animation with request_repaint() does not work when deferred viewport is open

Open
#4,945 2 comments 1 reaction 0 assignees View on GitHub
bug viewports
Dominant language
Rust
Stars
30.6k
Forks
2.1k
Avg merge
1d 9h
Merged PRs (30d)
72

Description

**Describe the bug**
When multiple viewports are open, animations using request_repaint() work only on the active viewport, and requests to update other viewports are ignored.

**To Reproduce**
I have created a minimal demonstration, which is included below. Compile and run. See how animation works only on window that is clicked.
Replace show_viewport_deferred() on line 41 to show_viewport_immediate() to see expected behaviour.

**Expected behavior**
Animation to work identically in both windows.

**Demonstration**
```rust
use egui::{Color32, Painter, Shape, Ui, ViewportId};

fn main() -> eframe::Result {
let native_options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_position([0.0, 0.0])
.with_inner_size([500.0, 500.0]),
..Default::default()
};
return eframe::run_native(
"My egui App",
native_options,
Box::new(|_cc| Ok(Box::new(MyApp::default()))),
);
}

#[derive(Default)]
pub struct MyApp {
}

impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
paint_animation(ui);
second_viewport(ui);
request_updates(ui);
});
}
}

pub fn second_viewport(ui: &mut egui::Ui) -> ViewportId {
let title = "second viewport";
let id: ViewportId = ViewportId::from_hash_of(title);

ui.ctx().show_viewport_deferred(
id.clone(),
egui::ViewportBuilder::default()
.with_title(title)
.with_position([510.0, 0.0])
.with_inner_size([500.0, 500.0]),
move |ctx, _class| {
egui::CentralPanel::default().show(ctx, |ui| {
paint_animation(ui);
request_updates(ui);
});
},
);

id
}

pub fn paint_animation(ui: &mut Ui) {
let painter = Painter::new(
ui.ctx().clone(),
ui.layer_id(),
ui.available_rect_before_wrap(),
);

let step = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.subsec_millis()
/ 5;

painter.add(Shape::circle_filled(
[100.0 + step as f32, 100.0 + step as f32].into(),
100.0,
Color32::RED,
));
// Make sure we allocate what we used (everything)
ui.expand_to_include_rect(painter.clip_rect());
}

fn request_updates(ui: &mut Ui) {
let mut ids: Vec = Vec::new();
ui.ctx().input(|i| {
ids = i.raw.viewports.keys().cloned().collect();
});
for id in ids {
ui.ctx().request_repaint_of(id);
};
}

```

Contributor guide

Open the contributing guide

Research direction

Start by running the supplied Rust reproduction and compare show_viewport_deferred() with show_viewport_immediate(). Trace request_repaint_of() for each ViewportId and how deferred viewports are handled. Done means animations update identically in both windows when repaint requests are sent to all viewports.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop-dev, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.