From 843ad38b3c427adb0bf319e9613d9813c8d9246c Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Wed, 7 Jun 2017 16:45:28 -0700 Subject: Implement Tray Icons This commit implements the StatusNotifierItem protocol, and enables swaybar to show tray icons. It also uses `xembedsniproxy` in order to communicate with xembed applications. The tray is completely optional, and can be disabled on compile time with the `enable-tray` option. Or on runtime with the bar config option `tray_output none`. Overview of changes: In swaybar very little is changed outside the tray subfolder except that all events are now polled in `event_loop.c`, this creates no functional difference. Six bar configuration options were added, these are detailed in sway-bar(5) The tray subfolder is where all protocol implementation takes place and is organised as follows: tray/sni_watcher.c: This file contains the StatusNotifierWatcher. It keeps track of items and hosts and reports when they come or go. tray/tray.c This file contains the StatusNotifierHost. It keeps track of sway's version of the items and represents the tray itself. tray/sni.c This file contains the StatusNotifierItem struct and all communication with individual items. tray/icon.c This file implements the icon theme protocol. It allows for finding icons by name, rather than by pixmap. tray/dbus.c This file allows for asynchronous DBus communication. See #986 #343 --- swaybar/bar.c | 135 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 101 insertions(+), 34 deletions(-) (limited to 'swaybar/bar.c') diff --git a/swaybar/bar.c b/swaybar/bar.c index abde1cc9..cdaf6a37 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -7,10 +7,17 @@ #include #include #include +#ifdef ENABLE_TRAY +#include +#include "swaybar/tray/sni_watcher.h" +#include "swaybar/tray/tray.h" +#include "swaybar/tray/sni.h" +#endif #include "swaybar/ipc.h" #include "swaybar/render.h" #include "swaybar/config.h" #include "swaybar/status_line.h" +#include "swaybar/event_loop.h" #include "swaybar/bar.h" #include "ipc-client.h" #include "list.h" @@ -50,18 +57,39 @@ static void spawn_status_cmd_proc(struct bar *bar) { } } +#ifdef ENABLE_TRAY +static void spawn_xembed_sni_proxy() { + pid_t pid = fork(); + if (pid == 0) { + int wstatus; + do { + pid = fork(); + if (pid == 0) { + execlp("xembedsniproxy", "xembedsniproxy", NULL); + _exit(EXIT_FAILURE); + } + waitpid(pid, &wstatus, 0); + } while (!WIFEXITED(wstatus)); + _exit(EXIT_FAILURE); + } +} +#endif + struct output *new_output(const char *name) { struct output *output = malloc(sizeof(struct output)); output->name = strdup(name); output->window = NULL; output->registry = NULL; output->workspaces = create_list(); +#ifdef ENABLE_TRAY + output->items = create_list(); +#endif return output; } static void mouse_button_notify(struct window *window, int x, int y, uint32_t button, uint32_t state_w) { - sway_log(L_DEBUG, "Mouse button %d clicked at %d %d %d\n", button, x, y, state_w); + sway_log(L_DEBUG, "Mouse button %d clicked at %d %d %d", button, x, y, state_w); if (!state_w) { return; } @@ -92,6 +120,30 @@ static void mouse_button_notify(struct window *window, int x, int y, break; } } + +#ifdef ENABLE_TRAY + uint32_t tray_padding = swaybar.config->tray_padding; + int tray_width = window->width * window->scale; + + for (int i = 0; i < clicked_output->items->length; ++i) { + struct sni_icon_ref *item = + clicked_output->items->items[i]; + int icon_width = cairo_image_surface_get_width(item->icon); + + tray_width -= tray_padding; + if (x <= tray_width && x >= tray_width - icon_width) { + if (button == swaybar.config->activate_button) { + sni_activate(item->ref, x, y); + } else if (button == swaybar.config->context_button) { + sni_context_menu(item->ref, x, y); + } else if (button == swaybar.config->secondary_button) { + sni_secondary(item->ref, x, y); + } + break; + } + tray_width -= icon_width; + } +#endif } static void mouse_scroll_notify(struct window *window, enum scroll_direction direction) { @@ -136,6 +188,9 @@ void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { /* initialize bar with default values */ bar_init(bar); + /* Initialize event loop lists */ + init_event_loop(); + /* connect to sway ipc */ bar->ipc_socketfd = ipc_open_socket(socket_path); bar->ipc_event_socketfd = ipc_open_socket(socket_path); @@ -178,23 +233,54 @@ void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { } /* spawn status command */ spawn_status_cmd_proc(bar); + +#ifdef ENABLE_TRAY + // We should have at least one output to serve the tray to + if (!swaybar.config->tray_output || strcmp(swaybar.config->tray_output, "none") != 0) { + /* Connect to the D-Bus */ + dbus_init(); + + /* Start the SNI watcher */ + init_sni_watcher(); + + /* Start the SNI host */ + init_tray(); + + /* Start xembedsniproxy */ + spawn_xembed_sni_proxy(); + } +#endif } -void bar_run(struct bar *bar) { - int pfds = bar->outputs->length + 2; - struct pollfd *pfd = malloc(pfds * sizeof(struct pollfd)); - bool dirty = true; +bool dirty = true; - pfd[0].fd = bar->ipc_event_socketfd; - pfd[0].events = POLLIN; - pfd[1].fd = bar->status_read_fd; - pfd[1].events = POLLIN; +static void respond_ipc(int fd, short mask, void *_bar) { + struct bar *bar = (struct bar *)_bar; + sway_log(L_DEBUG, "Got IPC event."); + dirty = handle_ipc_event(bar); +} + +static void respond_command(int fd, short mask, void *_bar) { + struct bar *bar = (struct bar *)_bar; + dirty = handle_status_line(bar); +} + +static void respond_output(int fd, short mask, void *_output) { + struct output *output = (struct output *)_output; + if (wl_display_dispatch(output->registry->display) == -1) { + sway_log(L_ERROR, "failed to dispatch wl: %d", errno); + } +} + +void bar_run(struct bar *bar) { + add_event(bar->ipc_event_socketfd, POLLIN, respond_ipc, bar); + add_event(bar->status_read_fd, POLLIN, respond_command, bar); int i; for (i = 0; i < bar->outputs->length; ++i) { struct output *output = bar->outputs->items[i]; - pfd[i+2].fd = wl_display_get_fd(output->registry->display); - pfd[i+2].events = POLLIN; + add_event(wl_display_get_fd(output->registry->display), + POLLIN, respond_output, output); } while (1) { @@ -212,29 +298,10 @@ void bar_run(struct bar *bar) { dirty = false; - poll(pfd, pfds, -1); - - if (pfd[0].revents & POLLIN) { - sway_log(L_DEBUG, "Got IPC event."); - dirty = handle_ipc_event(bar); - } - - if (bar->config->status_command && pfd[1].revents & POLLIN) { - sway_log(L_DEBUG, "Got update from status command."); - dirty = handle_status_line(bar); - } - - // dispatch wl_display events - for (i = 0; i < bar->outputs->length; ++i) { - struct output *output = bar->outputs->items[i]; - if (pfd[i+2].revents & POLLIN) { - if (wl_display_dispatch(output->registry->display) == -1) { - sway_log(L_ERROR, "failed to dispatch wl: %d", errno); - } - } else { - wl_display_dispatch_pending(output->registry->display); - } - } + event_loop_poll(); +#ifdef ENABLE_TRAY + dispatch_dbus(); +#endif } } -- cgit v1.2.3 From 1451ee8fd13dd35227d11e393c80871c70ad90f0 Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Wed, 7 Jun 2017 21:32:48 -0700 Subject: Reorganize Tray Code Remove tray code from bar.c and render.c --- swaybar/bar.c | 60 +++++++---------------------------------------------------- 1 file changed, 7 insertions(+), 53 deletions(-) (limited to 'swaybar/bar.c') diff --git a/swaybar/bar.c b/swaybar/bar.c index cdaf6a37..5d480b63 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -27,6 +27,9 @@ static void bar_init(struct bar *bar) { bar->config = init_config(); bar->status = init_status_line(); bar->outputs = create_list(); +#ifdef ENABLE_TRAY + bar->xembed_pid = 0; +#endif } static void spawn_status_cmd_proc(struct bar *bar) { @@ -57,24 +60,6 @@ static void spawn_status_cmd_proc(struct bar *bar) { } } -#ifdef ENABLE_TRAY -static void spawn_xembed_sni_proxy() { - pid_t pid = fork(); - if (pid == 0) { - int wstatus; - do { - pid = fork(); - if (pid == 0) { - execlp("xembedsniproxy", "xembedsniproxy", NULL); - _exit(EXIT_FAILURE); - } - waitpid(pid, &wstatus, 0); - } while (!WIFEXITED(wstatus)); - _exit(EXIT_FAILURE); - } -} -#endif - struct output *new_output(const char *name) { struct output *output = malloc(sizeof(struct output)); output->name = strdup(name); @@ -122,27 +107,7 @@ static void mouse_button_notify(struct window *window, int x, int y, } #ifdef ENABLE_TRAY - uint32_t tray_padding = swaybar.config->tray_padding; - int tray_width = window->width * window->scale; - - for (int i = 0; i < clicked_output->items->length; ++i) { - struct sni_icon_ref *item = - clicked_output->items->items[i]; - int icon_width = cairo_image_surface_get_width(item->icon); - - tray_width -= tray_padding; - if (x <= tray_width && x >= tray_width - icon_width) { - if (button == swaybar.config->activate_button) { - sni_activate(item->ref, x, y); - } else if (button == swaybar.config->context_button) { - sni_context_menu(item->ref, x, y); - } else if (button == swaybar.config->secondary_button) { - sni_secondary(item->ref, x, y); - } - break; - } - tray_width -= icon_width; - } + tray_mouse_event(clicked_output, x, y, button, state_w); #endif } @@ -235,20 +200,7 @@ void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { spawn_status_cmd_proc(bar); #ifdef ENABLE_TRAY - // We should have at least one output to serve the tray to - if (!swaybar.config->tray_output || strcmp(swaybar.config->tray_output, "none") != 0) { - /* Connect to the D-Bus */ - dbus_init(); - - /* Start the SNI watcher */ - init_sni_watcher(); - - /* Start the SNI host */ - init_tray(); - - /* Start xembedsniproxy */ - spawn_xembed_sni_proxy(); - } + init_tray(bar); #endif } @@ -300,6 +252,8 @@ void bar_run(struct bar *bar) { event_loop_poll(); #ifdef ENABLE_TRAY + tray_upkeep(bar); + dispatch_dbus(); #endif } -- cgit v1.2.3 From 8f4bc0a3741b63c64bb6059bb632e7584c595d14 Mon Sep 17 00:00:00 2001 From: Yury Krivopalov Date: Mon, 12 Jun 2017 23:01:19 +0300 Subject: swaybar: Group child processes for signalling Fixes child proccess killing, when status_command is a complex command like "i3status | wrapper.sh". Set the process group id of the child process by calling `setpgid` after forking and before calling `exec`. The process group ID will be set to the process ID of the forked process. Processes spawned by this child process will also have this group ID. Send signals to the process group with `killpg`. This will send the signal to all of the process group. --- swaybar/bar.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'swaybar/bar.c') diff --git a/swaybar/bar.c b/swaybar/bar.c index abde1cc9..5ed0d266 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -34,6 +34,7 @@ static void spawn_status_cmd_proc(struct bar *bar) { close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); close(pipefd[1]); + setpgid(bar->status_command_pid, 0); char *const cmd[] = { "sh", "-c", @@ -274,7 +275,7 @@ static void free_outputs(list_t *outputs) { static void terminate_status_command(pid_t pid) { if (pid) { // terminate status_command process - int ret = kill(pid, SIGTERM); + int ret = killpg(pid, SIGTERM); if (ret != 0) { sway_log(L_ERROR, "Unable to terminate status_command [pid: %d]", pid); } else { -- cgit v1.2.3 From 33fdae2001f489c40667797ce3bc50eedb352ee0 Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Tue, 13 Jun 2017 12:42:11 -0700 Subject: Remove Xembed Support Xembed support is premature in sway and should be postponed. This commit only removes swaybar starting xembedsniproxy, if users would like, they can still start xembedsniproxy manually, however there will be no official support. --- swaybar/bar.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'swaybar/bar.c') diff --git a/swaybar/bar.c b/swaybar/bar.c index 5d480b63..5e87eac9 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -27,9 +27,6 @@ static void bar_init(struct bar *bar) { bar->config = init_config(); bar->status = init_status_line(); bar->outputs = create_list(); -#ifdef ENABLE_TRAY - bar->xembed_pid = 0; -#endif } static void spawn_status_cmd_proc(struct bar *bar) { @@ -252,8 +249,6 @@ void bar_run(struct bar *bar) { event_loop_poll(); #ifdef ENABLE_TRAY - tray_upkeep(bar); - dispatch_dbus(); #endif } -- cgit v1.2.3