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