]> git.sur5r.net Git - i3/i3/blob - i3bar/src/workspaces.c
Merge branch 'bar-config' into next
[i3/i3] / i3bar / src / workspaces.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3bar - an xcb-based status- and ws-bar for i3
5  *
6  * © 2010-2011 Axel Wagner and contributors
7  *
8  * See file LICNSE for license information
9  *
10  * src/workspaces.c: Maintaining the workspace-lists
11  *
12  */
13 #include <string.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <yajl/yajl_parse.h>
18 #include <yajl/yajl_version.h>
19
20 #include "common.h"
21
22 /* A datatype to pass through the callbacks to save the state */
23 struct workspaces_json_params {
24     struct ws_head *workspaces;
25     i3_ws          *workspaces_walk;
26     char           *cur_key;
27     char           *json;
28 };
29
30 /*
31  * Parse a boolean value (visible, focused, urgent)
32  *
33  */
34 static int workspaces_boolean_cb(void *params_, int val) {
35     struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
36
37     if (!strcmp(params->cur_key, "visible")) {
38         params->workspaces_walk->visible = val;
39         FREE(params->cur_key);
40         return 1;
41     }
42
43     if (!strcmp(params->cur_key, "focused")) {
44         params->workspaces_walk->focused = val;
45         FREE(params->cur_key);
46         return 1;
47     }
48
49     if (!strcmp(params->cur_key, "urgent")) {
50         params->workspaces_walk->urgent = val;
51         FREE(params->cur_key);
52         return 1;
53     }
54
55     FREE(params->cur_key);
56
57     return 0;
58 }
59
60 /*
61  * Parse an integer (num or the rect)
62  *
63  */
64 #if YAJL_MAJOR >= 2
65 static int workspaces_integer_cb(void *params_, long long val) {
66 #else
67 static int workspaces_integer_cb(void *params_, long val) {
68 #endif
69     struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
70
71     if (!strcmp(params->cur_key, "num")) {
72         params->workspaces_walk->num = (int) val;
73         FREE(params->cur_key);
74         return 1;
75     }
76
77     if (!strcmp(params->cur_key, "x")) {
78         params->workspaces_walk->rect.x = (int) val;
79         FREE(params->cur_key);
80         return 1;
81     }
82
83     if (!strcmp(params->cur_key, "y")) {
84         params->workspaces_walk->rect.y = (int) val;
85         FREE(params->cur_key);
86         return 1;
87     }
88
89     if (!strcmp(params->cur_key, "width")) {
90         params->workspaces_walk->rect.w = (int) val;
91         FREE(params->cur_key);
92         return 1;
93     }
94
95     if (!strcmp(params->cur_key, "height")) {
96         params->workspaces_walk->rect.h = (int) val;
97         FREE(params->cur_key);
98         return 1;
99     }
100
101     FREE(params->cur_key);
102     return 0;
103 }
104
105 /*
106  * Parse a string (name, output)
107  *
108  */
109 #if YAJL_MAJOR >= 2
110 static int workspaces_string_cb(void *params_, const unsigned char *val, size_t len) {
111 #else
112 static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) {
113 #endif
114         struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
115
116         char *output_name;
117
118         if (!strcmp(params->cur_key, "name")) {
119             /* Save the name */
120             params->workspaces_walk->name = smalloc(sizeof(const unsigned char) * (len + 1));
121             strncpy(params->workspaces_walk->name, (const char*) val, len);
122             params->workspaces_walk->name[len] = '\0';
123
124             /* Convert the name to ucs2, save its length in glyphs and calculate its rendered width */
125             int ucs2_len;
126             xcb_char2b_t *ucs2_name = (xcb_char2b_t*) convert_utf8_to_ucs2(params->workspaces_walk->name, &ucs2_len);
127             params->workspaces_walk->ucs2_name = ucs2_name;
128             params->workspaces_walk->name_glyphs = ucs2_len;
129             params->workspaces_walk->name_width =
130                 predict_text_extents(params->workspaces_walk->ucs2_name,
131                 params->workspaces_walk->name_glyphs);
132
133             DLOG("Got Workspace %s, name_width: %d, glyphs: %d\n",
134                  params->workspaces_walk->name,
135                  params->workspaces_walk->name_width,
136                  params->workspaces_walk->name_glyphs);
137             FREE(params->cur_key);
138
139             return 1;
140         }
141
142         if (!strcmp(params->cur_key, "output")) {
143             /* We add the ws to the TAILQ of the output, it belongs to */
144             output_name = smalloc(sizeof(const unsigned char) * (len + 1));
145             strncpy(output_name, (const char*) val, len);
146             output_name[len] = '\0';
147             i3_output *target = get_output_by_name(output_name);
148             if (target) {
149                 params->workspaces_walk->output = target;
150
151                 TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces,
152                                   params->workspaces_walk,
153                                   tailq);
154             }
155
156             FREE(output_name);
157             return 1;
158         }
159
160         return 0;
161 }
162
163 /*
164  * We hit the start of a json-map (rect or a new output)
165  *
166  */
167 static int workspaces_start_map_cb(void *params_) {
168     struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
169
170     i3_ws *new_workspace = NULL;
171
172     if (params->cur_key == NULL) {
173         new_workspace = smalloc(sizeof(i3_ws));
174         new_workspace->num = -1;
175         new_workspace->name = NULL;
176         new_workspace->visible = 0;
177         new_workspace->focused = 0;
178         new_workspace->urgent = 0;
179         memset(&new_workspace->rect, 0, sizeof(rect));
180         new_workspace->output = NULL;
181
182         params->workspaces_walk = new_workspace;
183         return 1;
184     }
185
186     return 1;
187 }
188
189 /*
190  * Parse a key.
191  *
192  * Essentially we just save it in the parsing-state
193  *
194  */
195 #if YAJL_MAJOR >= 2
196 static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
197 #else
198 static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) {
199 #endif
200     struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
201     FREE(params->cur_key);
202
203     params->cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1));
204     strncpy(params->cur_key, (const char*) keyVal, keyLen);
205     params->cur_key[keyLen] = '\0';
206
207     return 1;
208 }
209
210 /* A datastructure to pass all these callbacks to yajl */
211 yajl_callbacks workspaces_callbacks = {
212     NULL,
213     &workspaces_boolean_cb,
214     &workspaces_integer_cb,
215     NULL,
216     NULL,
217     &workspaces_string_cb,
218     &workspaces_start_map_cb,
219     &workspaces_map_key_cb,
220     NULL,
221     NULL,
222     NULL
223 };
224
225 /*
226  * Start parsing the received json-string
227  *
228  */
229 void parse_workspaces_json(char *json) {
230     /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret
231      * JSON in chunks */
232     struct workspaces_json_params params;
233
234     free_workspaces();
235
236     params.workspaces_walk = NULL;
237     params.cur_key = NULL;
238     params.json = json;
239
240     yajl_handle handle;
241     yajl_status state;
242 #if YAJL_MAJOR < 2
243     yajl_parser_config parse_conf = { 0, 0 };
244
245     handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) &params);
246 #else
247     handle = yajl_alloc(&workspaces_callbacks, NULL, (void*) &params);
248 #endif
249
250     state = yajl_parse(handle, (const unsigned char*) json, strlen(json));
251
252     /* FIXME: Propper errorhandling for JSON-parsing */
253     switch (state) {
254         case yajl_status_ok:
255             break;
256         case yajl_status_client_canceled:
257 #if YAJL_MAJOR < 2
258         case yajl_status_insufficient_data:
259 #endif
260         case yajl_status_error:
261             ELOG("Could not parse workspaces-reply!\n");
262             exit(EXIT_FAILURE);
263             break;
264     }
265
266     yajl_free(handle);
267
268     FREE(params.cur_key);
269 }
270
271 /*
272  * free() all workspace data-structures. Does not free() the heads of the tailqueues.
273  *
274  */
275 void free_workspaces() {
276     i3_output *outputs_walk;
277     if (outputs == NULL) {
278         return;
279     }
280     i3_ws     *ws_walk;
281
282     SLIST_FOREACH(outputs_walk, outputs, slist) {
283         if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) {
284             TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
285                 FREE(ws_walk->name);
286                 FREE(ws_walk->ucs2_name);
287             }
288             FREE_TAILQ(outputs_walk->workspaces, i3_ws);
289         }
290     }
291 }