]> git.sur5r.net Git - i3/i3/commitdiff
i3bar: Add current binding mode indicator
authorPavel Löbl <lobl.pavel@gmail.com>
Sat, 10 Nov 2012 12:41:39 +0000 (13:41 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Fri, 16 Nov 2012 12:44:29 +0000 (13:44 +0100)
i3bar/include/common.h
i3bar/include/mode.h [new file with mode: 0644]
i3bar/include/xcb.h
i3bar/src/ipc.c
i3bar/src/mode.c [new file with mode: 0644]
i3bar/src/xcb.c

index e2582a02053bab03caacbc486774a47a27166cfa..870e6dbeea3cf9944cbd636042aa8bea5e8d1413 100644 (file)
@@ -50,6 +50,7 @@ TAILQ_HEAD(statusline_head, status_block) statusline_head;
 #include "outputs.h"
 #include "util.h"
 #include "workspaces.h"
+#include "mode.h"
 #include "trayclients.h"
 #include "xcb.h"
 #include "config.h"
diff --git a/i3bar/include/mode.h b/i3bar/include/mode.h
new file mode 100644 (file)
index 0000000..a8491aa
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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
+ *
+ */
+#ifndef MODE_H_
+#define MODE_H_
+
+#include <xcb/xproto.h>
+
+#include "common.h"
+
+/* Name of current binding mode and its render width */
+struct mode {
+    i3String *name;
+    int width;
+};
+
+typedef struct mode mode;
+
+/*
+ * Start parsing the received json-string
+ *
+ */
+void parse_mode_json(char *json);
+
+#endif
index dcc4d78116e9a6b1f9a4ca954acb251e2d65e153..75019c8d2a93ecc4b3893047eea0e6e8fed9442a 100644 (file)
@@ -118,4 +118,10 @@ void draw_bars(bool force_unhide);
  */
 void redraw_bars(void);
 
+/*
+ * Set the current binding mode
+ *
+ */
+void set_current_mode(struct mode *mode);
+
 #endif
index fc8c6492d9b9759211142aa7450740ddf1225e5d..2170e50965466f6082f055677a5ccdbe8e42ebbf 100644 (file)
@@ -138,10 +138,22 @@ void got_output_event(char *event) {
     }
 }
 
+/*
+ * 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
 };
 
 /*
@@ -297,8 +309,8 @@ void destroy_connection(void) {
  */
 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\" ]");
     }
 }
diff --git a/i3bar/src/mode.c b/i3bar/src/mode.c
new file mode 100644 (file)
index 0000000..7363971
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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*) &params);
+#else
+    handle = yajl_alloc(&mode_callbacks, NULL, (void*) &params);
+#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);
+}
index 2c0d2a6a15e2e02ba7a83c836330706653add8a8..5ae8023af7dbc973a506b553e3be9bfff2567298 100644 (file)
@@ -74,6 +74,9 @@ ev_check   *xcb_chk;
 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;
@@ -1527,6 +1530,41 @@ void draw_bars(bool unhide) {
             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;
@@ -1566,3 +1604,13 @@ void redraw_bars(void) {
         xcb_flush(xcb_connection);
     }
 }
+
+/*
+ * Set the current binding mode
+ *
+ */
+void set_current_mode(struct mode *current) {
+    I3STRING_FREE(binding.name);
+    binding = *current;
+    return;
+}