diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | src/imv.c | 35 | ||||
-rw-r--r-- | src/ipc.c | 131 | ||||
-rw-r--r-- | src/ipc.h | 15 |
4 files changed, 176 insertions, 6 deletions
@@ -29,6 +29,7 @@ SOURCES += src/console.c SOURCES += src/image.c SOURCES += src/imv.c SOURCES += src/ini.c +SOURCES += src/ipc.c SOURCES += src/keyboard.c SOURCES += src/list.c SOURCES += src/log.c @@ -16,6 +16,7 @@ #include "console.h" #include "image.h" #include "ini.h" +#include "ipc.h" #include "keyboard.h" #include "list.h" #include "log.h" @@ -56,7 +57,8 @@ struct backend_chain { enum internal_event_type { NEW_IMAGE, BAD_IMAGE, - NEW_PATH + NEW_PATH, + COMMAND }; struct internal_event { @@ -73,6 +75,9 @@ struct internal_event { struct { char *path; } new_path; + struct { + char *text; + } command; } data; }; @@ -162,6 +167,7 @@ struct imv { struct imv_source *last_source; struct imv_commands *commands; struct imv_console *console; + struct imv_ipc *ipc; struct imv_viewport *view; struct imv_keyboard *keyboard; struct imv_canvas *canvas; @@ -368,11 +374,18 @@ static void source_callback(struct imv_source_message *msg) static void command_callback(const char *text, void *data) { struct imv *imv = data; - struct list *commands = list_create(); - list_append(commands, strdup(text)); - imv_command_exec_list(imv->commands, commands, imv); - list_deep_free(commands); - imv->need_redraw = true; + + struct internal_event *event = calloc(1, sizeof *event); + event->type = COMMAND; + event->data.command.text = strdup(text); + + struct imv_event e = { + .type = IMV_EVENT_CUSTOM, + .data = { + .custom = event + } + }; + imv_window_push_event(imv->window, &e); } static void key_handler(struct imv *imv, int scancode, bool pressed) @@ -498,6 +511,8 @@ struct imv *imv_create(void) imv->commands = imv_commands_create(); imv->console = imv_console_create(); imv_console_set_command_callback(imv->console, &command_callback, imv); + imv->ipc = imv_ipc_create(); + imv_ipc_set_command_callback(imv->ipc, &command_callback, imv); imv->title_text = strdup( "imv - [${imv_current_index}/${imv_file_count}]" " [${imv_width}x${imv_height}] [${imv_scale}%]" @@ -583,6 +598,7 @@ void imv_free(struct imv *imv) } imv_commands_free(imv->commands); imv_console_free(imv->console); + imv_ipc_free(imv->ipc); imv_viewport_free(imv->view); imv_keyboard_free(imv->keyboard); imv_canvas_free(imv->canvas); @@ -1138,6 +1154,13 @@ static void consume_internal_event(struct imv *imv, struct internal_event *event free(event->data.new_path.path); /* Need to update image count in title */ imv->need_redraw = true; + + } else if (event->type == COMMAND) { + struct list *commands = list_create(); + list_append(commands, event->data.command.text); + imv_command_exec_list(imv->commands, commands, imv); + list_deep_free(commands); + imv->need_redraw = true; } free(event); diff --git a/src/ipc.c b/src/ipc.c new file mode 100644 index 0000000..745433f --- /dev/null +++ b/src/ipc.c @@ -0,0 +1,131 @@ +#include "ipc.h" + +#include <ctype.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +struct imv_ipc { + int fd; + imv_ipc_callback callback; + void *data; +}; + +struct connection { + struct imv_ipc *ipc; + int fd; +}; + +static void get_ipc_filename(char *buf, size_t len) +{ + const char *base = getenv("XDG_RUNTIME_DIR"); + if (!base) { + base = "/tmp"; + } + snprintf(buf, len, "%s/imv-%d.sock", base, getpid()); +} + +void *wait_for_commands(void* void_conn) +{ + struct connection *conn = void_conn; + + while (1) { + char buf[1024]; + ssize_t len = recv(conn->fd, buf, sizeof buf - 1, 0); + if (len == -1) { + break; + } + + buf[len] = 0; + while (len > 0 && isspace(buf[len-1])) { + buf[len-1] = 0; + --len; + } + + if (conn->ipc->callback) { + conn->ipc->callback(buf, conn->ipc->data); + } + } + + close(conn->fd); + free(conn); + return NULL; +} + +void *wait_for_connections(void* void_ipc) +{ + struct imv_ipc *ipc = void_ipc; + (void)ipc; + + while (1) { + int client = accept(ipc->fd, NULL, NULL); + if (client == -1) { + break; + } + struct connection *conn = calloc(1, sizeof *conn); + conn->ipc = ipc; + conn->fd = client; + + pthread_t thread; + pthread_create(&thread, NULL, wait_for_commands, conn); + pthread_detach(thread); + } + return NULL; +} + +struct imv_ipc *imv_ipc_create(void) +{ + int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) { + return NULL; + } + + struct sockaddr_un desc = { + .sun_family = AF_UNIX + }; + get_ipc_filename(desc.sun_path, sizeof desc.sun_path); + + unlink(desc.sun_path); + + if (bind(sockfd, (struct sockaddr*)&desc, sizeof desc) == -1) { + return NULL; + } + + if (listen(sockfd, 5) == -1) { + close(sockfd); + return NULL; + } + + struct imv_ipc *ipc = calloc(1, sizeof *ipc); + ipc->fd = sockfd; + + pthread_t thread; + pthread_create(&thread, NULL, wait_for_connections, ipc); + pthread_detach(thread); + return ipc; +} + +void imv_ipc_free(struct imv_ipc *ipc) +{ + if (!ipc) { + return; + } + + char ipc_filename[1024]; + get_ipc_filename(ipc_filename, sizeof ipc_filename); + unlink(ipc_filename); + close(ipc->fd); + + free(ipc); +} + +void imv_ipc_set_command_callback(struct imv_ipc *ipc, + imv_ipc_callback callback, void *data) +{ + ipc->callback = callback; + ipc->data = data; +} + diff --git a/src/ipc.h b/src/ipc.h new file mode 100644 index 0000000..9737a8f --- /dev/null +++ b/src/ipc.h @@ -0,0 +1,15 @@ +#ifndef IMV_IPC_H +#define IMV_IPC_H + +struct imv_ipc; + +struct imv_ipc *imv_ipc_create(void); + +void imv_ipc_free(struct imv_ipc *ipc); + +typedef void (*imv_ipc_callback)(const char *command, void *data); + +void imv_ipc_set_command_callback(struct imv_ipc *ipc, + imv_ipc_callback callback, void *data); + +#endif |