diff --git a/include/kiwmi/frontend.h b/include/kiwmi/frontend.h index 3772ca6..0f225d0 100644 --- a/include/kiwmi/frontend.h +++ b/include/kiwmi/frontend.h @@ -9,9 +9,16 @@ #define KIWMI_FRONTEND_H #include +#include + +#include struct kiwmi_frontend { const char *frontend_path; + int sock_fd; + char *sock_path; + struct wl_event_source *sock_event_source; + struct wl_listener display_destroy; }; bool frontend_init(struct kiwmi_frontend *frontend, const char *frontend_path); diff --git a/include/kiwmi/server.h b/include/kiwmi/server.h index 42f772c..5b3bdbe 100644 --- a/include/kiwmi/server.h +++ b/include/kiwmi/server.h @@ -16,6 +16,7 @@ struct kiwmi_server { struct wl_display *wl_display; + struct wl_event_loop *wl_event_loop; struct wlr_backend *backend; const char *socket; struct kiwmi_desktop desktop; diff --git a/kiwmi/frontend.c b/kiwmi/frontend.c index bc082e5..a112ea4 100644 --- a/kiwmi/frontend.c +++ b/kiwmi/frontend.c @@ -7,13 +7,163 @@ #include "kiwmi/frontend.h" +#include #include #include +#include +#include +#include +#include +#include #include #include +#include "kiwmi/server.h" + +static void +display_destroy_notify(struct wl_listener *listener, void *UNUSED(data)) +{ + struct kiwmi_frontend *frontend = + wl_container_of(listener, frontend, display_destroy); + + if (frontend->sock_event_source) { + wl_event_source_remove(frontend->sock_event_source); + } + + close(frontend->sock_fd); + unlink(frontend->sock_path); + free(frontend->sock_path); + + wl_list_remove(&frontend->display_destroy.link); +} + +static int +ipc_connection(int fd, uint32_t mask, void *UNUSED(data)) +{ + wlr_log(WLR_DEBUG, "Received an IPC event"); + + if (!(mask & WL_EVENT_READABLE)) { + return 0; + } + + int client_fd = accept(fd, NULL, NULL); + + if (client_fd < 0) { + wlr_log(WLR_ERROR, "Failed to accept client connection"); + return 0; + } + + FILE *client_file = fdopen(client_fd, "r+"); + + size_t buffer_size = BUFSIZ; + size_t msg_len = 0; + char *msg = malloc(buffer_size); + if (!msg) { + wlr_log(WLR_ERROR, "Failed to allocate memory"); + fclose(client_file); + return 0; + } + + int c; + while ((c = getc(client_file)) != '\0') { + if (msg_len >= buffer_size) { + buffer_size *= 2; + char *tmp = realloc(msg, buffer_size); + if (!tmp) { + wlr_log(WLR_ERROR, "Failed to allocate memory"); + fclose(client_file); + free(msg); + return 0; + } + msg = tmp; + } + + msg[msg_len++] = c; + } + + msg[msg_len] = '\0'; + + wlr_log(WLR_ERROR, "%s", msg); + + // TODO: handle properly + + fclose(client_file); + free(msg); + + return 0; +} + +static bool +ipc_init(struct kiwmi_frontend *frontend) +{ + struct kiwmi_server *server = wl_container_of(frontend, server, frontend); + struct sockaddr_un sock_addr; + + memset(&sock_addr, 0, sizeof(sock_addr)); + + size_t path_len = snprintf( + sock_addr.sun_path, + sizeof(sock_addr.sun_path), + "%s/kiwmi_%" PRIdMAX ".sock", + getenv("XDG_RUNTIME_DIR"), + (intmax_t)getpid()); + + frontend->sock_path = malloc(path_len + 1); + if (!frontend->sock_path) { + wlr_log(WLR_ERROR, "Failed to allocate memory"); + return false; + } + + strcpy(frontend->sock_path, sock_addr.sun_path); + + setenv("KIWMI_SOCKET", sock_addr.sun_path, true); + + sock_addr.sun_family = AF_UNIX; + + if ((frontend->sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + wlr_log(WLR_ERROR, "Failed to create socket"); + return false; + } + + if (fcntl(frontend->sock_fd, F_SETFD, FD_CLOEXEC) < 0) { + wlr_log(WLR_ERROR, "Failed to set CLOEXEC on socket"); + return false; + } + + if (fcntl(frontend->sock_fd, F_SETFD, O_NONBLOCK) < 0) { + wlr_log(WLR_ERROR, "Failed to set NONBLOCK on socket"); + } + + unlink(sock_addr.sun_path); + + if (bind( + frontend->sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) + < 0) { + wlr_log(WLR_ERROR, "Failed to bind socket"); + return false; + } + + if (listen(frontend->sock_fd, 3) < 0) { + wlr_log(WLR_ERROR, "Failed to listen to socket"); + return false; + } + + frontend->display_destroy.notify = display_destroy_notify; + wl_display_add_destroy_listener( + server->wl_display, &frontend->display_destroy); + + frontend->sock_event_source = wl_event_loop_add_fd( + server->wl_event_loop, + frontend->sock_fd, + WL_EVENT_READABLE, + ipc_connection, + server); + + return true; +} + static bool spawn_frontend(const char *path) { @@ -38,6 +188,11 @@ frontend_init(struct kiwmi_frontend *frontend, const char *frontend_path) { frontend->frontend_path = frontend_path; + if (!ipc_init(frontend)) { + wlr_log(WLR_ERROR, "Failed to create socket"); + return false; + } + if (strcmp(frontend_path, "NONE") == 0) { wlr_log(WLR_ERROR, "Launching without a frontend"); return true; diff --git a/kiwmi/server.c b/kiwmi/server.c index 98d1248..fce1d71 100644 --- a/kiwmi/server.c +++ b/kiwmi/server.c @@ -20,6 +20,7 @@ server_init(struct kiwmi_server *server, const char *frontend_path) wlr_log(WLR_DEBUG, "Initializing Wayland server"); server->wl_display = wl_display_create(); + server->wl_event_loop = wl_display_get_event_loop(server->wl_display); server->backend = wlr_backend_autocreate(server->wl_display, NULL); if (!server->backend) { wlr_log(WLR_ERROR, "Failed to create backend"); @@ -42,6 +43,13 @@ server_init(struct kiwmi_server *server, const char *frontend_path) return false; } + server->socket = wl_display_add_socket_auto(server->wl_display); + if (!server->socket) { + wlr_log(WLR_ERROR, "Failed to open Wayland socket"); + wl_display_destroy(server->wl_display); + return false; + } + if (!frontend_init(&server->frontend, frontend_path)) { wlr_log(WLR_ERROR, "Failed to initialize frontend"); wl_display_destroy(server->wl_display); @@ -54,13 +62,6 @@ server_init(struct kiwmi_server *server, const char *frontend_path) bool server_run(struct kiwmi_server *server) { - server->socket = wl_display_add_socket_auto(server->wl_display); - if (!server->socket) { - wlr_log(WLR_ERROR, "Failed to open Wayland socket"); - wl_display_destroy(server->wl_display); - return false; - } - wlr_log( WLR_DEBUG, "Running Wayland server on display '%s'", server->socket);