I’m trying to prevent multiple callbacks from executing tasks triggered by the “activate” signal(s) generated by the user hitting “Enter” in the main window. It SEEMS that the “activate” signal is being re-sent, instead of being “consumed” by my callbacks.
I had inferred from GLib.idle_add() that all callbacks for signals should return False, so that the signal won’t be sent again. Then I found this post about gtk2, and it claims
If you return 1 (or TRUE) then you’re telling GTK that you have handled the event, and the signal emission chain will stop.
I found documentation for GObject.signal_emit, and Object.connect. Those pages don’t specify anything about the callback. The PyGObject tutorial generally describes the callbacks assigned with GObject.commit() but does not mention the callback’s return value.
So how can I stop the signal emission chain, and consume signals?
Current readers may be interested that the (Free versions of) the AIs Gemini, ChatGPT, Claude, and CoPilot give very different answers from each other.
My first prompt was
In Python bindings for gtk4, should “activate” signals from Widget callbacks return True to indicate that the signal has been handled and to stop propagation of the signal?
Only Gemini 2.5 Flash claims that an “activate” callback can return True to stop the signal from propagating.
I changed the prompt to
In Python bindings for gtk4, can “activate” signal callbacks connected to Widgets return True to indicate that the signal has been handled and to stop propagation of the signal?
For this prompt, Gemini 2.5 pro claimed The short answer is: Yes, absolutely. while Copilot Deep Research responded with an overly-long report (12 pages!?) containing the paragraph:
GTK4’s default for “activate”: For almost all widgets and in the majority of GTK’s built-in activate implementations, the signal’s accumulator is not set to g_signal_accumulator_true_handled, and the return type is void or ignored. Therefore, the return value has no effect—it doesn’t halt propagation. This means all connected handlers are always run, and emitting “activate” is more like a “notification” or “invocation” rather than a filterable event.
Hilariously, the bots used the question in this original post above as references for their opposing answers!
If you want to know if a callback has a return value, you read the documentation; for instance: GLib.idle_add.
I really don’t understand what you’re trying to achieve, but stopping the behaviour of a default signal handler is, generally speaking, an indication of some misunderstanding on your side.
Let’s back up a bit: what are you trying to achieve, here?
Also: stop asking bots/LLMs. They have no idea what they are doing, and they haven’t been trained on anything even remotely recent. You’re just getting random hallucinations.
Currently, my app has a big “Capture” button in the center of the window, a simple menu, and a keyboard shortcut, all of which are connected to a “Start” action. That worked well, until I added a “Search for barcode” Gtk.SearchEntry, which has the default focus. It is not connected to the Start action. The real fun is that the user normally has a barcode scanner. And when the device scans a barcode, it automatically sends an “Enter” as well.
Currently, both the Start action and the “activate” signal from the SearchEntry are triggered. I added logic in the Start action that says “If the SearchEntry widget text contains a valid barcode, then return without continuing.” But it seems that after my barcode handler is finished, the Start action then gets the “activate” signal again.
This is why I think my barcode callback is not consuming the signal, First, my callback returned None, now it returns False. But I get the undesired behavior each time. Now I suspect that I will need to abandon the Start action and listen for mouse events. That was not my preference.
The book is face-down facing a camera. The Barcode is on the back of the book. Normally, the user scans the back of the book, to get the barcode. If there’s no barcode, or the barcode is not valid, The user can click the “Capture” button or use the keyboard shortcut to start Optical Character Recognition of the text on the cover. The workflow should not require the user to enable or disable the scanner or the button, it should be implicit depending upon what the user did.