diff options
Diffstat (limited to 'sway/ipc-json.c')
-rw-r--r-- | sway/ipc-json.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/sway/ipc-json.c b/sway/ipc-json.c new file mode 100644 index 00000000..69412023 --- /dev/null +++ b/sway/ipc-json.c | |||
@@ -0,0 +1,326 @@ | |||
1 | #include <json-c/json.h> | ||
2 | #include <ctype.h> | ||
3 | #include <string.h> | ||
4 | #include "container.h" | ||
5 | #include "util.h" | ||
6 | #include "ipc-json.h" | ||
7 | |||
8 | static json_object *ipc_json_create_rect(swayc_t *c) { | ||
9 | json_object *rect = json_object_new_object(); | ||
10 | |||
11 | json_object_object_add(rect, "x", json_object_new_int((int32_t)c->x)); | ||
12 | json_object_object_add(rect, "y", json_object_new_int((int32_t)c->y)); | ||
13 | json_object_object_add(rect, "width", json_object_new_int((int32_t)c->width)); | ||
14 | json_object_object_add(rect, "height", json_object_new_int((int32_t)c->height)); | ||
15 | |||
16 | return rect; | ||
17 | } | ||
18 | |||
19 | static const char *ipc_json_border_description(swayc_t *c) { | ||
20 | const char *border; | ||
21 | |||
22 | switch (c->border_type) { | ||
23 | case B_PIXEL: | ||
24 | border = "1pixel"; | ||
25 | break; | ||
26 | |||
27 | case B_NORMAL: | ||
28 | border = "normal"; | ||
29 | break; | ||
30 | |||
31 | case B_NONE: // fallthrough | ||
32 | default: | ||
33 | border = "none"; | ||
34 | break; | ||
35 | } | ||
36 | |||
37 | return border; | ||
38 | } | ||
39 | |||
40 | static const char *ipc_json_layout_description(swayc_t *c) { | ||
41 | const char *layout; | ||
42 | |||
43 | switch (c->layout) { | ||
44 | case L_VERT: | ||
45 | layout = "splitv"; | ||
46 | break; | ||
47 | |||
48 | case L_HORIZ: | ||
49 | layout = "splith"; | ||
50 | break; | ||
51 | |||
52 | case L_TABBED: | ||
53 | layout = "tabbed"; | ||
54 | break; | ||
55 | |||
56 | case L_STACKED: | ||
57 | layout = "stacked"; | ||
58 | break; | ||
59 | |||
60 | case L_FLOATING: | ||
61 | layout = "floating"; | ||
62 | break; | ||
63 | |||
64 | case L_NONE: // fallthrough | ||
65 | case L_LAYOUTS: // fallthrough; this should never happen, I'm just trying to silence compiler warnings | ||
66 | default: | ||
67 | layout = "null"; | ||
68 | break; | ||
69 | } | ||
70 | |||
71 | return layout; | ||
72 | } | ||
73 | |||
74 | static float ipc_json_child_percentage(swayc_t *c) { | ||
75 | float percent = 0; | ||
76 | swayc_t *parent = c->parent; | ||
77 | |||
78 | if (parent) { | ||
79 | switch (parent->layout) { | ||
80 | case L_VERT: | ||
81 | percent = c->height / parent->height; | ||
82 | break; | ||
83 | |||
84 | case L_HORIZ: | ||
85 | percent = c->width / parent->width; | ||
86 | break; | ||
87 | |||
88 | case L_STACKED: // fallthrough | ||
89 | case L_TABBED: // fallthrough | ||
90 | percent = 1.0; | ||
91 | break; | ||
92 | |||
93 | default: | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | return percent; | ||
99 | } | ||
100 | |||
101 | static void ipc_json_describe_output(swayc_t *output, json_object *object) { | ||
102 | json_object_object_add(object, "active", json_object_new_boolean(true)); | ||
103 | json_object_object_add(object, "primary", json_object_new_boolean(false)); | ||
104 | json_object_object_add(object, "layout", json_object_new_string("output")); | ||
105 | json_object_object_add(object, "type", json_object_new_string("output")); | ||
106 | json_object_object_add(object, "current_workspace", | ||
107 | (output->focused) ? json_object_new_string(output->focused->name) : NULL); | ||
108 | } | ||
109 | |||
110 | static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) { | ||
111 | int num = (isdigit(workspace->name[0])) ? atoi(workspace->name) : -1; | ||
112 | bool focused = root_container.focused == workspace->parent && workspace->parent->focused == workspace; | ||
113 | |||
114 | json_object_object_add(object, "num", json_object_new_int(num)); | ||
115 | json_object_object_add(object, "visible", json_object_new_boolean(workspace->visible)); | ||
116 | json_object_object_add(object, "focused", json_object_new_boolean(focused)); | ||
117 | json_object_object_add(object, "output", json_object_new_string((workspace->parent) ? workspace->parent->name : "null")); | ||
118 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
119 | json_object_object_add(object, "type", json_object_new_string("workspace")); | ||
120 | json_object_object_add(object, "layout", json_object_new_string(ipc_json_layout_description(workspace))); | ||
121 | } | ||
122 | |||
123 | static void ipc_json_describe_view(swayc_t *view, json_object *object) { | ||
124 | float percent = ipc_json_child_percentage(view); | ||
125 | |||
126 | json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(view))); | ||
127 | json_object_object_add(object, "current_border_width", json_object_new_int(view->border_thickness)); | ||
128 | json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : json_object_new_string("null")); | ||
129 | // TODO: make urgency actually work once Sway supports it | ||
130 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
131 | json_object_object_add(object, "focused", json_object_new_boolean(view->is_focused)); | ||
132 | json_object_object_add(object, "type", json_object_new_string((view->is_floating) ? "floating_con" : "con")); | ||
133 | json_object_object_add(object, "layout", json_object_new_string(ipc_json_layout_description(view))); | ||
134 | |||
135 | if (view->class) { | ||
136 | json_object_object_add(object, "class", json_object_new_string(view->class)); | ||
137 | } | ||
138 | |||
139 | if (view->app_id) { | ||
140 | json_object_object_add(object, "app_id", json_object_new_string(view->app_id)); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | json_object *ipc_json_describe_container(swayc_t *c) { | ||
145 | if (!(sway_assert(c, "Container must not be null."))) { | ||
146 | return NULL; | ||
147 | } | ||
148 | |||
149 | json_object *object = json_object_new_object(); | ||
150 | |||
151 | json_object_object_add(object, "id", json_object_new_int((int64_t)&c)); | ||
152 | json_object_object_add(object, "name", json_object_new_string(c->name)); | ||
153 | json_object_object_add(object, "rect", ipc_json_create_rect(c)); | ||
154 | |||
155 | switch (c->type) { | ||
156 | case C_ROOT: | ||
157 | json_object_object_add(object, "type", json_object_new_string("root")); | ||
158 | break; | ||
159 | |||
160 | case C_OUTPUT: | ||
161 | ipc_json_describe_output(c, object); | ||
162 | break; | ||
163 | |||
164 | case C_CONTAINER: // fallthrough | ||
165 | case C_VIEW: | ||
166 | ipc_json_describe_view(c, object); | ||
167 | break; | ||
168 | |||
169 | case C_WORKSPACE: | ||
170 | ipc_json_describe_workspace(c, object); | ||
171 | break; | ||
172 | |||
173 | case C_TYPES: // fallthrough; this should never happen, I'm just trying to silence compiler warnings | ||
174 | default: | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | return object; | ||
179 | } | ||
180 | |||
181 | json_object *ipc_json_get_version() { | ||
182 | json_object *version = json_object_new_object(); | ||
183 | |||
184 | #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE | ||
185 | char *full_version = calloc(strlen(SWAY_GIT_VERSION) + strlen(SWAY_GIT_BRANCH) + strlen(SWAY_VERSION_DATE) + 20, 1); | ||
186 | strcat(full_version, SWAY_GIT_VERSION); | ||
187 | strcat(full_version, " ("); | ||
188 | strcat(full_version, SWAY_VERSION_DATE); | ||
189 | strcat(full_version, ", branch \""); | ||
190 | strcat(full_version, SWAY_GIT_BRANCH); | ||
191 | strcat(full_version, "\")"); | ||
192 | |||
193 | json_object_object_add(version, "human_readable", json_object_new_string(full_version)); | ||
194 | json_object_object_add(version, "variant", json_object_new_string("sway")); | ||
195 | // Todo once we actually release a version | ||
196 | json_object_object_add(version, "major", json_object_new_int(0)); | ||
197 | json_object_object_add(version, "minor", json_object_new_int(0)); | ||
198 | json_object_object_add(version, "patch", json_object_new_int(1)); | ||
199 | #else | ||
200 | json_object_object_add(version, "human_readable", json_object_new_string("version not found")); | ||
201 | json_object_object_add(version, "major", json_object_new_int(0)); | ||
202 | json_object_object_add(version, "minor", json_object_new_int(0)); | ||
203 | json_object_object_add(version, "patch", json_object_new_int(0)); | ||
204 | #endif | ||
205 | |||
206 | return version; | ||
207 | } | ||
208 | |||
209 | json_object *ipc_json_describe_bar_config(struct bar_config *bar) { | ||
210 | if (!sway_assert(bar, "Bar must not be NULL")) { | ||
211 | return NULL; | ||
212 | } | ||
213 | |||
214 | json_object *json = json_object_new_object(); | ||
215 | json_object_object_add(json, "id", json_object_new_string(bar->id)); | ||
216 | json_object_object_add(json, "tray_output", NULL); | ||
217 | json_object_object_add(json, "mode", json_object_new_string(bar->mode)); | ||
218 | json_object_object_add(json, "hidden_state", json_object_new_string(bar->hidden_state)); | ||
219 | json_object_object_add(json, "modifier", json_object_new_string(get_modifier_name_by_mask(bar->modifier))); | ||
220 | switch (bar->position) { | ||
221 | case DESKTOP_SHELL_PANEL_POSITION_TOP: | ||
222 | json_object_object_add(json, "position", json_object_new_string("top")); | ||
223 | break; | ||
224 | case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: | ||
225 | json_object_object_add(json, "position", json_object_new_string("bottom")); | ||
226 | break; | ||
227 | case DESKTOP_SHELL_PANEL_POSITION_LEFT: | ||
228 | json_object_object_add(json, "position", json_object_new_string("left")); | ||
229 | break; | ||
230 | case DESKTOP_SHELL_PANEL_POSITION_RIGHT: | ||
231 | json_object_object_add(json, "position", json_object_new_string("right")); | ||
232 | break; | ||
233 | } | ||
234 | json_object_object_add(json, "status_command", json_object_new_string(bar->status_command)); | ||
235 | json_object_object_add(json, "font", json_object_new_string((bar->font) ? bar->font : config->font)); | ||
236 | if (bar->separator_symbol) { | ||
237 | json_object_object_add(json, "separator_symbol", json_object_new_string(bar->separator_symbol)); | ||
238 | } | ||
239 | json_object_object_add(json, "bar_height", json_object_new_int(bar->height)); | ||
240 | json_object_object_add(json, "workspace_buttons", json_object_new_boolean(bar->workspace_buttons)); | ||
241 | json_object_object_add(json, "strip_workspace_numbers", json_object_new_boolean(bar->strip_workspace_numbers)); | ||
242 | json_object_object_add(json, "binding_mode_indicator", json_object_new_boolean(bar->binding_mode_indicator)); | ||
243 | json_object_object_add(json, "verbose", json_object_new_boolean(bar->verbose)); | ||
244 | json_object_object_add(json, "pango_markup", json_object_new_boolean(bar->pango_markup)); | ||
245 | |||
246 | json_object *colors = json_object_new_object(); | ||
247 | json_object_object_add(colors, "background", json_object_new_string(bar->colors.background)); | ||
248 | json_object_object_add(colors, "statusline", json_object_new_string(bar->colors.statusline)); | ||
249 | json_object_object_add(colors, "separator", json_object_new_string(bar->colors.separator)); | ||
250 | |||
251 | json_object_object_add(colors, "focused_workspace_border", json_object_new_string(bar->colors.focused_workspace_border)); | ||
252 | json_object_object_add(colors, "focused_workspace_bg", json_object_new_string(bar->colors.focused_workspace_bg)); | ||
253 | json_object_object_add(colors, "focused_workspace_text", json_object_new_string(bar->colors.focused_workspace_text)); | ||
254 | |||
255 | json_object_object_add(colors, "inactive_workspace_border", json_object_new_string(bar->colors.inactive_workspace_border)); | ||
256 | json_object_object_add(colors, "inactive_workspace_bg", json_object_new_string(bar->colors.inactive_workspace_bg)); | ||
257 | json_object_object_add(colors, "inactive_workspace_text", json_object_new_string(bar->colors.inactive_workspace_text)); | ||
258 | |||
259 | json_object_object_add(colors, "active_workspace_border", json_object_new_string(bar->colors.active_workspace_border)); | ||
260 | json_object_object_add(colors, "active_workspace_bg", json_object_new_string(bar->colors.active_workspace_bg)); | ||
261 | json_object_object_add(colors, "active_workspace_text", json_object_new_string(bar->colors.active_workspace_text)); | ||
262 | |||
263 | json_object_object_add(colors, "urgent_workspace_border", json_object_new_string(bar->colors.urgent_workspace_border)); | ||
264 | json_object_object_add(colors, "urgent_workspace_bg", json_object_new_string(bar->colors.urgent_workspace_bg)); | ||
265 | json_object_object_add(colors, "urgent_workspace_text", json_object_new_string(bar->colors.urgent_workspace_text)); | ||
266 | |||
267 | json_object_object_add(colors, "binding_mode_border", json_object_new_string(bar->colors.binding_mode_border)); | ||
268 | json_object_object_add(colors, "binding_mode_bg", json_object_new_string(bar->colors.binding_mode_bg)); | ||
269 | json_object_object_add(colors, "binding_mode_text", json_object_new_string(bar->colors.binding_mode_text)); | ||
270 | |||
271 | json_object_object_add(json, "colors", colors); | ||
272 | |||
273 | // Add outputs if defined | ||
274 | if (bar->outputs && bar->outputs->length > 0) { | ||
275 | json_object *outputs = json_object_new_array(); | ||
276 | int i; | ||
277 | for (i = 0; i < bar->outputs->length; ++i) { | ||
278 | const char *name = bar->outputs->items[i]; | ||
279 | json_object_array_add(outputs, json_object_new_string(name)); | ||
280 | } | ||
281 | json_object_object_add(json, "outputs", outputs); | ||
282 | } | ||
283 | |||
284 | return json; | ||
285 | } | ||
286 | |||
287 | json_object *ipc_json_describe_container_recursive(swayc_t *c) { | ||
288 | json_object *object = ipc_json_describe_container(c); | ||
289 | int i; | ||
290 | |||
291 | json_object *floating = json_object_new_array(); | ||
292 | if (c->floating && c->floating->length > 0) { | ||
293 | for (i = 0; i < c->floating->length; ++i) { | ||
294 | json_object_array_add(floating, ipc_json_describe_container_recursive(c->floating->items[i])); | ||
295 | } | ||
296 | } | ||
297 | json_object_object_add(object, "floating_nodes", floating); | ||
298 | |||
299 | json_object *children = json_object_new_array(); | ||
300 | if (c->children && c->children->length > 0) { | ||
301 | for (i = 0; i < c->children->length; ++i) { | ||
302 | json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); | ||
303 | } | ||
304 | } | ||
305 | json_object_object_add(object, "nodes", children); | ||
306 | |||
307 | json_object *unmanaged = json_object_new_array(); | ||
308 | if (c->unmanaged && c->unmanaged->length > 0) { | ||
309 | for (i = 0; i < c->unmanaged->length; ++i) { | ||
310 | json_object_array_add(unmanaged, ipc_json_describe_container_recursive(c->unmanaged->items[i])); | ||
311 | } | ||
312 | } | ||
313 | json_object_object_add(object, "unmanaged_nodes", unmanaged); | ||
314 | |||
315 | if (c->type == C_ROOT) { | ||
316 | json_object *scratchpad_json = json_object_new_array(); | ||
317 | if (scratchpad->length > 0) { | ||
318 | for (i = 0; i < scratchpad->length; ++i) { | ||
319 | json_object_array_add(scratchpad_json, ipc_json_describe_container_recursive(scratchpad->items[i])); | ||
320 | } | ||
321 | } | ||
322 | json_object_object_add(object, "scratchpad", scratchpad_json); | ||
323 | } | ||
324 | |||
325 | return object; | ||
326 | } | ||