2 * i3bar - an xcb-based status- and ws-bar for i3
4 * © 2010 Axel Wagner and contributors
6 * See file LICNSE for license information
8 * src/workspaces.c: Maintaining the workspace-lists
15 #include <yajl/yajl_parse.h>
19 /* A datatype to pass through the callbacks to save the state */
20 struct workspaces_json_params {
21 struct ws_head *workspaces;
22 i3_ws *workspaces_walk;
28 * Parse a booleant-value (visible, focused, urgent)
31 static int workspaces_boolean_cb(void *params_, bool val) {
32 struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
34 if (!strcmp(params->cur_key, "visible")) {
35 params->workspaces_walk->visible = val;
36 FREE(params->cur_key);
40 if (!strcmp(params->cur_key, "focused")) {
41 params->workspaces_walk->focused = val;
42 FREE(params->cur_key);
46 if (!strcmp(params->cur_key, "urgent")) {
47 params->workspaces_walk->urgent = val;
48 FREE(params->cur_key);
52 FREE(params->cur_key);
58 * Parse an integer (num or the rect)
61 static int workspaces_integer_cb(void *params_, long val) {
62 struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
64 if (!strcmp(params->cur_key, "num")) {
65 params->workspaces_walk->num = (int) val;
66 FREE(params->cur_key);
70 if (!strcmp(params->cur_key, "x")) {
71 params->workspaces_walk->rect.x = (int) val;
72 FREE(params->cur_key);
76 if (!strcmp(params->cur_key, "y")) {
77 params->workspaces_walk->rect.y = (int) val;
78 FREE(params->cur_key);
82 if (!strcmp(params->cur_key, "width")) {
83 params->workspaces_walk->rect.w = (int) val;
84 FREE(params->cur_key);
88 if (!strcmp(params->cur_key, "height")) {
89 params->workspaces_walk->rect.h = (int) val;
90 FREE(params->cur_key);
94 FREE(params->cur_key);
99 * Parse a string (name, output)
102 static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) {
104 struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
108 if (!strcmp(params->cur_key, "name")) {
110 params->workspaces_walk->name = malloc(sizeof(const unsigned char) * (len + 1));
111 strncpy(params->workspaces_walk->name, (const char*) val, len);
112 params->workspaces_walk->name[len] = '\0';
114 /* Convert the name to ucs2, save it's length in glyphs and calculate it'srendered width */
116 xcb_char2b_t *ucs2_name = (xcb_char2b_t*) convert_utf8_to_ucs2(params->workspaces_walk->name, &ucs2_len);
117 params->workspaces_walk->ucs2_name = ucs2_name;
118 params->workspaces_walk->name_glyphs = ucs2_len;
119 params->workspaces_walk->name_width =
120 predict_text_extents(params->workspaces_walk->ucs2_name,
121 params->workspaces_walk->name_glyphs);
123 DLOG("Got Workspace %s, name_width: %d, glyphs: %d\n",
124 params->workspaces_walk->name,
125 params->workspaces_walk->name_width,
126 params->workspaces_walk->name_glyphs);
127 FREE(params->cur_key);
132 if (!strcmp(params->cur_key, "output")) {
133 /* We add the ws to the TAILQ of the output, it belongs to */
134 output_name = malloc(sizeof(const unsigned char) * (len + 1));
135 strncpy(output_name, (const char*) val, len);
136 output_name[len] = '\0';
137 params->workspaces_walk->output = get_output_by_name(output_name);
139 TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces,
140 params->workspaces_walk,
151 * We hit the start of a json-map (rect or a new output)
154 static int workspaces_start_map_cb(void *params_) {
155 struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
157 i3_ws *new_workspace = NULL;
159 if (params->cur_key == NULL) {
160 new_workspace = malloc(sizeof(i3_ws));
161 new_workspace->num = -1;
162 new_workspace->name = NULL;
163 new_workspace->visible = 0;
164 new_workspace->focused = 0;
165 new_workspace->urgent = 0;
166 memset(&new_workspace->rect, 0, sizeof(rect));
167 new_workspace->output = NULL;
169 params->workspaces_walk = new_workspace;
179 * Essentially we just save it in the parsing-state
182 static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) {
183 struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
184 FREE(params->cur_key);
186 params->cur_key = malloc(sizeof(unsigned char) * (keyLen + 1));
187 if (params->cur_key == NULL) {
188 ELOG("Could not allocate memory: %s\n", strerror(errno));
191 strncpy(params->cur_key, (const char*) keyVal, keyLen);
192 params->cur_key[keyLen] = '\0';
197 /* A datastructure to pass all these callbacks to yajl */
198 yajl_callbacks workspaces_callbacks = {
200 &workspaces_boolean_cb,
201 &workspaces_integer_cb,
204 &workspaces_string_cb,
205 &workspaces_start_map_cb,
206 &workspaces_map_key_cb,
213 * Start parsing the received json-string
216 void parse_workspaces_json(char *json) {
217 /* FIXME: Fasciliate stream-processing, i.e. allow starting to interpret
219 struct workspaces_json_params params;
223 params.workspaces_walk = NULL;
224 params.cur_key = NULL;
228 yajl_parser_config parse_conf = { 0, 0 };
231 handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) ¶ms);
233 state = yajl_parse(handle, (const unsigned char*) json, strlen(json));
235 /* FIXME: Propper errorhandling for JSON-parsing */
239 case yajl_status_client_canceled:
240 case yajl_status_insufficient_data:
241 case yajl_status_error:
242 ELOG("Could not parse workspaces-reply!\n");
249 FREE(params.cur_key);
253 * free() all workspace data-structures
256 void free_workspaces() {
257 i3_output *outputs_walk;
258 if (outputs == NULL) {
263 SLIST_FOREACH(outputs_walk, outputs, slist) {
264 if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) {
265 TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
267 FREE(ws_walk->ucs2_name);
269 FREE_TAILQ(outputs_walk->workspaces, i3_ws);