diff options
Diffstat (limited to 'src/dwm.c')
| -rw-r--r-- | src/dwm.c | 445 |
1 files changed, 0 insertions, 445 deletions
diff --git a/src/dwm.c b/src/dwm.c deleted file mode 100644 index eda553e..0000000 --- a/src/dwm.c +++ /dev/null @@ -1,445 +0,0 @@ -#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; - -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_debug("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_run_command(DwmIpc *dwm, const char *cmd, JsonNode **args) -{ - // { - // "command": "<name>", - // "args": [ ... ] - // } - - JsonBuilder *builder = json_builder_new(); - - json_builder_begin_object(builder); - - json_builder_set_member_name(builder, "command"); - json_builder_add_string_value(builder, cmd); - - json_builder_set_member_name(builder, "args"); - json_builder_begin_array(builder); - - while (*args != NULL) { - json_builder_add_value(builder, *args++); - } - - json_builder_end_array(builder); - 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_debug("Sending run_command to dwm ipc: %s", msg); - ipc_send(dwm, IPC_TYPE_RUN_COMMAND, msg, msg_len); - - json_node_free(root); - g_object_unref(gen); - g_object_unref(builder); - g_free(msg); -} - -static void ipc_get_tags(DwmIpc *dwm) -{ - log_debug("Sending get_tags to dwm ipc"); - ipc_send(dwm, IPC_TYPE_GET_TAGS, "", 1); -} - -#define JSON_FIELD(reader, member) (json_reader_end_member(reader), json_reader_read_member(reader, member)) - -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)); - - switch (type) { - case IPC_TYPE_EVENT: - { - if (json_reader_read_member(reader, IPC_EVENT_TAG_CHANGE)) { - log_debug("Handling 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("Selected tag mask: %ld", selected); - - if (dwm->tags[0] != NULL) { - for (int i = 0; i < 9; i++) - dwm->tags[i]->color = selected & (1 << i) ? dwm->selected : dwm->color; - - state_request_redraw(dwm->state, false); - } - } else if (JSON_FIELD(reader, IPC_EVENT_CLIENT_FOCUS_CHANGE)) { - log_debug("Handling dwm ipc event [event=%s]", IPC_EVENT_CLIENT_FOCUS_CHANGE); - - json_reader_read_member(reader, "new_win_id"); - long win_id = json_reader_get_int_value(reader); - json_reader_end_member(reader); - json_reader_end_member(reader); - - char *msg = g_strdup_printf("{ \"client_window_id\": %ld }\n", win_id); - dwm->change_title = true; - ipc_send(dwm, IPC_TYPE_GET_DWM_CLIENT, msg, strlen(msg)); - g_free(msg); - } else if (JSON_FIELD(reader, IPC_EVENT_LAYOUT_CHANGE)) { - log_debug("Ignoring dwm ipc event [event=%s]", IPC_EVENT_LAYOUT_CHANGE); - // TODO - - } else if (JSON_FIELD(reader, IPC_EVENT_MONITOR_FOCUS_CHANGE)) { - log_debug("Ignoring dwm ipc event [event=%s]", IPC_EVENT_MONITOR_FOCUS_CHANGE); - // TODO - - } else if (JSON_FIELD(reader, IPC_EVENT_FOCUSED_TITLE_CHANGE)) { - log_debug("Ignoring dwm ipc event [event=%s]", IPC_EVENT_FOCUSED_TITLE_CHANGE); - // TODO - - } else if (JSON_FIELD(reader, IPC_EVENT_FOCUSED_STATE_CHANGE)) { - log_debug("Ignoring dwm ipc event [event=%s]", IPC_EVENT_FOCUSED_STATE_CHANGE); - // TODO - - } else { - const char *event = "?"; - if (json_reader_read_element(reader, 0)) - event = json_reader_get_string_value(reader); - - log_warning("Unrecognized dwm ipc event: %s", event); - } - break; - } - - case IPC_TYPE_GET_DWM_CLIENT: - { - log_debug("Received dwm client information message [type=%d]", type); - - if (dwm->change_title) { - json_reader_read_member(reader, "name"); - const char *title = json_reader_get_string_value(reader); - - log_debug("Changing current program title: %s", title ? title : "?"); - if (title == NULL || *title == '\0') { - state_remove_button(dwm->state, dwm->title); - dwm->hidden_title = true; - } else { - button_simple_set_text(dwm->title, g_strdup(title), dwm->text_color); - if (dwm->hidden_title) { - state_add_button(dwm->state, dwm->title); - state_order_button(dwm->state); - dwm->hidden_title = false; - } - } - - dwm->change_title = false; - state_request_redraw(dwm->state, true); - json_reader_end_member(reader); - } - break; - } - - case IPC_TYPE_GET_TAGS: - { - log_debug("Received dwm tag information message [type=%d]", type); - - guint index = 0; - while (json_reader_read_element(reader, index)) { - - json_reader_read_member(reader, "bit_mask"); - int mask = json_reader_get_int_value(reader); - json_reader_end_element(reader); - - // XXX: Handle nicely - g_assert_cmpint(mask, ==, 1 << index); - - // Set the tag names accordingly - json_reader_read_member(reader, "name"); - const char *name = json_reader_get_string_value(reader); - json_reader_end_element(reader); - - g_assert(index < 9); - button_simple_set_text(dwm->tags[index], g_strdup(name), dwm->text_color); - - json_reader_end_element(reader); - index++; - } - - break; - } - - default: - { - log_debug("Ignoring dwm ipc message [type=%d]", type); - //log_debug("%s", reply); - break; - } - } - - g_object_unref(reader); - g_object_unref(parser); -} - -static gboolean socket_callback(GSocket *socket, GIOCondition condition, gpointer data) -{ - if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) return G_SOURCE_REMOVE; - GError *error = NULL; - - DwmIpcHeader header; - gssize size = 0; - while (size < sizeof(DwmIpcHeader)) { - gssize read = g_socket_receive(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("Malformed dwm 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(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(data, msg_type, reply, reply_size); - g_free(reply); - - return G_SOURCE_CONTINUE; -} - -DwmIpc *dwm_create(State *state, const char *socket) -{ - DwmIpc *dwm = g_malloc0(sizeof(DwmIpc)); - dwm->state = state; - - 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_debug("Failed to connect socket %s: %s", socket, error->message); - log_info("Skipped dwm ipc [socket=%s]", socket); - - g_error_free(error); - g_object_unref(dwm->socket); - g_free(dwm); - return NULL; - } - - dwm->source = g_socket_create_source(dwm->socket, G_IO_IN, NULL); - g_source_set_static_name(dwm->source, "DwmIpcSource"); - g_source_set_callback(dwm->source, (GSourceFunc)socket_callback, dwm, NULL); - - const char *events[] = { - IPC_EVENT_TAG_CHANGE, - IPC_EVENT_CLIENT_FOCUS_CHANGE, - IPC_EVENT_LAYOUT_CHANGE, - IPC_EVENT_MONITOR_FOCUS_CHANGE, - IPC_EVENT_FOCUSED_TITLE_CHANGE, - IPC_EVENT_FOCUSED_STATE_CHANGE, - }; - for (int i = 0; i < G_N_ELEMENTS(events); ++i) - ipc_subscribe(dwm, events[i]); - - g_source_attach(dwm->source, NULL); - log_info("Attached dwm ipc source [socket=%s]", socket); - - g_object_unref(addr); - return dwm; -} - -static void change_tag_action(Button *btn) -{ - ButtonSimple *sbtn = CAST(btn, ButtonSimple); - DwmIpc *dwm = sbtn->data; - - int n = sbtn->text[0] - '0'; - g_assert(n >= 1 && n <= 9); - - log_info("Toggled tag %d", n); - - JsonNode *args[] = { - json_node_init_int(json_node_alloc(), 1 << (n - 1)), - NULL - }; - ipc_run_command(dwm, "view", args); -} - -void dwm_register_tags(DwmIpc *dwm, Color color, Color selected, Color text_color) -{ - if (dwm == NULL) return; - - dwm->color = color; - dwm->text_color = text_color; - dwm->selected = selected; - - // Tags button - for (int i = 0; i < 9; ++i) { - char text[] = { '1' + i, '\0' }; - dwm->tags[i] = button_simple_create(PANGO_ALIGN_LEFT, color); - button_simple_set_text(dwm->tags[i], g_strdup(text), text_color); - button_simple_set_action(dwm->tags[i], change_tag_action, dwm); - state_add_button(dwm->state, dwm->tags[i]); - } - - // This will set the tag names - ipc_get_tags(dwm); - - dwm->title = button_simple_create(PANGO_ALIGN_CENTER, color); - dwm->hidden_title = true; - - // FIXME: Set the first tag - CAST(dwm->tags[0], ButtonSimple)->action(dwm->tags[0]); - dwm->tags[0]->color = dwm->selected; -} - -void dwm_destroy(DwmIpc *dwm) -{ - if (dwm == NULL) return; - - g_source_destroy(dwm->source); - g_source_unref(dwm->source); - g_object_unref(dwm->socket); - - if (dwm->hidden_title) - button_destroy(dwm->title); - - g_free(dwm); -} - -// vim: ts=4 sw=4 et |
