aboutsummaryrefslogtreecommitdiff
path: root/i3bar/src/mode.c
blob: aea43ab4f36ceac4eb38ffb0e47ddedccee2291e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * vim:ts=4:sw=4:expandtab
 *
 * i3bar - an xcb-based status- and ws-bar for i3
 * © 2010 Axel Wagner and contributors (see also: LICENSE)
 *
 * mode.c: Handle mode event and show current binding mode in the bar
 *
 */
#include "common.h"

#include <stdlib.h>
#include <string.h>

#include <yajl/yajl_parse.h>

/* A datatype to pass through the callbacks to save the state */
struct mode_json_params {
    char *cur_key;
    char *name;
    bool pango_markup;
    mode *mode;
};

/*
 * Parse a string (change)
 *
 */
static int mode_string_cb(void *params_, const unsigned char *val, size_t len) {
    struct mode_json_params *params = (struct mode_json_params *)params_;

    if (!strcmp(params->cur_key, "change")) {
        sasprintf(&(params->name), "%.*s", len, val);
        FREE(params->cur_key);
        return 1;
    }

    FREE(params->cur_key);
    return 0;
}

/*
 * Parse a boolean.
 *
 */
static int mode_boolean_cb(void *params_, int val) {
    struct mode_json_params *params = (struct mode_json_params *)params_;

    if (strcmp(params->cur_key, "pango_markup") == 0) {
        DLOG("Setting pango_markup to %d.\n", val);
        params->pango_markup = val;

        FREE(params->cur_key);
        return 1;
    }

    FREE(params->cur_key);
    return 0;
}

/*
 * Parse a key.
 *
 * Essentially we just save it in the parsing state
 *
 */
static int mode_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
    struct mode_json_params *params = (struct mode_json_params *)params_;
    FREE(params->cur_key);
    sasprintf(&(params->cur_key), "%.*s", keyLen, keyVal);
    return 1;
}

static int mode_end_map_cb(void *params_) {
    struct mode_json_params *params = (struct mode_json_params *)params_;

    /* Save the name */
    params->mode->name = i3string_from_utf8(params->name);
    i3string_set_markup(params->mode->name, params->pango_markup);
    /* Save its rendered width */
    params->mode->name_width = predict_text_width(params->mode->name);

    DLOG("Got mode change: %s\n", i3string_as_utf8(params->mode->name));
    FREE(params->cur_key);

    return 1;
}

/* A datastructure to pass all these callbacks to yajl */
static yajl_callbacks mode_callbacks = {
    .yajl_string = mode_string_cb,
    .yajl_boolean = mode_boolean_cb,
    .yajl_map_key = mode_map_key_cb,
    .yajl_end_map = mode_end_map_cb,
};

/*
 * Parse the received JSON string
 *
 */
void parse_mode_json(const unsigned char *json, size_t size) {
    struct mode_json_params params;
    mode binding;
    params.cur_key = NULL;
    params.mode = &binding;

    yajl_handle handle = yajl_alloc(&mode_callbacks, NULL, (void *)&params);
    yajl_status state = yajl_parse(handle, json, size);

    /* FIXME: Proper error handling for JSON parsing */
    switch (state) {
        case yajl_status_ok:
            break;
        case yajl_status_client_canceled:
        case yajl_status_error:
            ELOG("Could not parse mode event!\n");
            exit(EXIT_FAILURE);
            break;
    }

    /* We don't want to indicate default binding mode */
    if (strcmp("default", i3string_as_utf8(params.mode->name)) == 0)
        I3STRING_FREE(params.mode->name);

    /* Set the new binding mode */
    set_current_mode(&binding);

    yajl_free(handle);

    FREE(params.cur_key);
}