aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/comet.c4
-rw-r--r--src/dwm.c285
-rw-r--r--src/dwm.h14
3 files changed, 303 insertions, 0 deletions
diff --git a/src/comet.c b/src/comet.c
index b6b36c5..5feab31 100644
--- a/src/comet.c
+++ b/src/comet.c
@@ -11,6 +11,7 @@
#include "draw.h"
#include "connect.h"
#include "state.h"
+#include "dwm.h"
#define EVEN(n) ((int)(n) - ((int)(n) % 2 != 0))
@@ -364,6 +365,8 @@ int main(int argc, char **argv)
button_group_append(group, menu);
state_add_button(state, group);
+ DwmIpc *dwm = dwm_create(state, "/tmp/dwm.sock");
+
connect_attach_state(con, state);
connect_attach_source(con);
@@ -387,6 +390,7 @@ int main(int argc, char **argv)
g_list_free(menu_ctx.toggled);
// Buttons are freed by state_destroy
+ dwm_destroy(dwm);
state_destroy(state);
draw_destroy(draw);
window_destroy(win);
diff --git a/src/dwm.c b/src/dwm.c
new file mode 100644
index 0000000..513f08a
--- /dev/null
+++ b/src/dwm.c
@@ -0,0 +1,285 @@
+#include <stdbool.h>
+#include <stdint.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <json-glib/json-glib.h>
+#include <json-glib/json-builder.h>
+
+#include "dwm.h"
+#include "log.h"
+
+#define IPC_MAGIC "DWM-IPC"
+#define IPC_MAGIC_LEN 7
+
+typedef struct {
+ uint8_t magic[IPC_MAGIC_LEN];
+ uint32_t size;
+ uint8_t type;
+} __attribute__((packed)) DwmIpcHeader;
+
+struct DwmIpc {
+ GSource source;
+ GSocket *socket;
+ State *state;
+};
+
+typedef enum {
+ IPC_TYPE_RUN_COMMAND = 0,
+ IPC_TYPE_GET_MONITORS = 1,
+ IPC_TYPE_GET_TAGS = 2,
+ IPC_TYPE_GET_LAYOUTS = 3,
+ IPC_TYPE_GET_DWM_CLIENT = 4,
+ IPC_TYPE_SUBSCRIBE = 5,
+ IPC_TYPE_EVENT = 6
+} DwmIpcMessage;
+
+#define IPC_EVENT_TAG_CHANGE "tag_change_event"
+#define IPC_EVENT_CLIENT_FOCUS_CHANGE "client_focus_change_event"
+#define IPC_EVENT_LAYOUT_CHANGE "layout_change_event"
+#define IPC_EVENT_MONITOR_FOCUS_CHANGE "monitor_focus_change_event"
+#define IPC_EVENT_FOCUSED_TITLE_CHANGE "focused_title_change_event"
+#define IPC_EVENT_FOCUSED_STATE_CHANGE "focused_state_change_event"
+
+static void ipc_send(DwmIpc *dwm, DwmIpcMessage msg_type, uint8_t *msg, uint32_t msg_size)
+{
+ DwmIpcHeader header;
+ memcpy(header.magic, IPC_MAGIC, IPC_MAGIC_LEN);
+ header.size = msg_size;
+ header.type = msg_type;
+
+ GError *error = NULL;
+
+ gssize size = 0;
+ while (size < sizeof(DwmIpcHeader)) {
+ gssize sent = g_socket_send(dwm->socket, (void *)&header + size, sizeof(DwmIpcHeader) - size, NULL, &error);
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
+ g_error_free(error);
+ continue;
+ }
+ g_assert(sent != -1);
+ size += sent;
+ }
+
+ size = 0;
+ while (size < msg_size) {
+ gssize sent = g_socket_send(dwm->socket, msg + size, msg_size - size, NULL, &error);
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
+ g_error_free(error);
+ continue;
+ }
+ g_assert(sent != -1);
+ size += sent;
+ }
+
+ log_debug("Sent ipc message [type=%d, size=%d]", msg_type, msg_size);
+}
+
+static void ipc_subscribe(DwmIpc *dwm, const char *event)
+{
+ // {
+ // "event": "<event>",
+ // "action": "subscribe"
+ // }
+
+ JsonBuilder *builder = json_builder_new();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "event");
+ json_builder_add_string_value(builder, event);
+
+ json_builder_set_member_name(builder, "action");
+ json_builder_add_string_value(builder, "subscribe");
+
+ json_builder_end_object(builder);
+
+ JsonNode *root = json_builder_get_root(builder);
+
+ JsonGenerator *gen = json_generator_new();
+ json_generator_set_root(gen, root);
+
+ gsize msg_len = 0;
+ gchar *msg = json_generator_to_data(gen, &msg_len);
+
+ log_info("Subscribing to dwm ipc: %s", msg);
+ ipc_send(dwm, IPC_TYPE_SUBSCRIBE, msg, msg_len);
+
+ json_node_free(root);
+ g_object_unref(gen);
+ g_object_unref(builder);
+ g_free(msg);
+}
+
+static void ipc_handle(DwmIpc *dwm, DwmIpcMessage type, char *reply, uint32_t reply_size)
+{
+ GError *error = NULL;
+ JsonParser *parser = json_parser_new();
+ if (!json_parser_load_from_data(parser, reply, reply_size - 1, &error)) {
+ log_warning("Failed to parse dwm ipc reply: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ JsonReader *reader = json_reader_new(json_parser_get_root(parser));
+
+ if (type == IPC_TYPE_EVENT) {
+ if (json_reader_read_member(reader, IPC_EVENT_TAG_CHANGE)) {
+ log_debug("Reading dwm ipc event [event=%s]", IPC_EVENT_TAG_CHANGE);
+
+ json_reader_read_member(reader, "new_state");
+ json_reader_read_member(reader, "selected");
+ long selected = json_reader_get_int_value(reader);
+ json_reader_end_member (reader);
+ json_reader_end_member (reader);
+ json_reader_end_member (reader);
+
+ log_debug("Dwm tag mask: %ld", selected);
+
+ for (int i = 0; i < 9; i++) {
+ Button *btn = g_list_nth_data(dwm->state->btns, i);
+ g_assert_nonnull(btn);
+
+ Color color = { 0.4, 0.4, 0.4, 1 };
+ Color sel_color = { 0.3, 0.5, 0.2, 1 };
+
+ if (selected & (1 << i))
+ btn->color = sel_color;
+ else
+ btn->color = color;
+ }
+
+ state_redraw(dwm->state, false);
+ } else if (json_reader_read_member(reader, IPC_EVENT_CLIENT_FOCUS_CHANGE)) {
+ log_info("Ignoring dwm ipc event [event=%s]", IPC_EVENT_CLIENT_FOCUS_CHANGE);
+ // TODO
+
+ } else if (json_reader_read_member(reader, IPC_EVENT_LAYOUT_CHANGE)) {
+ log_info("Ignoring dwm ipc event [event=%s]", IPC_EVENT_LAYOUT_CHANGE);
+ // TODO
+
+ } else if (json_reader_read_member(reader, IPC_EVENT_MONITOR_FOCUS_CHANGE)) {
+ log_info("Ignoring dwm ipc event [event=%s]", IPC_EVENT_MONITOR_FOCUS_CHANGE);
+ // TODO
+
+ } else if (json_reader_read_member(reader, IPC_EVENT_FOCUSED_TITLE_CHANGE)) {
+ log_info("Ignoring dwm ipc event [event=%s]", IPC_EVENT_FOCUSED_TITLE_CHANGE);
+ // TODO
+
+ } else if (json_reader_read_member(reader, IPC_EVENT_FOCUSED_STATE_CHANGE)) {
+ log_info("Ignoring dwm ipc event [event=%s]", IPC_EVENT_FOCUSED_STATE_CHANGE);
+ // TODO
+
+ } else {
+ log_warning("Unrecognized dwm ipc event");
+ }
+ } else {
+ log_debug("Ignoring dwm ipc message [type=%d]", type);
+ }
+
+ g_object_unref (reader);
+ g_object_unref (parser);
+}
+
+static gboolean source_check(GSource *source)
+{
+ DwmIpc *dwm = (DwmIpc *)source;
+ GIOCondition flags = g_socket_condition_check(dwm->socket, G_IO_IN);
+ return flags & G_IO_IN;
+}
+
+static gboolean source_dispatch(GSource *source, GSourceFunc callback, gpointer data)
+{
+ DwmIpc *dwm = (DwmIpc *)source;
+ DwmIpcHeader header;
+ GError *error = NULL;
+
+ gssize size = 0;
+ while (size < sizeof(DwmIpcHeader)) {
+ gssize read = g_socket_receive(dwm->socket, (void *)&header + size, sizeof(DwmIpcHeader) - size, NULL, &error);
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
+ g_error_free(error);
+ continue;
+ }
+ g_assert(read != -1);
+ size += read;
+ }
+
+ if (memcmp(&header, IPC_MAGIC, IPC_MAGIC_LEN) != 0) {
+ log_warning("Erroneous ipc message");
+ return G_SOURCE_CONTINUE;;
+ }
+
+ uint32_t reply_size;
+ memcpy(&reply_size, (void *)&header + IPC_MAGIC_LEN, sizeof(uint32_t));
+
+ uint8_t msg_type;
+ memcpy(&msg_type, (void *)&header + IPC_MAGIC_LEN + sizeof(uint32_t), sizeof(uint8_t));
+
+ char *reply = g_malloc(reply_size);
+
+ size = 0;
+ while (size < reply_size) {
+ gssize read = g_socket_receive(dwm->socket, reply + size, reply_size - size, NULL, NULL);
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
+ g_error_free(error);
+ continue;
+ }
+ g_assert(read != -1);
+ size += read;
+ }
+
+ //log_debug("Received dwm ipc response: %s", reply);
+ ipc_handle(dwm, msg_type, reply, reply_size);
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void source_finalize(GSource *source)
+{
+ g_object_unref(((DwmIpc *)source)->socket);
+}
+
+static GSourceFuncs source_fns = {
+ NULL,
+ source_check,
+ source_dispatch,
+ source_finalize,
+};
+
+DwmIpc *dwm_create(State *state, const char *socket)
+{
+ DwmIpc *dwm = (DwmIpc *)g_source_new(&source_fns, sizeof(DwmIpc));
+ g_source_set_static_name((GSource *)dwm, "DwmIpc");
+
+ GError *error = NULL;
+ dwm->socket = g_socket_new(G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, 0, &error);
+ g_assert_nonnull(dwm->socket);
+
+ GSocketAddress *addr = g_unix_socket_address_new(socket);
+
+ if (!g_socket_connect(dwm->socket, addr, NULL, &error)) {
+ g_assert_nonnull(error);
+ log_error("Failed to connect to %s: %s", socket, error->message);
+ }
+
+ g_source_attach((GSource *)dwm, NULL);
+
+ dwm->state = state;
+
+ const char *events[] = {
+ IPC_EVENT_TAG_CHANGE,
+ IPC_EVENT_FOCUSED_STATE_CHANGE,
+ };
+ for (int i = 0; i < G_N_ELEMENTS(events); ++i)
+ ipc_subscribe(dwm, events[i]);
+
+ log_debug("Attached dwm ipc source");
+
+ return dwm;
+}
+
+void dwm_destroy(DwmIpc *dwm)
+{
+ g_source_destroy((GSource *)dwm);
+ g_source_unref((GSource *)dwm);
+}
diff --git a/src/dwm.h b/src/dwm.h
new file mode 100644
index 0000000..eab8ddb
--- /dev/null
+++ b/src/dwm.h
@@ -0,0 +1,14 @@
+#ifndef COMET_DWM_H
+#define COMET_DWM_H
+
+#include "state.h"
+
+typedef struct DwmIpc DwmIpc;
+
+DwmIpc *dwm_create(State *state, const char *socket);
+
+void dwm_destroy(DwmIpc *dwm);
+
+#endif
+
+// vim: ts=4 sw=4 et