From fab57205765e35a6071279bdbd43eb304f958757 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Tue, 20 Jun 2017 16:03:40 -0400 Subject: [PATCH 1/5] Use fork in swaygrab instead of popen. --- swaygrab/main.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/swaygrab/main.c b/swaygrab/main.c index c437653d..6e851899 100644 --- a/swaygrab/main.c +++ b/swaygrab/main.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "log.h" #include "ipc-client.h" @@ -47,17 +48,27 @@ void grab_and_apply_magick(const char *file, const char *payload, return; } - const char *fmt = "convert -depth 8 -size %dx%d+0 rgba:- -flip %s"; - char *cmd = malloc(strlen(fmt) - 6 /*args*/ - + numlen(width) + numlen(height) + strlen(file) + 1); - sprintf(cmd, fmt, width, height, file); + char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits + sprintf(size, "%dx%d+0", width, height); - FILE *f = popen(cmd, "w"); - fwrite(pixels, 1, len, f); - fflush(f); - fclose(f); - free(pixels - 9); - free(cmd); + pid_t child; + int fd[2]; + pipe(fd); + + if ((child = fork()) < 0) { + sway_log(L_ERROR, "Swaygrab failed to fork."); + exit(EXIT_FAILURE); + } else if (child == 0) { + close(fd[1]); + write(fd[0], pixels, len); + free(pixels - 9); + waitpid(child, NULL, 0); + } else { + close(fd[0]); + execlp("convert", "-depth", "8", "-size", size, "rgba:-", "-flip", file, NULL); + sway_log(L_ERROR, "Swaygrab could not run convert."); + exit(EXIT_FAILURE); + } } void grab_and_apply_movie_magic(const char *file, const char *payload, From 65022e1cbf0ccf8764dcef7e2a738feb3331deeb Mon Sep 17 00:00:00 2001 From: "akokshar@redhat.com" Date: Tue, 29 Aug 2017 11:19:43 +0200 Subject: [PATCH 2/5] click_events as documented at https://i3wm.org/docs/i3bar-protocol.html --- include/swaybar/bar.h | 1 + include/swaybar/status_line.h | 10 +++++ swaybar/bar.c | 52 ++++++++++++++++++---- swaybar/render.c | 3 ++ 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 { int ipc_event_socketfd; int ipc_socketfd; int status_read_fd; + int status_write_fd; pid_t status_command_pid; }; 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 { list_t *block_line; const char *text_line; command_protocol protocol; + bool click_events; }; struct status_block { @@ -31,6 +32,10 @@ struct status_block { int border_bottom; int border_left; int border_right; + + // Set during rendering + int x; + int width; }; /** @@ -43,6 +48,11 @@ struct status_line *init_status_line(); */ bool handle_status_line(struct bar *bar); +/** + * Handle mouse clicks. + */ +bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button); + /** * Free status line struct. */ 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 @@ #include #include #include +#include #ifdef ENABLE_TRAY #include #include "swaybar/tray/sni_watcher.h" @@ -31,16 +32,30 @@ static void bar_init(struct bar *bar) { static void spawn_status_cmd_proc(struct bar *bar) { if (bar->config->status_command) { - int pipefd[2]; - if (pipe(pipefd) != 0) { - sway_log(L_ERROR, "Unable to create pipe for status_command fork"); + int pipe_read_fd[2]; + int pipe_write_fd[2]; + + if (pipe(pipe_read_fd) != 0) { + sway_log(L_ERROR, "Unable to create pipes for status_command fork"); return; } + if (pipe(pipe_write_fd) != 0) { + sway_log(L_ERROR, "Unable to create pipe for status_command fork (write)"); + close(pipe_read_fd[0]); + close(pipe_read_fd[1]); + return; + } + bar->status_command_pid = fork(); if (bar->status_command_pid == 0) { - close(pipefd[0]); - dup2(pipefd[1], STDOUT_FILENO); - close(pipefd[1]); + close(pipe_read_fd[0]); + dup2(pipe_read_fd[1], STDOUT_FILENO); + close(pipe_read_fd[1]); + + dup2(pipe_write_fd[0], STDIN_FILENO); + close(pipe_write_fd[0]); + close(pipe_write_fd[1]); + char *const cmd[] = { "sh", "-c", @@ -51,9 +66,13 @@ static void spawn_status_cmd_proc(struct bar *bar) { return; } - close(pipefd[1]); - bar->status_read_fd = pipefd[0]; + close(pipe_read_fd[1]); + bar->status_read_fd = pipe_read_fd[0]; fcntl(bar->status_read_fd, F_SETFL, O_NONBLOCK); + + close(pipe_write_fd[0]); + bar->status_write_fd = pipe_write_fd[1]; + fcntl(bar->status_write_fd, F_SETFL, O_NONBLOCK); } } @@ -103,9 +122,22 @@ static void mouse_button_notify(struct window *window, int x, int y, } } + switch (button) { + case BTN_LEFT: + status_line_mouse_event(&swaybar, x, y, 1); + break; + case BTN_MIDDLE: + status_line_mouse_event(&swaybar, x, y, 2); + break; + case BTN_RIGHT: + status_line_mouse_event(&swaybar, x, y, 3); + break; + } + #ifdef ENABLE_TRAY tray_mouse_event(clicked_output, x, y, button, state_w); #endif + } static void mouse_scroll_notify(struct window *window, enum scroll_direction direction) { @@ -318,6 +350,10 @@ void bar_teardown(struct bar *bar) { close(bar->status_read_fd); } + if (bar->status_write_fd) { + close(bar->status_write_fd); + } + if (bar->ipc_socketfd) { close(bar->ipc_socketfd); } 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 double pos = *x; + block->x = (int) pos; + block->width = (int) block_width; + // render background if (block->background != 0x0) { 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 { static char line[1024]; static char line_rest[1024]; +static char event_buff[1024]; + static void free_status_block(void *item) { if (!item) { return; @@ -391,6 +393,67 @@ static int i3json_handle_fd(struct bar *bar) { return i3json_parse(bar); } +bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button) { + sway_log(L_DEBUG, "status_line_mouse_event."); + if (!bar->status->click_events) { + sway_log(L_DEBUG, "click_events are not enabled."); + return false; + } + + if (bar->status->protocol == I3BAR) { + sway_log(L_DEBUG, "Sending click event."); + + // find clicked block + struct status_block *clicked_block = NULL; + struct status_block *current_block = NULL; + int num_blocks = bar->status->block_line->length; + + if (num_blocks == 0) { + return false; + } + else { + current_block = bar->status->block_line->items[0]; + if (x < current_block->x) { + return false; + } + } + + for (int i = 0; i < num_blocks; i++) { + current_block = bar->status->block_line->items[i]; + if (x < (current_block->x + current_block->width)) { + clicked_block = current_block; + break; + } + } + + if (!clicked_block || !clicked_block->name) { + return false; + } + + // event example {"name":"capture","instance":"label","button":1,"x":3431,"y":18} + + struct json_object *event_json = json_object_new_object(); + json_object_object_add(event_json, "name", json_object_new_string(clicked_block->name)); + if (clicked_block->instance) { + json_object_object_add(event_json, "instance", json_object_new_string(clicked_block->instance)); + } + json_object_object_add(event_json, "button", json_object_new_int(button)); + json_object_object_add(event_json, "x", json_object_new_int(x)); + json_object_object_add(event_json, "y", json_object_new_int(y)); + + int len = snprintf(event_buff, sizeof(event_buff), "%s,\n", json_object_to_json_string(event_json)); + + json_object_put(event_json); + + if (len <= (int)sizeof(event_buff)) { // if not truncated + write(bar->status_write_fd, event_buff, len); + return true; + } + } + + return false; +} + bool handle_status_line(struct bar *bar) { bool dirty = false; @@ -418,15 +481,29 @@ bool handle_status_line(struct bar *bar) { if (line[0] == '{') { // detect i3bar json protocol json_object *proto = json_tokener_parse(line); - json_object *version; if (proto) { + + json_object *version; if (json_object_object_get_ex(proto, "version", &version) && json_object_get_int(version) == 1 ) { sway_log(L_DEBUG, "Switched to i3bar protocol."); bar->status->protocol = I3BAR; - i3json_handle_data(bar, line_rest); } + + json_object *click_events; + if (json_object_object_get_ex(proto, "click_events", &click_events) + && json_object_get_boolean(click_events) + ) { + sway_log(L_DEBUG, "Enabling click events."); + bar->status->click_events = true; + + const char *events_array = "[\n"; + write(bar->status_write_fd, events_array, strlen(events_array)); + } + + i3json_handle_data(bar, line_rest); + json_object_put(proto); } } @@ -441,6 +518,7 @@ struct status_line *init_status_line() { line->block_line = create_list(); line->text_line = NULL; line->protocol = UNDEF; + line->click_events = false; return line; } From d873d09f23180414fc0475b3893570a514efb0e0 Mon Sep 17 00:00:00 2001 From: "akokshar@redhat.com" Date: Tue, 29 Aug 2017 15:55:30 +0200 Subject: [PATCH 3/5] style fixes --- swaybar/status_line.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/swaybar/status_line.c b/swaybar/status_line.c index f0888273..f3bb3013 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -410,8 +410,7 @@ bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button) { if (num_blocks == 0) { return false; - } - else { + } else { current_block = bar->status->block_line->items[0]; if (x < current_block->x) { return false; From 39df3aed821d32644780df2875390a259941e353 Mon Sep 17 00:00:00 2001 From: "akokshar@redhat.com" Date: Tue, 29 Aug 2017 17:33:06 +0200 Subject: [PATCH 4/5] styling fixes --- swaybar/bar.c | 18 +++++++++--------- swaybar/render.c | 4 ++-- swaybar/status_line.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/swaybar/bar.c b/swaybar/bar.c index 89f7c8c1..85cb5270 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -123,15 +123,15 @@ static void mouse_button_notify(struct window *window, int x, int y, } switch (button) { - case BTN_LEFT: - status_line_mouse_event(&swaybar, x, y, 1); - break; - case BTN_MIDDLE: - status_line_mouse_event(&swaybar, x, y, 2); - break; - case BTN_RIGHT: - status_line_mouse_event(&swaybar, x, y, 3); - break; + case BTN_LEFT: + status_line_mouse_event(&swaybar, x, y, 1); + break; + case BTN_MIDDLE: + status_line_mouse_event(&swaybar, x, y, 2); + break; + case BTN_RIGHT: + status_line_mouse_event(&swaybar, x, y, 3); + break; } #ifdef ENABLE_TRAY diff --git a/swaybar/render.c b/swaybar/render.c index 232d254b..6fc09078 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -94,8 +94,8 @@ static void render_block(struct window *window, struct config *config, struct st double pos = *x; - block->x = (int) pos; - block->width = (int) block_width; + block->x = (int)pos; + block->width = (int)block_width; // render background if (block->background != 0x0) { diff --git a/swaybar/status_line.c b/swaybar/status_line.c index f3bb3013..7da311ac 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -492,7 +492,7 @@ bool handle_status_line(struct bar *bar) { json_object *click_events; if (json_object_object_get_ex(proto, "click_events", &click_events) - && json_object_get_boolean(click_events) + && json_object_get_boolean(click_events) == true ) { sway_log(L_DEBUG, "Enabling click events."); bar->status->click_events = true; From 2b927685cae73cb4e29e5c83f1fad5c906cb7857 Mon Sep 17 00:00:00 2001 From: "akokshar@redhat.com" Date: Wed, 30 Aug 2017 08:16:17 +0200 Subject: [PATCH 5/5] styling fixes --- swaybar/status_line.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 7da311ac..e0564c26 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -492,8 +492,8 @@ bool handle_status_line(struct bar *bar) { json_object *click_events; if (json_object_object_get_ex(proto, "click_events", &click_events) - && json_object_get_boolean(click_events) == true - ) { + && json_object_get_boolean(click_events)) { + sway_log(L_DEBUG, "Enabling click events."); bar->status->click_events = true;