3
0
mirror of https://github.com/britzl/monarch.git synced 2025-06-27 10:27:49 +02:00

Improved handling of unregistered screens (#93)

* Set cowait flag

* Set screen as unregistered

* Do not process screen which have been unregistered

* Java 17
This commit is contained in:
Björn Ritzl 2023-07-29 11:28:18 +02:00 committed by GitHub
parent 66d2c98ccc
commit c601174b9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 8 deletions

View File

@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: actions/setup-java@v1 - uses: actions/setup-java@v1
with: with:
java-version: '11' java-version: '17'
- name: Run.sh - name: Run.sh
env: env:
DEFOLD_USER: bjorn.ritzl@gmail.com DEFOLD_USER: bjorn.ritzl@gmail.com

View File

@ -3,6 +3,7 @@ local async = require "monarch.utils.async"
local M = {} local M = {}
local WAITFOR_COWAIT = hash("waitfor_cowait")
local WAITFOR_CONTEXT = hash("waitfor_monarch_context") local WAITFOR_CONTEXT = hash("waitfor_monarch_context")
local WAITFOR_PROXY_LOADED = hash("waitfor_proxy_loaded") local WAITFOR_PROXY_LOADED = hash("waitfor_proxy_loaded")
local WAITFOR_PROXY_UNLOADED = hash("waitfor_proxy_unloaded") local WAITFOR_PROXY_UNLOADED = hash("waitfor_proxy_unloaded")
@ -86,10 +87,13 @@ local function assign(to, from)
return to return to
end end
local function cowait(delay) local function cowait(screen, delay)
log("cowait()", screen.id, delay)
local co = coroutine.running() local co = coroutine.running()
assert(co, "You must run this from within a coroutine") assert(co, "You must run this from within a coroutine")
screen.wait_for = WAITFOR_COWAIT
timer.delay(delay, false, function() timer.delay(delay, false, function()
screen.wait_for = nil
assert(coroutine.resume(co)) assert(coroutine.resume(co))
end) end)
coroutine.yield() coroutine.yield()
@ -327,6 +331,7 @@ function M.unregister(id)
id = tohash(id) id = tohash(id)
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id))) assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
log("unregister()", id) log("unregister()", id)
local screen = screens[id]
screens[id] = nil screens[id] = nil
-- remove screen from stack -- remove screen from stack
for i = #stack, 1, -1 do for i = #stack, 1, -1 do
@ -334,6 +339,10 @@ function M.unregister(id)
table.remove(stack, i) table.remove(stack, i)
end end
end end
screen.unregistered = true
if screen.wait_for then
assert(coroutine.resume(screen.co))
end
end end
local function acquire_input(screen) local function acquire_input(screen)
@ -381,6 +390,7 @@ local function change_context(screen)
end end
local function unload(screen, force) local function unload(screen, force)
if screen.unregistered then return end
if screen.proxy then if screen.proxy then
log("unload() proxy", screen.id) log("unload() proxy", screen.id)
if screen.auto_preload and not force then if screen.auto_preload and not force then
@ -415,8 +425,8 @@ local function unload(screen, force)
-- we need to wait here in case the unloaded screen contained any screens -- we need to wait here in case the unloaded screen contained any screens
-- if this is the case we need to let these sub-screens have their final() -- if this is the case we need to let these sub-screens have their final()
-- functions called so that they have time to call unregister() -- functions called so that they have time to call unregister()
cowait(0) cowait(screen, 0)
cowait(0) cowait(screen, 0)
end end
@ -443,6 +453,9 @@ local function preload(screen)
msg.post(screen.proxy, MSG_ASYNC_LOAD) msg.post(screen.proxy, MSG_ASYNC_LOAD)
coroutine.yield() coroutine.yield()
screen.wait_for = nil screen.wait_for = nil
if screen.unregistered then
return false, "Screen was unregistered while loading"
end
elseif screen.factory then elseif screen.factory then
log("preload() factory") log("preload() factory")
if collectionfactory.get_status(screen.factory) == collectionfactory.STATUS_UNLOADED then if collectionfactory.get_status(screen.factory) == collectionfactory.STATUS_UNLOADED then
@ -450,6 +463,9 @@ local function preload(screen)
assert(coroutine.resume(screen.co)) assert(coroutine.resume(screen.co))
end) end)
coroutine.yield() coroutine.yield()
if screen.unregistered then
return false, "Screen was unregistered while loading"
end
end end
if collectionfactory.get_status(screen.factory) ~= collectionfactory.STATUS_LOADED then if collectionfactory.get_status(screen.factory) ~= collectionfactory.STATUS_LOADED then
@ -494,6 +510,7 @@ end
local function transition(screen, message_id, message, wait) local function transition(screen, message_id, message, wait)
log("transition()", screen.id) log("transition()", screen.id)
if screen.unregistered then return end
if screen.transition_url then if screen.transition_url then
screen.wait_for = WAITFOR_TRANSITION_DONE screen.wait_for = WAITFOR_TRANSITION_DONE
msg.post(screen.transition_url, message_id, message) msg.post(screen.transition_url, message_id, message)
@ -517,14 +534,15 @@ end
local function focus_lost(screen, next_screen) local function focus_lost(screen, next_screen)
log("focus_lost()", screen.id) log("focus_lost()", screen.id)
if screen.unregistered then return end
if screen.focus_url then if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.LOST, { id = next_screen and next_screen.id }) msg.post(screen.focus_url, M.FOCUS.LOST, { id = next_screen and next_screen.id })
-- if there's no transition on the screen losing focus and it gets -- if there's no transition on the screen losing focus and it gets
-- unloaded this will happen before the focus_lost message reaches -- unloaded this will happen before the focus_lost message reaches
-- the focus_url -- the focus_url
-- we add a delay to ensure the message queue has time to be processed -- we add a delay to ensure the message queue has time to be processed
cowait(0) cowait(screen, 0)
cowait(0) cowait(screen, 0)
else else
log("focus_lost() no focus url - ignoring") log("focus_lost() no focus url - ignoring")
end end
@ -645,7 +663,7 @@ local function show_in(screen, previous_screen, reload, add_to_stack, wait_for_t
return return
end end
-- wait one frame so that the init() of any script have time to run before starting transitions -- wait one frame so that the init() of any script have time to run before starting transitions
cowait(0) cowait(screen, 0)
reset_timestep(screen) reset_timestep(screen)
transition(screen, M.TRANSITION.SHOW_IN, { previous_screen = previous_screen and previous_screen.id }, wait_for_transition) transition(screen, M.TRANSITION.SHOW_IN, { previous_screen = previous_screen and previous_screen.id }, wait_for_transition)
screen.visible = true screen.visible = true
@ -671,7 +689,7 @@ local function back_in(screen, previous_screen, wait_for_transition, cb)
return return
end end
-- wait one frame so that the init() of any script have time to run before starting transitions -- wait one frame so that the init() of any script have time to run before starting transitions
cowait(0) cowait(screen, 0)
reset_timestep(screen) reset_timestep(screen)
if previous_screen and not previous_screen.popup then if previous_screen and not previous_screen.popup then
transition(screen, M.TRANSITION.BACK_IN, { previous_screen = previous_screen.id }, wait_for_transition) transition(screen, M.TRANSITION.BACK_IN, { previous_screen = previous_screen.id }, wait_for_transition)