From b79aa962d65a16dbfa0c9e04df166817e3c44513 Mon Sep 17 00:00:00 2001 From: Charlotte Meyer Date: Fri, 3 Jan 2020 18:40:11 +0000 Subject: [PATCH] Add kiwmic IPC --- include/luak/ipc.h | 18 +++++++ include/luak/luak.h | 1 + kiwmi/luak/ipc.c | 92 +++++++++++++++++++++++++++++++++++ kiwmi/luak/luak.c | 13 +++++ kiwmi/meson.build | 1 + kiwmic/main.c | 103 ++++++++++++++++++++++++++++++++++++++++ kiwmic/meson.build | 16 +++++++ meson.build | 2 + protocols/kiwmi-ipc.xml | 31 ++++++++++++ protocols/meson.build | 38 ++++++++++++++- 10 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 include/luak/ipc.h create mode 100644 kiwmi/luak/ipc.c create mode 100644 kiwmic/main.c create mode 100644 kiwmic/meson.build create mode 100644 protocols/kiwmi-ipc.xml diff --git a/include/luak/ipc.h b/include/luak/ipc.h new file mode 100644 index 0000000..c8da8e6 --- /dev/null +++ b/include/luak/ipc.h @@ -0,0 +1,18 @@ +/* Copyright (c), Charlotte 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_IPC_H +#define KIWMI_LUAK_IPC_H + +#include + +#include "luak/luak.h" +#include "server.h" + +bool luaK_ipc_init(struct kiwmi_server *server, struct kiwmi_lua *lua); + +#endif /* KIWMI_LUAK_IPC_H */ diff --git a/include/luak/luak.h b/include/luak/luak.h index 7559701..3a59ac5 100644 --- a/include/luak/luak.h +++ b/include/luak/luak.h @@ -17,6 +17,7 @@ struct kiwmi_lua { lua_State *L; struct wl_list callbacks; // lua_callback::link + struct wl_global *global; }; int luaK_callback_register_dispatch(lua_State *L); diff --git a/kiwmi/luak/ipc.c b/kiwmi/luak/ipc.c new file mode 100644 index 0000000..034dc9b --- /dev/null +++ b/kiwmi/luak/ipc.c @@ -0,0 +1,92 @@ +/* Copyright (c), Charlotte 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/ipc.h" + +#include +#include + +#include "kiwmi-ipc-server-protocol.h" +#include "luak/luak.h" + +static void +ipc_eval( + struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + const char *message) +{ + struct kiwmi_server *server = wl_resource_get_user_data(resource); + struct wl_resource *command_resource = + wl_resource_create(client, &kiwmi_command_interface, 1, id); + lua_State *L = server->lua->L; + + int top = lua_gettop(L); + + if (luaL_dostring(L, message)) { + const char *error = lua_tostring(L, -1); + wlr_log(WLR_ERROR, "Error running IPC command: %s", error); + kiwmi_command_send_done( + command_resource, KIWMI_COMMAND_ERROR_FAILURE, error); + return; + } + + int results = top - lua_gettop(L); + + if (results == 0) { + kiwmi_command_send_done( + command_resource, KIWMI_COMMAND_ERROR_SUCCESS, ""); + } else { + kiwmi_command_send_done( + command_resource, KIWMI_COMMAND_ERROR_SUCCESS, lua_tostring(L, -1)); + } +} + +static const struct kiwmi_ipc_interface kiwmi_ipc_implementation = { + .eval = ipc_eval, +}; + +static void +kiwmi_server_resource_destroy(struct wl_resource *UNUSED(resource)) +{ + // EMPTY +} + +static void +ipc_server_bind( + struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct kiwmi_server *server = data; + struct wl_resource *resource = + wl_resource_create(client, &kiwmi_ipc_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation( + resource, + &kiwmi_ipc_implementation, + server, + kiwmi_server_resource_destroy); +} + +bool +luaK_ipc_init(struct kiwmi_server *server, struct kiwmi_lua *lua) +{ + lua->global = wl_global_create( + server->wl_display, &kiwmi_ipc_interface, 1, server, ipc_server_bind); + if (!lua->global) { + wlr_log(WLR_ERROR, "Failed to create IPC global"); + return false; + } + + return true; +} diff --git a/kiwmi/luak/luak.c b/kiwmi/luak/luak.c index 66822f5..0cbc382 100644 --- a/kiwmi/luak/luak.c +++ b/kiwmi/luak/luak.c @@ -13,6 +13,7 @@ #include #include +#include "luak/ipc.h" #include "luak/kiwmi_lua_callback.h" #include "luak/kiwmi_server.h" #include "luak/kiwmi_view.h" @@ -54,6 +55,7 @@ luaK_create(struct kiwmi_server *server) lua_State *L = luaL_newstate(); if (!L) { + free(lua); return NULL; } @@ -71,6 +73,8 @@ luaK_create(struct kiwmi_server *server) if (error) { wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_close(L); + free(lua); return NULL; } @@ -79,6 +83,8 @@ luaK_create(struct kiwmi_server *server) lua_pushlightuserdata(L, server); if (lua_pcall(L, 1, 1, 0)) { wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_close(L); + free(lua); return NULL; } lua_setglobal(L, "kiwmi"); @@ -87,6 +93,13 @@ luaK_create(struct kiwmi_server *server) wl_list_init(&lua->callbacks); + if (!luaK_ipc_init(server, lua)) { + wlr_log(WLR_ERROR, "Failed to initialize IPC"); + lua_close(L); + free(lua); + return NULL; + } + return lua; } diff --git a/kiwmi/meson.build b/kiwmi/meson.build index 91c0594..6cc54a4 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -8,6 +8,7 @@ kiwmi_sources = files( 'input/cursor.c', 'input/input.c', 'input/keyboard.c', + 'luak/ipc.c', 'luak/kiwmi_lua_callback.c', 'luak/kiwmi_server.c', 'luak/kiwmi_view.c', diff --git a/kiwmic/main.c b/kiwmic/main.c new file mode 100644 index 0000000..a71c794 --- /dev/null +++ b/kiwmic/main.c @@ -0,0 +1,103 @@ +/* Copyright (c), Charlotte 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 +#include +#include + +#include + +#include "kiwmi-ipc-client-protocol.h" + +static void +command_done( + void *data, + struct kiwmi_command *UNUSED(kiwmi_command), + uint32_t error, + const char *message) +{ + int *exit_code = data; + FILE *out; + + if (error == KIWMI_COMMAND_ERROR_SUCCESS) { + *exit_code = EXIT_SUCCESS; + out = stdout; + } else { + *exit_code = EXIT_FAILURE; + out = stderr; + } + + if (message[0] != '\0') { + fprintf(out, "%s\n", message); + } +} + +static const struct kiwmi_command_listener command_listener = { + .done = command_done, +}; + +static void +registry_global( + void *data, + struct wl_registry *registry, + uint32_t name, + const char *interface, + uint32_t UNUSED(version)) +{ + struct kiwmi_ipc **ipc = data; + if (strcmp(interface, kiwmi_ipc_interface.name) == 0) { + *ipc = wl_registry_bind(registry, name, &kiwmi_ipc_interface, 1); + } +} + +static void +registry_global_remove( + void *UNUSED(data), + struct wl_registry *UNUSED(registry), + uint32_t UNUSED(name)) +{ + // EMPTY +} + +static const struct wl_registry_listener registry_listener = { + .global = registry_global, + .global_remove = registry_global_remove, +}; + +int +main(int argc, char **argv) +{ + if (argc < 2) { + fprintf(stderr, "Usage: kiwmic COMMAND\n"); + exit(EXIT_FAILURE); + } + + struct wl_display *display = wl_display_connect(NULL); + if (!display) { + fprintf(stderr, "Failed to connect to display\n"); + exit(EXIT_FAILURE); + } + + struct wl_registry *registry = wl_display_get_registry(display); + struct kiwmi_ipc *ipc = NULL; + + wl_registry_add_listener(registry, ®istry_listener, &ipc); + wl_display_roundtrip(display); + + if (!ipc) { + fprintf(stderr, "Failed to bind to kiwmi_ipc\n"); + exit(EXIT_FAILURE); + } + + struct kiwmi_command *command = kiwmi_ipc_eval(ipc, argv[1]); + int exit_code; + kiwmi_command_add_listener(command, &command_listener, &exit_code); + wl_display_roundtrip(display); + wl_display_disconnect(display); + + exit(exit_code); +} diff --git a/kiwmic/meson.build b/kiwmic/meson.build new file mode 100644 index 0000000..22dfe45 --- /dev/null +++ b/kiwmic/meson.build @@ -0,0 +1,16 @@ +kiwmic_sources = files( + 'main.c', +) + +kiwmic_deps = [ + protocols_client, + wayland_client, +] + +executable( + 'kiwmic', + kiwmic_sources, + include_directories: [include], + dependencies: kiwmic_deps, + install: true, +) diff --git a/meson.build b/meson.build index 1bd57f7..32a76a3 100644 --- a/meson.build +++ b/meson.build @@ -18,6 +18,7 @@ add_project_arguments( git = find_program('git', required: false) lua = dependency('lua') +wayland_client = dependency('wayland-client') wayland_protocols = dependency('wayland-protocols') wayland_scanner = dependency('wayland-scanner') wayland_server = dependency('wayland-server') @@ -49,3 +50,4 @@ endif subdir('protocols') subdir('kiwmi') +subdir('kiwmic') diff --git a/protocols/kiwmi-ipc.xml b/protocols/kiwmi-ipc.xml new file mode 100644 index 0000000..489387c --- /dev/null +++ b/protocols/kiwmi-ipc.xml @@ -0,0 +1,31 @@ + + + + Copyright (c), Charlotte Meyer <dev@buffet.sh> + + 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/. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/protocols/meson.build b/protocols/meson.build index a917ad1..7400f03 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -3,6 +3,7 @@ wayland_scanner_bin = wayland_scanner.get_pkgconfig_variable('wayland_scanner' protocols_server = [ wayland_protocols_dir / 'stable/xdg-shell/xdg-shell.xml', + 'kiwmi-ipc.xml', ] protocols_server_src = [] @@ -12,14 +13,14 @@ foreach protocol : protocols_server protocols_server_src += custom_target( protocol.underscorify() + '_server_c', input: protocol, - output: '@BASENAME@-protocol.c', + output: '@BASENAME@-server-protocol.c', command: [wayland_scanner_bin, 'private-code', '@INPUT@', '@OUTPUT@'], ) protocols_server_inc += custom_target( protocol.underscorify() + '_server_h', input: protocol, - output: '@BASENAME@-protocol.h', + output: '@BASENAME@-server-protocol.h', command: [wayland_scanner_bin, 'server-header', '@INPUT@', '@OUTPUT@'], ) endforeach @@ -33,3 +34,36 @@ protocols_server = declare_dependency( link_with: protocols_server_lib, sources: protocols_server_inc, ) + +protocols_client = [ + 'kiwmi-ipc.xml', +] + +protocols_client_src = [] +protocols_client_inc = [] + +foreach protocol : protocols_client + protocols_client_src += custom_target( + protocol.underscorify() + '_client_c', + input: protocol, + output: '@BASENAME@-client-protocol.c', + command: [wayland_scanner_bin, 'private-code', '@INPUT@', '@OUTPUT@'], + ) + + protocols_client_inc += custom_target( + protocol.underscorify() + '_client_h', + input: protocol, + output: '@BASENAME@-client-protocol.h', + command: [wayland_scanner_bin, 'client-header', '@INPUT@', '@OUTPUT@'], + ) +endforeach + +protocols_client_lib = static_library( + 'protocols_client', + [protocols_client_src, protocols_client_inc], +) + +protocols_client = declare_dependency( + link_with: protocols_client_lib, + sources: protocols_client_inc, +)