Generated code expects incorrect type for Gio::AsyncReadyCallback
wildeyedskies opened this issue · 5 comments
If you try to compile this branch of my project, you will get the following error.
https://gitlab.gnome.org/wildeyedskies/wince/-/tree/fix-geoclue-init
In lib/gi-crystal/src/auto/geoclue-2.0/simple.cr:264:76
264 | LibGeoclue.gclue_simple_new(desktop_id, accuracy_level, cancellable, callback, user_data)
^-------
Error: argument 'callback' of 'LibGeoclue#gclue_simple_new' must be Pointer(Void), not Proc((GObject::Object | Nil), Gio::AsyncResult, Nil)
This results from the generated code function requiring a Gio::AsyncReadyCallback, but the C call expects a pointer for the callback.
However, if you change the C call to instead take the pointer of the proc, you get a error, so I'm not entirely sure what's going on here.
However, if you change the C call to instead take the pointer of the proc, you get a error, so I'm not entirely sure what's going on here.
Here is the explanation why your attempt to fix didn't work.
Here is the explanation why your attempt to fix didn't work.
I don't think boxing is the reason for this. The signature for Gio.AsyncReadyCallback is actually not a Pointer(Void)
, so I'm pretty sure the libgen isn't working correctly.
I ran into this while trying to use Gio.Task which generates mismatched bindings between LibGio
and Gio
.
lib LIbGio
# generates the alias, but doesn't use it.
alias AsyncReadyCallback = Pointer(LibGObject::Object), Pointer(LibGio::AsyncResult), Pointer(Void) -> Void
fun g_task_new(source_object : Pointer(Void), cancellable : Pointer(Void), callback : Void*, callback_data : Pointer(Void)) : Pointer(Void)
end
module Gio
def self.new(source_object : GObject::Object?, cancellable : Gio::Cancellable?, callback : Gio::AsyncReadyCallback?, callback_data : Pointer(Void)?) : self
# g_task_new: (Constructor)
# @source_object: (nullable)
# @cancellable: (nullable)
# @callback: (nullable)
# @callback_data: (nullable)
# Returns: (transfer full)
# Generator::NullableArrayPlan
source_object = if source_object.nil?
Pointer(Void).null
else
source_object.to_unsafe
end
# Generator::NullableArrayPlan
cancellable = if cancellable.nil?
Pointer(Void).null
else
cancellable.to_unsafe
end
# Generator::NullableArrayPlan
callback_data = if callback_data.nil?
Pointer(Void).null
else
callback_data.to_unsafe
end
# C call
_retval = LibGio.g_task_new(source_object, cancellable, callback, callback_data)
# Return value handling
Gio::Task.new(_retval, GICrystal::Transfer::Full)
end
end
There's also a clear problem with trying to call #to_unsafe
on a callback_data, which is a Pointer(Void)
, but that's another issue.
Unfortunately, I'm not sure there are any workarounds that I can find.
Monkey patching isn't possible as you can't monkey patch C lib bindings. Trying to override the binding.yml
to use lib_ignore
for Gio also proves to be pretty difficult, as it can't conflict with Gio's already present binding.yml
Trying to use shard.override.yml
to use a separate gio.cr
with a differen't binding.yml
also ignores the binding.yml in gio.cr.
info - Pango - No binding config found for Gio-2.0.
Putting binding.yml
really anywhere in the project directory causes compile errors for the project like:
Error: can't find file '../../../../../src/bindings/g_lib/error.cr' relative to '/Users/skinnyjames/dsrc/big_editor/lib/gi-crystal/src/auto/g_lib-2.0/g_lib.cr'bi
So it seems that binding.yml
is coupled with the lib repo, and the lib repo can't be swapped out.
While the lib is cool, I can't seem to make an app do moderate computation without blocking the UI thread. Definitely open to suggestions. It'd be really great if Lib<Gio/Gtk/whatever>
generations were decoupled from their corresponding Gio/Gtk/whatever
abstractions, which make it a lot more complicated to work with, especially when there are bugs.
The Lib*
objects must be coupled only with other Lib*
form C libraries it depends, any other coupling must be interpreted as a bug. I mean, must be possible to monkey patch things to fix the gi-crystal bugs.
Callback need more <3 for sure. On top of my head it needs:
- Use Box objects to encapsulate the Crystal Proc.
- Use
ClosureManager
to keep the Box objects in memory while the callback can be called. - De-register the callback from
ClosureManager
to avoid memory leaks.
It's possible to mimic a async API in libtest to be able to fix and test these issues in gi-crystal.
I'm trying to use Gio::Subprocess
and this issue is now blocking me too 😬.
The problem is that the method doesn't have a DestroyNotify
parameter, so GICrystal doesn't recognize it as a callback.
Anyway... I also need to think a better way to map these GObject assync API to Crystal... probably:
proc = Gio::Subprocess.new(argv: ["ls", "-l"], flags: :none)
proc.wait_async(cancelable) do |result|
...
end
This would cause GI-Crystal to call g_subprocess_wait_async
with GAsyncReadyCallback
being a wrapper function that would call the user callback then de-register itself from ClosureManager.