Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/pr-changelogs/3359.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* added the unsynced `AllowQuit` callin; returning false keeps the game running when the window close button or Alt+F4 is used (`Spring.Quit` and `/quitforce` still quit unconditionally)
18 changes: 12 additions & 6 deletions rts/Game/UI/MouseHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,15 +883,21 @@ void CMouseHandler::HideMouse()
void CMouseHandler::ToggleMiddleClickScroll()
{
RECOIL_DETAILED_TRACY_ZONE;
if (locked) {
ShowMouse();
} else {
HideMouse();
}

locked = !locked;
mmbScroll = !mmbScroll;
ignoreMove = mmbScroll;

if (locked) {
HideMouse();
} else {
ShowMouse();

const int2 cursorPos = GetViewMouseCenter();
lastx = cursorPos.x;
lasty = cursorPos.y;
mouseInput->SetWarpPos(cursorPos);
UpdateCursorCameraDir();
}
}


Expand Down
26 changes: 26 additions & 0 deletions rts/Lua/LuaHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3824,6 +3824,32 @@ bool CLuaHandle::CommandNotify(const Command& cmd)
}


/*** Called when the window is about to be closed (close button, Alt+F4, or a quit request from the OS).
*
* Every unsynced handle is asked and one `false` is enough to keep the game running. `Spring.Quit` and `/quitforce` do not ask, so a game that vetoed can still quit later and the user can always force an exit. One click can trigger this twice, once per SDL event. Not asked while the game is still loading, so LuaIntro never receives it.
*
* @function Callins:AllowQuit
* @return boolean allow false keeps the game running
*/
bool CLuaHandle::AllowQuit()
{
RECOIL_DETAILED_TRACY_ZONE;
LUA_CALL_IN_CHECK(L, true);
luaL_checkstack(L, 2, __func__);
static const LuaHashString cmdStr(__func__);

if (!cmdStr.GetGlobalFunc(L))
return true;

if (!RunCallIn(L, cmdStr, 0, 1))
return true;

const bool retval = luaL_optboolean(L, -1, true);
lua_pop(L, 1);
return retval;
}


/*** Called when text is entered into the console (e.g. `Spring.Echo`).
*
* @function Callins:AddConsoleLine
Expand Down
1 change: 1 addition & 0 deletions rts/Lua/LuaHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ class CLuaHandle : public CEventClient
void MiniMapGeometryChanged(const int2 newPos, const int2 newDim, const int2 oldPos, const int2 oldDim) override;

bool CommandNotify(const Command& cmd) override;
bool AllowQuit() override;

bool AddConsoleLine(const std::string& msg, const std::string& section, int level) override;

Expand Down
2 changes: 2 additions & 0 deletions rts/Lua/LuaShaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,8 @@ int LuaShaders::CreateShader(lua_State* L)
if (!graphicSrcEmpty && !computeSrcEmpty)
return 0;

CLuaHandle::GetActiveShaders(L).errorLog.clear();

bool success;
const GLuint vertObj = CompileObject(L, shdrDefs, vertSrcs, GL_VERTEX_SHADER, success);

Expand Down
1 change: 1 addition & 0 deletions rts/System/EventClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ void CEventClient::MiniMapRotationChanged(const float newRot, const float oldRot
void CEventClient::MiniMapStateChanged(const bool isMinimized, const bool isMaximized, const bool isSlaved) {}
void CEventClient::MiniMapGeometryChanged(const int2 newPos, const int2 newDim, const int2 oldPos, const int2 oldDim) {}
bool CEventClient::CommandNotify(const Command& cmd) { return false; }
bool CEventClient::AllowQuit() { return true; }

bool CEventClient::AddConsoleLine(const std::string& msg, const std::string& section, int level) { return false; }

Expand Down
1 change: 1 addition & 0 deletions rts/System/EventClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ class CEventClient
virtual void MiniMapStateChanged(const bool isMinimized, const bool isMaximized, const bool isSlaved);
virtual void MiniMapGeometryChanged(const int2 newPos, const int2 newDim, const int2 oldPos, const int2 oldDim);
virtual bool CommandNotify(const Command& cmd);
virtual bool AllowQuit();

virtual bool AddConsoleLine(const std::string& msg, const std::string& section, int level);

Expand Down
6 changes: 6 additions & 0 deletions rts/System/EventHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,12 @@ bool CEventHandler::CommandNotify(const Command& cmd)
return ControlReverseIterateDefTrue(listCommandNotify, &CEventClient::CommandNotify, cmd);
}

bool CEventHandler::AllowQuit()
{
ZoneScoped;
return ControlIterateDefTrue(listAllowQuit, &CEventClient::AllowQuit);
}

void CEventHandler::KeyBindingsChanged()
{
ZoneScoped;
Expand Down
1 change: 1 addition & 0 deletions rts/System/EventHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ class CEventHandler
void MiniMapStateChanged(const bool isMinimized, const bool isMaximized, const bool isSlaved);
void MiniMapGeometryChanged(const int2 newPos, const int2 newDim, const int2 oldPos, const int2 oldDim);
bool CommandNotify(const Command& cmd);
bool AllowQuit();

bool AddConsoleLine(const std::string& msg, const std::string& section, int level);

Expand Down
1 change: 1 addition & 0 deletions rts/System/Events.def
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
SETUP_EVENT(MiniMapStateChanged, MANAGED_BIT | UNSYNCED_BIT)
SETUP_EVENT(MiniMapGeometryChanged, MANAGED_BIT | UNSYNCED_BIT)
SETUP_EVENT(CommandNotify, MANAGED_BIT | UNSYNCED_BIT | CONTROL_BIT)
SETUP_EVENT(AllowQuit, MANAGED_BIT | UNSYNCED_BIT | CONTROL_BIT)
SETUP_EVENT(AddConsoleLine, MANAGED_BIT | UNSYNCED_BIT)
SETUP_EVENT(GroupChanged, MANAGED_BIT | UNSYNCED_BIT)
SETUP_EVENT(GameSetup, MANAGED_BIT | UNSYNCED_BIT | CONTROL_BIT)
Expand Down
2 changes: 1 addition & 1 deletion rts/System/Sound/ISound.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class ISound {
virtual bool Mute() = 0;
virtual bool IsMuted() const = 0;

virtual void DeviceChanged(uint32_t sdlDeviceIndex) = 0;
virtual void DeviceChanged(uint32_t sdlDeviceIndex, bool added) = 0;

///change current output device
static bool ChangeOutput(bool forceNullSound = false);
Expand Down
2 changes: 1 addition & 1 deletion rts/System/Sound/Null/NullSound.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class NullSound : public ISound
bool Mute() override { return true; }
bool IsMuted() const override { return true; }

void DeviceChanged(uint32_t sdlDeviceIndex) override {}
void DeviceChanged(uint32_t sdlDeviceIndex, bool added) override {}

void Iconified(bool state) override {}

Expand Down
8 changes: 6 additions & 2 deletions rts/System/Sound/OpenAL/Sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,15 @@ bool CSound::Mute()
return mute;
}

void CSound::DeviceChanged(uint32_t sdlDeviceIndex)
void CSound::DeviceChanged(uint32_t sdlDeviceIndex, bool added)
{
// handles SDL_AUDIODEVICEREMOVED and SDL_AUDIODEVICEADDED

if (!hasAlcSoftLoopBack || sdlDeviceIndex != sdlDeviceID)
if (!hasAlcSoftLoopBack)
return;

// sdlDeviceIndex is an instance id for REMOVED events but a device index for ADDED ones
if (added ? (sdlDeviceID != 0) : (sdlDeviceIndex != sdlDeviceID))
return;

LOG("[Sound::%s] SDL failed to handle device change, reopening", __func__);
Expand Down
2 changes: 1 addition & 1 deletion rts/System/Sound/OpenAL/Sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class CSound : public ISound
bool Mute() override;
bool IsMuted() const override { return mute; }

void DeviceChanged(uint32_t sdlDeviceIndex) override;
void DeviceChanged(uint32_t sdlDeviceIndex, bool added) override;

void Iconified(bool state) override;

Expand Down
28 changes: 24 additions & 4 deletions rts/System/SpringApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,26 @@ void SpringApp::Kill(bool fromRun)
}


// close button, Alt+F4, SDL_QUIT; quitforce and Spring.Quit set globalQuit directly and skip this
static void RequestQuit()
{
if (gu->globalQuit)
return;

// don't call into Lua while loading, events are pumped from the load thread and handles are still registering
if (game != nullptr && !game->IsDoneLoading()) {
gu->globalQuit = true;
return;
}

if (!eventHandler.AllowQuit()) {
LOG("[SpringApp::%s] quit vetoed by Lua (AllowQuit), use /quitforce to override", __func__);
return;
}

gu->globalQuit = true;
}

bool SpringApp::MainEventHandler(const SDL_Event& event)
{
switch (event.type) {
Expand Down Expand Up @@ -1227,20 +1247,20 @@ bool SpringApp::MainEventHandler(const SDL_Event& event)
} break;

case SDL_WINDOWEVENT_CLOSE: {
gu->globalQuit = true;
RequestQuit();
} break;
};
} break;
case SDL_AUDIODEVICEREMOVED: {
LOG("[SpringApp::%s][SDL_AUDIODEVICEREMOVED][1] type=%u, which=%u, iscapture=%u", __func__, event.adevice.type, event.adevice.which, static_cast<uint32_t>(event.adevice.iscapture));
sound->DeviceChanged(event.adevice.which);
sound->DeviceChanged(event.adevice.which, false);
} break;
case SDL_AUDIODEVICEADDED: {
LOG("[SpringApp::%s][SDL_AUDIODEVICEADDED][1] type=%u, which=%u, iscapture=%u", __func__, event.adevice.type, event.adevice.which, static_cast<uint32_t>(event.adevice.iscapture));
sound->DeviceChanged(event.adevice.which);
sound->DeviceChanged(event.adevice.which, true);
} break;
case SDL_QUIT: {
gu->globalQuit = true;
RequestQuit();
} break;
case SDL_TEXTEDITING: {
if (activeController != nullptr)
Expand Down
Loading