2017-12-10 20:40:37 +00:00
|
|
|
#include "api.h"
|
2018-09-27 00:54:12 +00:00
|
|
|
#include "api/event.h"
|
2016-11-19 09:28:01 +00:00
|
|
|
#include "event/event.h"
|
2016-11-29 06:59:27 +00:00
|
|
|
|
2018-07-05 03:11:52 +00:00
|
|
|
const char* EventTypes[] = {
|
|
|
|
[EVENT_QUIT] = "quit",
|
|
|
|
[EVENT_FOCUS] = "focus",
|
|
|
|
[EVENT_THREAD_ERROR] = "threaderror",
|
|
|
|
};
|
2017-03-11 11:08:07 +00:00
|
|
|
|
2018-04-02 05:43:54 +00:00
|
|
|
static _Thread_local int pollRef;
|
2017-01-18 06:11:17 +00:00
|
|
|
|
2018-07-26 21:02:54 +00:00
|
|
|
void luax_checkvariant(lua_State* L, int index, Variant* variant) {
|
|
|
|
int type = lua_type(L, index);
|
|
|
|
switch (type) {
|
|
|
|
case LUA_TNIL:
|
|
|
|
variant->type = TYPE_NIL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TBOOLEAN:
|
|
|
|
variant->type = TYPE_BOOLEAN;
|
|
|
|
variant->value.boolean = lua_toboolean(L, index);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TNUMBER:
|
|
|
|
variant->type = TYPE_NUMBER;
|
|
|
|
variant->value.number = lua_tonumber(L, index);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TSTRING:
|
|
|
|
variant->type = TYPE_STRING;
|
|
|
|
size_t length;
|
|
|
|
const char* string = lua_tolstring(L, index, &length);
|
2019-01-29 10:49:09 +00:00
|
|
|
variant->value.string = malloc(length + 1);
|
|
|
|
lovrAssert(variant->value.string, "Out of memory");
|
2018-10-23 18:11:47 +00:00
|
|
|
memcpy(variant->value.string, string, length);
|
2019-01-29 10:49:09 +00:00
|
|
|
variant->value.string[length] = '\0';
|
2018-07-26 21:02:54 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TUSERDATA:
|
|
|
|
variant->type = TYPE_OBJECT;
|
2018-10-23 18:11:47 +00:00
|
|
|
variant->value.ref = *(Ref**) lua_touserdata(L, index);
|
2018-07-26 21:02:54 +00:00
|
|
|
lovrRetain(variant->value.ref);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
lovrThrow("Bad type for Channel:push: %s", lua_typename(L, type));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int luax_pushvariant(lua_State* L, Variant* variant) {
|
|
|
|
switch (variant->type) {
|
|
|
|
case TYPE_NIL: lua_pushnil(L); return 1;
|
|
|
|
case TYPE_BOOLEAN: lua_pushboolean(L, variant->value.boolean); return 1;
|
|
|
|
case TYPE_NUMBER: lua_pushnumber(L, variant->value.number); return 1;
|
2019-01-13 04:50:43 +00:00
|
|
|
case TYPE_STRING: lua_pushstring(L, variant->value.string); return 1;
|
|
|
|
case TYPE_OBJECT: luax_pushobject(L, variant->value.ref); return 1;
|
2019-02-17 07:43:20 +00:00
|
|
|
default: return 0;
|
2018-07-26 21:02:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-29 06:59:27 +00:00
|
|
|
static int nextEvent(lua_State* L) {
|
2017-05-17 06:03:42 +00:00
|
|
|
Event event;
|
2016-11-29 06:59:27 +00:00
|
|
|
|
2017-05-17 06:03:42 +00:00
|
|
|
if (!lovrEventPoll(&event)) {
|
2016-11-29 06:59:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-26 21:02:54 +00:00
|
|
|
if (event.type == EVENT_CUSTOM) {
|
|
|
|
lua_pushstring(L, event.data.custom.name);
|
|
|
|
} else {
|
|
|
|
lua_pushstring(L, EventTypes[event.type]);
|
|
|
|
}
|
2018-02-26 00:40:48 +00:00
|
|
|
|
2017-05-17 06:03:42 +00:00
|
|
|
switch (event.type) {
|
2018-02-26 00:40:48 +00:00
|
|
|
case EVENT_QUIT:
|
|
|
|
if (event.data.quit.restart) {
|
2018-12-16 05:45:32 +00:00
|
|
|
lua_pushliteral(L, "restart");
|
2018-02-26 00:40:48 +00:00
|
|
|
} else {
|
2018-01-26 02:32:16 +00:00
|
|
|
lua_pushnumber(L, event.data.quit.exitCode);
|
2018-02-26 00:40:48 +00:00
|
|
|
}
|
2016-11-29 06:59:27 +00:00
|
|
|
return 2;
|
|
|
|
|
2018-02-26 00:40:48 +00:00
|
|
|
case EVENT_FOCUS:
|
2018-07-26 20:40:15 +00:00
|
|
|
lua_pushboolean(L, event.data.boolean.value);
|
2018-02-26 00:40:48 +00:00
|
|
|
return 2;
|
|
|
|
|
|
|
|
case EVENT_THREAD_ERROR:
|
2018-07-26 20:40:15 +00:00
|
|
|
luax_pushobject(L, event.data.thread.thread);
|
|
|
|
lua_pushstring(L, event.data.thread.error);
|
2019-04-20 20:11:11 +00:00
|
|
|
free(event.data.thread.error);
|
2018-02-17 17:49:24 +00:00
|
|
|
return 3;
|
|
|
|
|
2018-07-26 21:02:54 +00:00
|
|
|
case EVENT_CUSTOM:
|
|
|
|
for (int i = 0; i < event.data.custom.count; i++) {
|
2019-01-13 04:50:43 +00:00
|
|
|
Variant* variant = &event.data.custom.data[i];
|
|
|
|
luax_pushvariant(L, variant);
|
|
|
|
lovrVariantDestroy(variant);
|
2018-07-26 21:02:54 +00:00
|
|
|
}
|
|
|
|
return event.data.custom.count + 1;
|
|
|
|
|
2016-11-29 06:59:27 +00:00
|
|
|
default:
|
2018-02-26 00:40:48 +00:00
|
|
|
return 1;
|
2016-11-29 06:59:27 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-10 06:28:17 +00:00
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventClear(lua_State* L) {
|
2016-11-29 06:59:27 +00:00
|
|
|
lovrEventClear();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventPoll(lua_State* L) {
|
2017-01-18 06:11:17 +00:00
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, pollRef);
|
2016-11-29 06:59:27 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventPump(lua_State* L) {
|
2016-11-29 06:59:27 +00:00
|
|
|
lovrEventPump();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventPush(lua_State* L) {
|
2018-07-26 21:02:54 +00:00
|
|
|
CustomEvent eventData;
|
|
|
|
const char* name = luaL_checkstring(L, 1);
|
|
|
|
strncpy(eventData.name, name, MAX_EVENT_NAME_LENGTH - 1);
|
|
|
|
eventData.count = MIN(lua_gettop(L) - 1, 4);
|
|
|
|
for (int i = 0; i < eventData.count; i++) {
|
|
|
|
luax_checkvariant(L, 2 + i, &eventData.data[i]);
|
2016-11-29 06:59:27 +00:00
|
|
|
}
|
|
|
|
|
2018-07-26 21:02:54 +00:00
|
|
|
lovrEventPush((Event) { .type = EVENT_CUSTOM, .data.custom = eventData });
|
2016-08-10 06:28:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventQuit(lua_State* L) {
|
2018-01-26 02:32:16 +00:00
|
|
|
EventData data;
|
|
|
|
|
|
|
|
int argType = lua_type(L, 1);
|
|
|
|
if (argType == LUA_TSTRING && 0 == strcmp("restart", lua_tostring(L, 1))) {
|
|
|
|
data.quit.restart = true;
|
|
|
|
data.quit.exitCode = 0;
|
|
|
|
} else if (argType == LUA_TNUMBER || lua_isnoneornil(L, 1)) {
|
|
|
|
data.quit.restart = false;
|
|
|
|
data.quit.exitCode = luaL_optint(L, 1, 0);
|
|
|
|
} else {
|
|
|
|
return luaL_argerror (L, 1, "number, nil or the exact string 'restart' expected");
|
|
|
|
}
|
|
|
|
|
|
|
|
EventType type = EVENT_QUIT;
|
|
|
|
Event event = { .type = type, .data = data };
|
|
|
|
lovrEventPush(event);
|
2018-01-27 03:01:20 +00:00
|
|
|
return 0;
|
2016-08-10 06:28:17 +00:00
|
|
|
}
|
2017-03-11 11:08:07 +00:00
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static const luaL_Reg lovrEvent[] = {
|
2017-03-11 11:08:07 +00:00
|
|
|
{ "clear", l_lovrEventClear },
|
|
|
|
{ "poll", l_lovrEventPoll },
|
|
|
|
{ "pump", l_lovrEventPump },
|
|
|
|
{ "push", l_lovrEventPush },
|
|
|
|
{ "quit", l_lovrEventQuit },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
2018-09-27 01:27:38 +00:00
|
|
|
|
|
|
|
int luaopen_lovr_event(lua_State* L) {
|
|
|
|
lua_newtable(L);
|
|
|
|
luaL_register(L, NULL, lovrEvent);
|
|
|
|
|
|
|
|
// Store nextEvent in the registry to avoid creating a closure every time we poll for events.
|
|
|
|
lua_pushcfunction(L, nextEvent);
|
|
|
|
pollRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
|
|
2018-11-19 16:08:56 +00:00
|
|
|
if (lovrEventInit()) {
|
|
|
|
luax_atexit(L, lovrEventDestroy);
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
return 1;
|
|
|
|
}
|