spk121 / guile-gi

Bindings for GObject Introspection and libgirepository for Guile
GNU General Public License v3.0
58 stars 7 forks source link

How do I use Gtk, Gdk, etc., functions and constants? #122

Open sirgazil opened 2 years ago

sirgazil commented 2 years ago

Hi,

I asked this question on Guile's mailing list, but I thought I might have better luck here.

In summary, I haven't been able to figure out how to call functions, like Gtk's show_uri, or use constants, like Gdk's CURRENT_TIME.

Take this application for example:

(use-modules (gi) (gi repository))

(require "Gio" "2.0")
(require "Gtk" "4.0")

(load-by-name "Gio" "Application") ;; activate, run
(load-by-name "Gtk" "Application")
(load-by-name "Gtk" "ApplicationWindow")
(load-by-name "Gtk" "Button")
(load-by-name "Gtk" "Window")

(define (on-activate app)
  (let* ((window (make <GtkApplicationWindow>
                   #:application app
                   #:default-height 200
                   #:default-width 200
                   #:title "Window"))
         (button (make <GtkButton> #:label "Help")))

    (set-child window button)
    (connect button clicked (lambda _ (show-uri window "help:gedit" CURRENT_TIME)))
    (present window)))

(define (main)
  (let ((app (make <GtkApplication> #:application-id "org.gtk.example")))

    (connect app activate on-activate)
    (run app (command-line))))

(main)

When I click the Help button, the application shuts down and says that show-uri is unbound.

$ guile gtk-functions.scm 
WARNING: (guile-user): imported module (gi) overrides core binding `quit'
WARNING: (guile-user): imported module (gi) overrides core binding `command-line'
WARNING: (guile-user): imported module (gi) overrides core binding `shutdown'
WARNING: (guile-user): imported module (gi) overrides core binding `connect'
Backtrace:
In ice-9/boot-9.scm:
  1752:10  7 (with-exception-handler _ _ #:unwind? _ # _)
In unknown file:
           6 (apply-smob/0 #<thunk 7f33c1417080>)
In ice-9/boot-9.scm:
    724:2  5 (call-with-prompt _ _ #<procedure default-prompt-handle…>)
In ice-9/eval.scm:
    619:8  4 (_ #(#(#<directory (guile-user) 7f33c141dc80>)))
In ice-9/boot-9.scm:
   2835:4  3 (save-module-excursion _)
  4380:12  2 (_)
In unknown file:
           1 (application:run #<<GtkApplication> 7f33c04782a0> ("gt…"))
In /home/yo/Descargas/gtk-functions.scm:
    22:39  0 (_ . _)

/home/yo/Descargas/gtk-functions.scm:22:39: Unbound variable: show-uri

If you use Guix, you can run the example above in Guix shell using the following manifest:

#| GNU Guix manifest.

guix 579e9e9
repository URL: https://git.savannah.gnu.org/git/guix.git
branch: master
commit: 579e9e9509f45fdc8543323b3c9f662b53dbfc6d |#

(use-modules (gnu packages))

(specifications->manifest
 (list ;; "gnome@41.0"  ; For containerized environment only.
       "gobject-introspection@1.66.1"
       "gtk@4.4.1"
       "guile@3.0.7"
       "guile-gi@0.3.2"))
lshoravi commented 2 years ago

The following works for me:

(define-module (example)
  #:use-module (gi)
  #:use-module (gi repository))

(use-typelibs ("Gtk" "4.0"))

show-uri

Using:

  (inputs `(("guile" ,guile-3.0)
            ("guile-gi" ,guile-gi)
            ("gtk4" ,gtk)

and guix shell --no-grafts

It's possible that show-uri isn't in any of the namespaces you imported through load-by-name, but I don't know if it's possible to look up functions in that way.

lshoravi commented 2 years ago

Apropos doesn't seem to help either:

scheme@(guile-user)> (use-modules (gi) (gi repository))
scheme@(guile-user)> (use-typelibs ("Gtk" "4.0"))

...

scheme@(guile-user)> ,apropos show-uri
(gi Gtk-4.0): show-uri  #<<generic> show-uri (1)>
(gi Gtk-4.0): show-uri-full #<<generic> show-uri-full (4)>
(gi Gtk-4.0): show-uri-full-finish? #<<generic> show-uri-full-finish? (1)>
scheme@(guile-user)> 
sirgazil commented 2 years ago

@lshoravi thanks for commenting :)

I can confirm that using use-typelibs I can simply call the function and it works. So I guess the question is, what would I need to load using the require and load-by-name strategy to be able to call show-uri?

But here is a modified version of the initial example, anyway, doing what it was expected to do:

(use-modules (gi) (gi repository))
(use-typelibs ("Gdk" "4.0")  ; CURRENT_TIME
              ("Gtk" "4.0")
              ("Gio" "2.0"))  ; XXX: MUST BE HERE

(define (on-activate app)
  (let* ((window (make <GtkApplicationWindow>
                   #:application app
                   #:default-height 200
                   #:default-width 200
                   #:title "Window"))
         (button (make <GtkButton> #:label "Help")))

    (set-child window button)
    (connect button clicked (lambda _ (show-uri window "help:gedit" CURRENT_TIME)))
    (present window)))

(define (main)
  (let ((app (make <GtkApplication> #:application-id "org.gtk.example")))

    (connect app activate on-activate)
    (run app (command-line))))

(main)

Note that I added Gdk, which I forgot to do in the first example. Then, I could run it like so:

guix shell guile guile-gi gtk   # It worked without --no-grafts
guile app.scm

Something unexpected here is that placing Gio import before Gdk, makes the application fail to run with the following message, so I had to move the import of Gio to the end.

Backtrace:
In ice-9/boot-9.scm:
  1752:10  7 (with-exception-handler _ _ #:unwind? _ # _)
In unknown file:
           6 (apply-smob/0 #<thunk 7fdc3d781080>)
In ice-9/boot-9.scm:
    724:2  5 (call-with-prompt _ _ #<procedure default-prompt-handle…>)
In ice-9/eval.scm:
    619:8  4 (_ #(#(#<directory (guile-user) 7fdc3d787c80>)))
In ice-9/boot-9.scm:
   2835:4  3 (save-module-excursion _)
  4380:12  2 (_)
In /home/yo/Descargas/guile-gi-functions/main-use-typelibs.scm:
     24:4  1 (main)
In gi/oop.scm:
    103:8  0 (connect-1 _ _ _ #:after? _ #:detail _)

gi/oop.scm:103:8: In procedure connect-1:
~S has no signal in ~S #<<GtkApplication> 7fdc34599650> #<<generic> activate (17)>

Another unexpected thing, although Guix-related, is that the application fails to run if I put the inputs in a manifest instead of passing them directly to guix shell. For example:

Manifest:

(use-modules (gnu packages))

(specifications->manifest
 (list "gtk"
       "guile"
       "guile-gi"))

Then:

guix shell -m manifest-unversioned.scm
guile app.scm

Results in critical errors:

(process:4201): GuileGI-WARNING **: 11:47:37.771: not redefining fundamental type GdkEvent

(process:4201): GuileGI-WARNING **: 11:47:37.790: no way of determining array size of GArray, coercing to pointer

(process:4201): GLib-GObject-WARNING **: 11:47:37.831: cannot register existing type 'GdkPixbuf'

(process:4201): GLib-GObject-CRITICAL **: 11:47:37.831: g_type_add_interface_static: assertion 'G_TYPE_IS_INSTANTIATABLE (instance_type)' failed

(process:4201): GLib-GObject-CRITICAL **: 11:47:37.831: g_type_add_interface_static: assertion 'G_TYPE_IS_INSTANTIATABLE (instance_type)' failed

(process:4201): GLib-CRITICAL **: 11:47:37.831: g_once_init_leave: assertion 'result != 0' failed

(process:4201): GLib-GObject-CRITICAL **: 11:47:37.831: g_param_spec_object: assertion 'g_type_is_a (object_type, G_TYPE_OBJECT)' failed

(process:4201): GLib-GObject-CRITICAL **: 11:47:37.831: validate_pspec_to_install: assertion 'G_IS_PARAM_SPEC (pspec)' failed

(process:4201): GLib-GObject-CRITICAL **: 11:47:37.831: g_param_spec_object: assertion 'g_type_is_a (object_type, G_TYPE_OBJECT)' failed

(process:4201): GLib-GObject-CRITICAL **: 11:47:37.831: validate_pspec_to_install: assertion 'G_IS_PARAM_SPEC (pspec)' failed

(process:4201): GLib-GObject-CRITICAL **: 11:47:37.831: g_param_spec_object: assertion 'g_type_is_a (object_type, G_TYPE_OBJECT)' failed

(process:4201): GLib-GObject-CRITICAL **: 11:47:37.831: validate_pspec_to_install: assertion 'G_IS_PARAM_SPEC (pspec)' failed

(process:4201): GuileGI-WARNING **: 11:47:37.832: Missing property cell-renderer-pixbuf:pixbuf

(process:4201): GuileGI-WARNING **: 11:47:37.832: Missing property cell-renderer-pixbuf:pixbuf-expander-closed

(process:4201): GuileGI-WARNING **: 11:47:37.832: Missing property cell-renderer-pixbuf:pixbuf-expander-open

(process:4201): GuileGI-WARNING **: 11:47:37.880: not redefining fundamental type GtkExpression

(process:4201): GuileGI-WARNING **: 11:47:37.909: no way of determining array size of GArray, coercing to pointer

(process:4201): GuileGI-WARNING **: 11:47:37.909: no way of determining array size of GArray, coercing to pointer
lshoravi commented 2 years ago

I had these issues as well, including #120.

The reason for this is that guix "grafts" packages, resulting in guile-gi being built for one version of Gtk but guix is using a slightly different version. Hence the reason for entering the development shell with --no-grafts. Doing so eliminates most errors for me.

There's ongoing discussion about this in #96.

lshoravi commented 2 years ago

As for what to give load-by-name, I have no idea.

LordYuuma commented 2 years ago

For completeness, load-by-name takes the unprefixed constant name, so for Gdk's CURRENT_TIME, that ought to be simply CURRENT_TIME. Constants can appear in two flavors: either as constants, in which they have their own entry, or as enums/flags, in which you need to import the corresponding enum instead.