i3
|
00001 /* 00002 * vim:ts=4:sw=4:expandtab 00003 * 00004 * i3 - an improved dynamic tiling window manager 00005 * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) 00006 * 00007 * load_layout.c: Restore (parts of) the layout, for example after an inplace 00008 * restart. 00009 * 00010 */ 00011 #include "all.h" 00012 00013 #include <yajl/yajl_common.h> 00014 #include <yajl/yajl_gen.h> 00015 #include <yajl/yajl_parse.h> 00016 #include <yajl/yajl_version.h> 00017 00018 /* TODO: refactor the whole parsing thing */ 00019 00020 static char *last_key; 00021 static Con *json_node; 00022 static Con *to_focus; 00023 static bool parsing_swallows; 00024 static bool parsing_rect; 00025 static bool parsing_window_rect; 00026 static bool parsing_geometry; 00027 static bool parsing_focus; 00028 struct Match *current_swallow; 00029 00030 /* This list is used for reordering the focus stack after parsing the 'focus' 00031 * array. */ 00032 struct focus_mapping { 00033 int old_id; 00034 TAILQ_ENTRY(focus_mapping) focus_mappings; 00035 }; 00036 00037 static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings = 00038 TAILQ_HEAD_INITIALIZER(focus_mappings); 00039 00040 static int json_start_map(void *ctx) { 00041 LOG("start of map, last_key = %s\n", last_key); 00042 if (parsing_swallows) { 00043 LOG("creating new swallow\n"); 00044 current_swallow = smalloc(sizeof(Match)); 00045 match_init(current_swallow); 00046 TAILQ_INSERT_TAIL(&(json_node->swallow_head), current_swallow, matches); 00047 } else { 00048 if (!parsing_rect && !parsing_window_rect && !parsing_geometry) { 00049 if (last_key && strcasecmp(last_key, "floating_nodes") == 0) { 00050 DLOG("New floating_node\n"); 00051 Con *ws = con_get_workspace(json_node); 00052 json_node = con_new(NULL, NULL); 00053 json_node->parent = ws; 00054 DLOG("Parent is workspace = %p\n", ws); 00055 } else { 00056 Con *parent = json_node; 00057 json_node = con_new(NULL, NULL); 00058 json_node->parent = parent; 00059 } 00060 } 00061 } 00062 return 1; 00063 } 00064 00065 static int json_end_map(void *ctx) { 00066 LOG("end of map\n"); 00067 if (!parsing_swallows && !parsing_rect && !parsing_window_rect && !parsing_geometry) { 00068 LOG("attaching\n"); 00069 con_attach(json_node, json_node->parent, true); 00070 json_node = json_node->parent; 00071 } 00072 if (parsing_rect) 00073 parsing_rect = false; 00074 if (parsing_window_rect) 00075 parsing_window_rect = false; 00076 if (parsing_geometry) 00077 parsing_geometry = false; 00078 return 1; 00079 } 00080 00081 static int json_end_array(void *ctx) { 00082 LOG("end of array\n"); 00083 parsing_swallows = false; 00084 if (parsing_focus) { 00085 /* Clear the list of focus mappings */ 00086 struct focus_mapping *mapping; 00087 TAILQ_FOREACH_REVERSE(mapping, &focus_mappings, focus_mappings_head, focus_mappings) { 00088 LOG("focus (reverse) %d\n", mapping->old_id); 00089 Con *con; 00090 TAILQ_FOREACH(con, &(json_node->focus_head), focused) { 00091 if (con->old_id != mapping->old_id) 00092 continue; 00093 LOG("got it! %p\n", con); 00094 /* Move this entry to the top of the focus list. */ 00095 TAILQ_REMOVE(&(json_node->focus_head), con, focused); 00096 TAILQ_INSERT_HEAD(&(json_node->focus_head), con, focused); 00097 break; 00098 } 00099 } 00100 while (!TAILQ_EMPTY(&focus_mappings)) { 00101 mapping = TAILQ_FIRST(&focus_mappings); 00102 TAILQ_REMOVE(&focus_mappings, mapping, focus_mappings); 00103 free(mapping); 00104 } 00105 parsing_focus = false; 00106 } 00107 return 1; 00108 } 00109 00110 #if YAJL_MAJOR < 2 00111 static int json_key(void *ctx, const unsigned char *val, unsigned int len) { 00112 #else 00113 static int json_key(void *ctx, const unsigned char *val, size_t len) { 00114 #endif 00115 LOG("key: %.*s\n", (int)len, val); 00116 FREE(last_key); 00117 last_key = scalloc((len+1) * sizeof(char)); 00118 memcpy(last_key, val, len); 00119 if (strcasecmp(last_key, "swallows") == 0) 00120 parsing_swallows = true; 00121 00122 if (strcasecmp(last_key, "rect") == 0) 00123 parsing_rect = true; 00124 00125 if (strcasecmp(last_key, "window_rect") == 0) 00126 parsing_window_rect = true; 00127 00128 if (strcasecmp(last_key, "geometry") == 0) 00129 parsing_geometry = true; 00130 00131 if (strcasecmp(last_key, "focus") == 0) 00132 parsing_focus = true; 00133 00134 return 1; 00135 } 00136 00137 #if YAJL_MAJOR >= 2 00138 static int json_string(void *ctx, const unsigned char *val, size_t len) { 00139 #else 00140 static int json_string(void *ctx, const unsigned char *val, unsigned int len) { 00141 #endif 00142 LOG("string: %.*s for key %s\n", len, val, last_key); 00143 if (parsing_swallows) { 00144 /* TODO: the other swallowing keys */ 00145 if (strcasecmp(last_key, "class") == 0) { 00146 current_swallow->class = scalloc((len+1) * sizeof(char)); 00147 memcpy(current_swallow->class, val, len); 00148 } 00149 LOG("unhandled yet: swallow\n"); 00150 } else { 00151 if (strcasecmp(last_key, "name") == 0) { 00152 json_node->name = scalloc((len+1) * sizeof(char)); 00153 memcpy(json_node->name, val, len); 00154 } else if (strcasecmp(last_key, "sticky_group") == 0) { 00155 json_node->sticky_group = scalloc((len+1) * sizeof(char)); 00156 memcpy(json_node->sticky_group, val, len); 00157 LOG("sticky_group of this container is %s\n", json_node->sticky_group); 00158 } else if (strcasecmp(last_key, "orientation") == 0) { 00159 char *buf = NULL; 00160 sasprintf(&buf, "%.*s", (int)len, val); 00161 if (strcasecmp(buf, "none") == 0) 00162 json_node->orientation = NO_ORIENTATION; 00163 else if (strcasecmp(buf, "horizontal") == 0) 00164 json_node->orientation = HORIZ; 00165 else if (strcasecmp(buf, "vertical") == 0) 00166 json_node->orientation = VERT; 00167 else LOG("Unhandled orientation: %s\n", buf); 00168 free(buf); 00169 } else if (strcasecmp(last_key, "border") == 0) { 00170 char *buf = NULL; 00171 sasprintf(&buf, "%.*s", (int)len, val); 00172 if (strcasecmp(buf, "none") == 0) 00173 json_node->border_style = BS_NONE; 00174 else if (strcasecmp(buf, "1pixel") == 0) 00175 json_node->border_style = BS_1PIXEL; 00176 else if (strcasecmp(buf, "normal") == 0) 00177 json_node->border_style = BS_NORMAL; 00178 else LOG("Unhandled \"border\": %s\n", buf); 00179 free(buf); 00180 } else if (strcasecmp(last_key, "layout") == 0) { 00181 char *buf = NULL; 00182 sasprintf(&buf, "%.*s", (int)len, val); 00183 if (strcasecmp(buf, "default") == 0) 00184 json_node->layout = L_DEFAULT; 00185 else if (strcasecmp(buf, "stacked") == 0) 00186 json_node->layout = L_STACKED; 00187 else if (strcasecmp(buf, "tabbed") == 0) 00188 json_node->layout = L_TABBED; 00189 else if (strcasecmp(buf, "dockarea") == 0) 00190 json_node->layout = L_DOCKAREA; 00191 else if (strcasecmp(buf, "output") == 0) 00192 json_node->layout = L_OUTPUT; 00193 else LOG("Unhandled \"layout\": %s\n", buf); 00194 free(buf); 00195 } else if (strcasecmp(last_key, "mark") == 0) { 00196 char *buf = NULL; 00197 sasprintf(&buf, "%.*s", (int)len, val); 00198 json_node->mark = buf; 00199 } else if (strcasecmp(last_key, "floating") == 0) { 00200 char *buf = NULL; 00201 sasprintf(&buf, "%.*s", (int)len, val); 00202 if (strcasecmp(buf, "auto_off") == 0) 00203 json_node->floating = FLOATING_AUTO_OFF; 00204 else if (strcasecmp(buf, "auto_on") == 0) 00205 json_node->floating = FLOATING_AUTO_ON; 00206 else if (strcasecmp(buf, "user_off") == 0) 00207 json_node->floating = FLOATING_USER_OFF; 00208 else if (strcasecmp(buf, "user_on") == 0) 00209 json_node->floating = FLOATING_USER_ON; 00210 free(buf); 00211 } else if (strcasecmp(last_key, "scratchpad_state") == 0) { 00212 char *buf = NULL; 00213 sasprintf(&buf, "%.*s", (int)len, val); 00214 if (strcasecmp(buf, "none") == 0) 00215 json_node->scratchpad_state = SCRATCHPAD_NONE; 00216 else if (strcasecmp(buf, "fresh") == 0) 00217 json_node->scratchpad_state = SCRATCHPAD_FRESH; 00218 else if (strcasecmp(buf, "changed") == 0) 00219 json_node->scratchpad_state = SCRATCHPAD_CHANGED; 00220 free(buf); 00221 } 00222 } 00223 return 1; 00224 } 00225 00226 #if YAJL_MAJOR >= 2 00227 static int json_int(void *ctx, long long val) { 00228 LOG("int %lld for key %s\n", val, last_key); 00229 #else 00230 static int json_int(void *ctx, long val) { 00231 LOG("int %ld for key %s\n", val, last_key); 00232 #endif 00233 if (strcasecmp(last_key, "type") == 0) 00234 json_node->type = val; 00235 00236 if (strcasecmp(last_key, "fullscreen_mode") == 0) 00237 json_node->fullscreen_mode = val; 00238 00239 if (strcasecmp(last_key, "num") == 0) 00240 json_node->num = val; 00241 00242 if (!parsing_swallows && strcasecmp(last_key, "id") == 0) 00243 json_node->old_id = val; 00244 00245 if (parsing_focus) { 00246 struct focus_mapping *focus_mapping = scalloc(sizeof(struct focus_mapping)); 00247 focus_mapping->old_id = val; 00248 TAILQ_INSERT_TAIL(&focus_mappings, focus_mapping, focus_mappings); 00249 } 00250 00251 if (parsing_rect || parsing_window_rect || parsing_geometry) { 00252 Rect *r; 00253 if (parsing_rect) 00254 r = &(json_node->rect); 00255 else if (parsing_window_rect) 00256 r = &(json_node->window_rect); 00257 else r = &(json_node->geometry); 00258 if (strcasecmp(last_key, "x") == 0) 00259 r->x = val; 00260 else if (strcasecmp(last_key, "y") == 0) 00261 r->y = val; 00262 else if (strcasecmp(last_key, "width") == 0) 00263 r->width = val; 00264 else if (strcasecmp(last_key, "height") == 0) 00265 r->height = val; 00266 else printf("WARNING: unknown key %s in rect\n", last_key); 00267 printf("rect now: (%d, %d, %d, %d)\n", 00268 r->x, r->y, r->width, r->height); 00269 } 00270 if (parsing_swallows) { 00271 if (strcasecmp(last_key, "id") == 0) { 00272 current_swallow->id = val; 00273 } 00274 if (strcasecmp(last_key, "dock") == 0) { 00275 current_swallow->dock = val; 00276 } 00277 if (strcasecmp(last_key, "insert_where") == 0) { 00278 current_swallow->insert_where = val; 00279 } 00280 } 00281 00282 return 1; 00283 } 00284 00285 static int json_bool(void *ctx, int val) { 00286 LOG("bool %d for key %s\n", val, last_key); 00287 if (strcasecmp(last_key, "focused") == 0 && val) { 00288 to_focus = json_node; 00289 } 00290 00291 if (parsing_swallows) { 00292 if (strcasecmp(last_key, "restart_mode") == 0) 00293 current_swallow->restart_mode = val; 00294 } 00295 00296 return 1; 00297 } 00298 00299 static int json_double(void *ctx, double val) { 00300 LOG("double %f for key %s\n", val, last_key); 00301 if (strcasecmp(last_key, "percent") == 0) { 00302 json_node->percent = val; 00303 } 00304 return 1; 00305 } 00306 00307 void tree_append_json(const char *filename) { 00308 /* TODO: percent of other windows are not correctly fixed at the moment */ 00309 FILE *f; 00310 if ((f = fopen(filename, "r")) == NULL) { 00311 LOG("Cannot open file\n"); 00312 return; 00313 } 00314 char *buf = malloc(65535); /* TODO */ 00315 int n = fread(buf, 1, 65535, f); 00316 LOG("read %d bytes\n", n); 00317 yajl_gen g; 00318 yajl_handle hand; 00319 yajl_callbacks callbacks; 00320 memset(&callbacks, '\0', sizeof(yajl_callbacks)); 00321 callbacks.yajl_start_map = json_start_map; 00322 callbacks.yajl_end_map = json_end_map; 00323 callbacks.yajl_end_array = json_end_array; 00324 callbacks.yajl_string = json_string; 00325 callbacks.yajl_map_key = json_key; 00326 callbacks.yajl_integer = json_int; 00327 callbacks.yajl_double = json_double; 00328 callbacks.yajl_boolean = json_bool; 00329 #if YAJL_MAJOR >= 2 00330 g = yajl_gen_alloc(NULL); 00331 hand = yajl_alloc(&callbacks, NULL, (void*)g); 00332 #else 00333 g = yajl_gen_alloc(NULL, NULL); 00334 hand = yajl_alloc(&callbacks, NULL, NULL, (void*)g); 00335 #endif 00336 yajl_status stat; 00337 json_node = focused; 00338 to_focus = NULL; 00339 parsing_rect = false; 00340 parsing_window_rect = false; 00341 parsing_geometry = false; 00342 setlocale(LC_NUMERIC, "C"); 00343 stat = yajl_parse(hand, (const unsigned char*)buf, n); 00344 if (stat != yajl_status_ok) 00345 { 00346 unsigned char * str = yajl_get_error(hand, 1, (const unsigned char*)buf, n); 00347 fprintf(stderr, "%s\n", (const char *) str); 00348 yajl_free_error(hand, str); 00349 } 00350 00351 setlocale(LC_NUMERIC, ""); 00352 #if YAJL_MAJOR >= 2 00353 yajl_complete_parse(hand); 00354 #else 00355 yajl_parse_complete(hand); 00356 #endif 00357 00358 fclose(f); 00359 if (to_focus) 00360 con_focus(to_focus); 00361 }