diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 010e1f84c..9f5bf4007 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -15,6 +15,9 @@ struct bar { int ipc_socketfd; int status_read_fd; pid_t status_command_pid; +#ifdef ENABLE_TRAY + pid_t xembed_pid; +#endif }; struct output { diff --git a/include/swaybar/tray/tray.h b/include/swaybar/tray/tray.h index 7d371008f..b718e555b 100644 --- a/include/swaybar/tray/tray.h +++ b/include/swaybar/tray/tray.h @@ -5,6 +5,7 @@ #include #include "swaybar/tray/dbus.h" #include "swaybar/tray/sni.h" +#include "swaybar/bar.h" #include "list.h" extern struct tray *tray; @@ -14,13 +15,18 @@ struct tray { }; /** - * Initializes the tray host with D-Bus + * Processes a mouse event on the bar */ -int init_tray(); +void tray_mouse_event(struct output *output, int x, int y, + uint32_t button, uint32_t state); + +uint32_t tray_render(struct output *output, struct config *config); + +void tray_upkeep(struct bar *bar); /** - * Returns an item if `x` and `y` collide with it and NULL otherwise + * Initializes the tray with D-Bus */ -struct StatusNotifierItem *collides_with_sni(int x, int y); +void init_tray(); #endif /* _SWAYBAR_TRAY_H */ diff --git a/swaybar/bar.c b/swaybar/bar.c index cdaf6a37c..5d480b63c 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 } diff --git a/swaybar/render.c b/swaybar/render.c index d02ecbbbd..6ec47e799 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -302,72 +302,9 @@ void render(struct output *output, struct config *config, struct status_line *li cairo_paint(cairo); #ifdef ENABLE_TRAY - // Tray icons - uint32_t tray_padding = config->tray_padding; - unsigned int tray_width = window->width * window->scale; - const int item_size = (window->height * window->scale) - (2 * tray_padding); - - if (item_size < 0) { - // Can't render items if the padding is too large - goto no_tray; - } - - if (config->tray_output && strcmp(config->tray_output, output->name) != 0) { - goto no_tray; - } - - for (int i = 0; i < tray->items->length; ++i) { - struct StatusNotifierItem *item = - tray->items->items[i]; - if (!item->image) { - continue; - } - - struct sni_icon_ref *render_item = NULL; - int j; - for (j = i; j < output->items->length; ++j) { - struct sni_icon_ref *ref = - output->items->items[j]; - if (ref->ref == item) { - render_item = ref; - break; - } else { - sni_icon_ref_free(ref); - list_del(output->items, j); - } - } - - if (!render_item) { - render_item = sni_icon_ref_create(item, item_size); - list_add(output->items, render_item); - } else if (item->dirty) { - // item needs re-render - sni_icon_ref_free(render_item); - output->items->items[j] = render_item = - sni_icon_ref_create(item, item_size); - } - - tray_width -= tray_padding; - tray_width -= item_size; - - cairo_operator_t op = cairo_get_operator(cairo); - cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); - cairo_set_source_surface(cairo, render_item->icon, tray_width, tray_padding); - cairo_rectangle(cairo, tray_width, tray_padding, item_size, item_size); - cairo_fill(cairo); - cairo_set_operator(cairo, op); - - item->dirty = false; - } - - - if (tray_width != window->width * window->scale) { - tray_width -= tray_padding; - } - -no_tray: + uint32_t tray_width = tray_render(output, config); #else - const int tray_width = window->width * window->scale; + const uint32_t tray_width = window->width * window->scale; #endif // Command output diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index 9a709fe4e..ca8b1341b 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c @@ -2,12 +2,15 @@ #include #include #include +#include #include #include "swaybar/bar.h" #include "swaybar/tray/tray.h" #include "swaybar/tray/dbus.h" #include "swaybar/tray/sni.h" +#include "swaybar/tray/sni_watcher.h" #include "swaybar/bar.h" +#include "swaybar/config.h" #include "list.h" #include "log.h" @@ -184,7 +187,7 @@ static DBusHandlerResult signal_handler(DBusConnection *connection, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -int init_tray() { +static int init_host() { tray = (struct tray *)malloc(sizeof(tray)); tray->items = create_list(); @@ -277,3 +280,129 @@ err: free(name); return -1; } + +void tray_mouse_event(struct output *output, int x, int y, + uint32_t button, uint32_t state) { + + struct window *window = output->window; + uint32_t tray_padding = swaybar.config->tray_padding; + int tray_width = window->width * window->scale; + + for (int i = 0; i < output->items->length; ++i) { + struct sni_icon_ref *item = + 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; + } +} + +uint32_t tray_render(struct output *output, struct config *config) { + struct window *window = output->window; + cairo_t *cairo = window->cairo; + + // Tray icons + uint32_t tray_padding = config->tray_padding; + uint32_t tray_width = window->width * window->scale; + const int item_size = (window->height * window->scale) - (2 * tray_padding); + + if (item_size < 0) { + // Can't render items if the padding is too large + return tray_width; + } + + if (config->tray_output && strcmp(config->tray_output, output->name) != 0) { + return tray_width; + } + + for (int i = 0; i < tray->items->length; ++i) { + struct StatusNotifierItem *item = + tray->items->items[i]; + if (!item->image) { + continue; + } + + struct sni_icon_ref *render_item = NULL; + int j; + for (j = i; j < output->items->length; ++j) { + struct sni_icon_ref *ref = + output->items->items[j]; + if (ref->ref == item) { + render_item = ref; + break; + } else { + sni_icon_ref_free(ref); + list_del(output->items, j); + } + } + + if (!render_item) { + render_item = sni_icon_ref_create(item, item_size); + list_add(output->items, render_item); + } else if (item->dirty) { + // item needs re-render + sni_icon_ref_free(render_item); + output->items->items[j] = render_item = + sni_icon_ref_create(item, item_size); + } + + tray_width -= tray_padding; + tray_width -= item_size; + + cairo_operator_t op = cairo_get_operator(cairo); + cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); + cairo_set_source_surface(cairo, render_item->icon, tray_width, tray_padding); + cairo_rectangle(cairo, tray_width, tray_padding, item_size, item_size); + cairo_fill(cairo); + cairo_set_operator(cairo, op); + + item->dirty = false; + } + + + if (tray_width != window->width * window->scale) { + tray_width -= tray_padding; + } + + return tray_width; +} + +void tray_upkeep(struct bar *bar) { + if (!bar->xembed_pid || + (bar->xembed_pid == waitpid(bar->xembed_pid, NULL, WNOHANG))) { + pid_t pid = fork(); + if (pid == 0) { + execlp("xembedsniproxy", "xembedsniproxy", NULL); + _exit(EXIT_FAILURE); + } else { + bar->xembed_pid = pid; + } + } +} + +void init_tray(struct bar *bar) { + if (!bar->config->tray_output || strcmp(bar->config->tray_output, "none") != 0) { + /* Connect to the D-Bus */ + dbus_init(); + + /* Start the SNI watcher */ + init_sni_watcher(); + + /* Start the SNI host */ + init_host(); + + /* Start xembedsniproxy */ + tray_upkeep(bar); + } +}