GNOME Bugzilla – Bug 727919
user data objects from GtkBuilder not passed to signal handlers
Last modified: 2018-01-10 20:42:37 UTC
Created attachment 273934 [details] user_data.glade I am attempting to use the object property of the signal interface element to pass user data to signal handlers defined in python. The object property contains the id of another object defined in the interface file. The signal handler is not being called with the user_data parameter. Attaching the interface file I am using.
Created attachment 273936 [details] test.py Running the attached Python code, clicking the button prints: TypeError: on_button_clicked() takes exactly 2 arguments (1 given)
Created attachment 273937 [details] test.c Equivalent code in C, which correctly prints "Label text: Label"
It looks like the user_data is passed as the first argument. connect_signals calls GObject.connect_object which exhibits the same behavior. This can be observed by removing the signal connection from the map and manually calling connect_object: def on_button_clicked(label): print(label.get_text()) button.connect_object('clicked', on_button_clicked, label) button = builder.get_object("button") label = builder.get_object("label") See: https://git.gnome.org/browse/pygobject/tree/gi/overrides/Gtk.py?id=3.12.0#n390 The connect_object behavior has been around since PyGTK, not sure about connect_signals with a glade file binding user_data though. But based on the connect_object behavior we can assume the entirety of PyGObject3: http://www.pygtk.org/docs/pygobject/class-gobject.html#method-gobject--connect-object Unfortunately this is most likely "won't fix" if a different behavior is desired because it would be an API break.
Created attachment 274031 [details] test.c So the problem is with connect_object? Using g_signal_connect_object still passes the object the signal is connected to as the first argument to the handler. Replacing test.c with a version that uses gtk_builder_connect_signals_full and g_signal_connect_object, and that still works as expected. I appreciate that existing code depends on the existing API, but would you consider providing a different method that provides the expected behavior when using builder signal handlers with user_data?
(In reply to comment #4) > So the problem is with connect_object? Using g_signal_connect_object still > passes the object the signal is connected to as the first argument to the > handler. Yep, the connect_object Python binding seems to work differently than the C API. I'm not sure of the historical reasoning. Also note bug 688064 shows other problems with connect_object. > I appreciate that existing code depends on the existing API, but would you > consider providing a different method that provides the expected behavior when > using builder signal handlers with user_data? New API for GObject.connect_object and Builder.connect_signals that more closely matches the C API sounds reasonable. I don't have any naming ideas beyond a '2' suffix like connect_object2... naming suggestions (and patches) welcome. Another idea would an enablement API which allows for an explicit API break, like in bug 723736. A short term workaround could be to pass the label as user_data in the signal map and remove it from user_data in the ui file: handlers = {"on_button_clicked": (on_button_clicked, builder.get_object("label")), "on_delete_event": Gtk.main_quit }
(In reply to comment #5) > New API for GObject.connect_object and Builder.connect_signals that more > closely matches the C API sounds reasonable. I don't have any naming ideas > beyond a '2' suffix like connect_object2... I hit this same issue when working out the details for GTK+ Composite Template support in bug 701843. The good news is I was able to work around it by adding a new template connection mechanism. This new mechanism could be used wholesale to fix the problem described here by explicitly a different connection scheme to Builder.connect_signals_full. The new connection mechanism is not public and named "_template_connect_callback" but this could be exposed and named more generically to something like: builder.connect_signals_full(Gtk.py_builder_connect_callbacks, self) or even: builder.connect_signals_with_ui_objects(self) I think either of the above should work out nicely, but better naming suggestions are welcome. This also brings up the point that an alternative workaround right now is to implement your own connection callback and use "connect_signals_full". Basically I think it would be as simple as (untested): def connect(builder, gobj, signal_name, handler_name, connect_obj, flags, obj): user_data = [connect_obj] if connect_obj else [] gobj.connect(signal_name, getattr(obj, handler_name), *user_data) builder.connect_signals_full(connect, self) See patches in bug 701843 for handling swap and after flags.
Adding bug 701843 as a dependency. While full template support is not required to fix this bug, at least half the patches over there are needed to fix this.
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/pygobject/issues/70.