diff options
Diffstat (limited to 'swaybar/status_line.c')
-rw-r--r-- | swaybar/status_line.c | 594 |
1 files changed, 97 insertions, 497 deletions
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 87e90caf..8afe4707 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c | |||
@@ -1,530 +1,130 @@ | |||
1 | #define _XOPEN_SOURCE 700 | 1 | #define _POSIX_C_SOURCE |
2 | #include <fcntl.h> | ||
3 | #include <json-c/json.h> | ||
2 | #include <stdlib.h> | 4 | #include <stdlib.h> |
3 | #include <string.h> | 5 | #include <string.h> |
6 | #include <stdio.h> | ||
4 | #include <unistd.h> | 7 | #include <unistd.h> |
5 | #include <json-c/json.h> | 8 | #include <wlr/util/log.h> |
6 | |||
7 | #include "swaybar/config.h" | 9 | #include "swaybar/config.h" |
8 | #include "swaybar/status_line.h" | 10 | #include "swaybar/status_line.h" |
9 | #include "log.h" | 11 | #include "readline.h" |
10 | #include "util.h" | ||
11 | |||
12 | #define I3JSON_MAXDEPTH 4 | ||
13 | #define I3JSON_UNKNOWN 0 | ||
14 | #define I3JSON_ARRAY 1 | ||
15 | #define I3JSON_STRING 2 | ||
16 | |||
17 | struct { | ||
18 | int bufsize; | ||
19 | char *buffer; | ||
20 | char *line_start; | ||
21 | char *parserpos; | ||
22 | bool escape; | ||
23 | int depth; | ||
24 | int bar[I3JSON_MAXDEPTH+1]; | ||
25 | } i3json_state = { 0, NULL, NULL, NULL, false, 0, { I3JSON_UNKNOWN } }; | ||
26 | |||
27 | static char line[1024]; | ||
28 | static char line_rest[1024]; | ||
29 | |||
30 | static char event_buff[1024]; | ||
31 | |||
32 | static void free_status_block(void *item) { | ||
33 | if (!item) { | ||
34 | return; | ||
35 | } | ||
36 | struct status_block *sb = (struct status_block*)item; | ||
37 | if (sb->full_text) { | ||
38 | free(sb->full_text); | ||
39 | } | ||
40 | if (sb->short_text) { | ||
41 | free(sb->short_text); | ||
42 | } | ||
43 | if (sb->align) { | ||
44 | free(sb->align); | ||
45 | } | ||
46 | if (sb->name) { | ||
47 | free(sb->name); | ||
48 | } | ||
49 | if (sb->instance) { | ||
50 | free(sb->instance); | ||
51 | } | ||
52 | free(sb); | ||
53 | } | ||
54 | |||
55 | static void parse_json(struct bar *bar, const char *text) { | ||
56 | json_object *results = json_tokener_parse(text); | ||
57 | if (!results) { | ||
58 | sway_log(L_DEBUG, "Failed to parse json"); | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | if (json_object_array_length(results) < 1) { | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | if (bar->status->block_line) { | ||
67 | list_foreach(bar->status->block_line, free_status_block); | ||
68 | list_free(bar->status->block_line); | ||
69 | } | ||
70 | |||
71 | bar->status->block_line = create_list(); | ||
72 | |||
73 | int i; | ||
74 | for (i = 0; i < json_object_array_length(results); ++i) { | ||
75 | json_object *full_text, *short_text, *color, *min_width, *align, *urgent; | ||
76 | json_object *name, *instance, *separator, *separator_block_width; | ||
77 | json_object *background, *border, *border_top, *border_bottom; | ||
78 | json_object *border_left, *border_right, *markup; | ||
79 | |||
80 | json_object *json = json_object_array_get_idx(results, i); | ||
81 | if (!json) { | ||
82 | continue; | ||
83 | } | ||
84 | |||
85 | json_object_object_get_ex(json, "full_text", &full_text); | ||
86 | json_object_object_get_ex(json, "short_text", &short_text); | ||
87 | json_object_object_get_ex(json, "color", &color); | ||
88 | json_object_object_get_ex(json, "min_width", &min_width); | ||
89 | json_object_object_get_ex(json, "align", &align); | ||
90 | json_object_object_get_ex(json, "urgent", &urgent); | ||
91 | json_object_object_get_ex(json, "name", &name); | ||
92 | json_object_object_get_ex(json, "instance", &instance); | ||
93 | json_object_object_get_ex(json, "markup", &markup); | ||
94 | json_object_object_get_ex(json, "separator", &separator); | ||
95 | json_object_object_get_ex(json, "separator_block_width", &separator_block_width); | ||
96 | json_object_object_get_ex(json, "background", &background); | ||
97 | json_object_object_get_ex(json, "border", &border); | ||
98 | json_object_object_get_ex(json, "border_top", &border_top); | ||
99 | json_object_object_get_ex(json, "border_bottom", &border_bottom); | ||
100 | json_object_object_get_ex(json, "border_left", &border_left); | ||
101 | json_object_object_get_ex(json, "border_right", &border_right); | ||
102 | |||
103 | struct status_block *new = calloc(1, sizeof(struct status_block)); | ||
104 | |||
105 | if (full_text) { | ||
106 | new->full_text = strdup(json_object_get_string(full_text)); | ||
107 | } | ||
108 | |||
109 | if (short_text) { | ||
110 | new->short_text = strdup(json_object_get_string(short_text)); | ||
111 | } | ||
112 | |||
113 | if (color) { | ||
114 | new->color = parse_color(json_object_get_string(color)); | ||
115 | } else { | ||
116 | new->color = bar->config->colors.statusline; | ||
117 | } | ||
118 | |||
119 | if (min_width) { | ||
120 | json_type type = json_object_get_type(min_width); | ||
121 | if (type == json_type_int) { | ||
122 | new->min_width = json_object_get_int(min_width); | ||
123 | } else if (type == json_type_string) { | ||
124 | /* the width will be calculated when rendering */ | ||
125 | new->min_width = 0; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | if (align) { | ||
130 | new->align = strdup(json_object_get_string(align)); | ||
131 | } else { | ||
132 | new->align = strdup("left"); | ||
133 | } | ||
134 | |||
135 | if (urgent) { | ||
136 | new->urgent = json_object_get_int(urgent); | ||
137 | } | ||
138 | 12 | ||
139 | if (name) { | 13 | void status_error(struct status_line *status, const char *text) { |
140 | new->name = strdup(json_object_get_string(name)); | 14 | close(status->read_fd); |
141 | } | 15 | close(status->write_fd); |
142 | 16 | status->protocol = PROTOCOL_ERROR; | |
143 | if (instance) { | 17 | status->text = text; |
144 | new->instance = strdup(json_object_get_string(instance)); | ||
145 | } | ||
146 | |||
147 | if (markup) { | ||
148 | new->markup = false; | ||
149 | const char *markup_str = json_object_get_string(markup); | ||
150 | if (strcmp(markup_str, "pango") == 0) { | ||
151 | new->markup = true; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | if (separator) { | ||
156 | new->separator = json_object_get_int(separator); | ||
157 | } else { | ||
158 | new->separator = true; // i3bar spec | ||
159 | } | ||
160 | |||
161 | if (separator_block_width) { | ||
162 | new->separator_block_width = json_object_get_int(separator_block_width); | ||
163 | } else { | ||
164 | new->separator_block_width = 9; // i3bar spec | ||
165 | } | ||
166 | |||
167 | // Airblader features | ||
168 | if (background) { | ||
169 | new->background = parse_color(json_object_get_string(background)); | ||
170 | } else { | ||
171 | new->background = 0x0; // transparent | ||
172 | } | ||
173 | |||
174 | if (border) { | ||
175 | new->border = parse_color(json_object_get_string(border)); | ||
176 | } else { | ||
177 | new->border = 0x0; // transparent | ||
178 | } | ||
179 | |||
180 | if (border_top) { | ||
181 | new->border_top = json_object_get_int(border_top); | ||
182 | } else { | ||
183 | new->border_top = 1; | ||
184 | } | ||
185 | |||
186 | if (border_bottom) { | ||
187 | new->border_bottom = json_object_get_int(border_bottom); | ||
188 | } else { | ||
189 | new->border_bottom = 1; | ||
190 | } | ||
191 | |||
192 | if (border_left) { | ||
193 | new->border_left = json_object_get_int(border_left); | ||
194 | } else { | ||
195 | new->border_left = 1; | ||
196 | } | ||
197 | |||
198 | if (border_right) { | ||
199 | new->border_right = json_object_get_int(border_right); | ||
200 | } else { | ||
201 | new->border_right = 1; | ||
202 | } | ||
203 | |||
204 | list_add(bar->status->block_line, new); | ||
205 | } | ||
206 | |||
207 | json_object_put(results); | ||
208 | } | 18 | } |
209 | 19 | ||
210 | // continue parsing from last parserpos | 20 | bool status_handle_readable(struct status_line *status) { |
211 | static int i3json_parse(struct bar *bar) { | 21 | char *line; |
212 | char *c = i3json_state.parserpos; | 22 | switch (status->protocol) { |
213 | int handled = 0; | 23 | case PROTOCOL_ERROR: |
214 | while (*c) { | ||
215 | if (i3json_state.bar[i3json_state.depth] == I3JSON_STRING) { | ||
216 | if (!i3json_state.escape && *c == '"') { | ||
217 | --i3json_state.depth; | ||
218 | } | ||
219 | i3json_state.escape = !i3json_state.escape && *c == '\\'; | ||
220 | } else { | ||
221 | switch (*c) { | ||
222 | case '[': | ||
223 | ++i3json_state.depth; | ||
224 | if (i3json_state.depth > I3JSON_MAXDEPTH) { | ||
225 | sway_abort("JSON too deep"); | ||
226 | } | ||
227 | i3json_state.bar[i3json_state.depth] = I3JSON_ARRAY; | ||
228 | if (i3json_state.depth == 2) { | ||
229 | i3json_state.line_start = c; | ||
230 | } | ||
231 | break; | ||
232 | case ']': | ||
233 | if (i3json_state.bar[i3json_state.depth] != I3JSON_ARRAY) { | ||
234 | sway_abort("JSON malformed"); | ||
235 | } | ||
236 | --i3json_state.depth; | ||
237 | if (i3json_state.depth == 1) { | ||
238 | // c[1] is valid since c[0] != '\0' | ||
239 | char p = c[1]; | ||
240 | c[1] = '\0'; | ||
241 | parse_json(bar, i3json_state.line_start); | ||
242 | c[1] = p; | ||
243 | ++handled; | ||
244 | i3json_state.line_start = c+1; | ||
245 | } | ||
246 | break; | ||
247 | case '"': | ||
248 | ++i3json_state.depth; | ||
249 | if (i3json_state.depth > I3JSON_MAXDEPTH) { | ||
250 | sway_abort("JSON too deep"); | ||
251 | } | ||
252 | i3json_state.bar[i3json_state.depth] = I3JSON_STRING; | ||
253 | break; | ||
254 | } | ||
255 | } | ||
256 | ++c; | ||
257 | } | ||
258 | i3json_state.parserpos = c; | ||
259 | return handled; | ||
260 | } | ||
261 | |||
262 | // Read line from file descriptor, only show the line tail if it is too long. | ||
263 | // In non-blocking mode treat "no more data" as a linebreak. | ||
264 | // If data after a line break has been read, return it in rest. | ||
265 | // If rest is non-empty, then use that as the start of the next line. | ||
266 | static int read_line_tail(int fd, char *buf, int nbyte, char *rest) { | ||
267 | if (fd < 0 || !buf || !nbyte) { | ||
268 | return -1; | ||
269 | } | ||
270 | int l; | ||
271 | char *buffer = malloc(nbyte*2+1); | ||
272 | char *readpos = buffer; | ||
273 | char *lf; | ||
274 | // prepend old data to new line if necessary | ||
275 | if (rest) { | ||
276 | l = strlen(rest); | ||
277 | if (l > nbyte) { | ||
278 | strcpy(buffer, rest + l - nbyte); | ||
279 | readpos += nbyte; | ||
280 | } else if (l) { | ||
281 | strcpy(buffer, rest); | ||
282 | readpos += l; | ||
283 | } | ||
284 | } | ||
285 | // read until a linefeed is found or no more data is available | ||
286 | while ((l = read(fd, readpos, nbyte)) > 0) { | ||
287 | readpos[l] = '\0'; | ||
288 | lf = strchr(readpos, '\n'); | ||
289 | if (lf) { | ||
290 | // linefeed found, replace with \0 | ||
291 | *lf = '\0'; | ||
292 | // give data from the end of the line, try to fill the buffer | ||
293 | if (lf-buffer > nbyte) { | ||
294 | strcpy(buf, lf - nbyte + 1); | ||
295 | } else { | ||
296 | strcpy(buf, buffer); | ||
297 | } | ||
298 | // we may have read data from the next line, save it to rest | ||
299 | if (rest) { | ||
300 | rest[0] = '\0'; | ||
301 | strcpy(rest, lf + 1); | ||
302 | } | ||
303 | free(buffer); | ||
304 | return strlen(buf); | ||
305 | } else { | ||
306 | // no linefeed found, slide data back. | ||
307 | int overflow = readpos - buffer + l - nbyte; | ||
308 | if (overflow > 0) { | ||
309 | memmove(buffer, buffer + overflow , nbyte + 1); | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | if (l < 0) { | ||
314 | free(buffer); | ||
315 | return l; | ||
316 | } | ||
317 | readpos[l]='\0'; | ||
318 | if (rest) { | ||
319 | rest[0] = '\0'; | ||
320 | } | ||
321 | if (nbyte < readpos - buffer + l - 1) { | ||
322 | memcpy(buf, readpos - nbyte + l + 1, nbyte); | ||
323 | } else { | ||
324 | strncpy(buf, buffer, nbyte); | ||
325 | } | ||
326 | buf[nbyte-1] = '\0'; | ||
327 | free(buffer); | ||
328 | return strlen(buf); | ||
329 | } | ||
330 | |||
331 | // make sure that enough buffer space is available starting from parserpos | ||
332 | static void i3json_ensure_free(int min_free) { | ||
333 | int _step = 10240; | ||
334 | int r = min_free % _step; | ||
335 | if (r) { | ||
336 | min_free += _step - r; | ||
337 | } | ||
338 | if (!i3json_state.buffer) { | ||
339 | i3json_state.buffer = malloc(min_free); | ||
340 | i3json_state.bufsize = min_free; | ||
341 | i3json_state.parserpos = i3json_state.buffer; | ||
342 | } else { | ||
343 | int len = 0; | ||
344 | int pos = 0; | ||
345 | if (i3json_state.line_start) { | ||
346 | len = strlen(i3json_state.line_start); | ||
347 | pos = i3json_state.parserpos - i3json_state.line_start; | ||
348 | if (i3json_state.line_start != i3json_state.buffer) { | ||
349 | memmove(i3json_state.buffer, i3json_state.line_start, len+1); | ||
350 | } | ||
351 | } else { | ||
352 | len = strlen(i3json_state.buffer); | ||
353 | } | ||
354 | if (i3json_state.bufsize < len+min_free) { | ||
355 | i3json_state.bufsize += min_free; | ||
356 | if (i3json_state.bufsize > 1024000) { | ||
357 | sway_abort("Status line json too long or malformed."); | ||
358 | } | ||
359 | i3json_state.buffer = realloc(i3json_state.buffer, i3json_state.bufsize); | ||
360 | if (!i3json_state.buffer) { | ||
361 | sway_abort("Could not allocate json buffer"); | ||
362 | } | ||
363 | } | ||
364 | if (i3json_state.line_start) { | ||
365 | i3json_state.line_start = i3json_state.buffer; | ||
366 | i3json_state.parserpos = i3json_state.buffer + pos; | ||
367 | } else { | ||
368 | i3json_state.parserpos = i3json_state.buffer; | ||
369 | } | ||
370 | } | ||
371 | if (!i3json_state.buffer) { | ||
372 | sway_abort("Could not allocate buffer."); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | // append data and parse it. | ||
377 | static int i3json_handle_data(struct bar *bar, char *data) { | ||
378 | int len = strlen(data); | ||
379 | i3json_ensure_free(len); | ||
380 | strcpy(i3json_state.parserpos, data); | ||
381 | return i3json_parse(bar); | ||
382 | } | ||
383 | |||
384 | // read data from fd and parse it. | ||
385 | static int i3json_handle_fd(struct bar *bar) { | ||
386 | i3json_ensure_free(10240); | ||
387 | // get fresh data at the end of the buffer | ||
388 | int readlen = read(bar->status_read_fd, i3json_state.parserpos, 10239); | ||
389 | if (readlen < 0) { | ||
390 | return readlen; | ||
391 | } | ||
392 | i3json_state.parserpos[readlen] = '\0'; | ||
393 | return i3json_parse(bar); | ||
394 | } | ||
395 | |||
396 | bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button) { | ||
397 | sway_log(L_DEBUG, "status_line_mouse_event."); | ||
398 | if (!bar->status->click_events) { | ||
399 | sway_log(L_DEBUG, "click_events are not enabled."); | ||
400 | return false; | 24 | return false; |
401 | } | 25 | case PROTOCOL_I3BAR: |
402 | 26 | if (i3bar_handle_readable(status) > 0) { | |
403 | if (bar->status->protocol == I3BAR) { | ||
404 | sway_log(L_DEBUG, "Sending click event."); | ||
405 | |||
406 | // find clicked block | ||
407 | struct status_block *clicked_block = NULL; | ||
408 | struct status_block *current_block = NULL; | ||
409 | int num_blocks = bar->status->block_line->length; | ||
410 | |||
411 | if (num_blocks == 0) { | ||
412 | return false; | ||
413 | } else { | ||
414 | current_block = bar->status->block_line->items[0]; | ||
415 | if (x < current_block->x) { | ||
416 | return false; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | for (int i = 0; i < num_blocks; i++) { | ||
421 | current_block = bar->status->block_line->items[i]; | ||
422 | if (x < (current_block->x + current_block->width)) { | ||
423 | clicked_block = current_block; | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | if (!clicked_block || !clicked_block->name) { | ||
429 | return false; | ||
430 | } | ||
431 | |||
432 | // event example {"name":"capture","instance":"label","button":1,"x":3431,"y":18} | ||
433 | |||
434 | struct json_object *event_json = json_object_new_object(); | ||
435 | json_object_object_add(event_json, "name", json_object_new_string(clicked_block->name)); | ||
436 | if (clicked_block->instance) { | ||
437 | json_object_object_add(event_json, "instance", json_object_new_string(clicked_block->instance)); | ||
438 | } | ||
439 | json_object_object_add(event_json, "button", json_object_new_int(button)); | ||
440 | json_object_object_add(event_json, "x", json_object_new_int(x)); | ||
441 | json_object_object_add(event_json, "y", json_object_new_int(y)); | ||
442 | |||
443 | int len = snprintf(event_buff, sizeof(event_buff), "%s\n", json_object_to_json_string(event_json)); | ||
444 | |||
445 | json_object_put(event_json); | ||
446 | |||
447 | if (len <= (int)sizeof(event_buff)) { // if not truncated | ||
448 | write(bar->status_write_fd, event_buff, len); | ||
449 | return true; | 27 | return true; |
450 | } | 28 | } |
451 | } | ||
452 | |||
453 | return false; | ||
454 | } | ||
455 | |||
456 | bool handle_status_line(struct bar *bar) { | ||
457 | bool dirty = false; | ||
458 | |||
459 | switch (bar->status->protocol) { | ||
460 | case I3BAR: | ||
461 | sway_log(L_DEBUG, "Got i3bar protocol."); | ||
462 | if (i3json_handle_fd(bar) > 0) { | ||
463 | dirty = true; | ||
464 | } | ||
465 | break; | 29 | break; |
466 | case TEXT: | 30 | case PROTOCOL_TEXT: |
467 | sway_log(L_DEBUG, "Got text protocol."); | 31 | line = read_line_buffer(status->read, |
468 | read_line_tail(bar->status_read_fd, line, sizeof(line), line_rest); | 32 | status->text_state.buffer, status->text_state.buffer_size); |
469 | dirty = true; | 33 | if (!line) { |
470 | bar->status->text_line = line; | 34 | status_error(status, "[error reading from status command]"); |
471 | break; | 35 | } else { |
472 | case UNDEF: | 36 | status->text = line; |
473 | sway_log(L_DEBUG, "Detecting protocol..."); | 37 | } |
474 | if (read_line_tail(bar->status_read_fd, line, sizeof(line), line_rest) < 0) { | 38 | return true; |
475 | break; | 39 | case PROTOCOL_UNDEF: |
40 | line = read_line_buffer(status->read, | ||
41 | status->text_state.buffer, status->text_state.buffer_size); | ||
42 | if (!line) { | ||
43 | status_error(status, "[error reading from status command]"); | ||
44 | return false; | ||
476 | } | 45 | } |
477 | dirty = true; | ||
478 | bar->status->text_line = line; | ||
479 | bar->status->protocol = TEXT; | ||
480 | if (line[0] == '{') { | 46 | if (line[0] == '{') { |
481 | // detect i3bar json protocol | ||
482 | json_object *proto = json_tokener_parse(line); | 47 | json_object *proto = json_tokener_parse(line); |
483 | if (proto) { | 48 | if (proto) { |
484 | |||
485 | json_object *version; | 49 | json_object *version; |
486 | if (json_object_object_get_ex(proto, "version", &version) | 50 | if (json_object_object_get_ex(proto, "version", &version) |
487 | && json_object_get_int(version) == 1 | 51 | && json_object_get_int(version) == 1) { |
488 | ) { | 52 | wlr_log(L_DEBUG, "Switched to i3bar protocol."); |
489 | sway_log(L_DEBUG, "Switched to i3bar protocol."); | 53 | status->protocol = PROTOCOL_I3BAR; |
490 | bar->status->protocol = I3BAR; | ||
491 | } | 54 | } |
492 | |||
493 | json_object *click_events; | 55 | json_object *click_events; |
494 | if (json_object_object_get_ex(proto, "click_events", &click_events) | 56 | if (json_object_object_get_ex( |
57 | proto, "click_events", &click_events) | ||
495 | && json_object_get_boolean(click_events)) { | 58 | && json_object_get_boolean(click_events)) { |
496 | 59 | wlr_log(L_DEBUG, "Enabled click events."); | |
497 | sway_log(L_DEBUG, "Enabling click events."); | 60 | status->i3bar_state.click_events = true; |
498 | bar->status->click_events = true; | ||
499 | |||
500 | const char *events_array = "[\n"; | 61 | const char *events_array = "[\n"; |
501 | write(bar->status_write_fd, events_array, strlen(events_array)); | 62 | ssize_t len = strlen(events_array); |
63 | if (write(status->write_fd, events_array, len) != len) { | ||
64 | status_error(status, | ||
65 | "[failed to write to status command]"); | ||
66 | } | ||
502 | } | 67 | } |
503 | |||
504 | i3json_handle_data(bar, line_rest); | ||
505 | |||
506 | json_object_put(proto); | 68 | json_object_put(proto); |
507 | } | 69 | } |
70 | |||
71 | status->protocol = PROTOCOL_I3BAR; | ||
72 | free(status->text_state.buffer); | ||
73 | wl_list_init(&status->blocks); | ||
74 | status->i3bar_state.buffer_size = 4096; | ||
75 | status->i3bar_state.buffer = | ||
76 | malloc(status->i3bar_state.buffer_size); | ||
77 | } else { | ||
78 | status->protocol = PROTOCOL_TEXT; | ||
79 | status->text = line; | ||
508 | } | 80 | } |
509 | break; | 81 | return true; |
510 | } | 82 | } |
511 | 83 | return false; | |
512 | return dirty; | ||
513 | } | 84 | } |
514 | 85 | ||
515 | struct status_line *init_status_line() { | 86 | struct status_line *status_line_init(char *cmd) { |
516 | struct status_line *line = malloc(sizeof(struct status_line)); | 87 | struct status_line *status = calloc(1, sizeof(struct status_line)); |
517 | line->block_line = create_list(); | 88 | status->text_state.buffer_size = 8192; |
518 | line->text_line = NULL; | 89 | status->text_state.buffer = malloc(status->text_state.buffer_size); |
519 | line->protocol = UNDEF; | ||
520 | line->click_events = false; | ||
521 | 90 | ||
522 | return line; | 91 | int pipe_read_fd[2]; |
523 | } | 92 | int pipe_write_fd[2]; |
93 | if (pipe(pipe_read_fd) != 0 || pipe(pipe_write_fd) != 0) { | ||
94 | wlr_log(L_ERROR, "Unable to create pipes for status_command fork"); | ||
95 | exit(1); | ||
96 | } | ||
97 | |||
98 | status->pid = fork(); | ||
99 | if (status->pid == 0) { | ||
100 | dup2(pipe_read_fd[1], STDOUT_FILENO); | ||
101 | close(pipe_read_fd[0]); | ||
102 | close(pipe_read_fd[1]); | ||
524 | 103 | ||
525 | void free_status_line(struct status_line *line) { | 104 | dup2(pipe_write_fd[0], STDIN_FILENO); |
526 | if (line->block_line) { | 105 | close(pipe_write_fd[0]); |
527 | list_foreach(line->block_line, free_status_block); | 106 | close(pipe_write_fd[1]); |
528 | list_free(line->block_line); | 107 | |
108 | char *const _cmd[] = { "sh", "-c", cmd, NULL, }; | ||
109 | execvp(_cmd[0], _cmd); | ||
110 | exit(1); | ||
529 | } | 111 | } |
112 | |||
113 | close(pipe_read_fd[1]); | ||
114 | status->read_fd = pipe_read_fd[0]; | ||
115 | fcntl(status->read_fd, F_SETFL, O_NONBLOCK); | ||
116 | close(pipe_write_fd[0]); | ||
117 | status->write_fd = pipe_write_fd[1]; | ||
118 | fcntl(status->write_fd, F_SETFL, O_NONBLOCK); | ||
119 | |||
120 | status->read = fdopen(status->read_fd, "r"); | ||
121 | status->write = fdopen(status->write_fd, "w"); | ||
122 | return status; | ||
123 | } | ||
124 | |||
125 | void status_line_free(struct status_line *status) { | ||
126 | close(status->read_fd); | ||
127 | close(status->write_fd); | ||
128 | kill(status->pid, SIGTERM); | ||
129 | free(status); | ||
530 | } | 130 | } |