How can I create the ready_callback_closure? The GObject.Closure constructors new_object and new_simple seem specific to C (require to give the size of the struct…) so I can’t see any way to pass my user data…
Setting the struct member directly doesn’t work either:
>>> c = GObject.Closure()
>>> c.data = "foobar"
ValueError: Pointer arguments are restricted to integers, capsules, and None. See: https://bugzilla.gnome.org/show_bug.cgi?id=683599
Thanks, but my actual problem was about passing user data to the callbacks.
Something like this is not possible anymore:
def ready_cb(file, res, user_data):
print(user_data) # should print "my user data"
...
file1.copy_async(file2, Gio.FileCopyFlags.OVERWRITE, GLib.PRIORITY_DEFAULT, None, None, ready_cb, "my user data")
I just figured out I can use a lambda instead:
def ready_cb(file, res, user_data):
print(user_data) # should print "my user data"
...
file1.copy_async(file2, Gio.FileCopyFlags.OVERWRITE, GLib.PRIORITY_DEFAULT, None, None, lambda *args: ready_cb(*args, "my user data"))
but that’s less convenient, and doesn’t match the usual user-data passing used by other async APIs.
Instead of remapping the copy_async to copy_async_with_closures (which is an API break for language bindings), I think it would have been wiser to add a new copy_async_with_progress, just like copy_async but with the missing progress destroy notification, and map it for the bindings.
Then add a documentation warning to copy_async mentioning it’s only suitable in C when the progress callback is not used, otherwise copy_async_with_progress should be preferred.
The g_file_copy_async() function is not bindable—as it shares the same user data argument across callbacks—so it cannot be used by language bindings. For that specific reason, g_file_copy_async_with_closures() was added to the C API, and it was marked to shadow g_file_copy_async() inside the introspection binary data that bindings like PyGObject use; since its introduction, Gio.File.copy_async() resolves to g_file_copy_async_with_closures(), and there’s nothing that PyGObject can do. It’s not an API break, so to speak, because Gio.File.copy_async() could not work in the past.
If you want to make the progress function optional, you’ll need an override inside PyGObject that shuffles around the arguments, something like:
def something():
string = "my user data"
def ready_cb(file, res):
file.copy_finish(res)
print(string) # => my user data
file1.copy_async(file2, Gio.FileCopyFlags.OVERWRITE, GLib.PRIORITY_DEFAULT, None, None, ready_cb)
That’s how capturing variables always works in Python. Nothing GObject- or GClosure-specific about it.
What you might be saying is that for non-GClosure callbacks PyGObject also lets you pass a callback and an argument to it explicitly. IMO that’s a C-ism, and it’s always intended that in languages that have language-level support for closures, you’d use closures. But I can also see how that could be handy, and also indeed that creates an inconsistency between plain callbacks and GClosure.