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

Commit

Permalink
sequencing tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
IanButterworth committed Jan 19, 2022
1 parent 5d459da commit 757327f
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 15 deletions.
2 changes: 2 additions & 0 deletions src/GLib/GLib.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ bytestring(s::Ptr{UInt8}) = unsafe_string(s)
g_malloc(s::Integer) = ccall((:g_malloc, libglib), Ptr{Nothing}, (Csize_t,), s)
g_free(p::Ptr) = ccall((:g_free, libglib), Nothing, (Ptr{Nothing},), p)

main_depth() = ccall((:g_main_depth, libglib), Cint, ())

ccall((:g_type_init, libgobject), Nothing, ())

include("MutableTypes.jl")
Expand Down
46 changes: 34 additions & 12 deletions src/Gtk.jl
Original file line number Diff line number Diff line change
Expand Up @@ -160,40 +160,61 @@ function __init__()
end

auto_idle[] = get(ENV, "GTK_AUTO_IDLE", "true") == "true"

# by default, defer starting the event loop until either `show`, `showall`, or `g_idle_add` is called
enable_eventloop(!auto_idle[])
# by default, defer starting the event loop until widgets are "realized"
if auto_idle[]
# Start-stopping the event loop once makes the auto-stop process
# more stable. Reason unknown
enable_eventloop(true)
enable_eventloop(false)
else
enable_eventloop(true)
end
end

const auto_idle = Ref{Bool}(true) # control default via ENV["GTK_AUTO_IDLE"]
const enable_eventloop_lock = Base.ReentrantLock()
const eventloop_instructed_to_stop = Ref{Bool}(false)

"""
Gtk.enable_eventloop(b::Bool = true)
Set whether Gtk's event loop is running.
"""
function enable_eventloop(b::Bool = true)
function enable_eventloop(b::Bool = true; wait = true)
lock(enable_eventloop_lock) do # handle widgets that are being shown/destroyed from different threads
if b
if !is_eventloop_running()
eventloop_instructed_to_stop[] = false
global gtk_main_task = schedule(Task(gtk_main))
if !is_eventloop_running() && wait
t = Timer(5) # TODO: replace with Base.timedwait when 1.3 is dropped
while isopen(t) && !is_eventloop_running()
sleep(0.1)
end
isopen(t) || @debug "enable_eventloop: timed-out waiting for eventloop to start"
end
end
else
if is_eventloop_running()
recursive_quit_main()
eventloop_instructed_to_stop[] = true
if is_eventloop_running() && wait
t = Timer(5) # TODO: replace with Base.timedwait when 1.3 is dropped
while isopen(t) && is_eventloop_running()
sleep(0.1)
end
isopen(t) || @debug "enable_eventloop: timed-out waiting for eventloop to stop"
end
end
end
return is_eventloop_running()
end
end
main_depth() = ccall((:g_main_depth, Gtk.GLib.libglib), Cint, ())

function recursive_quit_main()
gtk_main_quit()
if main_depth() > 1
@idle_add begin
recursive_quit_main()
end
if GLib.main_depth() > 1
@idle_add recursive_quit_main()
end
end

Expand All @@ -205,12 +226,12 @@ pausing. Respects whether Gtk.jl is configured to allow auto-stopping of the
eventloop, unless `force = true`.
"""
function pause_eventloop(f; force = false)
was_running = is_eventloop_running()
was_running = eventloop_instructed_to_stop[] ? false : is_eventloop_running()
(force || auto_idle[]) && enable_eventloop(false)
try
f()
finally
(force || auto_idle[]) && was_running && enable_eventloop()
(force || auto_idle[]) && enable_eventloop(was_running)
end
end

Expand All @@ -219,7 +240,8 @@ end
Check whether Gtk's event loop is running.
"""
is_eventloop_running() = main_depth() > 0
is_eventloop_running() = GLib.main_depth() > 0


const ser_version = Serialization.ser_version
let cachedir = joinpath(splitdir(@__FILE__)[1], "..", "gen")
Expand Down
6 changes: 3 additions & 3 deletions src/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ const shown_widgets = WeakKeyDict()
function handle_auto_idle(w::GtkWidget)
if auto_idle[]
signal_connect(w, :realize) do w
enable_eventloop(true)
enable_eventloop(true, wait = false) # can't wait in a callback, unfortunately
shown_widgets[w] = nothing
signal_connect(w, :destroy, #= after =# true) do w
signal_connect(w, :destroy, #= after =# false) do w
delete!(shown_widgets, w)
isempty(shown_widgets) && enable_eventloop(false)
isempty(shown_widgets) && enable_eventloop(false, wait = false)
end
end
yield() # issue #610
Expand Down

0 comments on commit 757327f

Please sign in to comment.