aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar/bar.c
diff options
context:
space:
mode:
authorLibravatar Calvin Lee <cyrus296@gmail.com>2017-06-07 16:45:28 -0700
committerLibravatar Calvin Lee <cyrus296@gmail.com>2017-06-07 17:49:16 -0700
commit843ad38b3c427adb0bf319e9613d9813c8d9246c (patch)
treee02a5b06e2b6923371fd53724791c147c18a1fa4 /swaybar/bar.c
parentMerge pull request #1232 from johalun/master-freebsd (diff)
downloadsway-843ad38b3c427adb0bf319e9613d9813c8d9246c.tar.gz
sway-843ad38b3c427adb0bf319e9613d9813c8d9246c.tar.zst
sway-843ad38b3c427adb0bf319e9613d9813c8d9246c.zip
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
Diffstat (limited to 'swaybar/bar.c')
-rw-r--r--swaybar/bar.c135
1 files changed, 101 insertions, 34 deletions
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 @@
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#ifdef ENABLE_TRAY
11#include <dbus/dbus.h>
12#include "swaybar/tray/sni_watcher.h"
13#include "swaybar/tray/tray.h"
14#include "swaybar/tray/sni.h"
15#endif
10#include "swaybar/ipc.h" 16#include "swaybar/ipc.h"
11#include "swaybar/render.h" 17#include "swaybar/render.h"
12#include "swaybar/config.h" 18#include "swaybar/config.h"
13#include "swaybar/status_line.h" 19#include "swaybar/status_line.h"
20#include "swaybar/event_loop.h"
14#include "swaybar/bar.h" 21#include "swaybar/bar.h"
15#include "ipc-client.h" 22#include "ipc-client.h"
16#include "list.h" 23#include "list.h"
@@ -50,18 +57,39 @@ static void spawn_status_cmd_proc(struct bar *bar) {
50 } 57 }
51} 58}
52 59
60#ifdef ENABLE_TRAY
61static void spawn_xembed_sni_proxy() {
62 pid_t pid = fork();
63 if (pid == 0) {
64 int wstatus;
65 do {
66 pid = fork();
67 if (pid == 0) {
68 execlp("xembedsniproxy", "xembedsniproxy", NULL);
69 _exit(EXIT_FAILURE);
70 }
71 waitpid(pid, &wstatus, 0);
72 } while (!WIFEXITED(wstatus));
73 _exit(EXIT_FAILURE);
74 }
75}
76#endif
77
53struct output *new_output(const char *name) { 78struct output *new_output(const char *name) {
54 struct output *output = malloc(sizeof(struct output)); 79 struct output *output = malloc(sizeof(struct output));
55 output->name = strdup(name); 80 output->name = strdup(name);
56 output->window = NULL; 81 output->window = NULL;
57 output->registry = NULL; 82 output->registry = NULL;
58 output->workspaces = create_list(); 83 output->workspaces = create_list();
84#ifdef ENABLE_TRAY
85 output->items = create_list();
86#endif
59 return output; 87 return output;
60} 88}
61 89
62static void mouse_button_notify(struct window *window, int x, int y, 90static void mouse_button_notify(struct window *window, int x, int y,
63 uint32_t button, uint32_t state_w) { 91 uint32_t button, uint32_t state_w) {
64 sway_log(L_DEBUG, "Mouse button %d clicked at %d %d %d\n", button, x, y, state_w); 92 sway_log(L_DEBUG, "Mouse button %d clicked at %d %d %d", button, x, y, state_w);
65 if (!state_w) { 93 if (!state_w) {
66 return; 94 return;
67 } 95 }
@@ -92,6 +120,30 @@ static void mouse_button_notify(struct window *window, int x, int y,
92 break; 120 break;
93 } 121 }
94 } 122 }
123
124#ifdef ENABLE_TRAY
125 uint32_t tray_padding = swaybar.config->tray_padding;
126 int tray_width = window->width * window->scale;
127
128 for (int i = 0; i < clicked_output->items->length; ++i) {
129 struct sni_icon_ref *item =
130 clicked_output->items->items[i];
131 int icon_width = cairo_image_surface_get_width(item->icon);
132
133 tray_width -= tray_padding;
134 if (x <= tray_width && x >= tray_width - icon_width) {
135 if (button == swaybar.config->activate_button) {
136 sni_activate(item->ref, x, y);
137 } else if (button == swaybar.config->context_button) {
138 sni_context_menu(item->ref, x, y);
139 } else if (button == swaybar.config->secondary_button) {
140 sni_secondary(item->ref, x, y);
141 }
142 break;
143 }
144 tray_width -= icon_width;
145 }
146#endif
95} 147}
96 148
97static void mouse_scroll_notify(struct window *window, enum scroll_direction direction) { 149static 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) {
136 /* initialize bar with default values */ 188 /* initialize bar with default values */
137 bar_init(bar); 189 bar_init(bar);
138 190
191 /* Initialize event loop lists */
192 init_event_loop();
193
139 /* connect to sway ipc */ 194 /* connect to sway ipc */
140 bar->ipc_socketfd = ipc_open_socket(socket_path); 195 bar->ipc_socketfd = ipc_open_socket(socket_path);
141 bar->ipc_event_socketfd = ipc_open_socket(socket_path); 196 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) {
178 } 233 }
179 /* spawn status command */ 234 /* spawn status command */
180 spawn_status_cmd_proc(bar); 235 spawn_status_cmd_proc(bar);
236
237#ifdef ENABLE_TRAY
238 // We should have at least one output to serve the tray to
239 if (!swaybar.config->tray_output || strcmp(swaybar.config->tray_output, "none") != 0) {
240 /* Connect to the D-Bus */
241 dbus_init();
242
243 /* Start the SNI watcher */
244 init_sni_watcher();
245
246 /* Start the SNI host */
247 init_tray();
248
249 /* Start xembedsniproxy */
250 spawn_xembed_sni_proxy();
251 }
252#endif
181} 253}
182 254
183void bar_run(struct bar *bar) { 255bool dirty = true;
184 int pfds = bar->outputs->length + 2;
185 struct pollfd *pfd = malloc(pfds * sizeof(struct pollfd));
186 bool dirty = true;
187 256
188 pfd[0].fd = bar->ipc_event_socketfd; 257static void respond_ipc(int fd, short mask, void *_bar) {
189 pfd[0].events = POLLIN; 258 struct bar *bar = (struct bar *)_bar;
190 pfd[1].fd = bar->status_read_fd; 259 sway_log(L_DEBUG, "Got IPC event.");
191 pfd[1].events = POLLIN; 260 dirty = handle_ipc_event(bar);
261}
262
263static void respond_command(int fd, short mask, void *_bar) {
264 struct bar *bar = (struct bar *)_bar;
265 dirty = handle_status_line(bar);
266}
267
268static void respond_output(int fd, short mask, void *_output) {
269 struct output *output = (struct output *)_output;
270 if (wl_display_dispatch(output->registry->display) == -1) {
271 sway_log(L_ERROR, "failed to dispatch wl: %d", errno);
272 }
273}
274
275void bar_run(struct bar *bar) {
276 add_event(bar->ipc_event_socketfd, POLLIN, respond_ipc, bar);
277 add_event(bar->status_read_fd, POLLIN, respond_command, bar);
192 278
193 int i; 279 int i;
194 for (i = 0; i < bar->outputs->length; ++i) { 280 for (i = 0; i < bar->outputs->length; ++i) {
195 struct output *output = bar->outputs->items[i]; 281 struct output *output = bar->outputs->items[i];
196 pfd[i+2].fd = wl_display_get_fd(output->registry->display); 282 add_event(wl_display_get_fd(output->registry->display),
197 pfd[i+2].events = POLLIN; 283 POLLIN, respond_output, output);
198 } 284 }
199 285
200 while (1) { 286 while (1) {
@@ -212,29 +298,10 @@ void bar_run(struct bar *bar) {
212 298
213 dirty = false; 299 dirty = false;
214 300
215 poll(pfd, pfds, -1); 301 event_loop_poll();
216 302#ifdef ENABLE_TRAY
217 if (pfd[0].revents & POLLIN) { 303 dispatch_dbus();
218 sway_log(L_DEBUG, "Got IPC event."); 304#endif
219 dirty = handle_ipc_event(bar);
220 }
221
222 if (bar->config->status_command && pfd[1].revents & POLLIN) {
223 sway_log(L_DEBUG, "Got update from status command.");
224 dirty = handle_status_line(bar);
225 }
226
227 // dispatch wl_display events
228 for (i = 0; i < bar->outputs->length; ++i) {
229 struct output *output = bar->outputs->items[i];
230 if (pfd[i+2].revents & POLLIN) {
231 if (wl_display_dispatch(output->registry->display) == -1) {
232 sway_log(L_ERROR, "failed to dispatch wl: %d", errno);
233 }
234 } else {
235 wl_display_dispatch_pending(output->registry->display);
236 }
237 }
238 } 305 }
239} 306}
240 307