}
}
+/*
+ * Called, when a mode-event arrives (i3 changed binding mode).
+ *
+ */
+void got_mode_event(char *event) {
+ DLOG("Got Mode Event!\n");
+ parse_mode_json(event);
+ draw_bars(false);
+}
+
+
/* Data-structure to easily call the reply-handlers later */
handler_t event_handlers[] = {
&got_workspace_event,
- &got_output_event
+ &got_output_event,
+ &got_mode_event
};
/*
*/
void subscribe_events(void) {
if (config.disable_ws) {
- i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"output\" ]");
+ i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"output\", \"mode\" ]");
} else {
- i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]");
+ i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\", \"mode\" ]");
}
}
--- /dev/null
+/*
+ * vim:ts=4:sw=4:expandtab
+ *
+ * i3bar - an xcb-based status- and ws-bar for i3
+ * © 2010-2012 Axel Wagner and contributors (see also: LICENSE)
+ *
+ * mode.c: Handle mode-event and show current binding mode in the bar
+ *
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <yajl/yajl_parse.h>
+#include <yajl/yajl_version.h>
+
+#include "common.h"
+
+/* A datatype to pass through the callbacks to save the state */
+struct mode_json_params {
+ char *json;
+ char *cur_key;
+ mode *mode;
+};
+
+/*
+ * Parse a string (change)
+ *
+ */
+#if YAJL_MAJOR >= 2
+static int mode_string_cb(void *params_, const unsigned char *val, size_t len) {
+#else
+static int mode_string_cb(void *params_, const unsigned char *val, unsigned int len) {
+#endif
+ struct mode_json_params *params = (struct mode_json_params*) params_;
+
+ if (!strcmp(params->cur_key, "change")) {
+
+ /* Save the name */
+ params->mode->name = i3string_from_utf8_with_length((const char *)val, len);
+ /* Save its rendered width */
+ params->mode->width = predict_text_width(params->mode->name);
+
+ DLOG("Got mode change: %s\n", i3string_as_utf8(params->mode->name));
+ FREE(params->cur_key);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Parse a key.
+ *
+ * Essentially we just save it in the parsing-state
+ *
+ */
+#if YAJL_MAJOR >= 2
+static int mode_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
+#else
+static int mode_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) {
+#endif
+ struct mode_json_params *params = (struct mode_json_params*) params_;
+ FREE(params->cur_key);
+
+ params->cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1));
+ strncpy(params->cur_key, (const char*) keyVal, keyLen);
+ params->cur_key[keyLen] = '\0';
+
+ return 1;
+}
+
+/* A datastructure to pass all these callbacks to yajl */
+yajl_callbacks mode_callbacks = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &mode_string_cb,
+ NULL,
+ &mode_map_key_cb,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * Start parsing the received json-string
+ *
+ */
+void parse_mode_json(char *json) {
+ /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret
+ * JSON in chunks */
+ struct mode_json_params params;
+
+ mode binding;
+
+ params.cur_key = NULL;
+ params.json = json;
+ params.mode = &binding;
+
+ yajl_handle handle;
+ yajl_status state;
+
+#if YAJL_MAJOR < 2
+ yajl_parser_config parse_conf = { 0, 0 };
+
+ handle = yajl_alloc(&mode_callbacks, &parse_conf, NULL, (void*) ¶ms);
+#else
+ handle = yajl_alloc(&mode_callbacks, NULL, (void*) ¶ms);
+#endif
+
+ state = yajl_parse(handle, (const unsigned char*) json, strlen(json));
+
+ /* FIXME: Propper errorhandling for JSON-parsing */
+ switch (state) {
+ case yajl_status_ok:
+ break;
+ case yajl_status_client_canceled:
+#if YAJL_MAJOR < 2
+ case yajl_status_insufficient_data:
+#endif
+ case yajl_status_error:
+ ELOG("Could not parse mode-event!\n");
+ exit(EXIT_FAILURE);
+ break;
+ }
+
+ /* We don't want to indicate default binding mode */
+ if (strcmp("default", i3string_as_utf8(params.mode->name)) == 0)
+ I3STRING_FREE(params.mode->name);
+
+ /* Set the new binding mode */
+ set_current_mode(&binding);
+
+ yajl_free(handle);
+
+ FREE(params.cur_key);
+}
ev_io *xcb_io;
ev_io *xkb_io;
+/* The name of current binding mode */
+static mode binding;
+
/* The parsed colors */
struct xcb_colors_t {
uint32_t bar_fg;
set_font_colors(outputs_walk->bargc, fg_color, bg_color);
draw_text(ws_walk->name, outputs_walk->buffer, outputs_walk->bargc, i + 5, 2, ws_walk->name_width);
i += 10 + ws_walk->name_width + 1;
+
+ }
+
+ if (binding.name) {
+
+ uint32_t fg_color = colors.urgent_ws_fg;
+ uint32_t bg_color = colors.urgent_ws_bg;
+ uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
+
+ uint32_t vals_border[] = { colors.urgent_ws_border, colors.urgent_ws_border };
+ xcb_change_gc(xcb_connection,
+ outputs_walk->bargc,
+ mask,
+ vals_border);
+ xcb_rectangle_t rect_border = { i, 0, binding.width + 10, font.height + 4 };
+ xcb_poly_fill_rectangle(xcb_connection,
+ outputs_walk->buffer,
+ outputs_walk->bargc,
+ 1,
+ &rect_border);
+
+ uint32_t vals[] = { bg_color, bg_color };
+ xcb_change_gc(xcb_connection,
+ outputs_walk->bargc,
+ mask,
+ vals);
+ xcb_rectangle_t rect = { i + 1, 1, binding.width + 8, font.height + 2 };
+ xcb_poly_fill_rectangle(xcb_connection,
+ outputs_walk->buffer,
+ outputs_walk->bargc,
+ 1,
+ &rect);
+
+ set_font_colors(outputs_walk->bargc, fg_color, bg_color);
+ draw_text(binding.name, outputs_walk->buffer, outputs_walk->bargc, i + 5, 2, binding.width);
}
i = 0;
xcb_flush(xcb_connection);
}
}
+
+/*
+ * Set the current binding mode
+ *
+ */
+void set_current_mode(struct mode *current) {
+ I3STRING_FREE(binding.name);
+ binding = *current;
+ return;
+}