Code Monkey home page Code Monkey logo

gtk4.cr's People

Contributors

1player avatar aramvisser avatar blobcodes avatar geopjr avatar hugopl avatar kianmeng avatar mamantoha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gtk4.cr's Issues

[Question] How to wait for a dialog to return a value?

Hi there!

Thank you for creating a practical GTK4 binding for the Crystal language.

I am working on a tool that shows data in a tabular format like this.
image

To add the ability to open a file, I wrote the following code.

      def get_file_path
        file_path = ""
        dialog = Gtk::FileChooserDialog.new(
          application: @app,
          title: "Open File",
          action: Gtk::FileChooserAction::Open,
          transient_for: window,
          modal: true
        )
        dialog.add_button("Cancel", Gtk::ResponseType::Cancel.value)
        dialog.add_button("Open", Gtk::ResponseType::Accept.value)
        dialog.response_signal.connect do |response|
          case Gtk::ResponseType.from_value(response)
          when .cancel?
          when .accept?
            file_path = dialog.file.try(&.path)
          end
          dialog.destroy
        end
        dialog.present
        file_path
      end

Here I tried to get the file path. This works.
The problem is that the method always return "".
It doesn't wait for the dialog to exit.

What am I missing?

Exception: Undefined constant GLib::Bytes

Using this code:

require "gtk4"

file = Gio::File.parse_name("/some/image/path.png")
file.load_bytes(Gio::Cancellable.new)

Results in this exception:

Showing last frame. Use --error-trace for full trace.

In lib/gtk4/src/gio-2.0/file.cr:747:55

 747 | def load_bytes(cancellable : Gio::Cancellable?) : GLib::Bytes
                                                         ^----------
Error: undefined constant GLib::Bytes

dependnecy requirement (libgirepository1.0-dev)

I started with the helloworld example and install the dependency written in the documentation.

I'm on ubuntu 22.04 and the error was:

shards 
Resolving dependencies
Fetching https://github.com/hugopl/gtk4.cr.git
Fetching https://github.com/hugopl/gi-crystal.git
Fetching https://github.com/hugopl/version_from_shard.git
Using version_from_shard (1.2.5)
Installing gi-crystal (0.14.0)
Postinstall of gi-crystal: shards build
Failed postinstall of gi-crystal on shards build:
Resolving dependencies
Fetching https://github.com/hugopl/version_from_shard.git
Using version_from_shard (1.2.5)
Writing shard.lock
Building: gi-crystal
Error target gi-crystal failed to compile:
/usr/bin/ld: impossibile trovare -lgirepository-1.0: File o directory non esistente
collect2: error: ld returned 1 exit status
Error: execution of command failed with code: 1: `cc "${@}" -o /home/marino/programmazione/personal/hellotk4/lib/gi-crystal/bin/gi-crystal  -rdynamic -L/snap/crystal/1315/bin/../lib/crystal -lxml2 -lgirepository-1.0 -lglib-2.0 -lgobject-2.0 -lglib-2.0 -lyaml -lpcre -lm -lgc -lpthread -levent -lrt -lpthread -ldl`

I ended to install also:

sudo apt install libgirepository1.0-dev

and the install works correctly.

Should this go in the docs?

Gdk::Cursor.new_from_name must return Gdk::Cursor but it is returning (Gdk::Cursor | Nil)

Trying to create the following cursor:

Gdk::Cursor.new_from_name("pointer", nil)

Results in the aforementioned compile-time error.

The generated method:

    def self.new_from_name(name : ::String, fallback : Gdk::Cursor?) : self
      # gdk_cursor_new_from_name: (Constructor)
      # @fallback: (nullable)
      # Returns: (transfer full)

      # Handle parameters
      fallback = if fallback.nil?
                   Pointer(Void).null
                 else
                   fallback.to_unsafe
                 end

      # C call
      _retval = LibGdk.gdk_cursor_new_from_name(name, fallback)

      # Return value handling
      Gdk::Cursor.new(_retval, GICrystal::Transfer::Full) unless _retval.null?
    end

`Gtk::DrawingArea#set_draw_func` is unusable

There's no type safety in current generated code, just some void pointers.

    def set_draw_func(draw_func : Pointer(Void)?, user_data : Pointer(Void)?, destroy : Pointer(Void)) : Nil
      # gtk_drawing_area_set_draw_func: (Method)
      # @draw_func: (nullable)
      # @user_data: (nullable)
      # Returns: (transfer none)

      # Handle parameters
      draw_func = if draw_func.nil?
                    LibGtk::DrawingAreaDrawFunc.null
                  else
                    draw_func.to_unsafe
                  end
      user_data = if user_data.nil?
                    Pointer(Void).null
                  else
                    user_data.to_unsafe
                  end

      # C call
      LibGtk.gtk_drawing_area_set_draw_func(self, draw_func, user_data, destroy)

      # Return value handling
    end

GC.collect instantly crashes application

In both of these given examples, the application crashes (in one example instantly, in the other one when pressing the button):

require "gtk4"

app = Gtk::Application.new("hello.example.com", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  GLib.idle_add(GLib::Priority.new(500)) do
    # Allocate memory until the gc collects or the ram is full
    Pointer(UInt8).malloc(1)
    true
  end
  window = Gtk::ApplicationWindow.new(app)
  window.present
end
app.run(ARGV)
require "gtk4"

app = Gtk::Application.new("hello.example.com", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  window = Gtk::ApplicationWindow.new(app)
  button = Gtk::Button.new(label: "Crash!")
  button.clicked_signal.connect { GC.collect }
  window.child = button
  window.present
end
app.run(ARGV)

Using GC.disable in either of the two examples fixes the problem, but that's not really a good solution.
I don't know if this issue actually belongs here or in gi-crystal.

Unable to wrap a Gio::File__Impl into a GValue

Using this code:

require "gtk4"

file = Gio::File.parse_name("/some/image/path.png")
Gtk::Picture.new(file: file)

results in this error:

Unhandled exception: Unable to wrap a Gio::File__Impl into a GValue, probably not implemented. (ArgumentError)
  from lib/gtk4/src/g_object-2.0/includes/value.cr:58:9 in 'g_type_for'
  from lib/gtk4/src/g_object-2.0/includes/value.cr:16:36 in 'init_g_value'
  from lib/gtk4/src/gtk-4.0/picture.cr:114:9 in 'initialize:file'
  from lib/gtk4/src/gtk-4.0/picture.cr:67:5 in 'new:file'
  from src/test2.cr:4:1 in '__crystal_main'
  from /usr/share/crystal/src/crystal/main.cr:110:5 in 'main_user_code'
  from /usr/share/crystal/src/crystal/main.cr:96:7 in 'main'
  from /usr/share/crystal/src/crystal/main.cr:119:3 in 'main'
  from /lib64/libc.so.6 in '??'
  from /lib64/libc.so.6 in '__libc_start_main'
  from /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp in '_start'
  from ???

`Gtk::Snapshot#append_texture` crashes program with SIGSEGV

The following code:

require "gtk4"

snapshot = Gtk::Snapshot.new
texture = Gdk::Texture.new_from_filename("/path/to/some/image.ext")
snapshot.append_texture(texture, Graphene::Rect.zero)

Causes the program to crash with the following message:

Invalid memory access (signal 11) at address 0xffffffffffffff98
[0x4b71b6] *Exception::CallStack::print_backtrace:Nil +118 in /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp
[0x49524a] ~procProc(Int32, Pointer(LibC::SiginfoT), Pointer(Void), Nil) +330 in /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp
[0x7f608dd6dac0] ?? +140052673256128 in /lib64/libc.so.6
[0x7f608e4bbc9e] ?? +140052680916126 in /lib64/libgtk-4.so.1
[0x7f608e4bd0cb] gtk_snapshot_append_texture +155 in /lib64/libgtk-4.so.1
[0x550de2] *Gtk::Snapshot#append_texture<Gdk::Texture+, Graphene::Rect>:Nil +18 in /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp
[0x479e47] __crystal_main +1335 in /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp
[0x554c86] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6 in /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp
[0x554bd9] *Crystal::main<Int32, Pointer(Pointer(UInt8))>:Int32 +41 in /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp
[0x487486] main +6 in /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp
[0x7f608dd58590] ?? +140052673168784 in /lib64/libc.so.6
[0x7f608dd58649] __libc_start_main +137 in /lib64/libc.so.6
[0x479845] _start +37 in /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp
[0x0] ???

This used to work in an older version of GI-Crystal.

GI-Crystal version: 0.12.0
Crystal version: 1.4.1

Properties set in GObject constructor leak memory

The following code:

require "gtk4"

app = Gtk::Application.new("test.test", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  window = Gtk::ApplicationWindow.new(application: app)
  window.child = box = Gtk::Box.new

  GLib.timeout_milliseconds(10) do
    child = Gtk::Label.new label: "Test!" * 10000 # * 10000 to make it more dramatic
    box.append child
    box.remove child
    puts child
    true
  end
  window.present
end
exit(app.run(ARGV))

Simplified:

require "gtk4"

app = Gtk::Application.new("test.test", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  loop do
    Gtk::Label.new label: "Test!" * 1000 # * 1000 to make it more dramatic
  end
end
exit(app.run(ARGV))

Will leak memory, even though it is now finalizing the Gtk::Label instances.

Crash when using intel and mesa 22.0

Everything works nice with mesa <= 21.3.7 on ArchLinux, but if I update to mesa 22.0 everything crashes on libiris.so. Looks like a mesa bug, but sometimes it's just a existing bug in the bindings that is now visible with the new version of this library.

How to reproduce

On Archlinux with a intel card, try to run the hello world example. The bug is not GC related, since it works with GC enable or not.

Thread 1 "hello_world" received signal SIGSEGV, Segmentation fault.
0x00007fffe36e308b in ?? () from /usr/lib/dri/iris_dri.so
(gdb) bt full
#0  0x00007fffe36e308b in  () at /usr/lib/dri/iris_dri.so
#1  0x00007fffe36e37e8 in  () at /usr/lib/dri/iris_dri.so
#2  0x00007fffe33e25d4 in  () at /usr/lib/dri/iris_dri.so
#3  0x00007fffe332b5d4 in  () at /usr/lib/dri/iris_dri.so
#4  0x00007fffe33311dc in  () at /usr/lib/dri/iris_dri.so
#5  0x00007fffe3333965 in  () at /usr/lib/dri/iris_dri.so
#6  0x00007fffe33fe940 in  () at /usr/lib/dri/iris_dri.so
#7  0x00007fffe3402a27 in  () at /usr/lib/dri/iris_dri.so
#8  0x00007fffe341673d in  () at /usr/lib/dri/iris_dri.so
#9  0x00007fffe324da59 in  () at /usr/lib/dri/iris_dri.so
#10 0x00007fffe2b1a9b7 in  () at /usr/lib/dri/iris_dri.so
#11 0x00007fffe2b1b84a in  () at /usr/lib/dri/iris_dri.so
#12 0x00007fffe365a643 in  () at /usr/lib/dri/iris_dri.so
#13 0x00007fffe2b1bb05 in  () at /usr/lib/dri/iris_dri.so
#14 0x00007fffe26fdbd8 in  () at /usr/lib/dri/iris_dri.so
#15 0x00007fffe26b14cf in  () at /usr/lib/dri/iris_dri.so
#16 0x00007fffe26bc889 in  () at /usr/lib/dri/iris_dri.so
#17 0x00007fffe26bc979 in  () at /usr/lib/dri/iris_dri.so
#18 0x00007ffff7c3c66d in gsk_gl_glyph_library_upload_glyph (uheight=<optimized out>, uwidth=<optimized out>, height=26, width=<optimized out>, y=1, x=4, value=0x7fffe4015700, key=<optimized out>, self=<optimized out>)
    at ../gtk/gsk/gl/gskglglyphlibrary.c:251
        tl = <optimized out>
        start_time = 0
        surface = 0x5555568ef800
        free_data = 0x0
        gl_format = <optimized out>
        pixel_data = <optimized out>
        gl_type = <optimized out>
        texture_id = <optimized out>
        stride = <optimized out>
        tl = <optimized out>
        value = 0x7fffe4015700
        packed_y = 0
        ink_rect = {x = 0, y = -12, width = 11, height = 13}
        width = <optimized out>
        height = 26
        packed_x = 3
        k = <optimized out>
        glyph_y = <optimized out>
        glyph_y2 = <optimized out>
        cx = <optimized out>
        texture_id = <optimized out>
        tx = <optimized out>
        tx2 = <optimized out>
        cy = 105
        glyph = <optimized out>
        glyph_x = <optimized out>
        glyph_x2 = <optimized out>
        ty = <optimized out>
        ty2 = <optimized out>
        font = <optimized out>
        glyphs = <optimized out>
        offset = <optimized out>
        text_scale = <optimized out>
        num_glyphs = <optimized out>
        x = <optimized out>
        y = <optimized out>
        library = <optimized out>
        batch = 0x5555568b5dd0
        x_position = 10829
        lookup = {font = 0x5555558af460, glyph = 76, xshift = 0, yshift = 2, scale = 2048}
        last_texture = 0
        vertices = 0x5555568bc630
        used = 0
        nc = {48128, 48128, 48128, 48128}
        cc = {15223, 15223, 15207, 15360}
        c = 0x7fffffffcdd8
        gi = 0x5555568ef560
        i = 0
        yshift = <optimized out>
        ypos = <optimized out>
#19 gsk_gl_glyph_library_add (out_value=<synthetic pointer>, key=<optimized out>, self=<optimized out>) at ../gtk/gsk/gl/gskglglyphlibrary.c:309
        tl = <optimized out>
        value = 0x7fffe4015700
        packed_y = 0
        ink_rect = {x = 0, y = -12, width = 11, height = 13}
        width = <optimized out>
        height = 26
        packed_x = 3
        k = <optimized out>
        glyph_y = <optimized out>
        glyph_y2 = <optimized out>
        cx = <optimized out>
        texture_id = <optimized out>
        tx = <optimized out>
        tx2 = <optimized out>
        cy = 105
        glyph = <optimized out>
        glyph_x = <optimized out>
        glyph_x2 = <optimized out>
        ty = <optimized out>
        ty2 = <optimized out>
        font = <optimized out>
        glyphs = <optimized out>
        offset = <optimized out>
        text_scale = <optimized out>
        num_glyphs = <optimized out>
        x = <optimized out>
        y = <optimized out>
        library = <optimized out>
        batch = 0x5555568b5dd0
        x_position = 10829
        lookup = {font = 0x5555558af460, glyph = 76, xshift = 0, yshift = 2, scale = 2048}
        last_texture = 0
        vertices = 0x5555568bc630
        used = 0
        nc = {48128, 48128, 48128, 48128}
        cc = {15223, 15223, 15207, 15360}
        c = 0x7fffffffcdd8
        gi = 0x5555568ef560
        i = 0
        yshift = <optimized out>
        ypos = <optimized out>
#20 gsk_gl_glyph_library_lookup_or_add (out_value=<synthetic pointer>, key=0x7fffffffcd70, self=<optimized out>) at ../gtk/gsk/gl/gskglglyphlibraryprivate.h:93
        k = <optimized out>
        glyph_y = <optimized out>
        glyph_y2 = <optimized out>
        cx = <optimized out>
        texture_id = <optimized out>
        tx = <optimized out>
        tx2 = <optimized out>
        cy = 105
        glyph = <optimized out>
        glyph_x = <optimized out>
        glyph_x2 = <optimized out>
        ty = <optimized out>
        ty2 = <optimized out>
        font = <optimized out>
        glyphs = <optimized out>
        offset = <optimized out>
        text_scale = <optimized out>
        num_glyphs = <optimized out>
        x = <optimized out>
        y = <optimized out>
        library = <optimized out>
        batch = 0x5555568b5dd0
        x_position = 10829
        lookup = {font = 0x5555558af460, glyph = 76, xshift = 0, yshift = 2, scale = 2048}
        last_texture = 0
        vertices = 0x5555568bc630
        used = 0
        nc = {48128, 48128, 48128, 48128}
        cc = {15223, 15223, 15207, 15360}
        c = 0x7fffffffcdd8
        gi = 0x5555568ef560
        i = 0
        yshift = <optimized out>
        ypos = <optimized out>
#21 gsk_gl_render_job_visit_text_node (job=job@entry=0x5555556c3c10, node=node@entry=0x7fffe4007370, color=<optimized out>, force_color=force_color@entry=0) at ../gtk/gsk/gl/gskglrenderjob.c:3069
        glyph_y = <optimized out>
        glyph_y2 = <optimized out>
        cx = <optimized out>
        texture_id = <optimized out>
        tx = <optimized out>
        tx2 = <optimized out>
        cy = 105
        glyph = <optimized out>
        glyph_x = <optimized out>
        glyph_x2 = <optimized out>
        ty = <optimized out>
        ty2 = <optimized out>
        font = <optimized out>
        glyphs = <optimized out>
        offset = <optimized out>
        text_scale = <optimized out>
        num_glyphs = <optimized out>
        x = <optimized out>
        y = <optimized out>
        library = <optimized out>
        batch = 0x5555568b5dd0
        x_position = 10829
        lookup = {font = 0x5555558af460, glyph = 76, xshift = 0, yshift = 2, scale = 2048}
        last_texture = 0
        vertices = 0x5555568bc630
        used = 0
        nc = {48128, 48128, 48128, 48128}
        cc = {15223, 15223, 15207, 15360}
        c = 0x7fffffffcdd8
        gi = 0x5555568ef560
        i = 0
        yshift = <optimized out>
        ypos = <optimized out>
#22 0x00007ffff7c3ea60 in gsk_gl_render_job_visit_node (job=0x5555556c3c10, node=0x7fffe4007370) at ../gtk/gsk/gl/gskglrenderjob.c:3809
        has_clip = 1
        __func__ = "gsk_gl_render_job_visit_node"
#23 0x00007ffff7c3e969 in gsk_gl_render_job_visit_node (job=0x5555556c3c10, node=<optimized out>) at ../gtk/gsk/gl/gskglrenderjob.c:3733
        child = 0x7fffe4007370
        i = 2
        n_children = 3
        has_clip = 0
        __func__ = "gsk_gl_render_job_visit_node"
#24 0x00007ffff7c3226b in gsk_gl_render_job_visit_transform_node (job=0x5555556c3c10, node=0x5555568be840) at ../gtk/gsk/gl/gskglrenderjob.c:2055
        dx = 17
        dy = 5
        transform = 0x5555568f77b0
        category = GSK_TRANSFORM_CATEGORY_2D_TRANSLATE
        child = 0x5555568d0100
        __func__ = "gsk_gl_render_job_visit_transform_node"
#25 0x00007ffff7c3ebdd in gsk_gl_render_job_visit_node (job=0x5555556c3c10, node=0x5555568be840) at ../gtk/gsk/gl/gskglrenderjob.c:3820
        has_clip = 0
        __func__ = "gsk_gl_render_job_visit_node"
#26 0x00007ffff7c30799 in gsk_gl_render_job_visit_clipped_child (job=0x5555556c3c10, child=0x5555568be840, clip=0x5555568be3a8) at ../gtk/gsk/gl/gskglrenderjob.c:1659
        transformed_clip = {origin = {x = 0, y = 0}, size = {width = 400, height = 400}}
        intersection = {bounds = {origin = {x = 0, y = 0}, size = {width = 400, height = 400}}, corner = {{width = 0, height = 0}, {width = 0, height = 0}, {width = 0, height = 0}, {width = 0, height = 0}}}
        __func__ = "gsk_gl_render_job_visit_clipped_child"
#27 0x00007ffff7c3f18b in gsk_gl_render_job_visit_clip_node (node=0x5555568be380, job=0x5555556c3c10) at ../gtk/gsk/gl/gskglrenderjob.c:1693
        clip = 0x5555568be3a8
        child = <optimized out>
        has_clip = 0
        __func__ = "gsk_gl_render_job_visit_node"
#28 gsk_gl_render_job_visit_node (job=0x5555556c3c10, node=0x5555568be380) at ../gtk/gsk/gl/gskglrenderjob.c:3686
        has_clip = 0
        __func__ = "gsk_gl_render_job_visit_node"
#29 0x00007ffff7c3e969 in gsk_gl_render_job_visit_node (job=0x5555556c3c10, node=<optimized out>) at ../gtk/gsk/gl/gskglrenderjob.c:3733
        child = 0x5555568be380
        i = 1
        n_children = 2
        has_clip = 1
        __func__ = "gsk_gl_render_job_visit_node"
#30 0x00007ffff7c22a13 in gsk_gl_render_job_render (root=0x5555568f1030, job=0x5555556c3c10) at ../gtk/gsk/gl/gskglrenderjob.c:4094
        start_time = 0
        scale_factor = 2
        surface_height = 400
        self = 0x5555558f9700
        render_region = 0x0
        viewport = {origin = {x = 0, y = 0}, size = {width = 400, height = 400}}
        job = 0x5555556c3c10
        surface = <optimized out>
        clear_framebuffer = <optimized out>
        scale_factor = <optimized out>
        __func__ = "gsk_gl_renderer_render"
#31 gsk_gl_renderer_render (renderer=0x5555558f9700, root=0x5555568f1030, update_area=<optimized out>) at ../gtk/gsk/gl/gskglrenderer.c:290
        self = 0x5555558f9700
        render_region = 0x0
        viewport = {origin = {x = 0, y = 0}, size = {width = 400, height = 400}}
        job = 0x5555556c3c10
        surface = <optimized out>
        clear_framebuffer = <optimized out>
        scale_factor = <optimized out>
        __func__ = "gsk_gl_renderer_render"
#32 0x00007ffff7c0900d in gsk_renderer_render (renderer=0x5555558f9700, root=0x5555568f1030, region=<optimized out>) at ../gtk/gsk/gskrenderer.c:467
        priv = 0x5555558f96c0
        clip = 0x5555556c8ab0
        __func__ = "gsk_renderer_render"
#33 0x00007ffff7abf146 in gtk_widget_render (widget=<optimized out>, surface=<optimized out>, region=0x5555568f0e40) at ../gtk/gtk/gtkwidget.c:11694
        priv = <optimized out>
        snapshot = <optimized out>
        renderer = 0x5555558f9700
        root = 0x5555568f1030
        x = 0
        y = 0
#34 0x00007ffff7abfeb9 in surface_render () at ../gtk/gtk/gtkwindow.c:5158
#35 0x00007ffff7b8a449 in _gdk_marshal_BOOLEAN__BOXEDv (closure=0x555555fb5df0, return_value=0x7fffffffdb60, instance=<optimized out>, args=<optimized out>, marshal_data=<optimized out>, n_params=<optimized out>, param_types=0x555555782040) at gdk/gdkmarshalers.c:130
        data1 = 0x5555556e84f0
        data2 = <optimized out>
        callback = 0x7ffff7abfea0 <surface_render>
        v_return = <optimized out>
        arg0 = 0x5555568f0e40
        args_copy = {{gp_offset = 32, fp_offset = 48, overflow_arg_area = 0x7fffffffdcf0, reg_save_area = 0x7fffffffdc30}}
        __func__ = "_gdk_marshal_BOOLEAN__BOXEDv"
#36 0x00007ffff75f86b6 in _g_closure_invoke_va (param_types=0x555555782040, n_params=1, args=0x7fffffffdc10, instance=0x5555556e84f0, return_value=<optimized out>, closure=<optimized out>) at ../glib/gobject/gclosure.c:893
        marshal = <optimized out>
        marshal_data = <optimized out>
        in_marshal = 0
        real_closure = <optimized out>
        return_accu = <optimized out>
        accu = {g_type = 0x14, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
        accumulator = 0x555555782060
        emission = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str
{next = 0x7fffffffddc0, instance = 0x5555556e84f0, ihint = {signal_id = 47, detail = 0, run_type = (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACCUMULATOR_FIRST_RUN)}, state = EMISSION_RUN, chain_type = }
        instance_type = <optimized out>
        emission_return = {g_type = 0x14, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
        rtype = 0x14
        static_scope = 0
        fastpath_handler = <optimized out>
        closure = <optimized out>
        run_type = <optimized out>
        hlist = <optimized out>
        l = <optimized out>
        fastpath = 1
        instance_and_params = <optimized out>
        signal_return_type = <optimized out>
        param_values = <optimized out>
        node = <optimized out>
        i = <optimized out>
        n_params = <optimized out>
        __func__ = "g_signal_emit_valist"
#37 g_signal_emit_valist (instance=0x5555556e84f0, signal_id=47, detail=<optimized out>, var_args=var_args@entry=0x7fffffffdc10) at ../glib/gobject/gsignal.c:3406
        return_accu = <optimized out>
        accu = {g_type = 0x14, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
        accumulator = 0x555555782060
        emission = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str
{next = 0x7fffffffddc0, instance = 0x5555556e84f0, ihint = {signal_id = 47, detail = 0, run_type = (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACCUMULATOR_FIRST_RUN)}, state = EMISSION_RUN, chain_type = }
        instance_type = <optimized out>
        emission_return = {g_type = 0x14, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
        rtype = 0x14
        static_scope = 0
        fastpath_handler = <optimized out>
        closure = <optimized out>
        run_type = <optimized out>
        hlist = <optimized out>
        l = <optimized out>
        fastpath = 1
        instance_and_params = <optimized out>
        signal_return_type = <optimized out>
        param_values = <optimized out>
        node = <optimized out>
        i = <optimized out>
        n_params = <optimized out>
        __func__ = "g_signal_emit_valist"
#38 0x00007ffff75f8824 in g_signal_emit (instance=instance@entry=0x5555556e84f0, signal_id=<optimized out>, detail=detail@entry=0) at ../glib/gobject/gsignal.c:3553
        var_args = {{gp_offset = 24, fp_offset = 48, overflow_arg_area = 0x7fffffffdcf0, reg_save_area = 0x7fffffffdc30}}
#39 0x00007ffff7bb735c in gdk_surface_process_updates_internal (surface=0x5555556e84f0) at ../gtk/gdk/gdksurface.c:1348
        expose_region = 0x5555568f0e40
        handled = 32767
        surface = 0x5555556e84f0
        __func__ = "gdk_surface_paint_on_clock"
#40 gdk_surface_paint_on_clock (clock=<optimized out>, data=0x5555556e84f0) at ../gtk/gdk/gdksurface.c:1436
        surface = 0x5555556e84f0
        __func__ = "gdk_surface_paint_on_clock"
#41 0x00007ffff75f86b6 in _g_closure_invoke_va (param_types=0x0, n_params=0, args=0x7fffffffdec0, instance=0x5555557d6310, return_value=<optimized out>, closure=<optimized out>) at ../glib/gobject/gclosure.c:893
        marshal = <optimized out>
        marshal_data = <optimized out>
        in_marshal = 0
        real_closure = <optimized out>
        return_accu = <optimized out>
        accu = {g_type = 0x0, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
        accumulator = 0x0
        emission = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str
{next = 0x0, instance = 0x5555557d6310, ihint = {signal_id = 43, detail = 0, run_type = (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACCUMULATOR_FIRST_RUN)}, state = EMISSION_RUN, chain_type = }
        instance_type = <optimized out>
        emission_return = {g_type = 0x0, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
        rtype = 0x4
        static_scope = 0
        fastpath_handler = <optimized out>
        closure = <optimized out>
        run_type = <optimized out>
        hlist = <optimized out>
        l = <optimized out>
        fastpath = 1
        instance_and_params = <optimized out>
        signal_return_type = <optimized out>
        param_values = <optimized out>
        node = <optimized out>
        i = <optimized out>
        n_params = <optimized out>
        __func__ = "g_signal_emit_valist"
#42 g_signal_emit_valist (instance=0x5555557d6310, signal_id=43, detail=<optimized out>, var_args=var_args@entry=0x7fffffffdec0) at ../glib/gobject/gsignal.c:3406
        return_accu = <optimized out>
        accu = {g_type = 0x0, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
        accumulator = 0x0
        emission = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str
{next = 0x0, instance = 0x5555557d6310, ihint = {signal_id = 43, detail = 0, run_type = (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACCUMULATOR_FIRST_RUN)}, state = EMISSION_RUN, chain_type = }
        instance_type = <optimized out>
        emission_return = {g_type = 0x0, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
        rtype = 0x4
        static_scope = 0
        fastpath_handler = <optimized out>
        closure = <optimized out>
        run_type = <optimized out>
        hlist = <optimized out>
        l = <optimized out>
        fastpath = 1
        instance_and_params = <optimized out>
        signal_return_type = <optimized out>
        param_values = <optimized out>
        node = <optimized out>
        i = <optimized out>
        n_params = <optimized out>
        __func__ = "g_signal_emit_valist"
#43 0x00007ffff75f8824 in g_signal_emit (instance=instance@entry=0x5555557d6310, signal_id=<optimized out>, detail=detail@entry=0) at ../glib/gobject/gsignal.c:3553
        var_args = {{gp_offset = 24, fp_offset = 48, overflow_arg_area = 0x7fffffffdfa0, reg_save_area = 0x7fffffffdee0}}
#44 0x00007ffff7babe09 in _gdk_frame_clock_emit_paint (frame_clock=0x5555557d6310) at ../gtk/gdk/gdkframeclock.c:708
        before = 0
        clock = 0x5555557d6310
        clock_idle = 0x5555557d6310
        priv = 0x5555557d6200
        skip_to_resume_events = 0
        timings = <optimized out>
        __func__ = "gdk_frame_clock_paint_idle"
#45 gdk_frame_clock_paint_idle (data=0x5555557d6310, data@entry=<error reading variable: value has been optimized out>) at ../gtk/gdk/gdkframeclockidle.c:605
        clock = 0x5555557d6310
        clock_idle = 0x5555557d6310
        priv = 0x5555557d6200
        skip_to_resume_events = 0
        timings = <optimized out>
        __func__ = "gdk_frame_clock_paint_idle"
#46 0x00007ffff74de958 in g_timeout_dispatch (source=0x5555568f2400, callback=<optimized out>, user_data=<optimized out>) at ../glib/glib/gmain.c:4971
        timeout_source = 0x5555568f2400
        again = <optimized out>
#47 0x00007ffff74de163 in g_main_dispatch (context=0x5555556a2230) at ../glib/glib/gmain.c:3417
        dispatch = 0x7ffff74de940 <g_timeout_dispatch>
        prev_source = 0x0
        begin_time_nsec = 6714916237286
        was_in_call = <optimized out>
        user_data = 0x5555557d6310
        callback = 0x7ffff7baba40 <gdk_frame_clock_paint_idle>
        cb_funcs = 0x7ffff75c53e0 <g_source_callback_funcs>
        cb_data = 0x7fffe4009380
        need_destroy = <optimized out>
        source = 0x5555568f2400
        current = 0x5555556bc370
        i = 0
#48 g_main_context_dispatch (context=0x5555556a2230) at ../glib/glib/gmain.c:4135
#49 0x00007ffff75349e9 in g_main_context_iterate.constprop.0 (context=context@entry=0x5555556a2230, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib/glib/gmain.c:4211
        max_priority = 120
        timeout = 0
        some_ready = 1
        nfds = 2
        allocated_nfds = 2
        fds = 0x5555556a2210
        begin_time_nsec = 6714916225988
#50 0x00007ffff74db6c5 in g_main_context_iteration (context=context@entry=0x5555556a2230, may_block=may_block@entry=1) at ../glib/glib/gmain.c:4276
        retval = <optimized out>
#51 0x00007ffff76f94ee in g_application_run (application=0x55555569f0e0, argc=-7852, argv=<optimized out>) at ../glib/gio/gapplication.c:2569
        arguments = 0x5555556a2210
        status = 0
        context = 0x5555556a2230
        acquired_context = <optimized out>
        __func__ = "g_application_run"
#52 0x000055555563e82e in run () at /home/hugo/src/gtk4/lib/gi-crystal/src/auto/gio-2.0/application.cr:955
#53 0x00005555555a0ae3 in __crystal_main () at /home/hugo/src/gtk4/examples/hello_world.cr:20
#54 0x0000555555643016 in main_user_code () at /usr/lib/crystal/crystal/main.cr:115
#55 0x0000555555642f74 in main () at /usr/lib/crystal/crystal/main.cr:101
#56 0x00005555555adde6 in main () at /usr/lib/crystal/crystal/main.cr:127

Workaround

Do not upgrade mesa package to version 22.0.

System

Archlinux kernel 5.17.1-arch1-1 x86_64
Video: Intel Corporation UHD Graphics 620 (rev 07)
GTK: 4.6.2
mesa: 22.0.0

`Gtk::CssProvider::ParsingErrorSignal#connect` does not compile

css_provider = Gtk::CssProvider.new
css_provider.parsing_error_signal.connect do |section, error|
  # debug
end

This code does not compile with the following error message:

In lib/libadwaita/lib/gi-crystal/src/auto/gtk-4.0/css_provider.cr:198:74

 198 | ::Box(Proc(Gtk::CssSection, GLib::Error, Nil)).unbox(_lib_box).call(section, error)
                                                                      ^---
Error: no overload matches 'Proc(Gtk::CssSection, GLib::Error, Nil)#call' with types Gtk::CssSection, Pointer(Void)

Overloads are:
 - Proc(*T, R)#call(*args : *T)

The generated code:

      def connect(handler : Proc(Gtk::CssSection, GLib::Error, Nil), *, after : Bool = false) : GObject::SignalConnection
        _box = ::Box.box(handler)
        handler = ->(_lib_sender : Pointer(Void), lib_section : Pointer(Void), lib_error : Pointer(Void), _lib_box : Pointer(Void)) {
          # Generator::BuiltInTypeArgPlan
          section = Gtk::CssSection.new(lib_section, :none)
          error = lib_error
          ::Box(Proc(Gtk::CssSection, GLib::Error, Nil)).unbox(_lib_box).call(section, error)
        }.pointer

        handler = LibGObject.g_signal_connect_data(@source, name, handler,
          GICrystal::ClosureDataManager.register(_box), ->GICrystal::ClosureDataManager.deregister, after.to_unsafe)
        GObject::SignalConnection.new(@source, handler)
      end

GI-Crystal version: 0.12.0
Crystal version: 1.4.1

`target` in `Gio::MenuItem#set_action_and_target_value` cannot be set (Runtime Exception)

The GVariant target cannot be passed to Gio::MenuItem#set_action_and_target_value.

Test code:

require "gtk4"

menu_item = Gio::MenuItem.new(nil, nil)

# Does not work
variant = GLib::Variant.new("test")
menu_item.set_action_and_target_value("app.some_action", variant)

# Also does not work
menu_item.set_action_and_target_value("app.some_action", "test")

# Not even this works
menu_item.set_action_and_target_value("app.some_action", nil)

Exception:

# Exception 1

Unhandled exception: Unable to wrap a Pointer(Void) into a GVariant. (ArgumentError)
  from lib/gtk4/lib/gi-crystal/src/bindings/g_lib/variant.cr:20:15 in 'initialize'
  from lib/gtk4/lib/gi-crystal/src/bindings/g_lib/variant.cr:5:5 in 'new'
  from lib/gtk4/lib/gi-crystal/src/auto/gio-2.0/menu_item.cr:272:7 in 'set_action_and_target_value'
  from src/test2.cr:19:1 in '__crystal_main'
  from /usr/share/crystal/src/crystal/main.cr:115:5 in 'main_user_code'
  from /usr/share/crystal/src/crystal/main.cr:101:7 in 'main'
  from /usr/share/crystal/src/crystal/main.cr:127:3 in 'main'
  from /lib64/libc.so.6 in '??'
  from /lib64/libc.so.6 in '__libc_start_main'
  from /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp in '_start'
  from ???

# Exception 2

Unhandled exception: Unable to wrap a Pointer(UInt8) into a GVariant. (ArgumentError)
  from lib/gtk4/lib/gi-crystal/src/bindings/g_lib/variant.cr:5:5 in 'initialize'
  from lib/gtk4/lib/gi-crystal/src/bindings/g_lib/variant.cr:5:5 in 'new'
  from lib/gtk4/lib/gi-crystal/src/auto/gio-2.0/menu_item.cr:272:7 in 'set_action_and_target_value'
  from src/test2.cr:17:1 in '__crystal_main'
  from /usr/share/crystal/src/crystal/main.cr:115:5 in 'main_user_code'
  from /usr/share/crystal/src/crystal/main.cr:101:7 in 'main'
  from /usr/share/crystal/src/crystal/main.cr:127:3 in 'main'
  from /lib64/libc.so.6 in '??'
  from /lib64/libc.so.6 in '__libc_start_main'
  from /var/home/blobcodes/.cache/crystal/crystal-run-test2.tmp in '_start'
  from ???

Gio::MenuItem#set_action_and_target_value implementation:

    def set_action_and_target_value(action : ::String?, target_value : _?) : Nil
      # g_menu_item_set_action_and_target_value: (Method)
      # @action: (nullable)
      # @target_value: (nullable)
      # Returns: (transfer none)

      # Generator::NullableArrayPlan
      action = if action.nil?
                 Pointer(LibC::Char).null
               else
                 action.to_unsafe
               end

      # Generator::NullableArrayPlan
      target_value = if target_value.nil?
                       Pointer(Void).null
                     else
                       target_value.to_unsafe
                     end

      # Generator::HandmadeArgPlan
      target_value = GLib::Variant.new(target_value) unless target_value.is_a?(GLib::Variant)

      # C call
      LibGio.g_menu_item_set_action_and_target_value(self, action, target_value)

      # Return value handling
    end

I think the conversion to a GLib::Variant has to be done before using to_unsafe.

GICrystal::ObjectCollectedError when trying to bind to a property from a UiTemplate

Using a property binding from within a .ui file will result in a GICrystal::ObjectCollectedError being raised.

Here's an example:

require "gtk4"

APP_ID = "com.example.test"

@[Gtk::UiTemplate(file: "src/test.ui")]
class TestWindow < Gtk::ApplicationWindow
  include Gtk::WidgetTemplate

  @[GObject::Property]
  property test = "hello"

  def initialize()
    super()
  end
end

app = Gtk::Application.new(APP_ID, Gio::ApplicationFlags::None)

app.activate_signal.connect do
  window = TestWindow.new
  window.application = app

  window.present
end

exit(app.run(ARGV))

test.ui:

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk" version="4.0"/>
  <template class="TestWindow" parent="GtkApplicationWindow">
    <property name="title" bind-source="TestWindow" bind-property="test" bind-flags="sync-create"/>
  </template>
</interface>

Output:

Unhandled exception:  (GICrystal::ObjectCollectedError)
  from src/test.cr:6:1 in '_vfunc_unsafe_get_property'
  from src/test.cr:6:1 in '->'
  from /lib64/libgobject-2.0.so.0 in 'g_object_get_property'
  from /lib64/libgobject-2.0.so.0 in '??'
  from /lib64/libgobject-2.0.so.0 in 'g_object_bind_property_full'
  from /lib64/libgobject-2.0.so.0 in 'g_object_bind_property'
  from /lib64/libgtk-4.so.1 in '??'
  from /lib64/libgtk-4.so.1 in 'gtk_builder_extend_with_template'
  from /lib64/libgtk-4.so.1 in 'gtk_widget_init_template'
  from src/test.cr:7:3 in '_instance_init'
  from src/test.cr:6:1 in '->'
  from /lib64/libgobject-2.0.so.0 in 'g_type_create_instance'
  from /lib64/libgobject-2.0.so.0 in '??'
  from /lib64/libgobject-2.0.so.0 in 'g_object_newv'
  from lib/gi-crystal/src/bindings/g_object/object.cr:607:18 in 'initialize'
  from lib/gi-crystal/src/auto/g_object-2.0/initially_unowned.cr:17:7 in 'initialize'
  from lib/gi-crystal/src/auto/gtk-4.0/widget.cr:26:7 in 'initialize'
  from lib/gi-crystal/src/auto/gtk-4.0/window.cr:35:7 in 'initialize'
  from lib/gi-crystal/src/auto/gtk-4.0/application_window.cr:41:7 in 'initialize'
  from src/test.cr:13:5 in 'initialize'
  from src/test.cr:12:3 in 'new'
  from src/test.cr:20:12 in '->'
  from lib/gi-crystal/src/auto/gio-2.0/application.cr:770:44 in '->'
  from /lib64/libgobject-2.0.so.0 in 'g_closure_invoke'
  from /lib64/libgobject-2.0.so.0 in '??'
  from /lib64/libgobject-2.0.so.0 in '??'
  from /lib64/libgobject-2.0.so.0 in 'g_signal_emit_valist'
  from /lib64/libgobject-2.0.so.0 in 'g_signal_emit'
  from /lib64/libgio-2.0.so.0 in '??'
  from /lib64/libgio-2.0.so.0 in 'g_application_run'
  from lib/gi-crystal/src/auto/gio-2.0/application.cr:544:7 in 'run'
  from src/test.cr:26:6 in '__crystal_main'
  from /usr/share/crystal/src/crystal/main.cr:129:5 in 'main_user_code'
  from /usr/share/crystal/src/crystal/main.cr:115:7 in 'main'
  from /usr/share/crystal/src/crystal/main.cr:141:3 in 'main'
  from /lib64/libc.so.6 in '??'
  from /lib64/libc.so.6 in '__libc_start_main'
  from /home/leah/.cache/crystal/crystal-run-test.tmp in '_start'
  from ???

Cannot initialize Graphene::Rect

The following code:

require "gtk4"

Graphene::Rect.new(
  origin: Graphene::Point.zero,
  size: Graphene::Size.zero
)

Results in the following compile-time exception:

In lib/gtk4/src/graphene-1.0/rect.cr:45:61

 45 | _var = (@pointer + 0).as(Pointer(LibGraphene::Point)).value = value.to_unsafe
                                                            ^----
Error: no overload matches 'Pointer(LibGraphene::Point)#value=' with type Pointer(Void)

Overloads are:
 - Pointer(T)#value=(value : T)

Gtk::Snapshot#append_border does not compile

The following code does not compile:

require "gtk4"

snapshot = Gtk::Snapshot.new

size = Graphene::Size.new(148, 405)

rect = Graphene::Rect.new(
  origin: Graphene::Point.new(0.0_f32, 0.0_f32),
  size: size
)

rounded_rect = Gsk::RoundedRect.new.init_from_rect(
  bounds: rect,
  radius: 90.0
)

snapshot.append_border(rounded_rect, [10f32, 10f32, 10f32, 10f32], [Gdk::RGBA.new(1.0, 0.0, 0.0, 1.0), Gdk::RGBA.new(1.0, 0.0, 0.0, 1.0), Gdk::RGBA.new(1.0, 0.0, 0.0, 1.0), Gdk::RGBA.new(1.0, 0.0, 0.0, 1.0)])

With the following error message:

In lib/gtk4/lib/gi-crystal/src/auto/gtk-4.0/snapshot.cr:58:56

 58 | LibGtk.gtk_snapshot_append_border(self, outline, border_width, border_color)
                                                       ^-----------
Error: argument 'border_width' of 'LibGtk#gtk_snapshot_append_border' must be Pointer(StaticArray(Float32, 4)), not Pointer(Float32)

GTK 4 Installation on linux mint 19 (64 bits)

I am not able to install the GTK4 dependendies.

$ sudo apt-get install libgtk-4-1 libgirepository1.0-dev gobject-introspection gir1.2-gtk-4.0

[sudo] password for .....
Reading package lists... Done
Building dependency tree
Reading state information... Done
Package libgtk-4-1 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'libgtk-4-1' has no installation candidate
E: Unable to locate package gir1.2-gtk-4.0
E: Couldn't find any package by glob 'gir1.2-gtk-4.0'
E: Couldn't find any package by regex 'gir1.2-gtk-4.0'

Update docs at https://hugopl.github.io/gtk4.cr/

I'm seeing awesome progress on this shard <3. I would like to continue my Crystal & GUI app-dev journey and I was thinking if you could update the docs in your site. I see 0.5.0v and looks like it's on 0.7.0 now. Thanks!

Gtk::Picture constructed using #new_for_? constructors print warning when garbage collected

The following code:

require "gtk4"

app = Gtk::Application.new("test.test", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  2.times { Gtk::Picture.new_for_filename(nil) }
  GC.collect
end
exit(app.run(ARGV))

Prints the following error message when run:

~Gtk::Picture at 0x15a2170 - ref count: 1

(crystal-run-test2.tmp:21424): Gtk-WARNING **: 15:54:42.874: A floating object was finalized. This means that someone
called g_object_unref() on an object that had only a floating
reference; the initial floating reference is not owned by anyone
and must be removed with g_object_ref_sink().

Also, this code:

require "gtk4"

app = Gtk::Application.new("test.test", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  2.times do
    box = Gtk::Box.new
    box.append Gtk::Picture.new_for_filename(nil)
  end
  GC.collect
end
exit(app.run(ARGV))

Even prints a critical error:

~Gtk::Box at 0x124d160 - ref count: 1
~Gtk::Picture at 0x1196170 - ref count: 0

(crystal-run-test2.tmp:22325): GLib-GObject-CRITICAL **: 16:02:42.554: g_object_unref: assertion 'G_IS_OBJECT (object)' failed

I don't know if those are actually two distinct errors, but they seem similar.

`Graphene::Rect#origin=` does not work

Generated code:

    def origin=(value : Graphene::Point)
      # Property setter
      _var = (@pointer + 0).as(Pointer(Void)).value = value.to_unsafe
      value
    end

Resulting error:

Error: no overload matches 'Pointer(Void)#value=' with type Pointer(Void)

Overloads are:
 - Pointer(T)#value=(value : T)

`Gtk::UiTemplate` always requires children

When trying to assign a ui template to a class without any children, you can't just leave out the children field in the annotation.

@[Gtk::UiTemplate(file: "(some path)", children: [] of Symbol)]
class Test < Gtk::Box
end

This works.

@[Gtk::UiTemplate(file: "(some path)")]
class Test < Gtk::Box
end

This raises the following exception:

In lib/gtk4/lib/gtk4/src/bindings/gtk/widget_template.cr:45:58

 45 | {% for child in @type.annotation(Gtk::UiTemplate)[:children] %}
                                                       ^
Error: `for` expression must be an array, hash, tuple, named tuple or a range literal, not NilLiteral:

nil

Glib seems to expect the first parameter of ARGV to be the app name

Using the following code:

require "gtk4"

app = Gtk::Application.new("test.test", Gio::ApplicationFlags::None)
exit(app.run(ARGV))

In the command line (app built as test2 in this example):

[blobcodes@toolbox mangaba]$ ./test2

(test2:23128): GLib-GIO-WARNING **: 16:10:17.211: Your application does not implement g_application_activate() and has no handlers connected to the 'activate' signal.  It should do one of these.
⬢[blobcodes@toolbox mangaba]$ ./test2 my_app_name

(my_app_name:23157): GLib-GIO-WARNING **: 16:10:35.782: Your application does not implement g_application_activate() and has no handlers connected to the 'activate' signal.  It should do one of these.
⬢[blobcodes@toolbox mangaba]$ ./test2 --help

(--help:23191): GLib-GIO-WARNING **: 16:10:52.199: Your application does not implement g_application_activate() and has no handlers connected to the 'activate' signal.  It should do one of these.
⬢[blobcodes@toolbox mangaba]$ ./test2 my_app_name --help
Usage:
  my_app_name [OPTION…]

Help Options:
  -h, --help                 Show help options
  --help-all                 Show all help options
  --help-gapplication        Show GApplication options

Using test2 --help did not open the help dialog but instead showed in the error message that our app is called --help.

To fix this, we would need to pass ARGV_UNSAFE to app.run, which we cannot because Pointer is not Enumerable.

We would need something like this:

require "gtk4"

app = Gtk::Application.new("test.test", Gio::ApplicationFlags::None)

argv_unsafe_as_enumerable = Array.new(ARGC_UNSAFE) do |i|
  String.new(ARGV_UNSAFE[i])
end
exit(app.run(argv_unsafe_as_enumerable))

..or:

require "gtk4"

app = Gtk::Application.new("test.test", Gio::ApplicationFlags::None)
exit(app.run([PROGRAM_NAME, *ARGV]))

So the examples need to be changed and it would be useful to be able to pass ARGV_UNSAFE directly to app.run. But I don't really know what's the best way to deal with this issue.

widget_template_using_resource.cr example is broken

When I try running the widget_template_using_resource.cr example I get this error below. I tried changing the path to "./resource.xml" or just "resource.xml" but I get the same error.

avrameisner@AvramsMBPM114 browser % crystal run lib/gtk4/examples/widget_template_using_resource.cr
ld: warning: ignoring duplicate libraries: '-lglib-2.0', '-lgobject-2.0', '-lintl'
Failed to open file “examples/resource.xml”: No such file or directory
Unhandled exception: Error opening file with mode 'r': 'crystal-gio-resource.gresource': No such file or directory (File::NotFoundError)
  from /opt/homebrew/Cellar/crystal/1.11.1/share/crystal/src/crystal/system/unix/file.cr:12:7 in 'open'
  from /opt/homebrew/Cellar/crystal/1.11.1/share/crystal/src/file.cr:162:5 in 'new'
  from /opt/homebrew/Cellar/crystal/1.11.1/share/crystal/src/file.cr:725:5 in 'read'
  from /opt/homebrew/Cellar/crystal/1.11.1/share/crystal/src/file.cr:739:3 in 'read'
  from lib/gtk4/examples/widget_template_using_resource.cr:25:12 in '__crystal_main'
  from /opt/homebrew/Cellar/crystal/1.11.1/share/crystal/src/crystal/main.cr:129:5 in 'main_user_code'
  from /opt/homebrew/Cellar/crystal/1.11.1/share/crystal/src/crystal/main.cr:115:7 in 'main'
  from /opt/homebrew/Cellar/crystal/1.11.1/share/crystal/src/crystal/main.cr:141:3 in 'main'

My specs: M1 MacBook Pro with macOS Sonoma 14.2.1 (23C71)

Error with ./gsk-4.0/path_point.cr

Edit: I realize this is most likely an issue with gi-crystal, but I'll leave the issue here as it also affects this repo as well

after cloning the repo and running shards install, running ./bin/gi-crystal gives the following output:

info - Starting at 2023-10-21 23:09:45 -05:00, project dir: /home/conner/git-projects/gtk4.cr
info - Gi-Crystal version 0.19.0, built with Crystal 1.9.2.
info - Generating bindings at /home/conner/git-projects/gtk4.cr/lib/gi-crystal/src/auto
info - Using binding config at /home/conner/git-projects/gtk4.cr/src/bindings/gdk/binding.yml
info - Using binding config at /home/conner/git-projects/gtk4.cr/src/bindings/gsk/binding.yml
info - Using binding config at /home/conner/git-projects/gtk4.cr/src/bindings/gtk/binding.yml
info - Using binding config at /home/conner/git-projects/gtk4.cr/lib/gi-crystal/src/bindings/g_lib
/binding.yml
info - Using binding config at /home/conner/git-projects/gtk4.cr/lib/gi-crystal/src/bindings/g_obj
ect/binding.yml
info - Using binding config at /home/conner/git-projects/gtk4.cr/lib/harfbuzz/src/bindings/harfbuz
z/binding.yml
info - Using binding config at /home/conner/git-projects/gtk4.cr/lib/gio/src/bindings/gio/binding.
yml
info - Using binding config at /home/conner/git-projects/gtk4.cr/lib/pango/src/bindings/pango/bind
ing.yml
info - Gdk - No binding config found for cairo-1.0.
info - Gdk - No binding config found for PangoCairo-1.0.
info - Gdk - No binding config found for GdkPixbuf-2.0.
warn - Gdk::TimeCoord axes field - Unknown conversion to crystal for fixed size array.
info - HarfBuzz - No binding config found for freetype2-2.0.
warn - HarfBuzz - Interface constant not supported.
warn - g_cancellable_connect - Callback without user_data!
warn - Gio::ActionEntry padding field - Unknown conversion to crystal for fixed size array.
warn - Gio::DBusInterfaceVTable padding field - Unknown conversion to crystal for fixed size array
.
warn - Gio::DBusSubtreeVTable padding field - Unknown conversion to crystal for fixed size array.
info - GdkPixbuf - No binding config found for GModule-2.0.
warn - gdk_pixbuf_get_options - Unknown conversion to crystal for GHash
info - Gsk - No binding config found for Graphene-1.0.
warn - gsk_border_node_get_widths - Unknown conversion to crystal for fixed size array.
warn - Boxed not working for enums
warn - Gtk::BuildableParser padding field - Unknown conversion to crystal for fixed size array.
syntax error in './gsk-4.0/path_point.cr:122:13': can't use variable name 'center' inside assignme
nt to variable 'center'
fatal - Error formating generated files at '/home/conner/git-projects/gtk4.cr/lib/gi-crystal/src/a
uto'.

Most notable being the actual error:
`syntax error in './gsk-4.0/path_point.cr:122:13': can't use variable name 'center' inside assignment to variable 'center'
fatal - Error formating generated files at '/home/conner/git-projects/gtk4.cr/lib/gi-crystal/src/auto'.`

I'm not sure if I have improper versions of programs or what, I can provide extra information as needed!

crystal: 1.9.2
gtk+4: 4.13.0
gobject-introspection: 1.72.0

Add more options to `register_resource`

On Collision I use the --sourcedir flag while compiling resources with glib-compile-resources. Should register_resource accept an extra parameter for it or maybe just an extra parameter for extra flags?

eg.

  macro register_resource(resource_file, flags)
    {%
      `glib-compile-resources #{flags} --target crystal-gio-resource.gresource #{resource_file}`
...

register_resource("./data.gresource.xml", "--sourcedir data")

Add CI to the project

Would be nice to have github actions to run the tests like https://github.com/hugopl/gi-crystal, this would also allow the project to be listed into https://github.com/veelenga/awesome-crystal.

The only reason I didn't do this before is because the default ubuntu image used on github actions doesn't have a GTK4 package OR I didn't tried enough.

If you want to help the project this is a good start, to run the tests you need to:

  • clone the repo.
  • run ./bin/gi-crystal to generate the bindings.
  • run crystal spec

Automatic documentation upload to gh-pages branch

Currently, the documentation at https://hugopl.github.io/gtk4.cr/ is made "manually", I mean... every time I need to update it I do:

git checkout gh-pages
git rm doc
git merge WHATEVER_NEW_VERSION
make doc
git add doc
git push origin gh-pages

These are simple and static steps that can be automatized by a github actions that runs every time a new tag is created in the repository.

Gtk::GestureDrag and retrieving x,y coordinates

Working on interactive constraints and trying to call methods
to get the point where the drag started

def start_point(x : Float64 | Nil, y : Float64| Nil) : Bool
end

and to get the offset from the start point.

def offset(x : Float64 | Nil, y : Float64 | Nil ) : Bool

If the gesture is active, this function returns true and fills in x and y with the drag start coordinates, in surface-relative coordinates

These x,y parameters are passed by value and not by reference, so not sure how these x,y values are returned.

The compiler complains with error

In lib/gi-crystal/src/auto/gtk-4.0/gesture_drag.cr:115:21

 115 | Float64.null

Removing widgets results in unstable behavior

Using the following code:

require "gtk4"

app = Gtk::Application.new("com.example.issue", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  window = Gtk::ApplicationWindow.new(app)
  box = Gtk::Box.new
  window.child = box

  label = Gtk::Label.new(label: "Test!")
  box.append(label)
  box.remove(label)

  window.present

  GLib.timeout_seconds(5) do
    GC.collect
    false
  end
end
app.run(ARGV)

Results in the following output (using -Ddebugmemory):

~Gtk::ApplicationWindow at 0x18f0350 - ref count: 2
~Gtk::Box at 0x183f180 - ref count: 1

(crystal-run-test2.tmp:54281): Gtk-CRITICAL **: 22:26:25.976: GtkBox 0x183f180 has a parent GtkApplicationWindow 0x18f0350 during dispose. Parents hold a reference, so this should not happen.
Did you call g_object_unref() instead of gtk_widget_unparent()?
~Gtk::Label at 0x18c6180 - ref count: 0

(crystal-run-test2.tmp:54281): GLib-GObject-CRITICAL **: 22:26:25.976: g_object_unref: assertion 'G_IS_OBJECT (object)' failed

(crystal-run-test2.tmp:54281): Gtk-CRITICAL **: 22:26:28.854: gtk_accessible_get_accessible_role: assertion 'GTK_IS_ACCESSIBLE (self)' failed

[continues like this]

..while making the program unstable (ex. header bar disappears or buttons in gtk inspector move to random places):
Bildschirmfoto vom 2022-04-13 22-37-42

[Feature Request] libadwaita bindings

I'm not sure if this is outside the scope of this repo but would be nice to have!
I don't know if gi-crystal is able to generate bindings for it (I couldn't manage to create them from a quick try).

Additional context:
I have to migrate Hashbrown to GTK 4 and need to follow GNOME HIG. Currently, with crystal-gobject I'm able to use libhandy widgets (through Glade ui files at least), but using gtk4.cr I get the following (expected) error:

(Test ui file with an `AdwAvatar` widget)

Gtk-ERROR **: 11:52:58.647: failed to add UI from file /home/geopjr/projects/gtk4.cr/examples/adw_test.ui: /home/geopjr/projects/gtk4.cr/examples/adw_test.ui:12:1 Invalid object type 'AdwAvatar'

Shards install error

Hi!

I'm completely new to Crystal, so this might be (or probably, rather) an issue on my end. However, when I try installing gtk4.cr in my project, I get the error in the screenshot:
image

Steps:

  1. shards init
  2. Add gtk4.cr as dependency. shard.yml looks like this:
name: 
version: 0.1.0

dependencies:
  gtk4:
    github: hugopl/gtk4.cr
  1. shards install
  2. The error mentioned above happens

Thanks in advance!
Cheers!


Also completely unrelated, but I thought I'd ask since you seem like a Crystal expert :D What's your IDE of choice for Crystal development? I couldn't get nvim to syntax highlight, so VScodium with the Crystal-lang extension seems to be the only option. I saw you were working on your own IDE as well, but that's still relatively early in development.

Thanks again!!

Gtk::Widget docs are incomplete

Currently, when generating the docs, the Gtk::Widget page ends like this:
Bildschirmfoto vom 2022-01-03 15-01-06

This is the related code:

  #     </object>
  #   </child>
  # </object>
  # ```
  #
  # `GtkWidget` allows style information such as style classes to
  # be associated with widgets, using the custom `<style>` element:
  #
  # ```xml

So it seems like the <style> element is actually interpreted as an html style element.

Git repo size very big (gh_pages branch?)

When trying to clone this git repo, I see the following on the terminal:

⬢[blobcodes@toolbox ~]$ time git clone https://github.com/hugopl/gtk4.cr.git
Cloning into 'gtk4.cr'...
remote: Enumerating objects: 46671, done.
remote: Counting objects: 100% (4742/4742), done.
remote: Compressing objects: 100% (369/369), done.
remote: Total 46671 (delta 4297), reused 4741 (delta 4297), pack-reused 41929
Receiving objects: 100% (46671/46671), 89.76 MiB | 9.54 MiB/s, done.
Resolving deltas: 100% (42290/42290), done.

real	0m18.722s
user	0m51.873s
sys	0m1.766s

The repo is just under 90 MB big, which will be downloaded everytime I use shards update. As you can see, this takes over 18 seconds, which is a lot for such a simple shard. Also I don't have the worst internet connection, others will probably need even more time.

I think this is because when cloning the repo, you download every version of the docs in the gh-pages branch. That is not really necessary and I would recommend either using GitLab CI so the docs do not need to be uploaded to the repo or to automatically purge the gh-pages branch.

Setting `can_target` in widget constructor does not work

I don't know if this is because of gtk4.cr or because of gtk itself, but the following code does not actually set can_target to false:

require "gtk4"

app = Gtk::Application.new("test.test", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  window = Gtk::Window.new(application: app)

  # Does not work
  window.child = Gtk::Button.new(can_target: false)
  # Does work
  # window.child = Gtk::Button.new.tap { |btn| btn.can_target = false }

  window.present
end
exit(app.run(ARGV))

can_target is not the only variable where this happens, the variables can_focus and focusable also have the same issue.

As shown in the inspector:
Bildschirmfoto vom 2022-04-11 14-17-27

Gdk::Texture.new_from_filename doesn't work (among other methods)

In this example code:

require "gtk4"

app = Gtk::Application.new("test.application", Gio::ApplicationFlags::None)
app.activate_signal.connect do
  window = Gtk::ApplicationWindow.new(app)
  texture = Gdk::Texture.new_from_filename("/path/to/image.png")
  window.child = Gtk::Picture.new_for_paintable(texture)
  window.present
end

exit(app.run(ARGV))

Using a Gdk::Texture created using the new_from_filename method doesn't work, printing the following messages to the console:

(crystal-run-test2.tmp:59108): Gdk-CRITICAL **: 01:54:55.937: gdk_texture_new_from_filename: assertion 'error == NULL || *error == NULL' failed
#<Gdk::Texture:0x7f906d33bde0>

(crystal-run-test2.tmp:59108): Gdk-CRITICAL **: 01:54:55.937: gdk_texture_get_height: assertion 'GDK_IS_TEXTURE (texture)' failed

I already found a fix, but there are lots of methods which have this issue, it probably needs a fix in gi-crystal.
The Gdk4 docs mention that this method requires an additional GError argument, which this library does not pass to the method.

Generated bindings:

lib LibGdk
  fun gdk_texture_new_from_filename(path : Pointer(LibC::Char)) : Pointer(Void)
end

class Gdk::Texture
    def self.new_from_filename(path : ::String) : Gdk::Texture
      # gdk_texture_new_from_filename: (Constructor | Throws)
      # Returns: (transfer full)

      _retval = LibGdk.gdk_texture_new_from_filename(path)
      Gdk::Texture.new(_retval, GICrystal::Transfer::Full)
    end
end

My modifications, which work:

lib LibGdk
  fun gdk_texture_new_from_filename(path : Pointer(LibC::Char), error : Void**) : Pointer(Void)
end

class Gdk::Texture
  def self.new_from_filename(path : ::String) : Gdk::Texture
    ptr = Pointer(Void).null
    _retval = LibGdk.gdk_texture_new_from_filename(path, pointerof(ptr))
    raise GLib::Error.new(ptr, GICrystal::Transfer::Full).message unless ptr.null?
    Gdk::Texture.new(_retval, GICrystal::Transfer::Full)
  end
end

Clipboard read_value_finish

I am working on a Gtk4 Clipboard example and need to call the method clipboard.read_value_finish

  @[GObject::Virtual]
  def activate
    ui  = get_ui()
    builder     = Gtk::Builder.new_from_string(ui, ui.bytesize.to_i64)
    window      = Gtk::Window.cast(builder["window"])
    text_entry  = Gtk::Entry.cast(builder["source_text"])
    text_entry.changed_signal.connect do
      text_entry_changed(text_entry)
    end

    source_file    = Gtk::Button.cast(builder["source_file"])
    copy_button  = Gtk::Button.cast(builder["copy_button"])
    paste_button = Gtk::Button.cast(builder["paste_button"])
    combobox     = Gtk::DropDown.cast(builder["source_chooser"])
    source_stack = Gtk::Stack.cast(builder["source_stack"])
    dest_stack     = Gtk::Stack.cast(builder["dest_stack"])

    source_clipboard   = source_stack.clipboard
    visible_child_name = ""

    copy_button.clicked_signal.connect do
      visible_child      = source_stack.visible_child
      visible_child_name = source_stack.visible_child_name
      case visible_child_name
        when "Text"

          text = visible_child.as(Gtk::Editable).text
          source_clipboard.set(text)
        when "Color"
        when "Image"
        when "File"
      end
    end

    paste_button.clicked_signal.connect do
      dest_clipboard = dest_stack.clipboard
      case visible_child_name
        when "Text"
          result = Gio::AsyncResult.new # ?????
          value  = source_clipboard.read_value_finish(result)
          if value
            dest_stack.set_visible_child_name = "Text"
            child = dest_stack.visible_child
            child.as(Gtk::Label).text = value
          end
      end
    end

    window.application = self
    window.present
  end

Problem I have is that the argument result has to be of type Gio::AsyncResult which is a module

Platform
Linux 21
Crystal 1.9.2 [1908c816f] (2023-07-19)
libgtk-4-1

`Gdk::ContentProvider#value` must accept a GType somehow

Using Gtk::TextBuffer#selection_content returns a Gdk::ContentProvider object, this object can return its contents wrapped in a GValue, however the called must initialize the GValue to the right type before calling Gdk::ContentProvider#value, otherwise an error is thrown when e.g. a call for #as_s is done in the returned GValue:

Unhandled exception: Cannot obtain raw value for g_type 0 (ArgumentError)
  from lib/gi-crystal/src/bindings/g_object/value.cr:113:9 in 'raw'
  from lib/gi-crystal/src/bindings/g_object/value.cr:120:7 in 'raw'
  from lib/gi-crystal/src/bindings/g_object/value.cr:123:5 in 'as_s'

Current Gdk::ContentProvider#value generated binding implementation:

    def value : GObject::Value
      # gdk_content_provider_get_value: (Method | Throws)
      # @value: (out) (caller-allocates)
      # Returns: (transfer none)

      _error = Pointer(LibGLib::Error).null

      # Generator::CallerAllocatesPlan
      value = GObject::Value.new
      # C call
      _retval = LibGdk.gdk_content_provider_get_value(to_unsafe, value, pointerof(_error))

      # Error check
      Gdk.raise_gerror(_error) unless _error.null?

      # Return value handling
      value
    end

Note that the return value is also lost... i.e. I need to decide what to do with the tons of out values the GTK API has.

Is there a particular reason why when I search the docs for seeing where a file it is defined in, I am getting a 404?

Hi, I am trying to make a GUI game engine with Crystal, and I wanted to use this library for GTK bindings. I am not trying to make an efficient 2-D/3-D engine, just one that works with simple design. I was browsing the docs for seeing where what is defined where and a lot come up with 404. I was wondering if it was normal: https://hugopl.github.io/gtk4.cr/

Thank you, otherwise keep up the great work! I love the idea of this project, regardless if I use GTK for my Game Engine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.