Spurious motion signal in GTK4

Hi,

There is a custom widget which will create a child widget (a GtkComboBox) at the position and grab focus when you click the mouse on it. But when the child widget show up, the custom widget will receive a motion event if you register a GtkEventControllerMotion to it. Is it supposed behavior of GTK4?

Thanks

Yes. A motion event is synthesized so that enter/hover state is propagated correctly.

Even if I register the GtkEventControllerMotion as GTK_PHASE_TARGET, the click and creation of child widget still trigger exactly one motion event. I don’t understand the reason of this behavior, since the cursor is not moved at all. And hover on the child widget do not trigger motion event on the custom widget.

In fact, this motion event combined with the click event will trigger a drag gesture which is weird behavior.

I write a simple test case with Rust. Since the original code base is a 10k LOC big custom widget. The code is really simple for illustration the issue. And I find that this behavior is not related to the cursor position, but to the child creation itself. You will get the motion event even your cursor is not above the location of the created child.

use glib::clone;
use gtk::gdk;
use gtk::glib;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::EventControllerMotionBuilder;
use gtk::GestureClickBuilder;
use gtk::LabelBuilder;
use gtk::PropagationPhase;

// Object holding the state
#[derive(Default)]
pub struct CustomWidget;

// The central trait for subclassing a GObject
#[glib::object_subclass]
impl ObjectSubclass for CustomWidget {
    const NAME: &'static str = "MyCustomWidget";
    type Type = super::CustomWidget;
    type ParentType = gtk::Widget;
}

// Trait shared by all GObjects
impl ObjectImpl for CustomWidget {
    fn constructed(&self, obj: &Self::Type) {
        let gesture_click = GestureClickBuilder::new()
            .button(gdk::BUTTON_PRIMARY)
            .build();
        gesture_click.connect_pressed(clone!(@strong obj => move |_, n_press, x, y| {
            if let None = obj.first_child() {
                let label = LabelBuilder::new().label("Hello World!").build();
                label.set_parent(&obj);
            }
        }));
        let motion = EventControllerMotionBuilder::new()
            .propagation_phase(PropagationPhase::Target)
            .build();
        motion.connect_motion(move |_, x, y| {
            println!("motion {} {}", x, y);
        });

        obj.add_controller(&gesture_click);
        obj.add_controller(&motion);
    }
}

// Trait shared by all widgets
impl WidgetImpl for CustomWidget {
    fn size_allocate(&self, widget: &Self::Type, width: i32, height: i32, baseline: i32) {
        if let Some (child) = widget.first_child() {
            let allocation = gtk::Allocation {
                x: 10, y: 10, width: 100, height: 100,
            };
            child.size_allocate(&allocation, baseline);
        }
    }
}

Here is the log:

motion 98 93
motion 97 93
motion 97 92.5

(testgtk4:31165): Gtk-WARNING **: 10:58:29.836: Allocating size to GtkLabel 0x55b80d669760 without calling gtk_widget_measure(). How does the code know the size to allocate?
motion 97 92.5

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