123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 | /**
* Copyright (c) 2006-2026 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "wrap_Event.h"
// LOVE
#include "common/runtime.h"
#include "common/Reference.h"
#include "sdl/Event.h"
#include <algorithm>
// Shove the wrap_Event.lua code directly into a raw string literal.
static const char event_lua[] =
#include "wrap_Event.lua"
;
namespace love
{
namespace event
{
#define instance() (Module::getInstance<Event>(Module::M_EVENT))
static int luax_pushmessage(lua_State *L, const Message &m)
{
luax_pushstring(L, m.name);
for (const Variant &v : m.args)
luax_pushvariant(L, v);
return (int) m.args.size() + 1;
}
static int w_poll_i(lua_State *L)
{
Message *m = nullptr;
if (instance()->poll(m) && m != nullptr)
{
int args = luax_pushmessage(L, *m);
m->release();
return args;
}
// No pending events.
return 0;
}
int w_pump(lua_State *L)
{
float waitTimeout = (float)luaL_optnumber(L, 1, 0.0f);
luax_catchexcept(L, [&]() { instance()->pump(waitTimeout); });
return 0;
}
int w_wait(lua_State *L)
{
luax_markdeprecated(L, 1, "love.event.wait", API_FUNCTION, DEPRECATED_REPLACED, "waitTimeout parameter in love.event.pump");
Message *m = nullptr;
luax_catchexcept(L, [&]() { m = instance()->wait(); });
if (m != nullptr)
{
int args = luax_pushmessage(L, *m);
m->release();
return args;
}
return 0;
}
int w_push(lua_State *L)
{
std::string name = luax_checkstring(L, 1);
std::vector<Variant> vargs;
int nargs = lua_gettop(L);
for (int i = 2; i <= nargs; i++)
{
if (lua_isnoneornil(L, i))
break;
luax_catchexcept(L, [&]() { vargs.push_back(luax_checkvariant(L, i)); });
if (vargs.back().getType() == Variant::UNKNOWN)
{
vargs.clear();
return luaL_error(L, "Argument %d can't be stored safely\nExpected boolean, number, string or userdata.", i);
}
}
StrongRef<Message> m(new Message(name, vargs), Acquire::NORETAIN);
instance()->push(m);
luax_pushboolean(L, true);
return 1;
}
int w_clear(lua_State *L)
{
luax_catchexcept(L, [&]() { instance()->clear(); });
return 0;
}
int w_quit(lua_State *L)
{
luax_catchexcept(L, [&]() {
std::vector<Variant> args;
for (int i = 1; i <= std::max(1, lua_gettop(L)); i++)
args.push_back(luax_checkvariant(L, i));
StrongRef<Message> m(new Message("quit", args), Acquire::NORETAIN);
instance()->push(m);
});
luax_pushboolean(L, true);
return 1;
}
int w_restart(lua_State *L)
{
luax_catchexcept(L, [&]() {
std::vector<Variant> args;
args.emplace_back("restart", strlen("restart"));
for (int i = 1; i <= lua_gettop(L); i++)
args.push_back(luax_checkvariant(L, i));
StrongRef<Message> m(new Message("quit", args), Acquire::NORETAIN);
instance()->push(m);
});
luax_pushboolean(L, true);
return 1;
}
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();
DrawCallbackData data = {};
data.r = r;
// 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)
{
auto r = (Reference *)context;
delete r;
}
int w_setModalDrawCallback(lua_State *L)
{
Event::ModalDrawData data = {};
if (!lua_isnoneornil(L, 1))
{
luaL_checktype(L, 1, LUA_TFUNCTION);
// Save the callback function as a Reference.
lua_pushvalue(L, 1);
Reference *r = new Reference(L);
lua_pop(L, 1);
data.draw = drawCallback;
data.cleanup = cleanupCallback;
data.context = r;
}
luax_catchexcept(L, [&]() { instance()->setModalDrawData(data); });
return 0;
}
int w__setDefaultModalDrawCallback(lua_State *L)
{
Event::ModalDrawData data = {};
if (!lua_isnoneornil(L, 1))
{
luaL_checktype(L, 1, LUA_TFUNCTION);
// Save the callback function as a Reference.
lua_pushvalue(L, 1);
Reference *r = new Reference(L);
lua_pop(L, 1);
data.draw = drawCallback;
data.cleanup = cleanupCallback;
data.context = r;
}
luax_catchexcept(L, [&]() { instance()->setDefaultModalDrawData(data); });
return 0;
}
// List of functions to wrap.
static const luaL_Reg functions[] =
{
{ "pump", w_pump },
{ "poll_i", w_poll_i },
{ "wait", w_wait },
{ "push", w_push },
{ "clear", w_clear },
{ "quit", w_quit },
{ "restart", w_restart },
{ "setModalDrawCallback", w_setModalDrawCallback },
{ "_setDefaultModalDrawCallback", w__setDefaultModalDrawCallback },
{ 0, 0 }
};
extern "C" int luaopen_love_event(lua_State *L)
{
Event *instance = instance();
if (instance == nullptr)
{
luax_catchexcept(L, [&](){ instance = new love::event::sdl::Event(); });
}
else
instance->retain();
WrappedModule w;
w.module = instance;
w.name = "event";
w.type = &Module::type;
w.functions = functions;
w.types = nullptr;
int ret = luax_register_module(L, w);
if (luaL_loadbuffer(L, (const char *)event_lua, sizeof(event_lua), "=[love \"wrap_Event.lua\"]") == 0)
lua_call(L, 0, 0);
else
lua_error(L);
return ret;
}
} // event
} // love
|