diff --git a/include/luak/kiwmi_lua_callback.h b/include/luak/kiwmi_lua_callback.h new file mode 100644 index 0000000..55ba3ed --- /dev/null +++ b/include/luak/kiwmi_lua_callback.h @@ -0,0 +1,26 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef KIWMI_LUAK_KIWMI_LUA_CALLBACK_H +#define KIWMI_LUAK_KIWMI_LUA_CALLBACK_H + +#include + +#include "luak/luak.h" + +struct kiwmi_lua_callback { + struct wl_list link; + struct kiwmi_server *server; + int callback_ref; + struct wl_listener listener; +}; + +int luaK_kiwmi_lua_callback_new(lua_State *L); +int luaK_kiwmi_lua_callback_register(lua_State *L); +void luaK_kiwmi_lua_callback_cleanup(struct kiwmi_lua *lua); + +#endif /* KIWMI_LUAK_KIWMI_LUA_CALLBACK_H */ diff --git a/include/luak/kiwmi_server.h b/include/luak/kiwmi_server.h new file mode 100644 index 0000000..a6728c3 --- /dev/null +++ b/include/luak/kiwmi_server.h @@ -0,0 +1,16 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef KIWMI_LUAK_KIWMI_SERVER_H +#define KIWMI_LUAK_KIWMI_SERVER_H + +#include + +int luaK_kiwmi_server_new(lua_State *L); +int luaK_kiwmi_server_register(lua_State *L); + +#endif /* KIWMI_LUAK_KIWMI_SERVER_H */ diff --git a/include/luak/kiwmi_view.h b/include/luak/kiwmi_view.h new file mode 100644 index 0000000..4762845 --- /dev/null +++ b/include/luak/kiwmi_view.h @@ -0,0 +1,16 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef KIWMI_LUAK_KIWMI_VIEW_H +#define KIWMI_LUAK_KIWMI_VIEW_H + +#include + +int luaK_kiwmi_view_new(lua_State *L); +int luaK_kiwmi_view_register(lua_State *L); + +#endif /* KIWMI_LUAK_KIWMI_VIEW_H */ diff --git a/include/luak.h b/include/luak/luak.h similarity index 72% rename from include/luak.h rename to include/luak/luak.h index bd3e9f2..08ee890 100644 --- a/include/luak.h +++ b/include/luak/luak.h @@ -5,8 +5,8 @@ * You can obtain one at https://mozilla.org/MPL/2.0/. */ -#ifndef KIWMI_LUAK_H -#define KIWMI_LUAK_H +#ifndef KIWMI_LUAK_LUAK_H +#define KIWMI_LUAK_LUAK_H #include @@ -19,8 +19,8 @@ struct kiwmi_lua { struct wl_list callbacks; // lua_callback::link }; -bool luaK_init(struct kiwmi_server *server); +struct kiwmi_lua *luaK_create(struct kiwmi_server *server); bool luaK_dofile(struct kiwmi_lua *lua, const char *config_path); -void luaK_fini(struct kiwmi_lua *lua); +void luaK_destroy(struct kiwmi_lua *lua); -#endif /* KIWMI_LUAK_H */ +#endif /* KIWMI_LUAK_LUAK_H */ diff --git a/kiwmi/luak.c b/kiwmi/luak.c deleted file mode 100644 index 1edfa70..0000000 --- a/kiwmi/luak.c +++ /dev/null @@ -1,485 +0,0 @@ -/* Copyright (c), Niclas Meyer - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "luak.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include "desktop/view.h" -#include "input/cursor.h" -#include "input/input.h" - -struct lua_callback { - struct wl_list link; - struct kiwmi_server *server; - int callback_ref; - struct wl_listener listener; -}; - -static int -l_lua_callback_cancel(lua_State *L) -{ - struct lua_callback *lc = - *(struct lua_callback **)luaL_checkudata(L, 1, "lua_callback"); - lua_pop(L, 1); - - wl_list_remove(&lc->listener.link); - wl_list_remove(&lc->link); - - luaL_unref(L, LUA_REGISTRYINDEX, lc->callback_ref); - - free(lc); - - return 0; -} - -static const luaL_Reg lua_callback_methods[] = { - {"cancel", l_lua_callback_cancel}, - {NULL, NULL}, -}; - -static int -lua_callback_create(lua_State *L) -{ - struct lua_callback *lc = lua_touserdata(L, 1); - - struct lua_callback **lc_ud = lua_newuserdata(L, sizeof(*lc_ud)); - luaL_getmetatable(L, "lua_callback"); - lua_setmetatable(L, -2); - - *lc_ud = lc; - - return 1; -} - -static int -lua_callback_register(lua_State *L) -{ - luaL_newmetatable(L, "lua_callback"); - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); - lua_settable(L, -3); - luaL_setfuncs(L, lua_callback_methods, 0); - - return 0; -} - -static int -l_kiwmi_view_close(lua_State *L) -{ - struct kiwmi_view *view = - *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); - - view_close(view); - - return 0; -} - -static int -l_kiwmi_view_focus(lua_State *L) -{ - struct kiwmi_view *view = - *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); - - view_focus(view); - - return 0; -} - -static int -l_kiwmi_view_hidden(lua_State *L) -{ - struct kiwmi_view *view = - *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); - - lua_pushboolean(L, view->hidden); - - return 1; -} - -static int -l_kiwmi_view_hide(lua_State *L) -{ - struct kiwmi_view *view = - *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); - - view->hidden = true; - - return 0; -} - -static int -l_kiwmi_view_move(lua_State *L) -{ - struct kiwmi_view *view = - *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); - - luaL_checktype(L, 2, LUA_TNUMBER); - luaL_checktype(L, 3, LUA_TNUMBER); - - view->x = lua_tonumber(L, 2); - view->y = lua_tonumber(L, 3); - - return 0; -} - -static int -l_kiwmi_view_show(lua_State *L) -{ - struct kiwmi_view *view = - *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); - - view->hidden = false; - - return 0; -} - -static const luaL_Reg kiwmi_view_methods[] = { - {"close", l_kiwmi_view_close}, - {"focus", l_kiwmi_view_focus}, - {"hidden", l_kiwmi_view_hidden}, - {"hide", l_kiwmi_view_hide}, - {"move", l_kiwmi_view_move}, - {"show", l_kiwmi_view_show}, - {NULL, NULL}, -}; - -static int -kiwmi_view_create(lua_State *L) -{ - luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // kiwmi_view - - struct kiwmi_view *view = lua_touserdata(L, 1); - - struct kiwmi_view **view_ud = lua_newuserdata(L, sizeof(*view_ud)); - luaL_getmetatable(L, "kiwmi_view"); - lua_setmetatable(L, -2); - - *view_ud = view; - - return 1; -} - -static int -kiwmi_view_register(lua_State *L) -{ - luaL_newmetatable(L, "kiwmi_view"); - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); - lua_settable(L, -3); - luaL_setfuncs(L, kiwmi_view_methods, 0); - - return 0; -} - -static int -l_kiwmi_server_on(lua_State *L) -{ - luaL_checkudata(L, 1, "kiwmi_server"); // server - luaL_checktype(L, 2, LUA_TSTRING); // type - luaL_checktype(L, 3, LUA_TFUNCTION); // callback - - // event_handler = registry['kiwmi_events'][type] - lua_pushliteral(L, "kiwmi_events"); - lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushvalue(L, 2); - lua_gettable(L, -2); - - luaL_argcheck(L, lua_iscfunction(L, -1), 2, "invalid event"); - - // stack: server type callback kiwmi_events register_callback - - lua_remove(L, 4); // remove kiwmi_events - lua_remove(L, 2); // remove type - lua_rotate(L, 1, 1); - - // stack: register_callback server callback - - // return register_callback(callback) - if (lua_pcall(L, 2, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - return 0; - } - - return 1; -} - -static void -on_cursor_button_notify(struct wl_listener *listener, void *data) -{ - struct lua_callback *lc = wl_container_of(listener, lc, listener); - struct kiwmi_server *server = lc->server; - struct lua_State *L = server->lua->L; - struct wlr_event_pointer_button *event = data; - - lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); - - lua_newtable(L); - - lua_pushlightuserdata(L, event->device); // TODO: make un-opaque - lua_setfield(L, -2, "device"); - - lua_pushinteger(L, event->time_msec); - lua_setfield(L, -2, "time"); - - lua_pushinteger(L, event->button); - lua_setfield(L, -2, "button"); - - lua_pushinteger(L, event->state); - lua_setfield(L, -2, "state"); - - if (lua_pcall(L, 1, 0, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - } -} - -static void -on_view_notify(struct wl_listener *listener, void *data) -{ - struct lua_callback *lc = wl_container_of(listener, lc, listener); - struct kiwmi_server *server = lc->server; - struct lua_State *L = server->lua->L; - struct kiwmi_view *view = data; - - lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); - - lua_pushcfunction(L, kiwmi_view_create); - lua_pushlightuserdata(L, view); - if (lua_pcall(L, 1, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - } - - if (lua_pcall(L, 1, 0, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - } -} - -static int -on_cursor_button(lua_State *L) -{ - struct kiwmi_server *server = - *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); - luaL_checktype(L, 2, LUA_TFUNCTION); // callback - - struct lua_callback *lc = malloc(sizeof(*lc)); - if (!lc) { - return luaL_error(L, "failed to allocate lua_callback"); - } - - struct kiwmi_cursor *cursor = server->input.cursor; - - wl_list_insert(&server->lua->callbacks, &lc->link); - - lc->server = server; - lc->callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); - - lc->listener.notify = on_cursor_button_notify; - wl_signal_add(&cursor->cursor->events.button, &lc->listener); - - lua_pushlightuserdata(L, lc); - lua_callback_create(L); - - return 1; -} - -static int -on_view(lua_State *L) -{ - struct kiwmi_server *server = - *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); - luaL_checktype(L, 2, LUA_TFUNCTION); // callback - - struct lua_callback *lc = malloc(sizeof(*lc)); - if (!lc) { - return luaL_error(L, "failed to allocate lua_callback"); - } - - wl_list_insert(&server->lua->callbacks, &lc->link); - - lc->server = server; - lc->callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); - - lc->listener.notify = on_view_notify; - wl_signal_add(&server->desktop.events.view_map, &lc->listener); - - lua_pushlightuserdata(L, lc); - lua_callback_create(L); - - return 1; -} - -static int -l_kiwmi_server_quit(lua_State *L) -{ - struct kiwmi_server *server = *(struct kiwmi_server**)luaL_checkudata(L, 1, "kiwmi_server"); - - wl_display_terminate(server->wl_display); - - return 0; -} - -static int -l_kiwmi_server_view_under_cursor(lua_State *L) -{ - struct kiwmi_server *server = *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); - - struct kiwmi_cursor *cursor = server->input.cursor; - - struct wlr_surface *surface; - double sx; - double sy; - - struct kiwmi_view *view = view_at( - &server->desktop, - cursor->cursor->x, - cursor->cursor->y, - &surface, - &sx, - &sy); - - if (view) { - lua_pushcfunction(L, kiwmi_view_create); - lua_pushlightuserdata(L, view); - if (lua_pcall(L, 1, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - } - } else { - lua_pushnil(L); - } - - return 1; -} - -static const luaL_Reg kiwmi_server_methods[] = { - {"on", l_kiwmi_server_on}, - {"quit", l_kiwmi_server_quit}, - {"view_under_cursor", l_kiwmi_server_view_under_cursor}, - {NULL, NULL}, -}; - -static int -kiwmi_server_create(lua_State *L) -{ - luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // kiwmi_server - - struct kiwmi_server *server = lua_touserdata(L, 1); - - struct kiwmi_server **server_ud = lua_newuserdata(L, sizeof(*server_ud)); - luaL_getmetatable(L, "kiwmi_server"); - lua_setmetatable(L, -2); - - *server_ud = server; - - return 1; -} - -static int -kiwmi_server_register(lua_State *L) -{ - luaL_newmetatable(L, "kiwmi_server"); - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); - lua_settable(L, -3); - luaL_setfuncs(L, kiwmi_server_methods, 0); - - return 0; -} - -static const luaL_Reg kiwmi_events[] = { - {"cursor_button", on_cursor_button}, - {"view", on_view}, - {NULL, NULL}, -}; - -bool -luaK_init(struct kiwmi_server *server) -{ - struct kiwmi_lua *lua = malloc(sizeof(*lua)); - if (!lua) { - wlr_log(WLR_ERROR, "Failed to allocate kiwmi_lua"); - return false; - } - - lua_State *L = luaL_newstate(); - if (!L) { - return false; - } - - luaL_openlibs(L); - - // registry['kiwmi_events'] = {'key_down' = l_key_down, ...} - lua_pushliteral(L, "kiwmi_events"); - luaL_newlib(L, kiwmi_events); - lua_settable(L, LUA_REGISTRYINDEX); - - // register types - int error = false; - - lua_pushcfunction(L, lua_callback_register); - error |= lua_pcall(L, 0, 0, 0); - lua_pushcfunction(L, kiwmi_view_register); - error |= lua_pcall(L, 0, 0, 0); - lua_pushcfunction(L, kiwmi_server_register); - error |= lua_pcall(L, 0, 0, 0); - - if (error) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - return false; - } - - // create kiwmi global - lua_pushcfunction(L, kiwmi_server_create); - lua_pushlightuserdata(L, server); - if (lua_pcall(L, 1, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - return false; - } - lua_setglobal(L, "kiwmi"); - - lua->L = L; - server->lua = lua; - - wl_list_init(&lua->callbacks); - - return true; -} - -bool -luaK_dofile(struct kiwmi_lua *lua, const char *config_path) -{ - if (luaL_dofile(lua->L, config_path)) { - wlr_log( - WLR_ERROR, "Error running config: %s", lua_tostring(lua->L, -1)); - return false; - } - - return true; -} - -void -luaK_fini(struct kiwmi_lua *lua) -{ - struct lua_callback *lc; - struct lua_callback *tmp; - wl_list_for_each_safe (lc, tmp, &lua->callbacks, link) { - wl_list_remove(&lc->listener.link); - wl_list_remove(&lc->link); - - luaL_unref(lua->L, LUA_REGISTRYINDEX, lc->callback_ref); - - free(lc); - } - - lua_close(lua->L); -} diff --git a/kiwmi/luak/kiwmi_lua_callback.c b/kiwmi/luak/kiwmi_lua_callback.c new file mode 100644 index 0000000..74fdfc5 --- /dev/null +++ b/kiwmi/luak/kiwmi_lua_callback.c @@ -0,0 +1,95 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "luak/kiwmi_lua_callback.h" + +#include + +#include +#include + +static int +l_kiwmi_lua_callback_cancel(lua_State *L) +{ + struct kiwmi_lua_callback *lc = + *(struct kiwmi_lua_callback **)luaL_checkudata( + L, 1, "kiwmi_lua_callback"); + + wl_list_remove(&lc->listener.link); + wl_list_remove(&lc->link); + + luaL_unref(L, LUA_REGISTRYINDEX, lc->callback_ref); + + free(lc); + return 0; +} + +static const luaL_Reg kiwmi_lua_callback_methods[] = { + {"cancel", l_kiwmi_lua_callback_cancel}, + {NULL, NULL}, +}; + +int +luaK_kiwmi_lua_callback_new(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // server + luaL_checktype(L, 2, LUA_TFUNCTION); // callback + luaL_checktype(L, 3, LUA_TLIGHTUSERDATA); // event_handler + luaL_checktype(L, 4, LUA_TLIGHTUSERDATA); // signal + + struct kiwmi_lua_callback **lc_ud = lua_newuserdata(L, sizeof(*lc_ud)); + luaL_getmetatable(L, "kiwmi_lua_callback"); + lua_setmetatable(L, -2); + + struct kiwmi_lua_callback *lc = malloc(sizeof(*lc)); + if (!lc) { + return luaL_error(L, "failed to allocate kiwmi_lua_callback"); + } + + *lc_ud = lc; + + struct kiwmi_server *server = lua_touserdata(L, 1); + + lc->server = server; + + lua_pushvalue(L, 2); + lc->callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + lc->listener.notify = lua_touserdata(L, 3); + wl_signal_add(lua_touserdata(L, 4), &lc->listener); + + wl_list_insert(&server->lua->callbacks, &lc->link); + + return 1; +} + +int +luaK_kiwmi_lua_callback_register(lua_State *L) +{ + luaL_newmetatable(L, "kiwmi_lua_callback"); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, kiwmi_lua_callback_methods, 0); + + return 0; +} + +void +luaK_kiwmi_lua_callback_cleanup(struct kiwmi_lua *lua) +{ + struct kiwmi_lua_callback *lc; + struct kiwmi_lua_callback *tmp; + wl_list_for_each_safe (lc, tmp, &lua->callbacks, link) { + wl_list_remove(&lc->listener.link); + wl_list_remove(&lc->link); + + luaL_unref(lua->L, LUA_REGISTRYINDEX, lc->callback_ref); + + free(lc); + } +} diff --git a/kiwmi/luak/kiwmi_server.c b/kiwmi/luak/kiwmi_server.c new file mode 100644 index 0000000..fae0772 --- /dev/null +++ b/kiwmi/luak/kiwmi_server.c @@ -0,0 +1,173 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "luak/kiwmi_server.h" + +#include +#include +#include +#include + +#include "desktop/view.h" +#include "input/cursor.h" +#include "luak/kiwmi_lua_callback.h" +#include "luak/kiwmi_view.h" +#include "server.h" + +static int +l_kiwmi_server_on(lua_State *L) +{ + luaL_checkudata(L, 1, "kiwmi_server"); // server + luaL_checktype(L, 2, LUA_TSTRING); // type + luaL_checktype(L, 3, LUA_TFUNCTION); // callback + + lua_getmetatable(L, 1); + lua_getfield(L, -1, "__events"); + lua_pushvalue(L, 2); + lua_gettable(L, -2); + + luaL_argcheck(L, lua_iscfunction(L, -1), 2, "invalid event"); + lua_pushvalue(L, 1); + lua_pushvalue(L, 3); + + if (lua_pcall(L, 2, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + +static int +l_kiwmi_server_quit(lua_State *L) +{ + struct kiwmi_server *server = + *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); + + wl_display_terminate(server->wl_display); + + return 0; +} + +static int +l_kiwmi_server_view_under_cursor(lua_State *L) +{ + struct kiwmi_server *server = + *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); + + struct kiwmi_cursor *cursor = server->input.cursor; + + struct wlr_surface *surface; + double sx; + double sy; + + struct kiwmi_view *view = view_at( + &server->desktop, + cursor->cursor->x, + cursor->cursor->y, + &surface, + &sx, + &sy); + + if (view) { + lua_pushcfunction(L, luaK_kiwmi_view_new); + lua_pushlightuserdata(L, view); + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + } else { + lua_pushnil(L); + } + + return 1; +} + +static const luaL_Reg kiwmi_server_methods[] = { + {"on", l_kiwmi_server_on}, + {"quit", l_kiwmi_server_quit}, + {"view_under_cursor", l_kiwmi_server_view_under_cursor}, + {NULL, NULL}, +}; + +static void +kiwmi_server_on_view_notify(struct wl_listener *listener, void *data) +{ + struct kiwmi_lua_callback *lc = wl_container_of(listener, lc, listener); + struct kiwmi_server *server = lc->server; + lua_State *L = server->lua->L; + struct kiwmi_view *view = data; + + lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); + + lua_pushcfunction(L, luaK_kiwmi_view_new); + lua_pushlightuserdata(L, view); + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + } + + if (lua_pcall(L, 1, 0, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + } +} + +static int +l_kiwmi_server_on_view(lua_State *L) +{ + struct kiwmi_server *server = + *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_server_on_view_notify); + lua_pushlightuserdata(L, &server->desktop.events.view_map); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + +static const luaL_Reg kiwmi_server_events[] = { + {"view", l_kiwmi_server_on_view}, + {NULL, NULL}, +}; + +int +luaK_kiwmi_server_new(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // kiwmi_server + + struct kiwmi_server *server = lua_touserdata(L, 1); + + struct kiwmi_server **server_ud = lua_newuserdata(L, sizeof(*server_ud)); + luaL_getmetatable(L, "kiwmi_server"); + lua_setmetatable(L, -2); + + *server_ud = server; + + return 1; +} + +int +luaK_kiwmi_server_register(lua_State *L) +{ + luaL_newmetatable(L, "kiwmi_server"); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, kiwmi_server_methods, 0); + + luaL_newlib(L, kiwmi_server_events); + lua_setfield(L, -2, "__events"); + + return 0; +} diff --git a/kiwmi/luak/kiwmi_view.c b/kiwmi/luak/kiwmi_view.c new file mode 100644 index 0000000..4a781c7 --- /dev/null +++ b/kiwmi/luak/kiwmi_view.c @@ -0,0 +1,120 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "luak/kiwmi_view.h" + +#include + +#include "desktop/view.h" + +static int +l_kiwmi_view_close(lua_State *L) +{ + struct kiwmi_view *view = + *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); + + view_close(view); + + return 0; +} + +static int +l_kiwmi_view_focus(lua_State *L) +{ + struct kiwmi_view *view = + *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); + + view_focus(view); + + return 0; +} + +static int +l_kiwmi_view_hidden(lua_State *L) +{ + struct kiwmi_view *view = + *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); + + lua_pushboolean(L, view->hidden); + + return 1; +} + +static int +l_kiwmi_view_hide(lua_State *L) +{ + struct kiwmi_view *view = + *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); + + view->hidden = true; + + return 0; +} + +static int +l_kiwmi_view_move(lua_State *L) +{ + struct kiwmi_view *view = + *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); + + luaL_checktype(L, 2, LUA_TNUMBER); + luaL_checktype(L, 3, LUA_TNUMBER); + + view->x = lua_tonumber(L, 2); + view->y = lua_tonumber(L, 3); + + return 0; +} + +static int +l_kiwmi_view_show(lua_State *L) +{ + struct kiwmi_view *view = + *(struct kiwmi_view **)luaL_checkudata(L, 1, "kiwmi_view"); + + view->hidden = false; + + return 0; +} + +static const luaL_Reg kiwmi_view_methods[] = { + {"close", l_kiwmi_view_close}, + {"focus", l_kiwmi_view_focus}, + {"hidden", l_kiwmi_view_hidden}, + {"hide", l_kiwmi_view_hide}, + {"move", l_kiwmi_view_move}, + {"show", l_kiwmi_view_show}, + {NULL, NULL}, +}; + +int +luaK_kiwmi_view_new(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // kiwmi_view + + struct kiwmi_view *view = lua_touserdata(L, 1); + + struct kiwmi_view **view_ud = lua_newuserdata(L, sizeof(*view_ud)); + luaL_getmetatable(L, "kiwmi_view"); + lua_setmetatable(L, -2); + + *view_ud = view; + + return 1; +} + +int +luaK_kiwmi_view_register(lua_State *L) +{ + luaL_newmetatable(L, "kiwmi_view"); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, kiwmi_view_methods, 0); + + return 0; +} diff --git a/kiwmi/luak/luak.c b/kiwmi/luak/luak.c new file mode 100644 index 0000000..7392dfd --- /dev/null +++ b/kiwmi/luak/luak.c @@ -0,0 +1,87 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "luak/luak.h" + +#include + +#include +#include +#include + +#include "luak/kiwmi_lua_callback.h" +#include "luak/kiwmi_server.h" +#include "luak/kiwmi_view.h" + +struct kiwmi_lua * +luaK_create(struct kiwmi_server *server) +{ + struct kiwmi_lua *lua = malloc(sizeof(*lua)); + if (!lua) { + wlr_log(WLR_ERROR, "Failed to allocate kiwmi_lua"); + return NULL; + } + + lua_State *L = luaL_newstate(); + if (!L) { + return NULL; + } + + luaL_openlibs(L); + + // register types + int error = 0; + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_register); + error |= lua_pcall(L, 0, 0, 0); + lua_pushcfunction(L, luaK_kiwmi_view_register); + error |= lua_pcall(L, 0, 0, 0); + lua_pushcfunction(L, luaK_kiwmi_server_register); + error |= lua_pcall(L, 0, 0, 0); + + if (error) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return NULL; + } + + // create kiwmi global + lua_pushcfunction(L, luaK_kiwmi_server_new); + lua_pushlightuserdata(L, server); + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return NULL; + } + lua_setglobal(L, "kiwmi"); + + lua->L = L; + + wl_list_init(&lua->callbacks); + + return lua; +} + +bool +luaK_dofile(struct kiwmi_lua *lua, const char *config_path) +{ + if (luaL_dofile(lua->L, config_path)) { + wlr_log( + WLR_ERROR, "Error running config: %s", lua_tostring(lua->L, -1)); + return false; + } + + return true; +} + +void +luaK_destroy(struct kiwmi_lua *lua) +{ + luaK_kiwmi_lua_callback_cleanup(lua); + + lua_close(lua->L); + + free(lua); +} diff --git a/kiwmi/meson.build b/kiwmi/meson.build index c82ca47..91c0594 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -1,5 +1,4 @@ kiwmi_sources = files( - 'luak.c', 'main.c', 'server.c', 'desktop/desktop.c', @@ -9,6 +8,10 @@ kiwmi_sources = files( 'input/cursor.c', 'input/input.c', 'input/keyboard.c', + 'luak/kiwmi_lua_callback.c', + 'luak/kiwmi_server.c', + 'luak/kiwmi_view.c', + 'luak/luak.c', ) kiwmi_deps = [ diff --git a/kiwmi/server.c b/kiwmi/server.c index bc3353c..ccc86b4 100644 --- a/kiwmi/server.c +++ b/kiwmi/server.c @@ -18,7 +18,7 @@ #include #include -#include "luak.h" +#include "luak/luak.h" bool server_init(struct kiwmi_server *server, char *config_path) @@ -87,7 +87,7 @@ server_init(struct kiwmi_server *server, char *config_path) server->config_path = config_path; - if (!luaK_init(server)) { + if (!(server->lua = luaK_create(server))) { wlr_log(WLR_ERROR, "Failed to initialize Lua"); wl_display_destroy(server->wl_display); return false; @@ -128,7 +128,7 @@ server_fini(struct kiwmi_server *server) wl_display_destroy_clients(server->wl_display); wl_display_destroy(server->wl_display); - luaK_fini(server->lua); + luaK_destroy(server->lua); free(server->config_path); }