]> git.sur5r.net Git - i3/i3/blob - i3bar/src/mode.c
4b27b110ae826b04b6dc22b4578cdafcfabe1200
[i3/i3] / i3bar / src / mode.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3bar - an xcb-based status- and ws-bar for i3
5  * © 2010 Axel Wagner and contributors (see also: LICENSE)
6  *
7  * mode.c: Handle mode event and show current binding mode in the bar
8  *
9  */
10 #include <string.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <errno.h>
14 #include <yajl/yajl_parse.h>
15 #include <yajl/yajl_version.h>
16
17 #include "common.h"
18
19 /* A datatype to pass through the callbacks to save the state */
20 struct mode_json_params {
21     char *json;
22     char *cur_key;
23     char *name;
24     bool pango_markup;
25     mode *mode;
26 };
27
28 /*
29  * Parse a string (change)
30  *
31  */
32 static int mode_string_cb(void *params_, const unsigned char *val, size_t len) {
33     struct mode_json_params *params = (struct mode_json_params *)params_;
34
35     if (!strcmp(params->cur_key, "change")) {
36         char *copy = smalloc(sizeof(const unsigned char) * (len + 1));
37         strncpy(copy, (const char *)val, len);
38         copy[len] = '\0';
39
40         params->name = copy;
41         FREE(params->cur_key);
42         return 1;
43     }
44
45     FREE(params->cur_key);
46     return 0;
47 }
48
49 /*
50  * Parse a boolean.
51  *
52  */
53 static int mode_boolean_cb(void *params_, int val) {
54     struct mode_json_params *params = (struct mode_json_params *)params_;
55
56     if (strcmp(params->cur_key, "pango_markup") == 0) {
57         DLOG("Setting pango_markup to %d.\n", val);
58         params->pango_markup = val;
59
60         FREE(params->cur_key);
61         return 1;
62     }
63
64     FREE(params->cur_key);
65     return 0;
66 }
67
68 /*
69  * Parse a key.
70  *
71  * Essentially we just save it in the parsing state
72  *
73  */
74 static int mode_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
75     struct mode_json_params *params = (struct mode_json_params *)params_;
76     FREE(params->cur_key);
77
78     params->cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1));
79     strncpy(params->cur_key, (const char *)keyVal, keyLen);
80     params->cur_key[keyLen] = '\0';
81
82     return 1;
83 }
84
85 static int mode_end_map_cb(void *params_) {
86     struct mode_json_params *params = (struct mode_json_params *)params_;
87
88     /* Save the name */
89     params->mode->name = i3string_from_utf8(params->name);
90     i3string_set_markup(params->mode->name, params->pango_markup);
91     /* Save its rendered width */
92     params->mode->width = predict_text_width(params->mode->name);
93
94     DLOG("Got mode change: %s\n", i3string_as_utf8(params->mode->name));
95     FREE(params->cur_key);
96
97     return 1;
98 }
99
100 /* A datastructure to pass all these callbacks to yajl */
101 static yajl_callbacks mode_callbacks = {
102     .yajl_string = mode_string_cb,
103     .yajl_boolean = mode_boolean_cb,
104     .yajl_map_key = mode_map_key_cb,
105     .yajl_end_map = mode_end_map_cb,
106 };
107
108 /*
109  * Start parsing the received JSON string
110  *
111  */
112 void parse_mode_json(char *json) {
113     /* FIXME: Fasciliate stream processing, i.e. allow starting to interpret
114      * JSON in chunks */
115     struct mode_json_params params;
116
117     mode binding;
118
119     params.cur_key = NULL;
120     params.json = json;
121     params.mode = &binding;
122
123     yajl_handle handle;
124     yajl_status state;
125
126     handle = yajl_alloc(&mode_callbacks, NULL, (void *)&params);
127
128     state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
129
130     /* FIXME: Propper error handling for JSON parsing */
131     switch (state) {
132         case yajl_status_ok:
133             break;
134         case yajl_status_client_canceled:
135         case yajl_status_error:
136             ELOG("Could not parse mode event!\n");
137             exit(EXIT_FAILURE);
138             break;
139     }
140
141     /* We don't want to indicate default binding mode */
142     if (strcmp("default", i3string_as_utf8(params.mode->name)) == 0)
143         I3STRING_FREE(params.mode->name);
144
145     /* Set the new binding mode */
146     set_current_mode(&binding);
147
148     yajl_free(handle);
149
150     FREE(params.cur_key);
151 }