i3
src/load_layout.c
Go to the documentation of this file.
00001 /*
00002  * vim:ts=4:sw=4:expandtab
00003  *
00004  * i3 - an improved dynamic tiling window manager
00005  * © 2009-2011 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 struct Match *current_swallow;
00028 
00029 static int json_start_map(void *ctx) {
00030     LOG("start of map, last_key = %s\n", last_key);
00031     if (parsing_swallows) {
00032         LOG("creating new swallow\n");
00033         current_swallow = smalloc(sizeof(Match));
00034         match_init(current_swallow);
00035         TAILQ_INSERT_TAIL(&(json_node->swallow_head), current_swallow, matches);
00036     } else {
00037         if (!parsing_rect && !parsing_window_rect && !parsing_geometry) {
00038             if (last_key && strcasecmp(last_key, "floating_nodes") == 0) {
00039                 DLOG("New floating_node\n");
00040                 Con *ws = con_get_workspace(json_node);
00041                 json_node = con_new(NULL, NULL);
00042                 json_node->parent = ws;
00043                 DLOG("Parent is workspace = %p\n", ws);
00044             } else {
00045                 Con *parent = json_node;
00046                 json_node = con_new(NULL, NULL);
00047                 json_node->parent = parent;
00048             }
00049         }
00050     }
00051     return 1;
00052 }
00053 
00054 static int json_end_map(void *ctx) {
00055     LOG("end of map\n");
00056     if (!parsing_swallows && !parsing_rect && !parsing_window_rect && !parsing_geometry) {
00057         LOG("attaching\n");
00058         con_attach(json_node, json_node->parent, true);
00059         json_node = json_node->parent;
00060     }
00061     if (parsing_rect)
00062         parsing_rect = false;
00063     if (parsing_window_rect)
00064         parsing_window_rect = false;
00065     if (parsing_geometry)
00066         parsing_geometry = false;
00067     return 1;
00068 }
00069 
00070 static int json_end_array(void *ctx) {
00071     LOG("end of array\n");
00072     parsing_swallows = false;
00073     return 1;
00074 }
00075 
00076 #if YAJL_MAJOR < 2
00077 static int json_key(void *ctx, const unsigned char *val, unsigned int len) {
00078 #else
00079 static int json_key(void *ctx, const unsigned char *val, size_t len) {
00080 #endif
00081     LOG("key: %.*s\n", (int)len, val);
00082     FREE(last_key);
00083     last_key = scalloc((len+1) * sizeof(char));
00084     memcpy(last_key, val, len);
00085     if (strcasecmp(last_key, "swallows") == 0) {
00086         parsing_swallows = true;
00087     }
00088     if (strcasecmp(last_key, "rect") == 0)
00089         parsing_rect = true;
00090     if (strcasecmp(last_key, "window_rect") == 0)
00091         parsing_window_rect = true;
00092     if (strcasecmp(last_key, "geometry") == 0)
00093         parsing_geometry = true;
00094     return 1;
00095 }
00096 
00097 #if YAJL_MAJOR >= 2
00098 static int json_string(void *ctx, const unsigned char *val, size_t len) {
00099 #else
00100 static int json_string(void *ctx, const unsigned char *val, unsigned int len) {
00101 #endif
00102     LOG("string: %.*s for key %s\n", len, val, last_key);
00103     if (parsing_swallows) {
00104         /* TODO: the other swallowing keys */
00105         if (strcasecmp(last_key, "class") == 0) {
00106             current_swallow->class = scalloc((len+1) * sizeof(char));
00107             memcpy(current_swallow->class, val, len);
00108         }
00109         LOG("unhandled yet: swallow\n");
00110     } else {
00111         if (strcasecmp(last_key, "name") == 0) {
00112             json_node->name = scalloc((len+1) * sizeof(char));
00113             memcpy(json_node->name, val, len);
00114         } else if (strcasecmp(last_key, "sticky_group") == 0) {
00115             json_node->sticky_group = scalloc((len+1) * sizeof(char));
00116             memcpy(json_node->sticky_group, val, len);
00117             LOG("sticky_group of this container is %s\n", json_node->sticky_group);
00118         } else if (strcasecmp(last_key, "orientation") == 0) {
00119             char *buf = NULL;
00120             sasprintf(&buf, "%.*s", (int)len, val);
00121             if (strcasecmp(buf, "none") == 0)
00122                 json_node->orientation = NO_ORIENTATION;
00123             else if (strcasecmp(buf, "horizontal") == 0)
00124                 json_node->orientation = HORIZ;
00125             else if (strcasecmp(buf, "vertical") == 0)
00126                 json_node->orientation = VERT;
00127             else LOG("Unhandled orientation: %s\n", buf);
00128             free(buf);
00129         } else if (strcasecmp(last_key, "border") == 0) {
00130             char *buf = NULL;
00131             sasprintf(&buf, "%.*s", (int)len, val);
00132             if (strcasecmp(buf, "none") == 0)
00133                 json_node->border_style = BS_NONE;
00134             else if (strcasecmp(buf, "1pixel") == 0)
00135                 json_node->border_style = BS_1PIXEL;
00136             else if (strcasecmp(buf, "normal") == 0)
00137                 json_node->border_style = BS_NORMAL;
00138             else LOG("Unhandled \"border\": %s\n", buf);
00139             free(buf);
00140         } else if (strcasecmp(last_key, "layout") == 0) {
00141             char *buf = NULL;
00142             sasprintf(&buf, "%.*s", (int)len, val);
00143             if (strcasecmp(buf, "default") == 0)
00144                 json_node->layout = L_DEFAULT;
00145             else if (strcasecmp(buf, "stacked") == 0)
00146                 json_node->layout = L_STACKED;
00147             else if (strcasecmp(buf, "tabbed") == 0)
00148                 json_node->layout = L_TABBED;
00149             else if (strcasecmp(buf, "dockarea") == 0)
00150                 json_node->layout = L_DOCKAREA;
00151             else if (strcasecmp(buf, "output") == 0)
00152                 json_node->layout = L_OUTPUT;
00153             else LOG("Unhandled \"layout\": %s\n", buf);
00154             free(buf);
00155         } else if (strcasecmp(last_key, "mark") == 0) {
00156             char *buf = NULL;
00157             sasprintf(&buf, "%.*s", (int)len, val);
00158             json_node->mark = buf;
00159         }
00160     }
00161     return 1;
00162 }
00163 
00164 #if YAJL_MAJOR >= 2
00165 static int json_int(void *ctx, long long val) {
00166     LOG("int %lld for key %s\n", val, last_key);
00167 #else
00168 static int json_int(void *ctx, long val) {
00169     LOG("int %ld for key %s\n", val, last_key);
00170 #endif
00171     if (strcasecmp(last_key, "type") == 0) {
00172         json_node->type = val;
00173     }
00174     if (strcasecmp(last_key, "fullscreen_mode") == 0) {
00175         json_node->fullscreen_mode = val;
00176     }
00177     if (strcasecmp(last_key, "num") == 0)
00178         json_node->num = val;
00179 
00180     if (parsing_rect || parsing_window_rect || parsing_geometry) {
00181         Rect *r;
00182         if (parsing_rect)
00183             r = &(json_node->rect);
00184         else if (parsing_window_rect)
00185             r = &(json_node->window_rect);
00186         else r = &(json_node->geometry);
00187         if (strcasecmp(last_key, "x") == 0)
00188             r->x = val;
00189         else if (strcasecmp(last_key, "y") == 0)
00190             r->y = val;
00191         else if (strcasecmp(last_key, "width") == 0)
00192             r->width = val;
00193         else if (strcasecmp(last_key, "height") == 0)
00194             r->height = val;
00195         else printf("WARNING: unknown key %s in rect\n", last_key);
00196         printf("rect now: (%d, %d, %d, %d)\n",
00197                 r->x, r->y, r->width, r->height);
00198     }
00199     if (parsing_swallows) {
00200         if (strcasecmp(last_key, "id") == 0) {
00201             current_swallow->id = val;
00202         }
00203         if (strcasecmp(last_key, "dock") == 0) {
00204             current_swallow->dock = val;
00205         }
00206         if (strcasecmp(last_key, "insert_where") == 0) {
00207             current_swallow->insert_where = val;
00208         }
00209     }
00210 
00211     return 1;
00212 }
00213 
00214 static int json_bool(void *ctx, int val) {
00215     LOG("bool %d for key %s\n", val, last_key);
00216     if (strcasecmp(last_key, "focused") == 0 && val) {
00217         to_focus = json_node;
00218     }
00219 
00220     return 1;
00221 }
00222 
00223 static int json_double(void *ctx, double val) {
00224     LOG("double %f for key %s\n", val, last_key);
00225     if (strcasecmp(last_key, "percent") == 0) {
00226         json_node->percent = val;
00227     }
00228     return 1;
00229 }
00230 
00231 void tree_append_json(const char *filename) {
00232     /* TODO: percent of other windows are not correctly fixed at the moment */
00233     FILE *f;
00234     if ((f = fopen(filename, "r")) == NULL) {
00235         LOG("Cannot open file\n");
00236         return;
00237     }
00238     char *buf = malloc(65535); /* TODO */
00239     int n = fread(buf, 1, 65535, f);
00240     LOG("read %d bytes\n", n);
00241     yajl_gen g;
00242     yajl_handle hand;
00243     yajl_callbacks callbacks;
00244     memset(&callbacks, '\0', sizeof(yajl_callbacks));
00245     callbacks.yajl_start_map = json_start_map;
00246     callbacks.yajl_end_map = json_end_map;
00247     callbacks.yajl_end_array = json_end_array;
00248     callbacks.yajl_string = json_string;
00249     callbacks.yajl_map_key = json_key;
00250     callbacks.yajl_integer = json_int;
00251     callbacks.yajl_double = json_double;
00252     callbacks.yajl_boolean = json_bool;
00253 #if YAJL_MAJOR >= 2
00254     g = yajl_gen_alloc(NULL);
00255     hand = yajl_alloc(&callbacks, NULL, (void*)g);
00256 #else
00257     g = yajl_gen_alloc(NULL, NULL);
00258     hand = yajl_alloc(&callbacks, NULL, NULL, (void*)g);
00259 #endif
00260     yajl_status stat;
00261     json_node = focused;
00262     to_focus = NULL;
00263     parsing_rect = false;
00264     parsing_window_rect = false;
00265     parsing_geometry = false;
00266     setlocale(LC_NUMERIC, "C");
00267     stat = yajl_parse(hand, (const unsigned char*)buf, n);
00268     if (stat != yajl_status_ok)
00269     {
00270         unsigned char * str = yajl_get_error(hand, 1, (const unsigned char*)buf, n);
00271         fprintf(stderr, "%s\n", (const char *) str);
00272         yajl_free_error(hand, str);
00273     }
00274 
00275     setlocale(LC_NUMERIC, "");
00276 #if YAJL_MAJOR >= 2
00277     yajl_complete_parse(hand);
00278 #else
00279     yajl_parse_complete(hand);
00280 #endif
00281 
00282     fclose(f);
00283     if (to_focus)
00284         con_focus(to_focus);
00285 }