lovr/src/api/l_event.c

219 lines
5.7 KiB
C
Raw Normal View History

2017-12-10 20:40:37 +00:00
#include "api.h"
2019-08-21 22:27:26 +00:00
#include "util.h"
2016-11-19 09:28:01 +00:00
#include "event/event.h"
#include "thread/thread.h"
#include "core/platform.h"
#include "core/ref.h"
2019-05-14 11:37:56 +00:00
#include <stdlib.h>
#include <string.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",
#ifdef LOVR_ENABLE_THREAD
2018-07-05 03:11:52 +00:00
[EVENT_THREAD_ERROR] = "threaderror",
#endif
2018-07-05 03:11:52 +00:00
};
2017-03-11 11:08:07 +00:00
2019-05-20 11:05:39 +00:00
static LOVR_THREAD_LOCAL int pollRef;
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);
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);
variant->value.string[length] = '\0';
2018-07-26 21:02:54 +00:00
break;
case LUA_TUSERDATA:
variant->type = TYPE_OBJECT;
Proxy* proxy = lua_touserdata(L, index);
lua_getmetatable(L, index);
lua_pushliteral(L, "__name");
lua_rawget(L, -2);
variant->value.object.type = (const char*) lua_touserdata(L, -1);
lua_pop(L, 1);
lua_pushliteral(L, "__destructor");
lua_rawget(L, -2);
2019-08-21 21:37:22 +00:00
variant->value.object.destructor = (void (*)(void*)) lua_tocfunction(L, -1);
lua_pop(L, 1);
variant->value.object.pointer = proxy->object;
lovrRetain(proxy->object);
2018-07-26 21:02:54 +00:00
break;
default:
2019-08-19 21:16:42 +00:00
lovrThrow("Bad variant type: %s", lua_typename(L, type));
2018-07-26 21:02:54 +00:00
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;
case TYPE_STRING: lua_pushstring(L, variant->value.string); return 1;
case TYPE_OBJECT: _luax_pushtype(L, variant->value.object.type, hash(variant->value.object.type), variant->value.object.pointer); 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) {
Event event;
2016-11-29 06:59:27 +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]);
}
switch (event.type) {
case EVENT_QUIT:
if (event.data.quit.restart) {
2018-12-16 05:45:32 +00:00
lua_pushliteral(L, "restart");
} else {
lua_pushnumber(L, event.data.quit.exitCode);
}
2016-11-29 06:59:27 +00:00
return 2;
case EVENT_FOCUS:
2018-07-26 20:40:15 +00:00
lua_pushboolean(L, event.data.boolean.value);
return 2;
#ifdef LOVR_ENABLE_THREAD
case EVENT_THREAD_ERROR:
luax_pushtype(L, Thread, event.data.thread.thread);
2018-07-26 20:40:15 +00:00
lua_pushstring(L, event.data.thread.error);
lovrRelease(Thread, event.data.thread.thread);
2018-02-17 17:49:24 +00:00
return 3;
#endif
2018-02-17 17:49:24 +00:00
2018-07-26 21:02:54 +00:00
case EVENT_CUSTOM:
2019-05-14 11:37:56 +00:00
for (uint32_t i = 0; i < event.data.custom.count; i++) {
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:
return 1;
2016-11-29 06:59:27 +00:00
}
}
2016-08-10 06:28:17 +00:00
static void hotkeyHandler(KeyCode key, ButtonAction action) {
2019-07-29 18:52:06 +00:00
if (action != BUTTON_PRESSED) {
return;
}
if (key == KEY_ESCAPE) {
lovrEventPush((Event) { .type = EVENT_QUIT, .data.quit.restart = false, .data.quit.exitCode = 0 });
} else if (key == KEY_F5) {
lovrEventPush((Event) { .type = EVENT_QUIT, .data.quit.restart = true });
}
}
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) {
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);
2019-05-14 11:37:56 +00:00
for (uint32_t i = 0; i < eventData.count; i++) {
2018-07-26 21:02:54 +00:00
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) {
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
2019-08-21 22:27:26 +00:00
LOVR_EXPORT int luaopen_lovr_event(lua_State* L) {
2018-09-27 01:27:38 +00:00
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);
if (lovrEventInit()) {
luax_atexit(L, lovrEventDestroy);
}
luax_pushconf(L);
lua_getfield(L, -1, "hotkeys");
if (lua_toboolean(L, -1)) {
lovrPlatformOnKeyboardEvent(hotkeyHandler);
}
lua_pop(L, 2);
2018-09-27 01:27:38 +00:00
return 1;
}