Skip to content
This repository has been archived by the owner on Jun 8, 2021. It is now read-only.

Commit

Permalink
Port cairo_threads example to use the new GLib MainContext channel in…
Browse files Browse the repository at this point in the history
…stead of polling

This ensures that the image is redrawn only if it actually changed and
more or less immediately after it has changed instead of waiting up to
100ms.
  • Loading branch information
sdroege committed Jan 25, 2019
1 parent d9a808d commit 5bc6b5b
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 17 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Expand Up @@ -60,6 +60,7 @@ name = "cairo_png"

[[bin]]
name = "cairo_threads"
required-features = ["glib/v2_36"]

[[bin]]
name = "cairotest"
Expand Down Expand Up @@ -134,3 +135,6 @@ name = "treeview"
[[bin]]
name = "status_icon"
required-features = ["gio_2_40"]

[patch."https://github.com/gtk-rs/glib"]
glib = { path = "../glib" }
32 changes: 15 additions & 17 deletions src/bin/cairo_threads.rs
Expand Up @@ -121,10 +121,10 @@ impl Image {
// The GUI thread holds an image per image part at all times and these images are painted on a
// DrawingArea in its 'draw' signal handler whenever needed.
//
// Additionally the GUI thread checks periodically every 100ms if any worker has sent a freshly
// rendered image. If there is a new image, the old image stored by the GUI thread is replaced with
// the new one and the old image is sent back to the worker thread. Then the appropriate part of
// the DrawingArea is invalidated prompting a redraw.
// Additionally the GUI thread has a channel for receiving the images from the worker threads. If
// there is a new image, the old image stored by the GUI thread is replaced with the new one and
// the old image is sent back to the worker thread. Then the appropriate part of the DrawingArea is
// invalidated prompting a redraw.
//
// The two images per thread are allocated and initialized once and sent back and forth repeatedly.

Expand All @@ -139,7 +139,8 @@ fn build_ui(application: &gtk::Application) {
let initial_image = draw_initial();

// This is the channel for sending results from the worker thread to the main thread
let (ready_tx, ready_rx) = mpsc::channel();
// For every received image, queue the corresponding part of the DrawingArea for redrawing
let (ready_tx, ready_rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);

let mut images = Vec::new();
let mut origins = Vec::new();
Expand Down Expand Up @@ -215,20 +216,17 @@ fn build_ui(application: &gtk::Application) {
Inhibit(false)
}));

// Check every 100ms if there are new images from any worker threads and if so queue the
// corresponding part of the DrawingArea for redrawing
gtk::timeout_add(100, move || {
while let Ok((thread_num, image)) = ready_rx.try_recv() {
let (ref images, ref origins, ref workers) = &*workspace;
ready_rx.attach(None, move |(thread_num, image)| {
let (ref images, ref origins, ref workers) = &*workspace;

// Swap the newly received image with the old stored one and send the old one back to
// the worker thread
let tx = &workers[thread_num];
let image = images[thread_num].replace(image);
let _ = tx.send(image);
// Swap the newly received image with the old stored one and send the old one back to
// the worker thread
let tx = &workers[thread_num];
let image = images[thread_num].replace(image);
let _ = tx.send(image);

area.queue_draw_area(origins[thread_num].0, origins[thread_num].1, WIDTH, HEIGHT);

area.queue_draw_area(origins[thread_num].0, origins[thread_num].1, WIDTH, HEIGHT);
}
Continue(true)
});

Expand Down

0 comments on commit 5bc6b5b

Please sign in to comment.