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

Issue with sigatom #391

Open
tknopp opened this issue Oct 5, 2018 · 19 comments
Open

Issue with sigatom #391

tknopp opened this issue Oct 5, 2018 · 19 comments

Comments

@tknopp
Copy link
Collaborator

tknopp commented Oct 5, 2018

Dear @vtjnash,

There is still a major limitation of the Julia Gtk bindings compared to other language bindings. Its that one can only do one thing at a time. I get

FATAL ERROR: Gtk state corrupted by error thrown in a callback:
ERROR: AssertionError: g_stack === nothing && !prev
Stacktrace:
 [1] g_sigatom(::Any) at /Users/knopp/.julia/packages/Gtk/ADDrn/src/GLib/signals.jl:165
 [2] macro expansion at /Users/knopp/.julia/packages/Gtk/ADDrn/src/GLib/signals.jl:191 [inlined]
 [3] update2 at /Users/knopp/.julia/dev/Gtk/example/task_issue.jl:22 [inlined]
 [4] (::getfield(Base, Symbol("##436#437")){typeof(update2),Timer})() at ./event.jl:475

if I execute the following test program:

using Gtk.ShortNames
using Dates

b = Box(:v)
win = Window(b,"test")
ent = Entry()
push!(b,ent)

button = Button("ok")
push!(b,button)
Gtk.showall(win)

function update_(::Timer)
  Gtk.@sigatom begin
    set_gtk_property!(ent, :text, "$(Dates.now())")
  end
end
timer = Timer(update_, 0.0, interval=0.1)

signal_connect(button, "clicked") do widget
  Gtk.@sigatom begin
    set_gtk_property!(button, :label, "$(rand(1:10))")
    sleep(1.0)
  end
end

You have to click on the button to see the crash.

The example is of course constructed but appears in a real application of mine. The sleep is actually a computation that takes some time.

It would be absolutely awesome if we could find a solution to this problem. Do you think JuliaLang/julia#13099 would solve this, if I just remove sigatom?

@jonathanBieler
Copy link
Collaborator

jonathanBieler commented Oct 5, 2018

I think that's the correct way to do that:

using GtkExtensions
using Gtk.ShortNames
using Dates

b = Box(:v)
win = Window(b,"test")
ent = Entry()
push!(b,ent)

button = Button("ok")
push!(b,button)
Gtk.showall(win)

function update_cb!(user_data)
    ent = unsafe_pointer_to_objref(user_data)
    set_gtk_property!(ent, :text, "$(Dates.now())")
    Cint(true)#keep running
end

g_timeout_add(100,update_cb!,ent) #do every 100ms

signal_connect(button, "clicked") do widget
    set_gtk_property!(button, :label, "$(rand(1:10))")
end

using this https://github.com/jonathanBieler/GtkExtensions.jl/blob/master/src/GtkExtensions.jl#L337

@tknopp
Copy link
Collaborator Author

tknopp commented Oct 5, 2018

If I remove "@sigatom" from something that changes the UI (set*) I get segfaults.

@jonathanBieler
Copy link
Collaborator

I never use @sigatom and I never had that kind of issues (on macOS at least). That said this one works fine too:

using GtkExtensions
using Gtk.ShortNames
using Dates

b = Box(:v)
win = Window(b,"test")
ent = Entry()
push!(b,ent)

button = Button("ok")
push!(b,button)
Gtk.showall(win)

function update_cb!(user_data)
    ent = unsafe_pointer_to_objref(user_data)
    Gtk.@sigatom begin
        set_gtk_property!(ent, :text, "$(Dates.now())")
    end
    Cint(true)#keep running
end

g_timeout_add(100,update_cb!,ent) #do every 100ms

signal_connect(button, "clicked") do widget
    Gtk.@sigatom begin
        set_gtk_property!(button, :label, "$(rand(1:10))")
    end
end

@tknopp
Copy link
Collaborator Author

tknopp commented Oct 5, 2018

Can you add a sleep to your original example?

@jonathanBieler
Copy link
Collaborator

It works fine with a sleep, it blocks the application for 0.1 second though.

@tknopp
Copy link
Collaborator Author

tknopp commented Oct 5, 2018

I cannot test your code in Julia 1.0 since cfunction is no more.

@tknopp
Copy link
Collaborator Author

tknopp commented Oct 6, 2018

Regarding sleep just try my original example and remove the sigatom, it will segfault. In reality I of course don't have a sleep in my code but it is very hard to prevent a yield if one has a large code base.

@jonathanBieler
Copy link
Collaborator

jonathanBieler commented Oct 6, 2018

Yes, I think the underlying problem is that it's not safe to interact with Gtk components outside of Gtk's main loop. As I understand sigatom is a workaround, but if you use g_timeout_add and such you'll won't have this problem in the first place since in that case everything is ran from the main loop.

@tknopp
Copy link
Collaborator Author

tknopp commented Oct 6, 2018

Could you add that function to Gtk.jl? It is in GLib so it fits.

@jonathanBieler
Copy link
Collaborator

jonathanBieler commented Oct 7, 2018

I will yes, I have a bunch of stuff in GtkExtensions that should be in Gtk but I haven't had time to move them yet.

Maybe having a look at what other languages do with this would be useful (it seems like Python also has this idle_add).

@tknopp
Copy link
Collaborator Author

tknopp commented Oct 7, 2018

yes looking into how other languages do this is a good thing. While my original is a valid use case, what I also would like is to have some heavy computation in the background while the UI is still responsive. For now I have solve this by braking my computation into chunks and using a task for it that always waits between the chunks.

@tknopp
Copy link
Collaborator Author

tknopp commented Jan 1, 2019

On julia 1.1 the following code does not segfault anymore:

using Gtk.ShortNames
using Dates

b = Box(:v)
win = Window(b,"test")
ent = Entry()
push!(b,ent)

button = Button("ok")
push!(b,button)
Gtk.showall(win)

function update_(::Timer)
  set_gtk_property!(ent, :text, "$(Dates.now())")
end
timer = Timer(update_, 0.0, interval=0.1)

signal_connect(button, "clicked") do widget
  set_gtk_property!(button, :label, "$(rand(1:10))")
  sleep(1.0)
end

@tknopp
Copy link
Collaborator Author

tknopp commented Oct 14, 2019

@vtjnash: I introduced a macro @idle_add that can be used to run code on the UI thread (or simply postpone it when being in a callback). This seems to be the correct solution for Gtk Python and C applications:

https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-timeout-add

After removing @sigatom from my application and replacing it with @idle_add I am wondering if we should simply remove @sigatom or at least not expose it as public API and better point to @idle_add instead. What do you think? @timholy, @jonathanBieler: Whats your take on this? Are you using @sigatom in user code?

@jonathanBieler
Copy link
Collaborator

I'm not using @sigatom no, it's also not used in Immerse.jl or GtkUtilities.jl (at least a quick search indicates), so I have no issues with removing it.

@timholy
Copy link
Member

timholy commented Apr 24, 2022

This is now coming up in the GtkObservables tests, specifically g_stack is sometimes a Task (and not the current_task()) at

@assert g_stack === nothing && !prev

Any ideas of how best to handle this? My knowledge of this part of the code is pretty minimal.

timholy added a commit to JuliaGizmos/GtkObservables.jl that referenced this issue Apr 24, 2022
@timholy
Copy link
Member

timholy commented Apr 24, 2022

There's a workaround in JuliaGizmos/GtkObservables.jl#30

timholy added a commit to JuliaGizmos/GtkObservables.jl that referenced this issue Apr 24, 2022
@tknopp
Copy link
Collaborator Author

tknopp commented Apr 24, 2022

We should probably just remove it. The only important location I just found was this:

gtk_main() = GLib.g_sigatom() do

@timholy
Copy link
Member

timholy commented Apr 27, 2022

That seems like a big one, though!

@tknopp
Copy link
Collaborator Author

tknopp commented Apr 27, 2022

Yes, indeed. It's the one that wraps everything.

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

3 participants