fork of github.com/rxi/lite that removes windows support and improves useability
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lite/src/api/system.c

403 lines
8.5 KiB

3 years ago
#include <SDL2/SDL.h>
#include <stdbool.h>
#include <ctype.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include "api.h"
#include "rencache.h"
extern SDL_Window *window;
static const char* button_name(int button)
{
switch (button) {
case 1 : return "left";
case 2 : return "middle";
case 3 : return "right";
default : return "?";
}
}
static char* key_name(char *dst, int sym)
{
strcpy(dst, SDL_GetKeyName(sym));
for (char *p = dst; *p; p++)
*p = tolower(*p);
return dst;
}
static int f_poll_event(lua_State *L)
{
char buf[16];
int mx, my, wx, wy;
SDL_Event e;
top:
if ( !SDL_PollEvent(&e) )
return 0;
switch (e.type) {
case SDL_QUIT:
lua_pushstring(L, "quit");
return 1;
case SDL_WINDOWEVENT:
if (e.window.event == SDL_WINDOWEVENT_RESIZED) {
lua_pushstring(L, "resized");
lua_pushnumber(L, e.window.data1);
lua_pushnumber(L, e.window.data2);
return 3;
} else if (e.window.event == SDL_WINDOWEVENT_EXPOSED) {
rencache_invalidate();
lua_pushstring(L, "exposed");
return 1;
}
/* on some systems, when alt-tabbing to the window SDL will
* queue up several KEYDOWN events for the `tab` key; we flush
* all keydown events on focus so these are discarded */
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
SDL_FlushEvent(SDL_KEYDOWN);
goto top;
case SDL_DROPFILE:
SDL_GetGlobalMouseState(&mx, &my);
SDL_GetWindowPosition(window, &wx, &wy);
lua_pushstring(L, "filedropped");
lua_pushstring(L, e.drop.file);
lua_pushnumber(L, mx - wx);
lua_pushnumber(L, my - wy);
SDL_free(e.drop.file);
return 4;
case SDL_KEYDOWN:
lua_pushstring(L, "keypressed");
lua_pushstring(L, key_name(buf, e.key.keysym.sym));
return 2;
case SDL_KEYUP:
lua_pushstring(L, "keyreleased");
lua_pushstring(L, key_name(buf, e.key.keysym.sym));
return 2;
case SDL_TEXTINPUT:
lua_pushstring(L, "textinput");
lua_pushstring(L, e.text.text);
return 2;
case SDL_MOUSEBUTTONDOWN:
if (e.button.button == 1)
SDL_CaptureMouse(1);
lua_pushstring(L, "mousepressed");
lua_pushstring(L, button_name(e.button.button));
lua_pushnumber(L, e.button.x);
lua_pushnumber(L, e.button.y);
lua_pushnumber(L, e.button.clicks);
return 5;
case SDL_MOUSEBUTTONUP:
if (e.button.button == 1)
SDL_CaptureMouse(0);
lua_pushstring(L, "mousereleased");
lua_pushstring(L, button_name(e.button.button));
lua_pushnumber(L, e.button.x);
lua_pushnumber(L, e.button.y);
return 4;
case SDL_MOUSEMOTION:
lua_pushstring(L, "mousemoved");
lua_pushnumber(L, e.motion.x);
lua_pushnumber(L, e.motion.y);
lua_pushnumber(L, e.motion.xrel);
lua_pushnumber(L, e.motion.yrel);
return 5;
case SDL_MOUSEWHEEL:
lua_pushstring(L, "mousewheel");
lua_pushnumber(L, e.wheel.y);
return 2;
default:
goto top;
}
return 0;
}
static int f_wait_event(lua_State *L)
{
double n = luaL_checknumber(L, 1);
lua_pushboolean(L, SDL_WaitEventTimeout(NULL, n * 1000));
return 1;
}
static SDL_Cursor* cursor_cache[SDL_SYSTEM_CURSOR_HAND + 1];
static const char *cursor_opts[] = {
"arrow",
"ibeam",
"sizeh",
"sizev",
"hand",
NULL
};
static const int cursor_enums[] = {
SDL_SYSTEM_CURSOR_ARROW,
SDL_SYSTEM_CURSOR_IBEAM,
SDL_SYSTEM_CURSOR_SIZEWE,
SDL_SYSTEM_CURSOR_SIZENS,
SDL_SYSTEM_CURSOR_HAND
};
static int f_set_cursor(lua_State *L)
{
int opt = luaL_checkoption(L, 1, "arrow", cursor_opts);
int n = cursor_enums[opt];
SDL_Cursor *cursor = cursor_cache[n];
if (!cursor) {
cursor = SDL_CreateSystemCursor(n);
cursor_cache[n] = cursor;
}
SDL_SetCursor(cursor);
return 0;
}
static int f_set_window_title(lua_State *L)
{
const char *title = luaL_checkstring(L, 1);
SDL_SetWindowTitle(window, title);
return 0;
}
static const char *window_opts[] = { "normal", "maximized", "fullscreen", 0 };
enum { WIN_NORMAL, WIN_MAXIMIZED, WIN_FULLSCREEN };
static int f_set_window_mode(lua_State *L)
{
int n = luaL_checkoption(L, 1, "normal", window_opts);
SDL_SetWindowFullscreen(window,
n == WIN_FULLSCREEN ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
if (n == WIN_NORMAL)
SDL_RestoreWindow(window);
if (n == WIN_MAXIMIZED)
SDL_MaximizeWindow(window);
return 0;
}
static int f_window_has_focus(lua_State *L)
{
unsigned flags = SDL_GetWindowFlags(window);
lua_pushboolean(L, flags & SDL_WINDOW_INPUT_FOCUS);
return 1;
}
static int f_show_confirm_dialog(lua_State *L)
{
const char *title = luaL_checkstring(L, 1);
const char *msg = luaL_checkstring(L, 2);
SDL_MessageBoxButtonData buttons[] = {
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "Yes" },
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "No" },
};
SDL_MessageBoxData data = {
.title = title,
.message = msg,
.numbuttons = 2,
.buttons = buttons,
};
int buttonid;
SDL_ShowMessageBox(&data, &buttonid);
lua_pushboolean(L, buttonid == 1);
return 1;
}
static int f_chdir(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
int err = chdir(path);
if (err)
luaL_error(L, "chdir() failed");
return 0;
}
static int f_list_dir(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
DIR *dir = opendir(path);
if (!dir) {
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
return 2;
}
lua_newtable(L);
int i = 1;
struct dirent *entry;
while ( (entry = readdir(dir)) ) {
if (strcmp(entry->d_name, "." ) == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
lua_pushstring(L, entry->d_name);
lua_rawseti(L, -2, i);
i++;
}
closedir(dir);
return 1;
}
static int f_absolute_path(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
char *res = realpath(path, NULL);
if (!res)
return 0;
lua_pushstring(L, res);
free(res);
return 1;
}
static int f_get_file_info(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
struct stat s;
int err = stat(path, &s);
if (err < 0) {
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
return 2;
}
lua_newtable(L);
lua_pushnumber(L, s.st_mtime);
lua_setfield(L, -2, "modified");
lua_pushnumber(L, s.st_size);
lua_setfield(L, -2, "size");
if (S_ISREG(s.st_mode)) {
lua_pushstring(L, "file");
} else if (S_ISDIR(s.st_mode)) {
lua_pushstring(L, "dir");
} else {
lua_pushnil(L);
}
lua_setfield(L, -2, "type");
return 1;
}
static int f_get_clipboard(lua_State *L)
{
char *text = SDL_GetClipboardText();
if (!text)
return 0;
lua_pushstring(L, text);
SDL_free(text);
return 1;
}
static int f_set_clipboard(lua_State *L)
{
const char *text = luaL_checkstring(L, 1);
SDL_SetClipboardText(text);
return 0;
}
static int f_get_time(lua_State *L)
{
double n = SDL_GetPerformanceCounter() / (double)SDL_GetPerformanceFrequency();
lua_pushnumber(L, n);
return 1;
}
static int f_sleep(lua_State *L)
{
double n = luaL_checknumber(L, 1);
SDL_Delay(n * 1000);
return 0;
}
static int f_exec(lua_State *L)
{
size_t len;
const char *cmd = luaL_checklstring(L, 1, &len);
char *buf = malloc(len + 32);
if (!buf)
luaL_error(L, "buffer allocation failed");
sprintf(buf, "%s &", cmd);
int res = system(buf);
(void) res;
free(buf);
return 0;
}
static int f_fuzzy_match(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
const char *ptn = luaL_checkstring(L, 2);
int score = 0;
int run = 0;
while (*str && *ptn) {
while (*str == ' ')
str++;
while (*ptn == ' ')
ptn++;
if (tolower(*str) == tolower(*ptn)) {
score += run * 10 - (*str != *ptn);
run++;
ptn++;
} else {
score -= 10;
run = 0;
}
str++;
}
if (*ptn)
return 0;
lua_pushnumber(L, score - (int) strlen(str));
return 1;
}
static const luaL_Reg lib[] = {
{ "poll_event", f_poll_event },
{ "wait_event", f_wait_event },
{ "set_cursor", f_set_cursor },
{ "set_window_title", f_set_window_title },
{ "set_window_mode", f_set_window_mode },
{ "window_has_focus", f_window_has_focus },
{ "show_confirm_dialog", f_show_confirm_dialog },
{ "chdir", f_chdir },
{ "list_dir", f_list_dir },
{ "absolute_path", f_absolute_path },
{ "get_file_info", f_get_file_info },
{ "get_clipboard", f_get_clipboard },
{ "set_clipboard", f_set_clipboard },
{ "get_time", f_get_time },
{ "sleep", f_sleep },
{ "exec", f_exec },
{ "fuzzy_match", f_fuzzy_match },
{ NULL, NULL }
};
int luaopen_system(lua_State *L)
{
luaL_newlib(L, lib);
return 1;
}