]> git.sur5r.net Git - i3/i3/blob - i3bar/src/workspaces.c
i3bar: add modelines to all files
[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 = malloc(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 = malloc(sizeof(const unsigned char) * (len + 1));
145             strncpy(output_name, (const char*) val, len);
146             output_name[len] = '\0';
147             params->workspaces_walk->output = get_output_by_name(output_name);
148
149             TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces,
150                               params->workspaces_walk,
151                               tailq);
152
153             FREE(output_name);
154             return 1;
155         }
156
157         return 0;
158 }
159
160 /*
161  * We hit the start of a json-map (rect or a new output)
162  *
163  */
164 static int workspaces_start_map_cb(void *params_) {
165     struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
166
167     i3_ws *new_workspace = NULL;
168
169     if (params->cur_key == NULL) {
170         new_workspace = malloc(sizeof(i3_ws));
171         new_workspace->num = -1;
172         new_workspace->name = NULL;
173         new_workspace->visible = 0;
174         new_workspace->focused = 0;
175         new_workspace->urgent = 0;
176         memset(&new_workspace->rect, 0, sizeof(rect));
177         new_workspace->output = NULL;
178
179         params->workspaces_walk = new_workspace;
180         return 1;
181     }
182
183     return 1;
184 }
185
186 /*
187  * Parse a key.
188  *
189  * Essentially we just save it in the parsing-state
190  *
191  */
192 #if YAJL_MAJOR >= 2
193 static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
194 #else
195 static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) {
196 #endif
197     struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
198     FREE(params->cur_key);
199
200     params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1));
201     if (params->cur_key == NULL) {
202         ELOG("Could not allocate memory: %s\n", strerror(errno));
203         exit(EXIT_FAILURE);
204     }
205     strncpy(params->cur_key, (const char*) keyVal, keyLen);
206     params->cur_key[keyLen] = '\0';
207
208     return 1;
209 }
210
211 /* A datastructure to pass all these callbacks to yajl */
212 yajl_callbacks workspaces_callbacks = {
213     NULL,
214     &workspaces_boolean_cb,
215     &workspaces_integer_cb,
216     NULL,
217     NULL,
218     &workspaces_string_cb,
219     &workspaces_start_map_cb,
220     &workspaces_map_key_cb,
221     NULL,
222     NULL,
223     NULL
224 };
225
226 /*
227  * Start parsing the received json-string
228  *
229  */
230 void parse_workspaces_json(char *json) {
231     /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret
232      * JSON in chunks */
233     struct workspaces_json_params params;
234
235     free_workspaces();
236
237     params.workspaces_walk = NULL;
238     params.cur_key = NULL;
239     params.json = json;
240
241     yajl_handle handle;
242     yajl_status state;
243 #if YAJL_MAJOR < 2
244     yajl_parser_config parse_conf = { 0, 0 };
245
246     handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) &params);
247 #else
248     handle = yajl_alloc(&workspaces_callbacks, NULL, (void*) &params);
249 #endif
250
251     state = yajl_parse(handle, (const unsigned char*) json, strlen(json));
252
253     /* FIXME: Propper errorhandling for JSON-parsing */
254     switch (state) {
255         case yajl_status_ok:
256             break;
257         case yajl_status_client_canceled:
258 #if YAJL_MAJOR < 2
259         case yajl_status_insufficient_data:
260 #endif
261         case yajl_status_error:
262             ELOG("Could not parse workspaces-reply!\n");
263             exit(EXIT_FAILURE);
264             break;
265     }
266
267     yajl_free(handle);
268
269     FREE(params.cur_key);
270 }
271
272 /*
273  * free() all workspace data-structures. Does not free() the heads of the tailqueues.
274  *
275  */
276 void free_workspaces() {
277     i3_output *outputs_walk;
278     if (outputs == NULL) {
279         return;
280     }
281     i3_ws     *ws_walk;
282
283     SLIST_FOREACH(outputs_walk, outputs, slist) {
284         if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) {
285             TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
286                 FREE(ws_walk->name);
287                 FREE(ws_walk->ucs2_name);
288             }
289             FREE_TAILQ(outputs_walk->workspaces, i3_ws);
290         }
291     }
292 }