Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

calling gtk_widget_add_tick_callback() #634

Closed
DylanMMarques opened this issue Mar 18, 2022 · 3 comments
Closed

calling gtk_widget_add_tick_callback() #634

DylanMMarques opened this issue Mar 18, 2022 · 3 comments

Comments

@DylanMMarques
Copy link

Hello,

I am trying to develop an animation using Gtk and I need to control the image displayed in each frame. I looked into the documentation and the function gtk_widget_add_tick_callback() allows me to do what I want. Unfortunately, I couldn't find a nice way of using Gtk.jl to setup the callback function so I tried to use the libgtk directly. The following code work as expected, and print "Update frame on global":

using Gtk

function f(widget, clock, data_)
    @show "update frame on global"
    return zero(Int32)
end

callback_c= @cfunction(f, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}))
gtk_callback(window, callback, data, notify) = @ccall Gtk.libgtk.gtk_widget_add_tick_callback(window::Ptr{Cvoid}, callback::Ptr{Cvoid}, data::Ptr{Cvoid}, notify::Ptr{Cvoid})::Culonglong

gtk_remove_callback(window, id) = @ccall Gtk.libgtk.gtk_widget_remove_tick_callback(window::Ptr{Cvoid}, id::Culonglong)::Cvoid

window = Gtk.Window("Tilte", 100, 100)
id = gtk_callback(window.handle, callback_c, C_NULL, C_NULL)

However, if I defined the same functions inside an package and call the module, the same code crashes. For example:

module callback_test
    using Gtk
    function f(widget, clock, data_)
        @show "update frame using module"
        return zero(Int32)
    end
    
    callback_c= @cfunction(f, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}))
    gtk_callback(window, callback, data, notify) = @ccall Gtk.libgtk.gtk_widget_add_tick_callback(window::Ptr{Cvoid}, callback::Ptr{Cvoid}, data::Ptr{Cvoid}, notify::Ptr{Cvoid})::Culonglong
    
    gtk_remove_callback(window, id) = @ccall Gtk.libgtk.gtk_widget_remove_tick_callback(window::Ptr{Cvoid}, id::Culonglong)::Cvoid
   
    function from_outside_module(window)
        gtk_callback(window.handle, callback_c, C_NULL, C_NULL)
    end
end

If then I run:

using callback_test
window = callback_test.Gtk.Window("Title", 100, 100)
callback_test.from_outside_module(window)

The program will crash with the outup:

Exception: EXCEPTION_ACCESS_VIOLATION at 0x0 -- unknown function (ip: 0000000000000000)
in expression starting at c:\Users\dylan\.julia\dev\OpenFP\test\callback.jl:16
unknown function (ip: 0000000000000000)
gtk_widget_on_frame_clock_update at /workspace/srcdir/gtk/build-gtk\../gtk\gtkwidget.c:5287
_g_closure_invoke_va at C:\Users\dylan\.julia\artifacts\99d6d05b9277238710d385cefa9ea814c8fa122c\bin\libgobject-2.0-0.dll (unknown line)
g_signal_emit_valist at C:\Users\dylan\.julia\artifacts\99d6d05b9277238710d385cefa9ea814c8fa122c\bin\libgobject-2.0-0.dll (unknown line)
g_signal_emit at C:\Users\dylan\.julia\artifacts\99d6d05b9277238710d385cefa9ea814c8fa122c\bin\libgobject-2.0-0.dll (unknown line)       
gdk_frame_clock_paint_idle at /workspace/srcdir/gtk/build-gtk\../gdk\gdkframeclockidle.c:547
gdk_threads_dispatch at /workspace/srcdir/gtk/build-gtk\../gdk\gdk.c:769
g_timeout_dispatch at C:\Users\dylan\.julia\artifacts\99d6d05b9277238710d385cefa9ea814c8fa122c\bin\libglib-2.0-0.dll (unknown line)     
g_main_context_dispatch at C:\Users\dylan\.julia\artifacts\99d6d05b9277238710d385cefa9ea814c8fa122c\bin\libglib-2.0-0.dll (unknown line)
g_main_context_iterate.isra.20 at C:\Users\dylan\.julia\artifacts\99d6d05b9277238710d385cefa9ea814c8fa122c\bin\libglib-2.0-0.dll (unknown line)
g_main_loop_run at C:\Users\dylan\.julia\artifacts\99d6d05b9277238710d385cefa9ea814c8fa122c\bin\libglib-2.0-0.dll (unknown line)
gtk_main at /workspace/srcdir/gtk/build-gtk\../gtk\gtkmain.c:1329
#253 at C:\Users\dylan\.julia\dev\Gtk\src\events.jl:2
unknown function (ip: 000000003f690513)
g_sigatom at C:\Users\dylan\.julia\dev\Gtk\src\GLib\signals.jl:176
gtk_main at C:\Users\dylan\.julia\dev\Gtk\src\events.jl:1
unknown function (ip: 000000003f6904b3)
jl_apply at /cygdrive/c/buildbot/worker/package_win64/build/src\julia.h:1788 [inlined]
start_task at /cygdrive/c/buildbot/worker/package_win64/build/src\task.c:877
Allocations: 2199451 (Pool: 2198269; Big: 1182); GC: 3

What is the reason why the program crashes when the function is defined inside a module? Is there a way around it?

Thanks,
Dylan

@DylanMMarques
Copy link
Author

This error is fixed by defining callback_c inside the local function as:

module callback_test
    using Gtk
    function f(widget, clock, data_)
        @show "update frame using module"
        return zero(Int32)
    end
    
    
    gtk_callback(window, callback, data, notify) = @ccall Gtk.libgtk.gtk_widget_add_tick_callback(window::Ptr{Cvoid}, callback::Ptr{Cvoid}, data::Ptr{Cvoid}, notify::Ptr{Cvoid})::Culonglong
    
    gtk_remove_callback(window, id) = @ccall Gtk.libgtk.gtk_widget_remove_tick_callback(window::Ptr{Cvoid}, id::Culonglong)::Cvoid
   
    function from_outside_module(window)
        callback_c= @cfunction(f, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}))
        gtk_callback(window.handle, callback_c, C_NULL, C_NULL)
    end
end
```**

@giordano
Copy link
Contributor

Yes, that has nothing to do with Gtk.jl, but only with how pointers work. Pointers must be determined at runtime, that's why the callback works in the REPL (you're defining the cfunction right there) or inside the function. Instead, if you put the cfunction definition in the top-level of the module, that's evaluated when the module is precompiled, but then you get a pointer which will very likely be invalid when you actually go and use it.

I'm moderately sure this is explained in the documentation about calling C code https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/, or anyway in this blog post about callbacks: https://julialang.org/blog/2013/05/callback/. Note that the latter is relatively old (almost 10 years ago!), but the general advices are still valid

@DylanMMarques
Copy link
Author

Thanks Giordano for the explications and for the references!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants