i3bar: Add current binding mode indicator
This commit is contained in:
parent
773654dbb8
commit
6148136e7c
|
@ -50,6 +50,7 @@ TAILQ_HEAD(statusline_head, status_block) statusline_head;
|
||||||
#include "outputs.h"
|
#include "outputs.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "workspaces.h"
|
#include "workspaces.h"
|
||||||
|
#include "mode.h"
|
||||||
#include "trayclients.h"
|
#include "trayclients.h"
|
||||||
#include "xcb.h"
|
#include "xcb.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
|
@ -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
|
|
@ -118,4 +118,10 @@ void draw_bars(bool force_unhide);
|
||||||
*/
|
*/
|
||||||
void redraw_bars(void);
|
void redraw_bars(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the current binding mode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void set_current_mode(struct mode *mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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 */
|
/* Data-structure to easily call the reply-handlers later */
|
||||||
handler_t event_handlers[] = {
|
handler_t event_handlers[] = {
|
||||||
&got_workspace_event,
|
&got_workspace_event,
|
||||||
&got_output_event
|
&got_output_event,
|
||||||
|
&got_mode_event
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -297,8 +309,8 @@ void destroy_connection(void) {
|
||||||
*/
|
*/
|
||||||
void subscribe_events(void) {
|
void subscribe_events(void) {
|
||||||
if (config.disable_ws) {
|
if (config.disable_ws) {
|
||||||
i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"output\" ]");
|
i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"output\", \"mode\" ]");
|
||||||
} else {
|
} else {
|
||||||
i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\" ]");
|
i3_send_msg(I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[ \"workspace\", \"output\", \"mode\" ]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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*) ¶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);
|
||||||
|
}
|
|
@ -74,6 +74,9 @@ ev_check *xcb_chk;
|
||||||
ev_io *xcb_io;
|
ev_io *xcb_io;
|
||||||
ev_io *xkb_io;
|
ev_io *xkb_io;
|
||||||
|
|
||||||
|
/* The name of current binding mode */
|
||||||
|
static mode binding;
|
||||||
|
|
||||||
/* The parsed colors */
|
/* The parsed colors */
|
||||||
struct xcb_colors_t {
|
struct xcb_colors_t {
|
||||||
uint32_t bar_fg;
|
uint32_t bar_fg;
|
||||||
|
@ -1527,6 +1530,41 @@ void draw_bars(bool unhide) {
|
||||||
set_font_colors(outputs_walk->bargc, fg_color, bg_color);
|
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);
|
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;
|
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;
|
i = 0;
|
||||||
|
@ -1566,3 +1604,13 @@ void redraw_bars(void) {
|
||||||
xcb_flush(xcb_connection);
|
xcb_flush(xcb_connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the current binding mode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void set_current_mode(struct mode *current) {
|
||||||
|
I3STRING_FREE(binding.name);
|
||||||
|
binding = *current;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue