Trying to use a GestureMultiPress; Having issues keeping it alive due to scope

Hi all,

As the title says, I’m trying to use a GestureMultiPress to capture mouse input. However, I’ve found Rust deallocates it once the scope it lives in ends.

My default approach to fix this would be to add a return argument mut reference to the function, but the function signature is fixed because it’s used in a call to connect_activate.

If instead I make a function which takes a return argument, and returns a closure, it either won’t let me mutate, because it’s a Fn (no mutation of captured vars allowed), or I make in an FnMut, which would allow mutation, but then it’s the incorrect type to be given to connect_activate.

That all said, I’m stuck. How am I supposed to keep the gesture alive here?

Here’s the original code; uncomment the Rc leak if you want to see the GestureMultiPress activate properly.

use std::rc::Rc;
use std::mem;

use gtk::gdk::EventMask;
use gtk::prelude::*;
use gtk::{DrawingArea, GestureMultiPress};

const APP_NAME : &'static str = "com.example.appname";
const APP_TITLE : &'static str = "Example App";

const APP_WIDTH : i32 = 600;
const APP_HEIGHT : i32 = 600;
const APP_BORDER_WIDTH : u32 = 20;

fn build_ui<'a>(application : &'a gtk::Application) {
  let window = gtk::ApplicationWindow::new(application);

  window.set_title(APP_TITLE);
  window.set_border_width(APP_BORDER_WIDTH);
  window.set_position(gtk::WindowPosition::Center);
  window.set_default_size(APP_WIDTH, APP_HEIGHT);

  let drw_area = {
    DrawingArea::builder()
      .width_request(APP_WIDTH - 2*APP_BORDER_WIDTH as i32)
      .height_request(APP_HEIGHT - 2*APP_BORDER_WIDTH as i32)
      .build()
  };

  drw_area.connect_draw(|a, c| {
    c.set_source_rgb(0.0, 0.0, 0.0);
    c.rectangle(0.0, 0.0, a.allocated_width() as f64, a.allocated_height() as f64);
    let _ = c.fill();
    Inhibit(false)
  });
  window.add(&drw_area);

  drw_area.add_events(EventMask::BUTTON_PRESS_MASK | EventMask::BUTTON_RELEASE_MASK);
  let gmpress =
    GestureMultiPress::builder()
      .widget(&drw_area)
      .button(0)
      .build();
  gmpress.connect_pressed(|g, npress, x, y| {
    println!("({}, {npress}, {x}, {y})", g.current_button());
  });

  let a = Rc::new(gmpress);
  // mem::forget(a.clone());

  window.show_all();
}

fn main() {
  let application =
    gtk::Application::new(Some(APP_NAME), Default::default());

  application.connect_activate(build_ui);
  application.run();
}

Ah, worked out how to do it using the basic_subclass example in the repository.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.