Search code examples
rustgtk

Why is this GestureMultiPress not registering my presses?


I'm making a small app using gtk-rs (GTK+ 3), and I can't get it to register my mouse clicks.

I have a DrawingArea, and I want to run some code every time there's a mouse click in that DrawingArea. My understanding is that I can use a GestureMultiPress to do this. (I am aware events can also do this, but my understanding is that the multi-press gesture can do this too, and I had the impression that they (Gestures) are the more modern style.)

Here's how I set up the GestureMultiPress code:

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

  ...

I was expecting this to print the mouse coords when I clicked/released in the drawing area, and not print when I clicked/released in the app border. However, it's not printing at all.

What am I missing / doing wrong here?

Full Code:

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(application : &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);

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

fn main() {
  let application =
    gtk::Application::new(Some(APP_NAME), Default::default());
  application.connect_activate(build_ui);
  application.run();
}

Solution

  • I have worked out the problem.

    At the end of the scope, Rust deallocates the GestureMultiPress because it isn't referenced anywhere.

    You can tell this by leaking a reference to it so that Rust doesn't deallocate it at the end of the scope.

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

    I'm not sure how to actually keep the gesture around properly, given it's allocated inside a function with a fixed signature, so I can't pass things out; but that's a different question.