diff --git a/src/app/app.cpp b/src/app/app.cpp index e5b6d6ff8..9ed3e5bae 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -267,9 +267,19 @@ int App::initialize(const AppOptions& options) #ifdef ENABLE_UI m_isGui = options.startUI() && !options.previewCLI(); + + // Notify the scripting engine that we're going to enter to GUI + // mode, this is useful so we can mark the stdin file handle as + // closed so no script can hang the program if it tries to read from + // stdin when the GUI is running. + #ifdef ENABLE_SCRIPTING + if (m_isGui) + m_engine->notifyRunningGui(); + #endif #else m_isGui = false; #endif + m_isShell = options.startShell(); m_coreModules = std::make_unique(); diff --git a/src/app/script/engine.cpp b/src/app/script/engine.cpp index 14153e016..4909e06b4 100644 --- a/src/app/script/engine.cpp +++ b/src/app/script/engine.cpp @@ -536,6 +536,24 @@ void Engine::destroy() L = nullptr; } +void Engine::notifyRunningGui() +{ + // Mark stdin file handle as closed so the following statements + // don't hang the program: + // - io.lines() + // - io.read('a') + // - io.stdin:read('a') + lua_getglobal(L, "io"); + lua_getfield(L, -1, "stdin"); + + auto p = ((luaL_Stream*)luaL_checkudata(L, -1, LUA_FILEHANDLE)); + ASSERT(p); + p->f = nullptr; + p->closef = nullptr; + + lua_pop(L, 2); +} + void Engine::printLastResult() { m_printLastResult = true; diff --git a/src/app/script/engine.h b/src/app/script/engine.h index a4936ff5d..77281b2f5 100644 --- a/src/app/script/engine.h +++ b/src/app/script/engine.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2023 Igara Studio S.A. +// Copyright (C) 2018-2024 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -97,6 +97,9 @@ namespace app { m_delegate = delegate; } + // Called if the GUI is going to be started. + void notifyRunningGui(); + void printLastResult(); bool evalCode(const std::string& code, const std::string& filename = std::string());