Merge pull request #2745 from myk002/myk_no_stuck_df_viewscreens

Prevent DF screens from getting stuck and corrupting the stack on transitions
develop
Myk 2023-01-29 16:58:36 -08:00 committed by GitHub
commit f4c4d4dcdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 4 deletions

@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## New Plugins ## New Plugins
## Fixes ## Fixes
-@ DF screens can no longer get "stuck" on transitions when DFHack tool windows are visible. Instead, those DF screens are force-paused while DFHack windows are visible so the player can close them first and not corrupt the screen sequence. The "force pause" indicator will appear on these DFHack windows to indicate what is happening.
-@ ``Screen``: allow `gui/launcher` and `gui/quickcmd` to launch themselves without hanging the game -@ ``Screen``: allow `gui/launcher` and `gui/quickcmd` to launch themselves without hanging the game
-@ Fix issues with clicks "passing through" some DFHack window elements, like scrollbars -@ Fix issues with clicks "passing through" some DFHack window elements, like scrollbars
- `getplants`: tree are now designated correctly - `getplants`: tree are now designated correctly

@ -714,7 +714,7 @@ end
function ZScreen:init() function ZScreen:init()
self.saved_pause_state = df.global.pause_state self.saved_pause_state = df.global.pause_state
if self.initial_pause then if self.initial_pause and dfhack.isMapLoaded() then
df.global.pause_state = true df.global.pause_state = true
end end
self.defocused = false self.defocused = false
@ -722,19 +722,39 @@ end
function ZScreen:dismiss() function ZScreen:dismiss()
ZScreen.super.dismiss(self) ZScreen.super.dismiss(self)
if self.force_pause or self.initial_pause then if (self.force_pause or self.initial_pause) and dfhack.isMapLoaded() then
-- never go from unpaused to paused, just from paused to unpaused -- never go from unpaused to paused, just from paused to unpaused
df.global.pause_state = df.global.pause_state and self.saved_pause_state df.global.pause_state = df.global.pause_state and self.saved_pause_state
end end
end end
local NO_LOGIC_SCREENS = {
'viewscreen_loadgamest',
'viewscreen_export_regionst',
'viewscreen_choose_game_typest',
'viewscreen_worldst',
}
for _,v in ipairs(NO_LOGIC_SCREENS) do
if not df[v] then
error('invalid class name: ' .. v)
end
NO_LOGIC_SCREENS[df[v]] = true
end
-- this is necessary for middle-click map scrolling to function -- this is necessary for middle-click map scrolling to function
function ZScreen:onIdle() function ZScreen:onIdle()
if self.force_pause then if self.force_pause and dfhack.isMapLoaded() then
df.global.pause_state = true df.global.pause_state = true
end end
if self._native and self._native.parent then if self._native and self._native.parent then
self._native.parent:logic() local vs_type = dfhack.gui.getDFViewscreen(true)._type
if NO_LOGIC_SCREENS[vs_type] then
self.force_pause = true
self.pass_movement_keys = false
self.pass_mouse_clicks = false
else
self._native.parent:logic()
end
end end
end end

@ -716,6 +716,21 @@ void dfhack_viewscreen::logic()
// Various stuff works poorly unless always repainting // Various stuff works poorly unless always repainting
Screen::invalidate(); Screen::invalidate();
// if the DF screen immediately beneath the DFHack viewscreens is waiting to
// be dismissed, raise it to the top so DF never gets stuck
auto *p = parent;
while (p) {
bool is_df_screen = !is_instance(p);
auto *next_p = p->parent;
if (is_df_screen && Screen::isDismissed(p)) {
DEBUG(screen).print("raising dismissed DF viewscreen %p\n", p);
Screen::raise(p);
}
if (is_df_screen)
break;
p = next_p;
}
} }
void dfhack_viewscreen::render() void dfhack_viewscreen::render()
@ -806,6 +821,13 @@ int dfhack_lua_viewscreen::do_destroy(lua_State *L)
auto self = get_self(L); auto self = get_self(L);
if (!self) return 0; if (!self) return 0;
if (!Screen::isDismissed(self)) {
WARN(screen).print("DFHack screen was destroyed before it was dismissed\n");
WARN(screen).print("Please tell the DFHack team which DF screen you were just viewing\n");
// run skipped onDismiss cleanup logic
Screen::dismiss(self);
}
lua_pushnil(L); lua_pushnil(L);
lua_rawsetp(L, LUA_REGISTRYINDEX, self); lua_rawsetp(L, LUA_REGISTRYINDEX, self);