Giter VIP home page Giter VIP logo

crystal-gobject's People

Contributors

aljelly avatar christopherzimmerman avatar fancycade avatar hugopl avatar jhass avatar mvz avatar ppibburr avatar renich avatar thiagojedi avatar viachpaliy 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  avatar

Watchers

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

crystal-gobject's Issues

About fun _init_AnyClass = gtk_any_class_get_type

I think, all this fun (for example, _init_AboutDialog) only return GType(a numerical value which represents the unique identifier of a registered type), not initialize any instance of class.Their uses in initialize methods make no sense.
It is only my opinion.

Freebsd, sample hello world fails.

crystal run samples/gtk_hello_world.cr
returns :
Syntax error in lib/gobject/g_i_repository/info/base_info.cr:115: unexpected token: :
def dump(dumper, & : BaseInfo ->)
I

How to explore methods of Gtk?

This is probably a noob question, so I admit I am pretty unfamiliar with Gtk and relatively new in Crystal. But I think the former is great to get a real app build and the latter is just a breeze to write.
So here come the question:

How is the best way to find out, what classes are available and how the methods are called on them? I am reading the GTK docs and also found great course material about TextView but they explain and describe the C code.

An example: Making a GTK TextView object editable seems to be done in C using

gtk_text_view_set_editable (text_view, true);

But to do this in Crystal I have to do this:

gtk_text_view_set_editable (text_view, true);

And how gtk_text_buffer_get_iter_at_line(โ€ฆ) translates to Crystal I have no clue, cannot find a similar method on the Gtk::TextBuffer instance. For this I use a macro that prints out all methods of a class.

So, what transformations are done with all the classes and methods? How do the C code translate to Crystal code? How is the best way to explore it? I somehow cannot really read it from the code in this Repo, so it seems still magic to me. :)

I appreciate a hint where to look and I strongly appreciate this Library and the work you put into it. Great stuff. Also, the examples also helped a bit (although the CSS example does not work for me, but that's probably another story I can figure out, when I know how to figure stuff out...)

So: Thanks again and in advance ๐Ÿ‘

Another GC related crash, now 100% reproduceable.

I thought about create this issue at malloc_pthread_shim shard, but as it's a fix for this one, I created here, please correct me if this isn't the right place.

To reproduce the crash:

$ git clone https://github.com/hugopl/tijolo.git
$ cd tijolo && git checkout 5b55a519e37c0c02fb4eed56cbf5f8be87494fe8
$ shards build
$ ./bin/tijolo

The crash doesn't happen with GC disabled. I tried to reduce the code to create a minimal example, but seems that it was not enough entropy to trigger the bug.

If I remove the require "malloc_pthread_shim" at src.main.cr it works... but crash later on GtkSource::Language.set_language as expected.

If I comment lines 66 and 68 (some signal connections) at src/application.cr it works... but probably just a coincidence.... anyway the crash happens inside the setup_actions.

Here's the output with the following libraries compiled as debug:

libgailutil-3.so
libgdk-3.so
libgio-2.0.so
libglib-2.0.so
libgmodule-2.0.so
libgobject-2.0.so
libgthread-2.0.so
libgtk-3.so
$ LD_LIBRARY_PATH=/opt/debug/usr/lib/ GC_PRINT_VERBOSE_STATS=1 ./bin/tijolo
Grow heap to 64 KiB after 0 bytes allocated
Number of processors = 8
Started 7 mark helper threads
Initiating full world-stop collection!
0 bytes in heap blacklisted for interior pointers

--> Marking for collection #1 after 0 allocated bytes
Pushed 1 thread stacks
Starting marking for mark phase number 0
Starting mark helper 0
Starting mark helper 1
Starting mark helper 2
Starting mark helper 3
Starting mark helper 4
Starting mark helper 5
Starting mark helper 6
Starting mark helper 7
Finished mark helper 0
Finished mark helper 7
Finished mark helper 4
Finished mark helper 2
Finished mark helper 1
Finished mark helper 6
Finished mark helper 5
Finished mark helper 3
Finished marking for mark phase number 0
GC #1 freed 0 bytes, heap 64 KiB (+ 0 KiB unmapped)
World-stopped marking took 1 msecs (1 in average)
Bytes recovered before sweep - f.l. count = 0
In-use heap: 0% (0 KiB pointers + 0 KiB other)
Immediately reclaimed 0 bytes, heapsize: 65536 bytes (0 unmapped)
0 finalization entries; 0/0 short/long disappearing links alive
0 finalization-ready objects; 0/0 short/long links cleared
Finalize plus initiate sweep took 0 + 0 msecs
Complete collection took 1 msecs
Adding block map for size of 3 granules (48 bytes)
Grow heap to 156 KiB after 48 bytes allocated
Adding block map for size of 0 granules (0 bytes)
Adding block map for size of 1 granules (16 bytes)
Adding block map for size of 16 granules (256 bytes)
Adding block map for size of 32 granules (512 bytes)
Adding block map for size of 128 granules (2048 bytes)
Adding block map for size of 2 granules (32 bytes)
Adding block map for size of 4 granules (64 bytes)
Adding block map for size of 6 granules (96 bytes)
Adding block map for size of 9 granules (144 bytes)
Adding block map for size of 5 granules (80 bytes)
Adding block map for size of 8 granules (128 bytes)
Adding block map for size of 10 granules (160 bytes)
Adding block map for size of 12 granules (192 bytes)
Grow heap to 220 KiB after 112400 bytes allocated
Adding block map for size of 64 granules (1024 bytes)
Grew fo table to 1 entries
Adding block map for size of 15 granules (240 bytes)
Grew fo table to 2 entries
Grow heap to 296 KiB after 140448 bytes allocated
Adding block map for size of 11 granules (176 bytes)
Grew fo table to 4 entries
Adding block map for size of 7 granules (112 bytes)
Adding block map for size of 17 granules (272 bytes)
Grew fo table to 8 entries
Grew dl table to 1 entries
Adding block map for size of 13 granules (208 bytes)
Grew dl table to 2 entries
Adding block map for size of 21 granules (336 bytes)
Grow heap to 396 KiB after 179504 bytes allocated
Adding block map for size of 20 granules (320 bytes)
Adding block map for size of 14 granules (224 bytes)
Grew fo table to 16 entries
Initiating full world-stop collection!
0 bytes in heap blacklisted for interior pointers

--> Marking for collection #2 after 242816 allocated bytes
Pushed 1 thread stacks
Starting marking for mark phase number 1
Starting mark helper 0
Starting mark helper 1
Starting mark helper 2
Starting mark helper 3
Starting mark helper 4
Starting mark helper 5
Starting mark helper 6
Finished mark helper 3
Finished mark helper 4
Finished mark helper 5
Finished mark helper 0
Finished mark helper 6
Finished mark helper 1
Finished mark helper 2
Finished marking for mark phase number 1
GC #2 freed 0 bytes, heap 396 KiB (+ 0 KiB unmapped)
World-stopped marking took 1 msecs (1 in average)
Bytes recovered before sweep - f.l. count = -126240
In-use heap: 54% (209 KiB pointers + 5 KiB other)
Immediately reclaimed -109856 bytes, heapsize: 405504 bytes (0 unmapped)
10 finalization entries; 3/0 short/long disappearing links alive
1 finalization-ready objects; 0/0 short/long links cleared
Finalize plus initiate sweep took 0 + 0 msecs
Complete collection took 1 msecs
Grow heap to 580 KiB after 0 bytes allocated
Adding block map for size of 42 granules (672 bytes)
Adding block map for size of 24 granules (384 bytes)
Adding block map for size of 50 granules (800 bytes)
Adding block map for size of 84 granules (1344 bytes)
Grow heap to 776 KiB after 354400 bytes allocated
Grow heap to 1036 KiB after 750640 bytes allocated
Adding block map for size of 18 granules (288 bytes)
Initiating full world-stop collection!
4096 bytes in heap blacklisted for interior pointers

--> Marking for collection #3 after 2088480 allocated bytes
Pushed 2 thread stacks
Starting marking for mark phase number 2
Starting mark helper 0
Starting mark helper 1
Starting mark helper 2
Starting mark helper 3
Starting mark helper 4
Starting mark helper 5
Starting mark helper 6
Starting mark helper 7
Finished mark helper 7
Finished mark helper 6
Finished mark helper 0
Finished mark helper 2
Finished mark helper 5
Finished mark helper 1
Finished mark helper 3
Finished mark helper 4
Finished marking for mark phase number 2
Recycle 65536/65536 scratch-allocated bytes at 0x7f6392888000
Grew mark stack to 8192 frames
GC #3 freed -24416 bytes, heap 1100 KiB (+ 0 KiB unmapped)
World-stopped marking took 2 msecs (1 in average)
Bytes recovered before sweep - f.l. count = -230480
In-use heap: 59% (652 KiB pointers + 7 KiB other)
Immediately reclaimed -222288 bytes, heapsize: 1126400 bytes (0 unmapped)
10 finalization entries; 3/0 short/long disappearing links alive
2 finalization-ready objects; 0/0 short/long links cleared
Finalize plus initiate sweep took 0 + 0 msecs
Complete collection took 2 msecs
Adding block map for size of 19 granules (304 bytes)
Adding block map for size of 23 granules (368 bytes)
Grow heap to 1468 KiB after 107824 bytes allocated
Adding block map for size of 22 granules (352 bytes)
Grow heap to 1960 KiB after 607136 bytes allocated
Initiating full world-stop collection!
0 bytes in heap blacklisted for interior pointers

--> Marking for collection #4 after 1296688 allocated bytes
Pushed 3 thread stacks
Starting marking for mark phase number 3
Starting mark helper 0
Starting mark helper 1
Starting mark helper 2
Starting mark helper 3
Starting mark helper 4
Starting mark helper 5
Starting mark helper 6
Starting mark helper 7
Finished mark helper 4
Finished mark helper 6
Finished mark helper 7
Finished mark helper 2
Finished mark helper 1
Finished mark helper 5
Finished mark helper 3
Finished mark helper 0
Finished marking for mark phase number 3
Recycle 131072/131072 scratch-allocated bytes at 0x7f63895c1000
Grew mark stack to 16384 frames
GC #4 freed -92608 bytes, heap 2088 KiB (+ 0 KiB unmapped)
World-stopped marking took 3 msecs (1 in average)
Bytes recovered before sweep - f.l. count = -100080
In-use heap: 72% (1502 KiB pointers + 5 KiB other)
Immediately reclaimed -91888 bytes, heapsize: 2138112 bytes (0 unmapped)
10 finalization entries; 3/0 short/long disappearing links alive
0 finalization-ready objects; 0/0 short/long links cleared
Finalize plus initiate sweep took 0 + 0 msecs
Complete collection took 3 msecs
Grow heap to 2792 KiB after 149440 bytes allocated
Grow heap to 3724 KiB after 978080 bytes allocated
Initiating full world-stop collection!
12288 bytes in heap blacklisted for interior pointers

--> Marking for collection #5 after 2542128 allocated bytes
Pushed 3 thread stacks
Starting marking for mark phase number 4
Starting mark helper 0
Starting mark helper 1
Starting mark helper 2
Starting mark helper 3
Starting mark helper 4
Starting mark helper 5
Starting mark helper 6
Starting mark helper 7
Finished mark helper 0
Finished mark helper 6
Finished mark helper 3
Finished mark helper 4
Finished mark helper 2
Finished mark helper 7
Finished mark helper 1
Finished mark helper 5
Finished marking for mark phase number 4
Recycle 262144/262144 scratch-allocated bytes at 0x7f6388c27000
Grew mark stack to 32768 frames
GC #5 freed -45568 bytes, heap 3980 KiB (+ 0 KiB unmapped)
World-stopped marking took 5 msecs (2 in average)
Bytes recovered before sweep - f.l. count = -77136
In-use heap: 80% (3185 KiB pointers + 5 KiB other)
Immediately reclaimed -64848 bytes, heapsize: 4075520 bytes (0 unmapped)
10 finalization entries; 3/0 short/long disappearing links alive
0 finalization-ready objects; 0/0 short/long links cleared
Finalize plus initiate sweep took 0 + 0 msecs
Complete collection took 6 msecs
Grow heap to 5308 KiB after 343744 bytes allocated
Invalid memory access (signal 11) at address 0x78b
Segmentation fault (core dumped)

exitcode 139.

GDB information about the crash:

(gdb) info threads
  Id   Target Id                                  Frame 
  1    Thread 0x7ffff4116980 (LWP 18561) "tijolo" 0x00007ffff6dda8f4 in do_futex_wait.constprop () from /usr/lib/libpthread.so.0
  2    Thread 0x7ffff4105700 (LWP 18565) "tijolo" 0x00007ffff6dd7e32 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
  3    Thread 0x7ffff3904700 (LWP 18566) "tijolo" 0x00007ffff6dd7e32 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
  4    Thread 0x7ffff3103700 (LWP 18567) "tijolo" 0x00007ffff6dd7e32 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
  5    Thread 0x7ffff2902700 (LWP 18568) "tijolo" 0x00007ffff6dd7e32 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
  6    Thread 0x7ffff2101700 (LWP 18569) "tijolo" 0x00007ffff6dd7e32 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
  7    Thread 0x7ffff1900700 (LWP 18570) "tijolo" 0x00007ffff6dd7e32 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
  8    Thread 0x7ffff10ff700 (LWP 18571) "tijolo" 0x00007ffff6dd7e32 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
* 9    Thread 0x7fffef4f4700 (LWP 18572) "gmain"  0x00007ffff6c7605f in poll () from /usr/lib/libc.so.6

Thread 9 backtrace:

#0  0x00007ffff6c7605f in poll () from /usr/lib/libc.so.6
#1  0x00007ffff70b4f28 in g_main_context_poll (priority=<optimized out>, n_fds=1, fds=0x7fffef807c50, timeout=<optimized out>, context=0x7fffef8839a0) at ../glib/glib/gmain.c:4346
#2  g_main_context_iterate.constprop.0 (context=context@entry=0x7fffef8839a0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib/glib/gmain.c:4042
#3  0x00007ffff7066211 in g_main_context_iteration (context=0x7fffef8839a0, may_block=may_block@entry=1) at ../glib/glib/gmain.c:4108
#4  0x00007ffff7066262 in glib_worker_main (data=<optimized out>) at ../glib/glib/gmain.c:5996
#5  0x00007ffff708f501 in g_thread_proxy (data=0x7fffef7fb360) at ../glib/glib/gthread.c:807
#6  0x00007ffff6e0eb35 in ?? () from /usr/lib/libgc.so.1
#7  0x00007ffff6dfcda7 in GC_call_with_stack_base () from /usr/lib/libgc.so.1
#8  0x00007ffff6dd1422 in start_thread () from /usr/lib/libpthread.so.0
#9  0x00007ffff6c80bf3 in clone () from /usr/lib/libc.so.6

Thread 1 backtrace:

#0  0x00007ffff6dda8f4 in do_futex_wait.constprop () from /usr/lib/libpthread.so.0
#1  0x00007ffff6dda9f8 in __new_sem_wait_slow.constprop.0 () from /usr/lib/libpthread.so.0
#2  0x00007ffff6df3454 in ?? () from /usr/lib/libgc.so.1
#3  0x00007ffff6e01ef9 in ?? () from /usr/lib/libgc.so.1
#4  0x00007ffff6e020bc in ?? () from /usr/lib/libgc.so.1
#5  0x00007ffff6e06a8a in ?? () from /usr/lib/libgc.so.1
#6  0x00007ffff6e06eaf in ?? () from /usr/lib/libgc.so.1
#7  0x00007ffff6e072b7 in ?? () from /usr/lib/libgc.so.1
#8  0x00007ffff6e0b61a in GC_generic_malloc () from /usr/lib/libgc.so.1
#9  0x00007ffff6e0b875 in GC_malloc_kind_global () from /usr/lib/libgc.so.1
#10 0x00007ffff6e0da34 in GC_posix_memalign () from /usr/lib/libgc.so.1
#11 0x0000555555625096 in posix_memalign () at /home/hugo/src/tijolo/lib/malloc_pthread_shim/src/malloc_pthread_shim.cr:200
#12 0x00007ffff708463a in allocator_memalign (memsize=2032, alignment=2048) at ../glib/glib/gslice.c:1411
#13 allocator_add_slab (allocator=0x7ffff713cf00 <allocator>, chunk_size=128, ix=<optimized out>) at ../glib/glib/gslice.c:1283
#14 slab_allocator_alloc_chunk (chunk_size=chunk_size@entry=128) at ../glib/glib/gslice.c:1329
#15 0x00007ffff7085df3 in magazine_cache_pop_magazine (countp=0x7ffff08ed888, ix=7) at ../glib/glib/gslice.c:730
#16 thread_memory_magazine1_reload (ix=7, tmem=<optimized out>) at ../glib/glib/gslice.c:800
#17 g_slice_alloc (mem_size=mem_size@entry=120) at ../glib/glib/gslice.c:1013
#18 0x00007ffff7085e4b in g_slice_alloc0 (mem_size=mem_size@entry=120) at ../glib/glib/gslice.c:1050
#19 0x00007ffff716e629 in g_type_create_instance (type=<optimized out>) at ../glib/gobject/gtype.c:1849
#20 0x00007ffff715ad29 in g_param_spec_internal (param_type=140737288140192, name=name@entry=0x7ffff72e1eed "fd", nick=0x7ffff72d9874 "File descriptor", blurb=blurb@entry=0x7ffff72d9858 "The sockets file descriptor", 
    flags=flags@entry=235) at ../glib/gobject/gparam.c:445
#21 0x00007ffff715af8b in g_param_spec_int (name=name@entry=0x7ffff72e1eed "fd", nick=<optimized out>, blurb=blurb@entry=0x7ffff72d9858 "The sockets file descriptor", minimum=minimum@entry=-2147483648, maximum=maximum@entry=2147483647, 
    default_value=default_value@entry=-1, flags=235) at ../glib/gobject/gparamspecs.c:1784
#22 0x00007ffff7222bb1 in g_socket_class_init (klass=0x7fffef899a80) at ../glib/gio/gsocket.c:961
#23 g_socket_class_intern_init (klass=0x7fffef899a80) at ../glib/gio/gsocket.c:268
#24 0x00007ffff7175092 in type_class_init_Wm (pclass=0x7ffff4110d80, node=0x7fffef83ed20) at ../glib/gobject/gtype.c:2235
#25 g_type_class_ref (type=<optimized out>) at ../glib/gobject/gtype.c:2950
#26 0x00007ffff729d2c1 in ensure_type (gtype=<optimized out>) at ../glib/gio/gdbusprivate.c:222
#27 ensure_required_types () at ../glib/gio/gdbusprivate.c:261
#28 _g_dbus_initialize () at ../glib/gio/gdbusprivate.c:1972
#29 0x00007ffff7291b1a in _g_dbus_initialize () at ../glib/gio/gdbusconnection.c:7334
#30 g_bus_get_sync (bus_type=G_BUS_TYPE_SESSION, cancellable=0x0, error=0x0) at ../glib/gio/gdbusconnection.c:7326
#31 0x00007ffff725fdb9 in g_application_impl_register (error=0x7fffffffdf20, cancellable=0x0, remote_actions=0x7fffef896098, exported_actions=0x7ffff08b1210, flags=G_APPLICATION_NON_UNIQUE, appid=0x7ffff4107880 "io.github.hugopl.Tijolo", 
    application=0x7fffef8960f0) at ../glib/gio/gapplicationimpl-dbus.c:601
#32 g_application_register (application=application@entry=0x7fffef8960f0, cancellable=cancellable@entry=0x0, error=error@entry=0x7fffffffdf20) at ../glib/gio/gapplication.c:2188
#33 0x00007ffff72608ac in g_application_real_local_command_line (application=0x7fffef8960f0, arguments=0x7fffffffdf88, exit_status=0x7fffffffdf84) at ../glib/gio/gapplication.c:1106
#34 0x00007ffff7260c0a in g_application_run (application=0x7fffef8960f0, argc=-8316, argv=<optimized out>) at ../glib/gio/gapplication.c:2528
#35 0x000055555570d496 in run () at /home/hugo/src/tijolo/lib/gobject/src/gtk/gtk.cr:4
#36 0x000055555570c88d in run () at /home/hugo/src/tijolo/src/application.cr:131
#37 0x0000555555609e59 in __crystal_main () at /home/hugo/src/tijolo/src/main.cr:18
#38 0x0000555555785e66 in main_user_code () at /usr/lib/crystal/crystal/main.cr:105
#39 0x0000555555785cfc in main () at /usr/lib/crystal/crystal/main.cr:91
#40 0x0000555555615026 in main () at /usr/lib/crystal/crystal/main.cr:114

The other threads were just waiting...

#0  0x00007ffff6dd7e32 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
#1  0x00007ffff6dfc555 in ?? () from /usr/lib/libgc.so.1
#2  0x00007ffff6dfc657 in ?? () from /usr/lib/libgc.so.1
#3  0x00007ffff6dd1422 in start_thread () from /usr/lib/libpthread.so.0
#4  0x00007ffff6c80bf3 in clone () from /usr/lib/libc.so.6

Environment: Archlinux, crystal 0.35, and debug versions of following Gtk packages: glib2 2.64.2-1, gtk3 1:3.24.20-1, gtksourceview4 4.6.0-1.

LibGranite: unexpected token: NEWLINE

If you manage to get past #37 and try to build something with require_gobject("Granite") included, it fails:

syntax error in /usr/lib/x86_64-linux-gnu/girepository-1.0/Granite-1.0.typelib/ServicesLogger:12
Error: unexpected token: NEWLINE

I don't know if this is due to my hacking around the array constant however.

LibGranite: Unhandled array constant

There's an array constant in this class (Granite-1.0.gir):

<class name="Application" c:type="GraniteApplication" glib:type-name="GraniteApplication" glib:get-type="granite_application_get_type" glib:t
ype-struct="ApplicationClass" parent="Gtk.Application" abstract="1" deprecated="1" deprecated-version="0.5.0">
  <field name="parent_instance">
    <type name="Gtk.Application" c:type="GtkApplication"/>
  </field>
  <field name="priv">
    <type name="ApplicationPrivate" c:type="GraniteApplicationPrivate*"/>
  </field>
  <field name="build_data_dir">
    <type name="utf8" c:type="gchar*"/>
  </field>
...
  <constant name="options" c:identifier="GRANITE_APPLICATION_options" value="(null)">
    <array>
      <type name="GLib.OptionEntry" c:type="GOptionEntry"/>
    </array>
  </constant>

Which results in:

Unhandled exception: Bug: Unhandled constant type ARRAY (Exception)

I tried making it at least compile:

--- constant_info_orig.cr	2020-01-20 07:24:10.511492609 +0000
+++ constant_info.cr	2020-01-20 07:23:23.614319006 +0000
@@ -49,6 +49,8 @@
         when .utf8?
           string = String.new(value.v_string)
           string.inspect
+        when .array?
+          "# ARRAY CONSTANT #{name} #{size}" # ???
         when .interface?
           "# INTERFACE CONSTANT #{name} #{size}" # debug, should never end up being generated
         else
@@ -60,6 +62,8 @@
     def lib_definition
       if type.tag.interface?
         "  # #{name} = ungeneratable value"
+      elsif type.tag.array?
+        "  # #{name} = ???"
       else
         "  #{name} = #{literal} # : #{type.lib_definition}"
       end

And it works (now the bindings at least generate), but this probably isn't how it should be handled. I don't know enough about GIRs or C. StaticArray?

(Granite source is here, relevant line seems to be this)

Getting mouse (x,y) position from Gtk::EventBox

Working on a small program which loads an image into a Gtk::Image.
I am trying to get the mouse (x,y) position when I click on the image and moves
the mouse. Using a Gtk::EventBox around the Gtk::Image.

Things seem to work, loading and displaying the image, capturing the mouse down and mouse move events
except I am not getting the correct x,y values.
Either these values are not set or most likely I am doing something wrong.

Here is the code

require "gobject/gtk/autorun"

builder = Gtk::Builder.new_from_file("#{__DIR__}/main.glade")
builder.connect_signals

window = Gtk::Window.cast builder["window1"]
# close application when window's 'x' button is clicked
window.connect("destroy", &->Gtk.main_quit)
window.set_default_size(1920,1080)

menu_filequit = Gtk::MenuItem.cast(builder["file_quit"])
menu_fileopen = Gtk::MenuItem.cast(builder["file_open"])
viewport = Gtk::Viewport.cast(builder["viewport1"])
imagebuffer = Gtk::Image.cast(builder["image1"])
eventbox = Gtk::EventBox.cast(builder["eventbox1"])

eventbox.events = Gdk::EventMask::EXPOSURE_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK | Gdk::EventMask::BUTTON_PRESS_MASK | Gdk::EventMask::POINTER_MOTION_MASK | Gdk::EventMask::POINTER_MOTION_HINT_MASK

statusbar1  = Gtk::Statusbar.cast(builder["statusbar1"])
filechooser_open   = Gtk::Button.cast(builder["filechooser_open"])
filechooser_cancel = Gtk::Button.cast(builder["filechooser_cancel"])
filechooser_dialog  = Gtk::FileChooserDialog.cast(builder["filechooserdialog1"])

# event is of type Gdk::EventButton
eventbox.on_button_press_event do |widget,eventbutton|
  context_id = statusbar1.context_id("statusbar")
  statusbar1.push(context_id, "mouse moved (#{eventbutton.x},#{eventbutton.y})") 
  true
end

# event is of type Gdk::EventMotion
eventbox.on_motion_notify_event do |widget,eventmotion|
  context_id = statusbar1.context_id("statusbar")
  statusbar1.push(context_id, "mouse moved (#{eventmotion.x},#{eventmotion.y})")
  true
end

# exit application
menu_filequit.on_activate do |button|
  exit
end

# file chooser dialog
menu_fileopen.on_activate do |button|
  filechooser_dialog.show
end

filechooser_open.on_clicked do |button|
  x = filechooser_dialog.filename()
  if File.directory?(x) == false && File.readable?(x)

    filechooser_dialog.hide()
    window.title = window.title + " | " + "loaded image #{x}"
    imagebuffer.file = x
  end
end

filechooser_cancel.on_clicked do |button|
  filechooser_dialog.hide()
end

# maximize shows title and window buttons
window.maximize
window.show_all

Destroy GTK events

Hello.
Please tell me how to destroy GTK events.
I have an application that shows notifications, but there is one problem.

When a notification is viewed, i.e. an GTK event and no longer fall into this cycle for the next notifi:

        while !Gtk.events_pending
          Gtk.main_iteration
          break if notification.on_closed { next true }
        end 

I am poorly versed in GTK and tried different options, and the best thing I think is to restart the application from myself with this code:

        if Gtk.events_pending
          File.write LOCK, e.pubDate 
          parent = Process.pid
          fork = Process.fork do
            Process.exec("#{PROGRAM_NAME}")
          end 
          Process.kill(Signal::KILL, parent)                      
        end

But the thought do this without restarting the application does not give me rest. :)

[question] removing Lib

how would i remove Lib from the following code?

# prints the supported filename extensions
list = GdkPixbuf::Pixbuf.formats
while !list.null?
  list = list.as(LibGLib::SList*)

  fp = list.value.data.as(LibGdkPixbuf::PixbufFormat*)
  f = GdkPixbuf::PixbufFormat.new fp
  f.extensions.each { |ext| puts ext }

  list = list.value.next_
end

i have to cast pointers to the Lib types

Can't generate bindings for libgee-0.8

Tried to generate bindings for Gee:

require_gobject("Gee")

Results in:

There was a problem expanding macro 'require_gobject'

Code in src/gtk-test.cr:5:1

 5 | require_gobject("Gee")
     ^
Called macro defined in lib/gobject/src/gobject.cr:7:1

 7 | macro require_gobject(namespace)

Which expanded to:

 > 1193 | get_remaining_capacity : -> Void
 > 1194 | get_is_full : -> Void
 > 1195 | UNBOUNDED_CAPACITY = -1 # : Int32
          ^
Error: expecting identifier 'end', not 'UNBOUNDED_CAPACITY'

It seems to generate an invalid struct:

 > 1186 |   struct Queue # interface
 > 1187 |     parent_iface : LibGObject::TypeInterface
 > 1188 |     offer : -> Void
 > 1189 |     peek : -> Void
 > 1190 |     poll : -> Void
 > 1191 |     drain : -> Void
 > 1192 |     get_capacity : -> Void
 > 1193 |     get_remaining_capacity : -> Void
 > 1194 |     get_is_full : -> Void
 > 1195 |     UNBOUNDED_CAPACITY = -1 # : Int32
 > 1196 |   # Requires Collection
 > 1197 |     # Virtual function offer
 > 1198 |     # Virtual function peek
 > 1199 |     # Virtual function poll
 > 1200 |     # Virtual function drain
 > 1201 |     # Virtual function get_capacity
 > 1202 |     # Virtual function get_remaining_capacity
 > 1203 |     # Virtual function get_is_full
 > 1204 |     # Property capacity : Int32
 > 1205 |     # Property remaining_capacity : Int32
 > 1206 |     # Property is_full : Bool
 > 1207 |   end

Proper parsing of codeblocks in generated documentation

Currently code blocks just get left as is, it would be nice to have them parse properly. An example is this:

|[<!-- language="C" --> enum {

PROP_0,
PROP_FOO,
PROP_LAST

}; ]|

It should be possible to get the parser to recognize these blocks and swap them out for proper markdown blocks.

Compilation problem trying to use Gtk::Editable interface signal.

Following code doesn't compile:

require "gobject/gtk/autorun"

def changed(widget : Gtk::Editable)
  puts Gtk::Entry.cast(widget).text
end

window = Gtk::Window.new(title: "Enter something!", border_width: 10)
window.connect "destroy", &->Gtk.main_quit
entry = Gtk::Entry.new

entry.on_changed(&->changed(Gtk::Editable))

window.add entry
window.show_all

Error:

Error target crash failed to compile:
Showing last frame. Use --error-trace for full trace.

There was a problem expanding macro 'require_gobject'

Code in lib/gobject/src/gtk/gtk.cr:7:1

 7 | require_gobject "Gtk"
     ^
Called macro defined in lib/gobject/src/gobject.cr:8:1

 8 | macro require_gobject(namespace)

Which expanded to:

 > 29256 | callback = ->(arg0 : LibGtk::Editable*) {
 > 29257 |   return_value = block.call(Editable.new(arg0))
 > 29258 |  return_value
                                                ^--
Error: undefined method 'new' for Gtk::Editable:Module

Errors on Graphene

(Hi, first of all, thanks for working on this โ€” I've been looking on GI bindings that work as compile-time macros / type providers, and for something to use Crystal forโ€ฆ :D)

I can't get examples working, first there's this:

Code in macro 'require_gobject'                                                                                       
                                                                                                                      
 7 | require_gobject("Graphene")                                                                                      
     ^                                                                                                                
Called macro defined in lib/gobject/gobject.cr:7:1                                                                    
                                                                                                                      
 7 | macro require_gobject(namespace)                                                                                 
                                                                                                                      
Which expanded to:                                                                                                    
                                                                                                                      
 > 513 | VEC3_LEN = 3 # : Int32                                                                                       
 > 514 | VEC4_LEN = 4 # : Int32                                                                                       
 > 515 | false = 0 # : Int32                                                                                          
         ^                                                                                                            
Error: unexpected token: false

I'm not sure why these constants are even there (reported: ebassi/graphene#180), but I added them to skip_info?. Then, new error:

syntax error in /usr/local/lib/girepository-1.0/Graphene-1.0.typelib/Matrix:164                                      
Error: expecting any of these tokens: IDENT, CONST, `, <<, <, <=, ==, ===, !=, =~, !~, >>, >, >=, +, -, *, /, //, !, ~
, %, &, |, ^, **, [], []?, []=, <=>, &+, &-, &*, &** (not 'NUMBER')

That one I'm not sure what's happeningโ€ฆ why isn't there a snippet of the generated source?

(Also not sure why it's even trying to use Graphite, according to my package manager it's only a dependency of gstreamer1-plugins-gl, while I'm not touching anything GStreamer related, just running Gtk examplesโ€ฆ)

Crash on C functions that may return null pointers

Not sure if this is caused by wrong GIR annotations on GtkSourceView [1], but the generated bindings for GtkSource::StyleSchemeManager#scheme is not returing nil when the C method returns a null pointer.

    def scheme(scheme_id : ::String)
      __return_value = LibGtkSource.style_scheme_manager_get_scheme(@pointer.as(LibGtkSource::StyleSchemeManager*), scheme_id.to_unsafe)
      GtkSource::StyleScheme.new(__return_value)
    end

So the following code crash:

require "gobject/gtk/autorun"
require_gobject "GtkSource"

GtkSource.init
manager = GtkSource::StyleSchemeManager.default
puts manager.to_unsafe
manager.scheme("any wrong id")

Backtrace

Pointer(LibGtkSource::StyleSchemeManager)@0x55fa564ff0e0
Invalid memory access (signal 11) at address 0x0
[0x55fa548e37f6] *CallStack::print_backtrace:Int32 +118
[0x55fa548d62ce] __crystal_sigfault_handler +286
[0x7f4d0efa5800] ???
[0x55fa5493a294] *GtkSource::StyleScheme +4
[0x55fa5493a286] *GtkSource::StyleScheme +6
[0x55fa5493a253] *GtkSource::StyleScheme#initialize<Pointer(LibGtkSource::StyleScheme)>:Nil +67
[0x55fa5493a1f8] *GtkSource::StyleScheme::new<Pointer(LibGtkSource::StyleScheme)>:GtkSource::StyleScheme +104
[0x55fa54939fe2] *GtkSource::StyleSchemeManager#scheme<String>:GtkSource::StyleScheme +66
[0x55fa548c1ae5] __crystal_main +1157
[0x55fa5493ad86] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6
[0x55fa548d633c] main +60
[0x7f4d0ed71023] __libc_start_main +243
[0x55fa548c158e] _start +46
[0x0] ???

[1] https://developer.gnome.org/gtksourceview/stable/GtkSourceStyleSchemeManager.html#gtk-source-style-scheme-manager-get-scheme

Unable to build gi-doc

I'm trying to build gi-doc so I can generate some documentation for myself. Unfortunately, running shards build produces this error:

ฮป shards build
Dependencies are satisfied
Building: gi-generator
Building: gi-dump
Building: gi-doc
Error target gi-doc failed to compile:
/usr/bin/ld: /var/lib/snapd/snap/crystal/331/share/crystal/src/llvm/ext/llvm_ext.o: in function `llvm::MetadataTracking::track(llvm::Metadata*&)':
llvm_ext.cc:(.text._ZN4llvm16MetadataTracking5trackERPNS_8MetadataE[_ZN4llvm16MetadataTracking5trackERPNS_8MetadataE]+0x42): undefined reference to `llvm::MetadataTracking::track(void*, llvm::Metadata&, llvm::PointerUnion<llvm::MetadataAsValue*, llvm::Metadata*>)'
collect2: error: ld returned 1 exit status
Error: execution of command failed with code: 1: `cc "${@}" -o '/home/sim/Downloads/crystal-gobject/bin/gi-doc'  -rdynamic  -lz `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libssl || printf %s '-lssl -lcrypto'` `command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s '-lcrypto'` /var/lib/snapd/snap/crystal/331/share/crystal/src/llvm/ext/llvm_ext.o `/usr/bin/llvm-config --libs --system-libs --ldflags 2> /dev/null` -lstdc++ -lgirepository-1.0 -lxml2 -lpcre -lm /var/lib/snapd/snap/crystal/331/bin/../lib/crystal/lib/libgc.a -lpthread /var/lib/snapd/snap/crystal/331/share/crystal/src/ext/libcrystal.a -levent -lrt -ldl -L/var/lib/snapd/snap/crystal/331/bin/../lib/crystal/lib -L/var/lib/snapd/snap/crystal/331/bin/../lib/crystal/lib`

I've got all the dependencies and LLVM installed. Is this a problem on my end, or is this an issue with the build?

using event_handler_set

hello again, here's another Lib usage:

def handler(event, data)
  puts event.value.type
end

LibGdk.event_handler_set ->handler, nil, nil

you can add this to the gdk_window sample, anywhere before GLib::MainLoop

crystal-gobject has problems handling GI_TYPELIB_PATH

i develop some gobject-introspectable libraries in vala. as those are not packaged when i develop them, they tend to land in /usr/local/lib/x86_64-linux-gnu/girepository-1.0 instead of /usr/lib/x86_64-linux-gnu/girepository-1.0.
Usually I am able to compensate with exporting the environment variable GI_TYPELIB_PATH:
export GI_TYPELIB_PATH=/usr/local/lib/x86_64-linux-gnu/girepository-1.0
However, crystal-gobject does not seem to be able to handle those libs. Strace shows that it indeed opens the correct typelib, but somehow fails to take the process further.

Strace for things in /usr:

open("/usr/lib/x86_64-linux-gnu/girepository-1.0/GFlow-0.2.typelib", O_RDONLY) = 9
open("/usr/lib/girepository-1.0", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 8
Generate GFlow... open("src/generated/lib_g_flow.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/g_flow.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/node_error.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/simple_node.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/simple_node_private.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/simple_sink.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/simple_sink_private.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/simple_source.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/simple_source_private.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/dock.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/node.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/sink.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/source.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
open("src/generated/g_flow/module_functions.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
done.

Strace for things in /usr/local:

open("/usr/local/lib/x86_64-linux-gnu/girepository-1.0", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 8
open("/usr/local/lib/x86_64-linux-gnu/girepository-1.0/GFlow-0.2.typelib", O_RDONLY) = 9
open("/usr/lib/x86_64-linux-gnu/girepository-1.0", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 8
open("/usr/lib/girepository-1.0", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 8
Generate GFlow... open("src/generated/lib_g_flow.cr", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644) = 8
Nil assertion failed (Exception)
open("./stage3", O_RDONLY|O_CLOEXEC)    = 7
0x562cdccbb0b0: not_nil! at /opt/crystal/src/class.cr 65:0
0x562cdccaca5e: [] at /opt/crystal/src/string.cr 821:5
0x562cdcce6c0d: lib_definition at /home/grindhold/git/crystal-gobject/src/generator/namespace.cr 376:7
0x562cdcce67f5: write_lib at /home/grindhold/git/crystal-gobject/src/generator/namespace.cr 55:7
0x562cdcce6643: write at /home/grindhold/git/crystal-gobject/src/generator/namespace.cr 41:5
0x562cdcc7db34: __crystal_main at /home/grindhold/git/crystal-gobject/src/generator/generator.cr 23:1
0x562cdcc8ff39: main at /opt/crystal/src/main.cr 12:15
0x7f24c1fc82b1: __libc_start_main at ??
0x562cdcc7ccaa: _start at ??
0x0: ??? at ??
+++ exited with 1 +++

libgee-0.8: undefined constant LibGee::FutureMapFunc

After the fix for #31, I tried building libgee again in the same way:

require_gobject("Gee")

Results in:

There was a problem expanding macro 'require_gobject'

Code in src/gtk-test.cr:5:1

 5 | require_gobject("Gee")
     ^
Called macro defined in lib/gobject/src/gobject.cr:7:1

 7 | macro require_gobject(namespace)

Which expanded to:

 > 899 | fun future_wait_async = gee_future_wait_async(this : Future*, _callback : LibGio::AsyncReadyCallback, _callback__target : Void*) : Void
 > 900 | fun future_wait_finish = gee_future_wait_finish(this : Future*, _res : LibGio::AsyncResult*, error : LibGLib::Error**) : Void*
 > 901 | fun future_map = gee_future_map(this : Future*, a_type : UInt64, a_dup_func : LibGObject::BoxedCopyFunc, a_destroy_func : LibGLib::DestroyNotify, func : LibGee::FutureMapFunc, func_target : Void*, func_target_destroy_notify : LibGLib::DestroyNotify) : LibGee::Future*
                                                                                                                                                                  ^--------------------
Error: undefined constant LibGee::FutureMapFunc

Context (from error trace):

 >  867 |   struct Future # interface
 >  868 |     parent_iface : LibGObject::TypeInterface
 >  869 |     wait : -> Void
 >  870 |     wait_until : -> Void
 >  871 |     wait_async : -> Void
 >  872 |     wait_finish : -> Void
 >  873 |     map : -> Void
 >  874 |     light_map : -> Void
 >  875 |     light_map_broken : -> Void
 >  876 |     zip : -> Void
 >  877 |     flat_map : -> Void
 >  878 |     get_value : -> Void
 >  879 |     get_ready : -> Void
 >  880 |     get_exception : -> Void
 >  881 |   # Requires Object
 >  882 |     # Virtual function wait
 >  883 |     # Virtual function wait_until
 >  884 |     # Virtual function wait_async
 >  885 |     # Virtual function wait_finish
 >  886 |     # Virtual function map
 >  887 |     # Virtual function light_map
 >  888 |     # Virtual function light_map_broken
 >  889 |     # Virtual function zip
 >  890 |     # Virtual function flat_map
 >  891 |     # Virtual function get_value
 >  892 |     # Virtual function get_ready
 >  893 |     # Virtual function get_exception
 >  894 |     # Property ready : Bool
 >  895 |     # Property exception : LibGLib::Error**
 >  896 |   end
 >  897 |   fun future_wait = gee_future_wait(this : Future*, error : LibGLib::Error**) : Void*
 >  898 |   fun future_wait_until = gee_future_wait_until(this : Future*, end_time : Int64, value : Void**, error : LibGLib::Error**) : Bool
 >  899 |   fun future_wait_async = gee_future_wait_async(this : Future*, _callback : LibGio::AsyncReadyCallback, _callback__target : Void*) : Void
 >  900 |   fun future_wait_finish = gee_future_wait_finish(this : Future*, _res : LibGio::AsyncResult*, error : LibGLib::Error**) : Void*
 >  901 |   # line causing error below
 >  901 |   fun future_map = gee_future_map(this : Future*, a_type : UInt64, a_dup_func : LibGObject::BoxedCopyFunc, a_destroy_func : LibGLib::DestroyNotify, func : LibGee::FutureMapFunc, func_target : Void*, func_target_destroy_notify : LibGLib::DestroyNotify) : LibGee::Future*
 >  902 |   fun future_light_map = gee_future_light_map_fixed(this : Future*, a_type : UInt64, a_dup_func : LibGObject::BoxedCopyFunc, a_destroy_func : LibGLib::DestroyNotify, func : LibGee::FutureLightMapFunc, func_target : Void*, func_target_destroy_notify : LibGLib::DestroyNotify) : LibGee::Future*
 >  903 |   fun future_light_map_broken = gee_future_light_map(this : Future*, a_type : UInt64, a_dup_func : LibGObject::BoxedCopyFunc, a_destroy_func : LibGLib::DestroyNotify, func : LibGee::FutureLightMapFunc, func_target : Void*) : LibGee::Future*
 >  904 |   fun future_zip = gee_future_zip(this : Future*, a_type : UInt64, a_dup_func : LibGObject::BoxedCopyFunc, a_destroy_func : LibGLib::DestroyNotify, b_type : UInt64, b_dup_func : LibGObject::BoxedCopyFunc, b_destroy_func : LibGLib::DestroyNotify, zip_func : LibGee::FutureZipFunc, zip_func_target : Void*, second : LibGee::Future*) : LibGee::Future*
 >  905 |   fun future_flat_map = gee_future_flat_map(this : Future*, a_type : UInt64, a_dup_func : LibGObject::BoxedCopyFunc, a_destroy_func : LibGLib::DestroyNotify, func : LibGee::FutureFlatMapFunc, func_target : Void*, func_target_destroy_notify : LibGLib::DestroyNotify) : LibGee::Future*
 >  906 |   fun future_get_value = gee_future_get_value(this : Future*) : Void*
 >  907 |   fun future_get_ready = gee_future_get_ready(this : Future*) : Bool
 >  908 |   fun future_get_exception = gee_future_get_exception(this : Future*) : LibGLib::Error**

Possibly the relevant file within Gee:

https://github.com/GNOME/libgee/blob/5e66324654b7d70d7c28793491a4edfe6d8a0d85/gee/future.vala#L132

Question about Interfaces and includes

Hi.

I was reading the Gtk documentation, and found that some classes, i.e. Gtk::ApplicationWindow, implement some interfaces, i.e. Gio::ActionMap.

The thing is it doesn't look like it's been mapped to crystal by the generator.

I found putting this at my project make it work:

module Gtk
  class Application
    include Gio::ActionMap
  end

  class ApplicationWindow
    include Gio::ActionMap
  end
end

Then I found the following code:

each_interface do |interface|
io.puts "#{indent} # Implements #{interface.name}"
end

And tried to change it to include #{interface.namespace}::#{interface.name}, but it seems to crash in some references.

Is there any plans to make it work at "generator-time" or do you think it's better to patch it by the consumer?

GtkSourceView crash on set_language method.

I'm experiencing a crash with GtkSourceView, looks like a memory corruption, a bad cast... not sure.
I wrote a similar line-by-line C version and it works perfectly, the Crystal version crash with

$ ./bin/crash
Markup/Markdown
Invalid memory access (signal 11) at address 0x0
[0x56443a8eab76] *CallStack::print_backtrace:Int32 +118
[0x56443a8dd64e] __crystal_sigfault_handler +286
[0x7f52fcd17800] ???
[0x7f52fcf016e4] pcre_exec +3156
[0x7f52fcfa331d] g_match_info_next +157
[0x7f52fcfa4510] g_regex_match_full +128
[0x7f52fcfa46b9] g_regex_replace_eval +201
[0x7f52fde1941d] ???
[0x7f52fde25ab7] ???
[0x7f52fde24c4f] ??? (5 times)
[0x7f52fde4ff4d] ???
[0x7f52fde6a6d6] gtk_source_buffer_set_language +294
[0x56443a941623] *GtkSource::Buffer#language=<(GtkSource::Language | Nil)>:Nil +67
[0x56443a8c8da7] __crystal_main +1767
[0x56443a942446] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6
[0x56443a8dd6bc] main +60
[0x7f52fcae3023] __libc_start_main +243
[0x56443a8c85ee] _start +46
[0x0] ???

Crystal code:

require "gobject/gtk/autorun"
require_gobject "GtkSource"

GtkSource.init

builder = Gtk::Builder.new_from_file("#{__DIR__}/main.glade")
builder.connect_signals

# Get editor
editor = GtkSource::View.cast(builder["editor"])
buffer = GtkSource::Buffer.cast(editor.buffer)
buffer.set_text("Some contents", -1)

# Here the problem, seems to be just with markdown syntax.
lang = GtkSource::LanguageManager.default.guess_language("README.md", nil)
puts "#{lang.try(&.section)}/#{lang.try(&.name)}"
buffer.language = lang

# Show main window
main_window = Gtk::Window.cast(builder["main_window"])
main_window.show_all

C version

#include <gtk/gtk.h>
#include <gtksourceview/gtksource.h>

int main(int argc, char *argv[]) {
  gtk_init(&argc, &argv);
  gtk_source_init();

  GtkBuilder* builder = gtk_builder_new_from_file("./src/main.glade");
  gtk_builder_connect_signals(builder, NULL);
  
  // get editor
  GtkSourceView* editor = GTK_SOURCE_VIEW(gtk_builder_get_object(builder, "editor"));
  GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(editor));
  gtk_text_buffer_set_text(buffer, "Some contents", -1);

  // Sets markdown syntax
  GtkSourceLanguageManager* manager = gtk_source_language_manager_get_default();
  GtkSourceLanguage* lang = gtk_source_language_manager_guess_language(manager, "README.md", NULL);
  if (lang)
    printf("%s/%s\n", gtk_source_language_get_section(lang), gtk_source_language_get_name(lang));
  gtk_source_buffer_set_language(GTK_SOURCE_BUFFER(buffer), lang);


  // Show main window
  GtkWidget* window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
  gtk_widget_show_all(GTK_WIDGET(window));
  gtk_main();  
  gtk_source_finalize();
}

XML used by GTK builder in the examples above.

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <requires lib="gtksourceview" version="4.0"/>
  <object class="GtkApplicationWindow" id="main_window">
    <property name="can_focus">False</property>
    <property name="default_width">800</property>
    <property name="default_height">600</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child type="titlebar">
      <placeholder/>
    </child>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkSourceView" id="editor">
            <property name="can_focus">False</property>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

Expected behavior

Works like the C version, i.e. just show a blank window with the text "Some Contents"

Current behavior

A crash.

More info

The weird info is that if I change the file name used to guess the language to e.g. "foo.yaml", it doesn't crash.

Tested on ArchLinux GTK package gtk3 1:3.24.20-1, GTK source view package gtksourceview4 4.6.0-1.

C version compiled with:

gcc `pkg-config --cflags gtk+-3.0` `pkg-config --cflags gtksourceview-4` crash.c -o crash_c `pkg-config --libs gtk+-3.0` `pkg-config --libs gtksourceview-4`

Gtk::MessageDialog have just a subset of GTK API

The generated bindings only show a subset of the C API https://developer.gnome.org/gtk3/stable/GtkMessageDialog.html, and as expected the wrapper only wrap this subset.

struct MessageDialog # object
  parent_instance : LibGtk::Dialog*
  priv : LibGtk::MessageDialogPrivate*
  # Property buttons : LibGtk::ButtonsType
  # Property image : LibGtk::Widget*
  # Property message_area : LibGtk::Widget*
  # Property message_type : LibGtk::MessageType
  # Property secondary_text : UInt8*
  # Property secondary_use_markup : Bool
  # Property text : UInt8*
  # Property use_markup : Bool
end
fun message_dialog_get_image = gtk_message_dialog_get_image(this : MessageDialog*) : LibGtk::Widget*
fun message_dialog_get_message_area = gtk_message_dialog_get_message_area(this : MessageDialog*) : LibGtk::Widget*
fun message_dialog_set_image = gtk_message_dialog_set_image(this : MessageDialog*, image : LibGtk::Widget*) : Void
fun message_dialog_set_markup = gtk_message_dialog_set_markup(this : MessageDialog*, str : UInt8*) : Void

As the gtk_message_dialog_new isn't available, creating these objects (without gtk builder) are impossible.

Bind generator doesn't use the GIR [array length=data_size] annotation

Bind generator doesn't use the GIR [array length=data_size] annotation, e.g. the Gio function:

gchar *
g_content_type_guess (const gchar *filename,
                      const guchar *data,
                      gsize data_size,
                      gboolean *result_uncertain);```
Has the annotations:
Parameter Type Annotation
filename a string, orย NULL. [nullable]
data a stream of data, orย NULL. [nullable][arraylength=data_size]
data_size the size ofย data ย 
result_uncertain return location for the certainty of the result, orย NULL. [out][optional]

And the generated binding is:

  def self.content_type_guess(filename : ::String?, data : ::String, data_size : ::Int, result_uncertain : Bool?)
    __return_value = LibGio.content_type_guess(filename ? filename.to_unsafe : nil, data ? data : nil, UInt64.new(data_size), result_uncertain)
    GObject.raise_unexpected_null("g_content_type_guess") if __return_value.null?
    ::String.new(__return_value)
  end

To make things more Crystal like it would be:

  def self.content_type_guess(filename : ::String?, result_uncertain : Bool?)
    __return_value = LibGio.content_type_guess(filename ? filename.to_unsafe : nil, data ? data : nil, filename ? filename.size : 0, out result_uncertain)
    GObject.raise_unexpected_null("g_content_type_guess") if __return_value.null?
    ::String.new(__return_value)
  end

BTW, this result_uncertain parameter is unusable the way it's now, but this is another issue, maybe if the parameter have the out annotation and it's a C primitive type, we could put it on return value as a Tuple with the current return value.

Compilation error generating TreeView#on_row_activated

TreeView row-activated signal is generating a bad signature.

GTK docs at https://developer.gnome.org/gtk3/stable/GtkTreeView.html#GtkTreeView-row-activated says the user function should be:

void user_function(GtkTreeView *tree_view,
                   GtkTreePath       *path,
                   GtkTreeViewColumn *column,
                   gpointer           user_data)

But the generated bindings have:

    alias RowActivatedSignal = TreeView, Gtk::TreePath, Gtk::TreeViewColumn ->
    def on_row_activated(&__block : RowActivatedSignal)
      __callback = ->(_arg0 : LibGtk::TreeView*, _arg1 : LibGtk::TreePath*, _arg2 : LibGtk::TreeViewColumn**) {
       __return_value = __block.call(TreeView.new(_arg0), Gtk::TreePath.new(_arg1), Gtk::TreeViewColumn.new(_arg2))
       __return_value
      }
      connect("row-activated", __callback)
    end

This doesn't compile, but if we monkey patch it with:

module Gtk
  class Gtk::TreeViewColumn
    def initialize(pointer : Pointer(Pointer(LibGtk::TreeViewColumn)))
      @pointer = pointer.as(Void*)
    end
  end
end

it does, however the TreePath object is all zeros:

Crystal code to test it (using the glade file from examples)

require "gobject/gtk/autorun"

builder = Gtk::Builder.new_from_file("#{__DIR__}/../lib/gobject/samples/tree_view.glade")
builder.connect_signals

# Insert something into the model
model = Gtk::TreeStore.cast(builder["tree_model"])
root = Gtk::TreeIter.new
model.append(root, nil)
model.set(root, [0], GObject::Value.new("Root"), 1)

module Gtk
  class Gtk::TreeViewColumn
    def initialize(pointer : Pointer(Pointer(LibGtk::TreeViewColumn)))
      @pointer = pointer.as(Void*)
    end
  end
end

# view
view = Gtk::TreeView.cast(builder["tree_view"])
puts "TreeView ptr before signal: #{view.to_unsafe}"
view.on_row_activated do |view, path, column|
  puts "TreeView ptr inside signal: #{view.to_unsafe}"
  puts "Path is empty!?: #{path.to_unsafe.value}"
  puts "Column pointer: #{column.to_unsafe}"
end

# Show main view.
main_window = Gtk::Window.cast(builder["main_window"])
main_window.show_all

The initial bug is the signal generated code, but this path issue seems like some memory corruption too and need some investigation, a C example doesn't behave like that, I can write down a C example if it helps to debug the issue.

Status of the project

Hello ! I've been monitoring this project for a while, since I want to use gtk for a crystal application I plan on writing.

I saw you're still pushing commits every once in a while. Could you provide more details as to how usable this project is ? What works and what would be likely to break, if anything ?

Also, I'm quite curious as to how you generated these bindings. I searched a bit how bindings work in Crystal, and found the bindgen tool that can autogenerate bindings for a C library. Are you using something similar ? If I needed to add to or fix some bindings the ones you've already implemented, would bindgen be a good solution ?

Thank you !

rename Libcairo

i created some bindings to cairo.h, and naturally i want to name the lib LibCairo, which causes confusion with Libcairo from this repo.

edit: alternatively, generate and include the cairo.h bindings here

Arguments for connect callbacks

Hi, i just started with GTK so if something is wrong on my part, i apologize.

I am trying to make a custom right click menu. The code below throws a Error: wrong number of block argument's arguments (given 1, expected 0):

connect("button-press-event", &->(e : Gdk::EventButton){
  if e.type == Gdk::EventType::BUTTON_PRESS && e.button == Gdk::BUTTON_SECONDARY
    menu.popup_at_pointer(e)
  end

  false
})

This is the entire code:

require "gobject/gtk"
require "gobject/g_lib"

class MainWindow < Gtk::ApplicationWindow
  def self.new(app : Gtk::Application)
    super
  end

  def initialize(ptr)
    super(ptr)

    self.border_width = 100
    self.title = "Hello"
    add Gtk::Label.new("Hello")

    hide_titlebar_when_maximized = true;
    maximize

    wallpaper_item = Gtk::MenuItem.new_with_label("Change Wallpaperโ€ฆ")
    displays_item = Gtk::MenuItem.new_with_label("Display Settingsโ€ฆ")
    separator = Gtk::SeparatorMenuItem.new
    settings_item = Gtk::MenuItem.new_with_label("System Settingsโ€ฆ")

    menu = Gtk::Menu.new
    menu.attach_to_widget(self, nil)
    menu.append(wallpaper_item);
    menu.append(displays_item);
    menu.append(separator);
    menu.append(settings_item);
    menu.show_all
    connect("button-press-event", &->(e : Gdk::EventButton){
      if e.type == Gdk::EventType::BUTTON_PRESS && e.button == Gdk::BUTTON_SECONDARY
        menu.popup_at_pointer(e)
      end

      false
    })

    # More to do down here
  end
end

class MyApp < Gtk::Application
  def self.new(id, flags : Gio::ApplicationFlags)
    super
  end

  def initialize(ptr)
    super(ptr)

    on_activate do |application|
      window = MainWindow.new(self)
      window.show_all
    end
  end
end

app = MyApp.new("org.crystal.mysample", :flags_none)
app.run()

Missing support for after signals.

In C we can connect signals using the macro g_signal_connect_after, that just connect the signal using the AFTER flag.

This is useful to e.g. connect focus-out-event signal, so your code is ran after the default signal handlers and some GTK widgets get happy with this.

My suggestion if to use a after_ prefix to connect these signals, e.g. for GtkWidget focus-out-event we would have on_focus_out_event and after_focus_out_event.

I tried to mimic this with current signals implementation but got no luck on my first tries:

require "gobject/gtk/autorun"

module Gtk
  class Widget
    def after_focus_out_event(&block : FocusOutEventSignal)
      __var0 = ->(arg0 : LibGtk::Widget*, arg1 : LibGdk::EventFocus*, box : Void*) {
        ::Box(FocusOutEventSignal).unbox(box).call(Widget.new(arg0), arg1.null? ? GObject.raise_unexpected_null("event in focus_out_event") : Gdk::EventFocus.new(arg1))
      }

      __var1 = ::Box.box(FocusOutEventSignal.new { |arg0, arg1|
        block.call(arg0, arg1)
      })
      LibGObject.signal_connect_data(@pointer.as(LibGObject::Object*), "focus-out-event", LibGObject::Callback.new(__var0.pointer, Pointer(Void).null), GObject::ClosureDataManager.register(__var1), ->GObject::ClosureDataManager.deregister, GObject::ConnectFlags::AFTER)
    end
  end
end

def hey(widget, event)
  puts "hey"
  false
end

def ho(widget, event)
  puts "ho"
  true
end

window = Gtk::Window.new(title: "Enter something!", border_width: 10)
window.connect "destroy", &->Gtk.main_quit
box = Gtk::Box.new(orientation: :vertical, spacing: 6)
window.add(box)

entry1 = Gtk::Entry.new
entry1.on_focus_out_event(&->hey(Gtk::Widget, Gdk::EventFocus))
entry1.after_focus_out_event(&->ho(Gtk::Widget, Gdk::EventFocus))

entry2 = Gtk::Entry.new

box.add(entry1)
box.add(entry2)

window.show_all

This was trying to mimic this C code:

#include <gtk/gtk.h>
#include <gtksourceview/gtksource.h>

gboolean focus_out1(GtkWidget *widget, GdkEvent *event,gpointer user_data) {
  printf("hey\n");
  return 0;
}

gboolean focus_out2(GtkWidget *widget, GdkEvent *event,gpointer user_data) {
  printf("ho\n");
  return 1;
}

int main(int argc, char *argv[]) {
  gtk_init(&argc, &argv);
  gtk_source_init();

  GtkWidget* wnd = gtk_window_new(0);
  g_signal_connect(wnd, "destroy", G_CALLBACK(gtk_main_quit), wnd);

  GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
  gtk_container_add(GTK_CONTAINER(wnd), GTK_WIDGET(box));

  GtkWidget* entry1 = gtk_entry_new();
  GtkWidget* entry2 = gtk_entry_new();

  g_signal_connect_data(entry1, "focus-out-event", G_CALLBACK(focus_out1), 0, 0, 0);
  g_signal_connect_data(entry1, "focus-out-event", G_CALLBACK(focus_out2), 0, 0, G_CONNECT_AFTER);
  // g_signal_connect(entry1, "focus-out-event", G_CALLBACK(focus_out1), entry1);
  // g_signal_connect_after(entry1, "focus-out-event", G_CALLBACK(focus_out2), entry1);

  gtk_container_add(GTK_CONTAINER(box), entry1);
  gtk_container_add(GTK_CONTAINER(box), entry2);

  // g_signal_connect(wnd, )


  gtk_widget_show_all(GTK_WIDGET(wnd));
  gtk_main();  
  gtk_source_finalize();
}

Cast problems if a widget is stored in a member variable.

The following program fail to compile

require "gobject/gtk"
require_gobject "GtkSource"

class TroubleMaker
  getter widget : Gtk::Label

  def initialize(builder)
    @widget = Gtk::Label.cast(builder["label"])
  end
end

LibGtk.init pointerof(ARGC_UNSAFE), pointerof(ARGV_UNSAFE)

GtkSource.init

builder = Gtk::Builder.new_from_string(<<-EOF, -1)
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.36.0 -->
<interface>
  <requires lib="gtk+" version="3.22"/>
  <object class="GtkApplicationWindow" id="main_window">
    <property name="can_focus">False</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child>
      <placeholder/>
    </child>
    <child type="titlebar">
      <placeholder/>
    </child>
  </object>
  <object class="GtkLabel" id="label">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="label" translatable="yes">label</property>
  </object>
</interface>
EOF

builder.connect_signals
main_window = Gtk::Window.cast(builder["main_window"])

trouble = TroubleMaker.new(builder)
# Compilation fail: Error: can't cast (Pointer(LibGtk::AccelLabel) | Pointer(LibGtk::Label)) to Pointer(LibGtk::Widget)
main_window.add(trouble.widget)

# But this works
# widget = Gtk::Label.cast(builder["label"])
# main_window.add(widget)

main_window.show_all
LibGtk.main

It fails with the error:

Which expanded to:

 > 13937 | def add(widget : Gtk::Widget)
 > 13938 |   LibGtk.container_add(@pointer.as(LibGtk::Container*), widget.to_unsafe.as(LibGtk::Widget*))
 > 13939 |   nil
                                                                   ^
Error: can't cast (Pointer(LibGtk::AccelLabel) | Pointer(LibGtk::Label)) to Pointer(LibGtk::Widget)

If I use Gtk::Widget instead of Gtk::Label it fails as well, just the union is bigger with all know widget subclasses.

Expected behavior

Show a small window with a label inside.

Current behavior

It fails to compile.

[error] LibCairo::Rectangle compiling demo

hello
first of all thank for this great work

trying the sample gtk_sample.cr I got this error

crystal run samples/gtk_sample.cr 
Showing last frame. Use --error-trace for full trace.
In src/lib_cairo.cr:20:18
 20 | rectangles : LibCairo::Rectangle*
                   ^------------------
Error: undefined constant LibCairo::Rectangle

please note that crystal-gobject (another great work) samples work on my machine

is it a problem with my cairo release ?
my env. is

Linux Mint19  5.3.0-40-generic #32~18.04.1-Ubuntu SMP
libgtk 3.22.30 (standard installed)
libcairo, libcairo-gobject2   1.15.10

thanks for help

Error: no overload matches 'Gtk::Builder#connect_signals' with type Nil

Hi,

When I use version 0.8.0 I am getting the following error

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

In lib/gobject/src/gtk/gtk.cr:18:7

 18 | connect_signals nil
      ^--------------
Error: no overload matches 'Gtk::Builder#connect_signals' with type Nil

Overloads are:
 - Gtk::Builder#connect_signals(user_data : ::Pointer(Void))
 - Gtk::Builder#connect_signals()

This error does not occur when I use branch v0.3.1

dependencies:
  gobject:
    github: jhass/crystal-gobject
    branch: v0.3.1

error compiling samples "undefined fun 'window_get_type' for LibGtk"

crystal build samples/gtk_hello_world.cr 
Error in samples/gtk_hello_world.cr:5: instantiating 'Gtk::Window#connect(String)'

window.connect "destroy", &->Gtk.main_quit
       ^~~~~~~

in src/g_object/object.cr:10: instantiating 'connect(String, Proc(Nil))'

      connect signal, callback
      ^~~~~~~

in src/g_object/object.cr:14: instantiating 'UInt64#tap()'

      LibGObject.signal_connect_data(to_unsafe.as(LibGObject::Object*),
                                                                        ^~~

in src/g_object/object.cr:14: instantiating 'UInt64#tap()'

      LibGObject.signal_connect_data(to_unsafe.as(LibGObject::Object*),
                                                                        ^~~

in src/g_object/object.cr:21: instantiating 'type_name()'

          raise ArgumentError.new("Couldn't connect signal #{signal} to #{type_name} (#{self.class})")
                                                                          ^~~~~~~~~

in src/g_object/object.cr:63: instantiating 'type()'

      GObject.type_name(type)
                        ^~~~

in src/generated/gtk/window.cr:157: undefined fun 'window_get_type' for LibGtk

      __return_value = LibGtk.window_get_type(to_unsafe.as(LibGtk::Window*))
                              ^~~~~~~~~~~~~~~

Even after running the generator, the "window_get_type" is not generated. To make it work I edited the files and added manually the line

fun window_get_type = gtk_window_get_type(this : Window*) : LibGdk::WindowType

libgtk3 version: 3.18.9-1ubuntu3.3
Crystal version 0.23.1 [e2a1389e8] (2017-07-13) LLVM 3.8.1

Boolean return value get messed on signals if using member variable one line before

If the block used on Glib.timeout method access some member variable one line before it returns, the return value get some memory garbage and GTK think it's true, not false.

How to reproduce

Compile and run the following code with -Dpreview_mt.

require "log"
require "gobject/gtk/autorun"

window = Gtk::Window.new(title: "Hello World!", border_width: 10)
window.connect("destroy", &->Gtk.main_quit)
button = Gtk::Button.new label: "Hello World!"
button.connect("clicked", &->window.destroy)
window.add(button)

window.show_all

class Foo
  @var = "hey"

  def bar
    spawn do
      puts "Hi, I'm a new thread."
      GLib.timeout(0) do
        puts "I'm on main thread"
        # access instance vars inside the block before the return call creates the problem
        # comment this line and it works
        @var = "ok"

        # If uncomment this line, everything works too.
        # Log.info { "fix" }
        false
      end
    end
  end
end

f = Foo.new
f.bar

Fail to compile with new version of Harfbuzz

A new version of pango and harfbuzz landed in Archlinux package repositories, when using then the generated bindings fail to compile, the problem seems to be on Harfbuzz, but Pango depends on Harfbuzz.

Broken versions:
Pango: 1.46.0
Harfbuzz: 2.7.1

Versions that work:
Pango: 1.44.7
Harfbuzz: 2.7.0

Test can be done with files under project sample directory:

$ crystal run gdk_window.cr 
There was a problem expanding macro 'require_gobject'

Code in macro 'require_gobject'

 7 | require_gobject("HarfBuzz", "0.0")
     ^
Called macro defined in lib/gobject/gobject.cr:25:1

 25 | macro require_gobject(namespace, version = nil)

Which expanded to:

 > 553 |   ###########################################
 > 554 | 
 > 555 |   union hb_var_int_t
                 ^
Error: expecting token 'CONST', not 'hb_var_int_t'
code 1

How can I use Glade templates?

Hi there!

I'd like to use Glade templates in my Gtk application but I'm stuck with Error: undefined method 'set_template_from_resource' for Gtk::Widget.class.

It seems that Gtk::Widget.class should implement set_template_from_resource or set_template https://lazka.github.io/pgi-docs/Gtk-3.0/classes/WidgetClass.html#Gtk.WidgetClass.set_template_from_resource to get it work.

To give you more context I'm rewriting a Ruby/Gtk3 application to Crystal/Gtk3 (https://github.com/jbox-web/ssh-tunnel) so I'm already using this technique and it works pretty well : https://github.com/jbox-web/ssh-tunnel/blob/master/lib/ssh-tunnel/ui/windows/application_window.rb

eventmask type conflict

Gdk::WindowAttr.new(
  event_mask: Gdk::EventMask::ZERO_NONE
  )
no overload matches 'Gdk::WindowAttr.new', event_mask: LibGdk::EventMask
Overloads are:
 - Gdk::WindowAttr.new(title : String | Nil = nil, event_mask : Int32 | Nil = nil, x : Int32 | Nil = nil, y : Int32 | Nil = nil, width : Int32 | Nil = nil, height : Int32 | Nil = nil, wclass : Gdk::WindowWindowClass | Nil = nil, visual : Gdk::Visual | Nil = nil, window_type : Gdk::WindowType | Nil = nil, cursor : Gdk::Cursor | Nil = nil, wmclass_name : String | Nil = nil, wmclass_class : String | Nil = nil, override_redirect : Bool | Nil = nil, type_hint : Gdk::WindowTypeHint | Nil = nil)
 - Gdk::WindowAttr.new(gdk_window_attr : ::Pointer(LibGdk::WindowAttr))

also the flags have type UInt32, but WindowAttr wants them as Int32

Undefined constant LibGObject::ObjectClass (Gtk 4 compat)

Next problem after #33 was fixed:

Called macro defined in lib/gobject/gobject.cr:7:1

 7 | macro require_gobject(namespace)

Which expanded to:

 > 6463 | fun editable_delegate_get_property = gtk_editable_delegate_get_property(object : LibGObject::Object*, prop_id : UInt32, value : LibGObject::Value*, pspec : LibGObject::ParamSpec*) : Bool
 > 6464 | fun editable_delegate_set_property = gtk_editable_delegate_set_property(object : LibGObject::Object*, prop_id : UInt32, value : LibGObject::Value*, pspec : LibGObject::ParamSpec*) : Bool
 > 6465 | fun editable_install_properties = gtk_editable_install_properties(object_class : LibGObject::ObjectClass*, first_prop : UInt32) : UInt32
                                                                                           ^----------------------
Error: undefined constant LibGObject::ObjectClass

(gtk3-3.24.10)

error compiling samples, greeter, casting to LibGtk::Widget*

crystal build samples/greeter.cr 
Error in samples/greeter.cr:27: instantiating 'greet(Gtk::Button+, Gtk::Window, Gtk::Label, Gtk::Entry)'

  greet button, info, info_text, name
  ^~~~~

in samples/greeter.cr:12: instantiating 'Gtk::Button+#sensitive=(Bool)'

  button.sensitive = false
         ^~~~~~~~~

in src/generated/gtk/widget.cr:1354: can't cast (Pointer(LibGtk::Button) | Pointer(LibGtk::CheckButton) | Pointer(LibGtk::ColorButton) | Pointer(LibGtk::FontButton) | Pointer(LibGtk::LinkButton) | Pointer(LibGtk::LockButton) | Pointer(LibGtk::MenuButton) | Pointer(LibGtk::ModelButton) | Pointer(LibGtk::RadioButton) | Pointer(LibGtk::ScaleButton) | Pointer(LibGtk::ToggleButton) | Pointer(LibGtk::VolumeButton)) to Pointer(LibGtk::Widget)

      LibGtk.widget_set_sensitive(to_unsafe.as(LibGtk::Widget*), sensitive)
                                  ^

libgtk3 version: 3.18.9-1ubuntu3.3
Crystal version 0.23.1 [e2a1389e8] (2017-07-13) LLVM 3.8.1

Gtk::Application

It would be nice to have a sample on how to instantiate and use a Gtk::Application object

struct has no field 'to_unsafe'

require "gobject/gdk"

attr = LibGdk::WindowAttr.new
win = Gdk::Window.new nil, attr, 0
$ crystal civ.cr
Error in ./civ.cr:4: instantiating 'Gdk::Window:Class#new(Nil, LibGdk::WindowAttr, Int32)'

win = Gdk::Window.new nil, attr, 0
                  ^~~

in ./libs/gobject/generated/gdk/window.cr:13: struct LibGdk::WindowAttr has no field 'to_unsafe'

      __return_value = LibGdk.window_new(parent && parent.to_unsafe.as(LibGdk::Window*), attributes.to_unsafe.as(LibGdk::WindowAttr*), attributes_mask)

                   ^~~~~~~~~

i'm not clear on when to use LibGdk vs Gdk

edit: it looks like we're supposed to do this?:

attrV = LibGdk::WindowAttr.new
attr = Gdk::WindowAttr.new pointerof(attrV)

Getting undefined reference to `g_object_new_with_properties'

Not sure what is happening here, but most of the samples don't work anymore

$ crystal version
Crystal 0.34.0 [4401e90f0] (2020-04-06)

LLVM: 8.0.0
Default target: x86_64-unknown-linux-gnu

shard.yml

dependencies:
  gobject:
    github: jhass/crystal-gobject
    version: ~> 0.8.0

Error when trying to run a sample

crystal build gtk_menu_and_actions.cr 
M-yA-pplication.o: In function `initialize:application_id':
/home/laptop/try/gtk/lib/gobject/samples/lib/gobject/gtk/gtk.cr:4: undefined reference to `g_object_new_with_properties'
G-tk5858A-pplicationW-indow.o: In function `initialize:application:title:default_width:default_height:icon_name':
/home/laptop/try/gtk/lib/gobject/samples/lib/gobject/gtk/gtk.cr:4: undefined reference to `g_object_new_with_properties'
G-tk5858M-enuI-tem.o: In function `initialize:label':
/home/laptop/try/gtk/lib/gobject/samples/lib/gobject/gtk/gtk.cr:4: undefined reference to `g_object_new_with_properties'
collect2: error: ld returned 1 exit status
Error: execution of command failed with code: 1: `cc "${@}" -o '/home/laptop/try/gtk/lib/gobject/samples/gtk_menu_and_actions'  -rdynamic  -lgdk-3 -lgtk-3 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lgobject-2.0 -lglib-2.0 -lpcre -lm /usr/bin/../lib/crystal/lib/libgc.a -lpthread /usr/share/crystal/src/ext/libcrystal.a -levent -lrt -ldl -L/usr/bin/../lib/crystal/lib -L/usr/bin/../lib/crystal/lib`

About Container#children method

I use XUbuntu19.10 (gir1.2-freedesktop 1.62.0-1)
Compile-time bindings has follow code :

def children
     __return_value = LibGtk.container_get_children(@pointer.as(LibGtk::Container*))
     GObject.raise_unexpected_null("gtk_container_get_children") if __return_value.null?
     GLib::ListIterator(Gtk::Widget, LibGtk::Widget*).new(GLib::SList.new(__return_value.as(LibGLib::List*)))
   end

Matter in

GLib::SList.new

because

LibGtk.container_get_children

returns

LibGLib::List*

In my opinion, this method must have code as is follow:

def children
      __return_value = LibGtk.container_get_children(@pointer.as(LibGtk::Container*))
      GObject.raise_unexpected_null("gtk_container_get_children") if __return_value.null?
      GLib::ListIterator(Gtk::Widget, LibGtk::Widget*).new(GLib::List.new(__return_value.as(LibGLib::List*)))
    end

How to inherit from a Gtk::Application ?

Hi, I'm translating some examples from Ruby-gnome2 bindings. The example Apps dir contains classes that inherits from Gtk::Application . I tried this:

require "gtk"

class ExampleAppWindow < Gtk::ApplicationWindow
  def open(file)
  end
end

class ExampleApp < Gtk::Application

  def initialize
    super   #   <----- error

    on_activate do |application|
      window = ExampleAppWindow.new(application)
      window.present
    end
...
end

I got:

wrong number of arguments for 'Gtk::Application#initialize' (given 0, expected 1)
Overloads are:
 - Gtk::Application#initialize(pointer : ::Pointer(LibGtk::Application))

    super
    ^~~~~

Can't generate bindings for libvips

I'm trying to generate bindings for libvips:

GIRepository::Repository.instance.require "Vips"
Namespace.new("Vips").write "src/generated"             

but it throws error:

Nil assertion failed (Exception)          
0x10f34e1a5: *CallStack::unwind:Array(Pointer(Void)) at ?? 
0x10f34e141: *CallStack#initialize:Array(Pointer(Void)) at ??                                                          
0x10f34e118: *CallStack::new:CallStack at ??               
0x10f335c85: *raise<Exception>:NoReturn at ??              
0x10f335c31: *raise<String>:NoReturn at ??                 
0x10f37e363: *Nil#not_nil!:NoReturn at ??                  
0x10f36ed5b: *String#[]<Regex, Int32>:String at ??         
0x10f3b095b: *Namespace#lib_definition<File>:Nil at ??     
0x10f3b0609: *Namespace#write_lib<String>:Nil at ??        
0x10f3b0475: *Namespace#write<String>:Nil at ??            
0x10f335719: __crystal_main at ??                          
0x10f34aa98: main at ??  

Crystal version: 0.23.0
vips version: 8.5.6

Samples don't compile

Hello!

I've tried gtk_hello_world and gdk_window samples, but they don't compile:

Error in src/shine-panel.cr:6: instantiating 'Gtk::Window:Class#new()'

 window = Gtk::Window.new
                      ^~~

in lib/gobject/src/gtk/gtk.cr:47: instantiating 'new(LibGtk::WindowType)'

      new LibGtk::WindowType::TOPLEVEL
      ^~~

in lib/gobject/src/generated/gtk/window.cr:50: instantiating 'cast(Gtk::Widget)'

      cast Gtk::Widget.new(__return_value)
      ^~~~

in lib/gobject/src/generated/gtk/window.cr:4: expanding macro

  class Window < Bin
  ^

in macro 'inherited' expanded macro: included:1, line 3:

   1.         # Add run-time check
   2.         def self.cast(object) : self
>  3.           new(object.to_unsafe as LibGtk::Window*)
   4.         end
   5.       

wrong number of arguments for 'Gtk::Widget#to_unsafe' (given 1, expected 0)
Overloads are:
 - Gtk::Widget#to_unsafe()
 - GObject::InitiallyUnowned#to_unsafe()
 - GObject::Object#to_unsafe()

Crystal version is 0.20.3
GTK 3.22.6

Thanks.

Can't install the shard with crystal v0.34.0

I get the following:

$ shards install
Resolving dependencies
Fetching https://github.com/jhass/crystal-gobject.git
Installing gobject (0.3.0 at 09f02b85e533e6cdb74a96c78ef76727fac53b56)
Unhandled exception: Error creating symlink: '../../lib' -> '/home/renich/test/lib/gobject/lib': File exists (File::AlreadyExistsError)
  from Crystal::System::File::symlink<String, String>:Int32
  from File::symlink<String, String>:Int32
  from Shards::Package#install:(Int32 | Nil)
  from Shards::Commands::Install#install<Shards::Package>:(Shards::Package | Nil)
  from Shards::Commands::Install#install<Array(Shards::Package)>:Nil
  from Shards::Commands::Install#run:Nil
  from Shards::Commands::Install
  from ~procProc(Array(String), Array(String), Nil)
  from OptionParser::ParseTask#parse:Nil
  from OptionParser#parse<Array(String)>:Nil
  from Shards::run:OptionParser
  from __crystal_main
  from Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil
  from Crystal::main<Int32, Pointer(Pointer(UInt8))>:Int32
  from main
  from __libc_start_main
  from _start
  from ???

Wrong code generated for GFileMonitorEvent

The following code fails to compile:

require "gobject/gio"

def file_changed(monitor : Gio::FileMonitor, file : Gio::File, other_file : Gio::File, event : Gio::FileMonitorEvent)
  puts "something happpened"
end

monitor = Gio::File.new_for_path(".").monitor_directory(:watch_moves, nil)
monitor.on_changed(&->file_changed(Gio::FileMonitor, Gio::File, Gio::File, Gio::FileMonitorEvent))

Error:

There was a problem expanding macro 'require_gobject'

Code in lib/gobject/gio/gio.cr:4:1

 4 | require_gobject "Gio"
     ^
Called macro defined in lib/gobject/gobject.cr:24:1

 24 | macro require_gobject(namespace, version = nil)

Which expanded to:

 > 17520 | def on_changed(&block : ChangedSignal)
 > 17521 |   __var0 = -> (arg1 : LibGio::File*, arg2 : LibGio::File*, arg3 : LibGio::FileMonitorEvent*, arg0 : LibGio::FileMonitor*) {
 > 17522 |     block.call(FileMonitor.new(arg0), Gio::File::Wrapper.new(arg1), Gio::File::Wrapper.new(arg2), Gio::FileMonitorEvent.new(arg3))
                                                                                                                                   ^--
Error: no overload matches 'Gio::FileMonitorEvent.new' with type Pointer(UInt32)

Overloads are:
 - Gio::FileMonitorEvent.new(value : ::UInt32)

GFileMonitorEvent is a enum in C.

Using GAction with Gtk Application

Hey!

I'm trying to use this lib to create a simple Gtk application, but I'm having issues to setup the menu.

Here's the gist: https://gist.github.com/thiagoabreu/39858db3345904249505a41ccf408bd8

The problem I have is with this line:

action_entries = [
      LibGio::ActionEntry.new(name: "quit", activate: ->{ puts "quit" }), # works
      LibGio::ActionEntry.new(name: "quit", activate: ->{ self.quit }), # doesn't work
    ]
    add_action_entries action_entries, action_entries.size, nil

The second entry raises an Error:
Error: can't set closure as C struct member

Is there something I'm doing wrong?

Avoid renaming to `new_internal`

button=Gtk::Entry.new
Error in ./efinder.cr:8: wrong number of arguments for 'Gtk::Entry#initialize' (given 0, expected 1)
Overloads are:
 - Gtk::Entry#initialize(gtk_entry)

entry=Gtk::Entry.new()

But where can i find gtk_entry?

Gtk::TreeStore#model returns the C pointer instead of Crystal wrapper

This may be related to the last fixes on signals, this example shows that the first signal parameter is a union type instead of a Crystal gobject wrapper.

require "gobject/gtk/autorun"

builder = Gtk::Builder.new_from_file("#{__DIR__}/../lib/gobject/samples/gtk_tree_view.glade")
builder.connect_signals

# Insert something into the model
model = Gtk::TreeStore.cast(builder["tree_model"])
root = Gtk::TreeIter.new
model.append(root, nil)
model.set(root, [0], GObject::Value.new("Root"), 1)

# view
view = Gtk::TreeView.cast(builder["tree_view"])
view.on_row_activated do |view, path, column|
  model = view.model.not_nil!

  puts "model type:  #{typeof(model)}"
  puts "path type:   #{typeof(path)}"
  puts "column type: #{typeof(column)}"
  if model.is_a?(Gtk::TreeStore)
    puts "Crystal friendly object"
  elsif model.is_a?(Pointer(LibGtk::TreeModel))
    puts "Got the C pointer!?"
  else
    abort("caos")
  end
end

# Show main view.
main_window = Gtk::Window.cast(builder["main_window"])
main_window.show_all

Output here after I double click in the tree view row:

model type:  (Gtk::TreeStore | Pointer(LibGtk::TreeModel))
path type:   Gtk::TreePath
column type: Gtk::TreeViewColumn
Got the C pointer!?

Tested on archlinux, crystal 0.34, crystal-gobject at 4f1e6c6.

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.