Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generated code expects incorrect type for Gio::AsyncReadyCallback #83

Open
wildeyedskies opened this issue Mar 5, 2023 · 4 comments
Open
Labels
bug Something isn't working

Comments

@wildeyedskies
Copy link

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.

@hugopl hugopl added the bug Something isn't working label Mar 7, 2023
@hugopl
Copy link
Owner

hugopl commented Jun 20, 2023

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.

@skinnyjames
Copy link

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.crwith 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.

@hugopl
Copy link
Owner

hugopl commented Oct 13, 2023

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.

@hugopl
Copy link
Owner

hugopl commented Dec 15, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants