andy128k / cl-gobject-introspection

BSD 2-Clause "Simplified" License
49 stars 15 forks source link

Can we use lambda/closures for GAsyncReadyCallback? #72

Closed Ambrevar closed 4 years ago

Ambrevar commented 4 years ago

I'm trying to run some javascript in a web view. The following works:

(cffi:defcallback javascript-callback :void ((gobject :pointer) (gasyncres :pointer)
                                             (user_data :pointer))
  (declare (ignore gasyncres))
  (format t "Javascript called on ~a with user data ~a~%" gobject user_data))

(gir:invoke (view 'run-javascript)
              "window.scrollBy(0, -20);"
              (cffi:null-pointer)
              (cffi:get-callback 'javascript-callback)
              (cffi:null-pointer))

But having to define the callbacks in advance is not very convenient. It also makes the passing of user data a bit cumbersome compared to closures.

Is there a way to use a lambda instead, as with gir:connect? Ideally, I'd like to write something like the following:

(gir:invoke (view 'run-javascript)
              "window.scrollBy(0, -20);"
              (cffi:null-pointer)
              (lambda (gobject gasyncres user_data)
                ...))

(Note that there would be no need for the last (cffi:null-pointer) argument of gir:invoke.)

andy128k commented 4 years ago

I am not even sure this is possible to do in generic way.

But you can do it in your code. Here you can find inspiration and hints how to do this. Idea is that you have global hash table with lambdas and single callback which uses that table to dispatch call.

Ambrevar commented 4 years ago

This could do it, thanks.

Out of curiosity, why is it different from gir:connect which can take a lambda?

andy128k commented 4 years ago

gir:connect works with GObject signals. They allow to pass GClosure -- data structure designed for representing functions and for marshaling/unmarshaling arguments/results.

Ambrevar commented 4 years ago

Makes sense, thanks!