Button press event propagation

In my GTK4 project, I attached a GtkGestureLongPress to a box and added a button into another child widget of this box. Now, when I (short) click the button, it also activates the long press handler of the parent widget’s parent.

The following code demonstrates the problem:

import sys

import gi

gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')

from gi.repository import Adw, Gtk

class MyWindow(Gtk.Window):
    def __init__(self, *args, **kwargs):
        super().__init__(title="Gesture Example", *args, **kwargs)
        self.set_default_size(400, 300)

        self.main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
        self.set_child(self.main_box)

        long_press = Gtk.GestureLongPress.new()
        long_press.connect("pressed", self.on_long_press)
        self.main_box.add_controller(long_press)

        middle_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
        self.main_box.append(middle_box)

        inner_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
        middle_box.append(inner_box)

        self.button = Gtk.Button(label="Click Me")
        self.button.connect("clicked", self.on_button_pressed)
        inner_box.append(self.button)

    def on_button_pressed(self, *args, **kwargs):
        print("Button clicked!")
        return True

    def on_long_press(self, gesture, x, y):
        print("Long press on main box!")


class MyApp(Adw.Application):
    def __init__(self, **kwargs):
        super().__init__(**kwargs, application_id="org.example.App")

    def do_activate(self):
        win = MyWindow(application=self)
        win.present()

app = MyApp()
app.run(sys.argv)

Even though on_button_pressed returns True, the signal is still propagated upwards. How can this be avoided in GTK4?

I have read the input handling documentation, but it doesn’t seem to address this specific problem.

Funny. Solved it myself right after I posted this! :rofl:

The secret is to attach a gesture click to the button and set the event state of the gesture click to Gtk.EventSequenceState.CLAIMED:

    def __init__(self, *args, **kwargs):
        super().__init__(title="Gesture Example", *args, **kwargs)

        # ...

        self.button = Gtk.Button(label="Click Me")
        gesture_click = Gtk.GestureClick.new()
        gesture_click.connect("pressed", self.on_button_pressed)
        self.button.add_controller(gesture_click)

    def on_button_pressed(self, click: Gtk.GestureClick, *args, **kwargs):
        print("Button clicked!")
        click.set_state(Gtk.EventSequenceState.CLAIMED)
2 Likes