aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--src/imv.c35
-rw-r--r--src/ipc.c131
-rw-r--r--src/ipc.h15
4 files changed, 176 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index a1e6289..41c9525 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/src/imv.c b/src/imv.c
index 1967591..363d95a 100644
--- a/src/imv.c
+++ b/src/imv.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