diff options
-rw-r--r-- | include/swaybar/bar.h | 1 | ||||
-rw-r--r-- | include/swaybar/status_line.h | 10 | ||||
-rw-r--r-- | swaybar/bar.c | 52 | ||||
-rw-r--r-- | swaybar/render.c | 3 | ||||
-rw-r--r-- | swaybar/status_line.c | 82 |
5 files changed, 138 insertions, 10 deletions
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 010e1f84..50d36e76 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h | |||
@@ -14,6 +14,7 @@ struct bar { | |||
14 | int ipc_event_socketfd; | 14 | int ipc_event_socketfd; |
15 | int ipc_socketfd; | 15 | int ipc_socketfd; |
16 | int status_read_fd; | 16 | int status_read_fd; |
17 | int status_write_fd; | ||
17 | pid_t status_command_pid; | 18 | pid_t status_command_pid; |
18 | }; | 19 | }; |
19 | 20 | ||
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h index 9b77e8a7..0664ddee 100644 --- a/include/swaybar/status_line.h +++ b/include/swaybar/status_line.h | |||
@@ -13,6 +13,7 @@ struct status_line { | |||
13 | list_t *block_line; | 13 | list_t *block_line; |
14 | const char *text_line; | 14 | const char *text_line; |
15 | command_protocol protocol; | 15 | command_protocol protocol; |
16 | bool click_events; | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | struct status_block { | 19 | struct status_block { |
@@ -31,6 +32,10 @@ struct status_block { | |||
31 | int border_bottom; | 32 | int border_bottom; |
32 | int border_left; | 33 | int border_left; |
33 | int border_right; | 34 | int border_right; |
35 | |||
36 | // Set during rendering | ||
37 | int x; | ||
38 | int width; | ||
34 | }; | 39 | }; |
35 | 40 | ||
36 | /** | 41 | /** |
@@ -44,6 +49,11 @@ struct status_line *init_status_line(); | |||
44 | bool handle_status_line(struct bar *bar); | 49 | bool handle_status_line(struct bar *bar); |
45 | 50 | ||
46 | /** | 51 | /** |
52 | * Handle mouse clicks. | ||
53 | */ | ||
54 | bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button); | ||
55 | |||
56 | /** | ||
47 | * Free status line struct. | 57 | * Free status line struct. |
48 | */ | 58 | */ |
49 | void free_status_line(struct status_line *line); | 59 | void free_status_line(struct status_line *line); |
diff --git a/swaybar/bar.c b/swaybar/bar.c index 5e87eac9..89f7c8c1 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <sys/wait.h> | 7 | #include <sys/wait.h> |
8 | #include <signal.h> | 8 | #include <signal.h> |
9 | #include <poll.h> | 9 | #include <poll.h> |
10 | #include <linux/input-event-codes.h> | ||
10 | #ifdef ENABLE_TRAY | 11 | #ifdef ENABLE_TRAY |
11 | #include <dbus/dbus.h> | 12 | #include <dbus/dbus.h> |
12 | #include "swaybar/tray/sni_watcher.h" | 13 | #include "swaybar/tray/sni_watcher.h" |
@@ -31,16 +32,30 @@ static void bar_init(struct bar *bar) { | |||
31 | 32 | ||
32 | static void spawn_status_cmd_proc(struct bar *bar) { | 33 | static void spawn_status_cmd_proc(struct bar *bar) { |
33 | if (bar->config->status_command) { | 34 | if (bar->config->status_command) { |
34 | int pipefd[2]; | 35 | int pipe_read_fd[2]; |
35 | if (pipe(pipefd) != 0) { | 36 | int pipe_write_fd[2]; |
36 | sway_log(L_ERROR, "Unable to create pipe for status_command fork"); | 37 | |
38 | if (pipe(pipe_read_fd) != 0) { | ||
39 | sway_log(L_ERROR, "Unable to create pipes for status_command fork"); | ||
40 | return; | ||
41 | } | ||
42 | if (pipe(pipe_write_fd) != 0) { | ||
43 | sway_log(L_ERROR, "Unable to create pipe for status_command fork (write)"); | ||
44 | close(pipe_read_fd[0]); | ||
45 | close(pipe_read_fd[1]); | ||
37 | return; | 46 | return; |
38 | } | 47 | } |
48 | |||
39 | bar->status_command_pid = fork(); | 49 | bar->status_command_pid = fork(); |
40 | if (bar->status_command_pid == 0) { | 50 | if (bar->status_command_pid == 0) { |
41 | close(pipefd[0]); | 51 | close(pipe_read_fd[0]); |
42 | dup2(pipefd[1], STDOUT_FILENO); | 52 | dup2(pipe_read_fd[1], STDOUT_FILENO); |
43 | close(pipefd[1]); | 53 | close(pipe_read_fd[1]); |
54 | |||
55 | dup2(pipe_write_fd[0], STDIN_FILENO); | ||
56 | close(pipe_write_fd[0]); | ||
57 | close(pipe_write_fd[1]); | ||
58 | |||
44 | char *const cmd[] = { | 59 | char *const cmd[] = { |
45 | "sh", | 60 | "sh", |
46 | "-c", | 61 | "-c", |
@@ -51,9 +66,13 @@ static void spawn_status_cmd_proc(struct bar *bar) { | |||
51 | return; | 66 | return; |
52 | } | 67 | } |
53 | 68 | ||
54 | close(pipefd[1]); | 69 | close(pipe_read_fd[1]); |
55 | bar->status_read_fd = pipefd[0]; | 70 | bar->status_read_fd = pipe_read_fd[0]; |
56 | fcntl(bar->status_read_fd, F_SETFL, O_NONBLOCK); | 71 | fcntl(bar->status_read_fd, F_SETFL, O_NONBLOCK); |
72 | |||
73 | close(pipe_write_fd[0]); | ||
74 | bar->status_write_fd = pipe_write_fd[1]; | ||
75 | fcntl(bar->status_write_fd, F_SETFL, O_NONBLOCK); | ||
57 | } | 76 | } |
58 | } | 77 | } |
59 | 78 | ||
@@ -103,9 +122,22 @@ static void mouse_button_notify(struct window *window, int x, int y, | |||
103 | } | 122 | } |
104 | } | 123 | } |
105 | 124 | ||
125 | switch (button) { | ||
126 | case BTN_LEFT: | ||
127 | status_line_mouse_event(&swaybar, x, y, 1); | ||
128 | break; | ||
129 | case BTN_MIDDLE: | ||
130 | status_line_mouse_event(&swaybar, x, y, 2); | ||
131 | break; | ||
132 | case BTN_RIGHT: | ||
133 | status_line_mouse_event(&swaybar, x, y, 3); | ||
134 | break; | ||
135 | } | ||
136 | |||
106 | #ifdef ENABLE_TRAY | 137 | #ifdef ENABLE_TRAY |
107 | tray_mouse_event(clicked_output, x, y, button, state_w); | 138 | tray_mouse_event(clicked_output, x, y, button, state_w); |
108 | #endif | 139 | #endif |
140 | |||
109 | } | 141 | } |
110 | 142 | ||
111 | static void mouse_scroll_notify(struct window *window, enum scroll_direction direction) { | 143 | static void mouse_scroll_notify(struct window *window, enum scroll_direction direction) { |
@@ -318,6 +350,10 @@ void bar_teardown(struct bar *bar) { | |||
318 | close(bar->status_read_fd); | 350 | close(bar->status_read_fd); |
319 | } | 351 | } |
320 | 352 | ||
353 | if (bar->status_write_fd) { | ||
354 | close(bar->status_write_fd); | ||
355 | } | ||
356 | |||
321 | if (bar->ipc_socketfd) { | 357 | if (bar->ipc_socketfd) { |
322 | close(bar->ipc_socketfd); | 358 | close(bar->ipc_socketfd); |
323 | } | 359 | } |
diff --git a/swaybar/render.c b/swaybar/render.c index 6ec47e79..232d254b 100644 --- a/swaybar/render.c +++ b/swaybar/render.c | |||
@@ -94,6 +94,9 @@ static void render_block(struct window *window, struct config *config, struct st | |||
94 | 94 | ||
95 | double pos = *x; | 95 | double pos = *x; |
96 | 96 | ||
97 | block->x = (int) pos; | ||
98 | block->width = (int) block_width; | ||
99 | |||
97 | // render background | 100 | // render background |
98 | if (block->background != 0x0) { | 101 | if (block->background != 0x0) { |
99 | cairo_set_source_u32(window->cairo, block->background); | 102 | cairo_set_source_u32(window->cairo, block->background); |
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 83e8ce2c..f0888273 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c | |||
@@ -27,6 +27,8 @@ struct { | |||
27 | static char line[1024]; | 27 | static char line[1024]; |
28 | static char line_rest[1024]; | 28 | static char line_rest[1024]; |
29 | 29 | ||
30 | static char event_buff[1024]; | ||
31 | |||
30 | static void free_status_block(void *item) { | 32 | static void free_status_block(void *item) { |
31 | if (!item) { | 33 | if (!item) { |
32 | return; | 34 | return; |
@@ -391,6 +393,67 @@ static int i3json_handle_fd(struct bar *bar) { | |||
391 | return i3json_parse(bar); | 393 | return i3json_parse(bar); |
392 | } | 394 | } |
393 | 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; | ||
401 | } | ||
402 | |||
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 | } | ||
414 | else { | ||
415 | current_block = bar->status->block_line->items[0]; | ||
416 | if (x < current_block->x) { | ||
417 | return false; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | for (int i = 0; i < num_blocks; i++) { | ||
422 | current_block = bar->status->block_line->items[i]; | ||
423 | if (x < (current_block->x + current_block->width)) { | ||
424 | clicked_block = current_block; | ||
425 | break; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | if (!clicked_block || !clicked_block->name) { | ||
430 | return false; | ||
431 | } | ||
432 | |||
433 | // event example {"name":"capture","instance":"label","button":1,"x":3431,"y":18} | ||
434 | |||
435 | struct json_object *event_json = json_object_new_object(); | ||
436 | json_object_object_add(event_json, "name", json_object_new_string(clicked_block->name)); | ||
437 | if (clicked_block->instance) { | ||
438 | json_object_object_add(event_json, "instance", json_object_new_string(clicked_block->instance)); | ||
439 | } | ||
440 | json_object_object_add(event_json, "button", json_object_new_int(button)); | ||
441 | json_object_object_add(event_json, "x", json_object_new_int(x)); | ||
442 | json_object_object_add(event_json, "y", json_object_new_int(y)); | ||
443 | |||
444 | int len = snprintf(event_buff, sizeof(event_buff), "%s,\n", json_object_to_json_string(event_json)); | ||
445 | |||
446 | json_object_put(event_json); | ||
447 | |||
448 | if (len <= (int)sizeof(event_buff)) { // if not truncated | ||
449 | write(bar->status_write_fd, event_buff, len); | ||
450 | return true; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | return false; | ||
455 | } | ||
456 | |||
394 | bool handle_status_line(struct bar *bar) { | 457 | bool handle_status_line(struct bar *bar) { |
395 | bool dirty = false; | 458 | bool dirty = false; |
396 | 459 | ||
@@ -418,15 +481,29 @@ bool handle_status_line(struct bar *bar) { | |||
418 | if (line[0] == '{') { | 481 | if (line[0] == '{') { |
419 | // detect i3bar json protocol | 482 | // detect i3bar json protocol |
420 | json_object *proto = json_tokener_parse(line); | 483 | json_object *proto = json_tokener_parse(line); |
421 | json_object *version; | ||
422 | if (proto) { | 484 | if (proto) { |
485 | |||
486 | json_object *version; | ||
423 | if (json_object_object_get_ex(proto, "version", &version) | 487 | if (json_object_object_get_ex(proto, "version", &version) |
424 | && json_object_get_int(version) == 1 | 488 | && json_object_get_int(version) == 1 |
425 | ) { | 489 | ) { |
426 | sway_log(L_DEBUG, "Switched to i3bar protocol."); | 490 | sway_log(L_DEBUG, "Switched to i3bar protocol."); |
427 | bar->status->protocol = I3BAR; | 491 | bar->status->protocol = I3BAR; |
428 | i3json_handle_data(bar, line_rest); | ||
429 | } | 492 | } |
493 | |||
494 | json_object *click_events; | ||
495 | if (json_object_object_get_ex(proto, "click_events", &click_events) | ||
496 | && json_object_get_boolean(click_events) | ||
497 | ) { | ||
498 | sway_log(L_DEBUG, "Enabling click events."); | ||
499 | bar->status->click_events = true; | ||
500 | |||
501 | const char *events_array = "[\n"; | ||
502 | write(bar->status_write_fd, events_array, strlen(events_array)); | ||
503 | } | ||
504 | |||
505 | i3json_handle_data(bar, line_rest); | ||
506 | |||
430 | json_object_put(proto); | 507 | json_object_put(proto); |
431 | } | 508 | } |
432 | } | 509 | } |
@@ -441,6 +518,7 @@ struct status_line *init_status_line() { | |||
441 | line->block_line = create_list(); | 518 | line->block_line = create_list(); |
442 | line->text_line = NULL; | 519 | line->text_line = NULL; |
443 | line->protocol = UNDEF; | 520 | line->protocol = UNDEF; |
521 | line->click_events = false; | ||
444 | 522 | ||
445 | return line; | 523 | return line; |
446 | } | 524 | } |