mirror of
https://github.com/love2d/love.git
synced 2026-08-28 18:26:55 +02:00
Fix quit events being dropped if they're processed during a modal draw.
Forward quit data to the next full event processing cycle, and skip love.quit callbacks being called for a second time in that case.
This commit is contained in:
@@ -55,10 +55,18 @@ Event::~Event()
|
||||
}
|
||||
|
||||
void Event::push(Message *msg)
|
||||
{
|
||||
push(msg, false);
|
||||
}
|
||||
|
||||
void Event::push(Message *msg, bool pushFront)
|
||||
{
|
||||
Lock lock(mutex);
|
||||
msg->retain();
|
||||
queue.push(msg);
|
||||
if (pushFront)
|
||||
queue.push_front(msg);
|
||||
else
|
||||
queue.push_back(msg);
|
||||
}
|
||||
|
||||
bool Event::poll(Message *&msg)
|
||||
@@ -67,7 +75,7 @@ bool Event::poll(Message *&msg)
|
||||
if (queue.empty())
|
||||
return false;
|
||||
msg = queue.front();
|
||||
queue.pop();
|
||||
queue.pop_front();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,9 +84,8 @@ void Event::clear()
|
||||
Lock lock(mutex);
|
||||
while (!queue.empty())
|
||||
{
|
||||
// std::queue::pop will remove the first (front) element.
|
||||
queue.front()->release();
|
||||
queue.pop();
|
||||
queue.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,12 +111,17 @@ void Event::modalDraw()
|
||||
if (!deferredExceptionMessage.empty())
|
||||
return;
|
||||
|
||||
// Also skip the draw if a previous one generated a return value that
|
||||
// needs to be passed down as a quit event.
|
||||
if (deferredReturnValues[0].getType() != Variant::NIL)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
if (modalDrawData.draw != nullptr)
|
||||
modalDrawData.draw(modalDrawData.context);
|
||||
modalDrawData.draw(modalDrawData.context, &deferredReturnValues[0], &deferredReturnValues[1]);
|
||||
else if (defaultModalDrawData.draw != nullptr)
|
||||
defaultModalDrawData.draw(defaultModalDrawData.context);
|
||||
defaultModalDrawData.draw(defaultModalDrawData.context, &deferredReturnValues[0], &deferredReturnValues[1]);
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "thread/threads.h"
|
||||
|
||||
// C++
|
||||
#include <queue>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
namespace love
|
||||
@@ -55,12 +55,13 @@ class Event : public Module
|
||||
{
|
||||
public:
|
||||
|
||||
typedef void (*ModalDrawCallback)(void *context);
|
||||
typedef void (*ModalDrawCallback)(void *context, Variant *returnValue0, Variant *returnValue1);
|
||||
typedef void (*ModalCleanupCallback)(void *context);
|
||||
|
||||
struct ModalDrawData
|
||||
{
|
||||
ModalDrawCallback draw;
|
||||
ModalDrawCallback cleanup;
|
||||
ModalCleanupCallback cleanup;
|
||||
void *context;
|
||||
};
|
||||
|
||||
@@ -84,12 +85,15 @@ protected:
|
||||
|
||||
Event(const char *name);
|
||||
|
||||
void push(Message *msg, bool pushFront);
|
||||
|
||||
ModalDrawData modalDrawData;
|
||||
ModalDrawData defaultModalDrawData;
|
||||
std::string deferredExceptionMessage;
|
||||
Variant deferredReturnValues[2];
|
||||
|
||||
love::thread::MutexRef mutex;
|
||||
std::queue<Message *> queue;
|
||||
std::deque<Message *> queue;
|
||||
|
||||
}; // Event
|
||||
|
||||
|
||||
@@ -174,8 +174,25 @@ void Event::pump(float waitTimeout)
|
||||
{
|
||||
std::string exceptionstr = deferredExceptionMessage;
|
||||
deferredExceptionMessage.clear();
|
||||
deferredReturnValues[0] = Variant();
|
||||
deferredReturnValues[1] = Variant();
|
||||
throw love::Exception("%s", exceptionstr.c_str());
|
||||
}
|
||||
|
||||
if (deferredReturnValues[0].getType() != Variant::NIL)
|
||||
{
|
||||
// Third arg being true will tell love.run to skip the love.quit callback,
|
||||
// since the original modal draw function already processed that.
|
||||
std::vector<Variant> args = {deferredReturnValues[0], deferredReturnValues[1], Variant(true)};
|
||||
|
||||
StrongRef<Message> msg(new Message("quit", args), Acquire::NORETAIN);
|
||||
|
||||
// Push to the front of queue so it's dealt with before any other event.
|
||||
push(msg, true);
|
||||
|
||||
deferredReturnValues[0] = Variant();
|
||||
deferredReturnValues[1] = Variant();
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldPoll)
|
||||
|
||||
@@ -152,18 +152,44 @@ int w_restart(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void drawCallback(void *context)
|
||||
struct DrawCallbackData
|
||||
{
|
||||
Variant returnValues[2];
|
||||
Reference *r;
|
||||
};
|
||||
|
||||
static int drawCallbackInner(lua_State *L)
|
||||
{
|
||||
auto data = (DrawCallbackData *)lua_touserdata(L, 1);
|
||||
|
||||
data->r->push(L);
|
||||
|
||||
lua_call(L, 0, 2);
|
||||
|
||||
data->returnValues[0] = luax_checkvariant(L, -2, false);
|
||||
data->returnValues[1] = luax_checkvariant(L, -1, false);
|
||||
|
||||
lua_pop(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drawCallback(void *context, Variant *returnVal0, Variant *returnVal1)
|
||||
{
|
||||
auto r = (Reference *)context;
|
||||
lua_State *L = r->getPinnedL();
|
||||
|
||||
r->push(L);
|
||||
DrawCallbackData data = {};
|
||||
data.r = r;
|
||||
|
||||
int err = lua_pcall(L, 0, 0, 0);
|
||||
// pcall into C code to catch errors from checkvariant as well as the lua_call.
|
||||
int err = lua_cpcall(L, drawCallbackInner, &data);
|
||||
|
||||
// Unfortunately, this eats the stack trace, too bad.
|
||||
if (err != 0)
|
||||
throw love::Exception("Error in modal draw callback: %s", lua_tostring(L, -1));
|
||||
|
||||
*returnVal0 = data.returnValues[0];
|
||||
*returnVal1 = data.returnValues[1];
|
||||
}
|
||||
|
||||
static void cleanupCallback(void *context)
|
||||
|
||||
@@ -175,7 +175,7 @@ function love.run()
|
||||
love.event.pump()
|
||||
for name, a,b,c,d,e,f,g,h in love.event.poll() do
|
||||
if name == "quit" then
|
||||
if not love.quit or not love.quit() then
|
||||
if c or not love.quit or not love.quit() then
|
||||
return a or 0, b
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user