1

I want to update a cairo drawing inside a DrawingArea. I tried to achieve this by calling DrawingArea::connect_draw(...) with a new function as the parameter. My issue is that it does not replace the original drawing function, but calls both when showing the window. Here is an example

extern crate cairo;
extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;

fn main() {
    let application = gtk::Application::new(Some("com.example"), Default::default())
        .expect("Initialization failed...");

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&vec![]);
}

fn build_ui(application: &gtk::Application) {
    let window = get_window(application);
    let drawing_area = Box::new(gtk::DrawingArea::new)();

    // Set drawing function
    drawing_area.connect_draw(|_, ctx| draw(ctx, 0.5, 2.0));
    // Change drawing function
    drawing_area.connect_draw(|_, ctx| draw(ctx, 0.9, 1.0)); // <-- Why is this not working as expected?

    window.add(&drawing_area);
    window.show_all();
}

fn get_window(application: &gtk::Application) -> gtk::ApplicationWindow {
    let window = gtk::ApplicationWindow::new(application);
    window.set_default_size(500i32, 500i32);

    // Set transparency
    set_visual(&window, None);
    window.connect_screen_changed(set_visual);
    window.set_app_paintable(true);

    window
}

fn draw(ctx: &cairo::Context, param1: f64, param2: f64) -> gtk::Inhibit {
    ctx.scale(500f64, 500f64);

    ctx.set_source_rgba(1.0, 0.2, 0.2, param1);
    ctx.arc(0.5, 0.5, 0.2, 0.0, 3.1414 * param2);
    ctx.fill();

    Inhibit(false)
}

fn set_visual(window: &gtk::ApplicationWindow, _screen: Option<&gdk::Screen>) {
    if let Some(screen) = window.get_screen() {
        if let Some(ref visual) = screen.get_rgba_visual() {
            window.set_visual(Some(visual));
        }
    }
}

I expect half a circle to be shown. Yet the old, full circle is still there, even though I tried to replace connect_draw. How can I properly replace this?

Natjo
  • 2,005
  • 29
  • 75
  • The docs state that `connect_draw` is used to attach a signal handler (https://gtk-rs.org/docs/gtk/trait.WidgetExt.html#tymethod.connect_draw). It seems that you're adding a second handler, not reseting it. – Chris Pearce Oct 12 '19 at 20:21
  • I thought so, but I couldn't find any functionality to replace the handler. – Natjo Oct 12 '19 at 20:23

1 Answers1

1

Using the connect_draw function attaches another signal handler, but will not replace existing handlers. However, the function returns a SignalHandlerId which you should then be able to use to disonnect your original signal handler using the signal_handler_disconnect function (see https://gtk-rs.org/docs/glib/signal/fn.signal_handler_disconnect.html).

Chris Pearce
  • 666
  • 5
  • 16
  • Do you either have an updated link (that one is broken), or know the specifics of how to call signal_handler_disconnect? This might be the solution to a problem I'm having as well, but I don't see where or how to call that. – Edward Peters Mar 27 '22 at 02:04