JuliaGraphics / Gtk.jl

Julia interface to Gtk windowing toolkit.
Other
290 stars 80 forks source link

Hangs when calling open_dialog()/open_dialog_native() non-interactively #576

Open MillironX opened 3 years ago

MillironX commented 3 years ago

When calling open_dialog() or open_dialog_native() from a script file, the value is never returned and the process hangs at the line where open_dialog() is called.

Steps to reproduce

Create a file with the following:

gtktest.jl

using Gtk
open_dialog_native("Select a file")

Run using

julia gtktest.jl

Select a file and double-click it or click "open"

Expected results

The path of the file you selected should be printed. E.g.

"/home/millironx/sample.csv"

Actual results

The dialog goes away, but the nothing is printed to the terminal, and the prompt doesn't return (the process hangs)

Running interactively

This problem does not occur if running in the REPL, although Gtk still complains

julia> using Gtk
Gtk-Message: 21:15:12.767: Failed to load module "colorreload-gtk-module"
Gtk-Message: 21:15:12.979: Failed to load module "colorreload-gtk-module"

(julia:28966): Gtk-WARNING **: 21:15:12.987: Could not load a pixbuf from /org/gtk/libgtk/theme/Adwaita/assets/bullet-symbolic.svg.
This may indicate that pixbuf loaders or the mime database could not be found.

julia> openpath = open_dialog_native(
           "Select a datasheet")
"/home/millironx/sample.csv"

What I've tried

My system info

BioTurboNick commented 2 years ago

Possibly similar issue: ask_dialog, when run in a script, doesn't close when a dialog choice is selected and thus never returns.

From: https://discourse.julialang.org/t/problem-with-gui-ask-dialog/73224/9

using Gtk
state = ask_dialog("Find Steady-state solution and start rom steady-state?", "No", "Yes")
println("never reached")
if !isinteractive()
    @async Gtk.gtk_main()
end
BioTurboNick commented 2 years ago

Sticking a println between dlg = and run(dlg) seems to cause the bug for ask_dialog to disappear.

tknopp commented 2 years ago

This works

using Gtk

win = GtkWindow("gtkwait")

if !isinteractive()
    @async Gtk.gtk_main()
end

@async begin
  state = ask_dialog("Find Steady-state solution and start rom steady-state?", "No", "Yes")
  println("never reached")
end

if !isinteractive()
    Gtk.waitforsignal(win,:destroy)
end

So the event loop needs to be started first. Then the ask_dialog needs to be in an async block since otherwise the Gtk.gtk_main() will not run because of a missing yield. An finally I need a window to stop the app from closing. This could of course also be done differently.

BioTurboNick commented 2 years ago

Ah good. Then we'll need the documentation to be adjusted. Currently it says to put all GUI code in front of Gtk.gtk_main().

https://juliagraphics.github.io/Gtk.jl/latest/manual/nonreplusage/#

tknopp commented 2 years ago

Yes. But my example is not yet nice for consumption within the docu. I think we need to distinguish two cases. The one where you have a window and no interactive code like above, i.e. GUI code in that context really means building the GUI and no callbacks/drawing involved.

The second use case is that with interactions going on. Then you need the extra task.

tknopp commented 2 years ago

Here is a better version of use case 2:

using Gtk

if !isinteractive()
    @async Gtk.gtk_main()
end

t = @async begin
  state = ask_dialog("Find Steady-state solution and start rom steady-state?", "No", "Yes")
  println("never reached")
end

if !isinteractive()
    wait(t)
end