summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-10-14 15:13:50 +0200
committerLibravatar GitHub <noreply@github.com>2018-10-14 15:13:50 +0200
commit4a05fbf8ab364657763b1d1058bdf9b4c2727b76 (patch)
treec405121528d191ba74fe329fdb18093810d9b73c
parentMerge pull request #2808 from RedSoxFan/bar-subcommands (diff)
parentswaybar: add documentation for hide/hidden_state subcommands (diff)
downloadsway-4a05fbf8ab364657763b1d1058bdf9b4c2727b76.tar.gz
sway-4a05fbf8ab364657763b1d1058bdf9b4c2727b76.tar.zst
sway-4a05fbf8ab364657763b1d1058bdf9b4c2727b76.zip
Merge pull request #2751 from ianyfan/swaybar
Bar mode/hidden_state events
-rw-r--r--include/ipc.h3
-rw-r--r--include/sway/config.h1
-rw-r--r--include/sway/ipc-server.h1
-rw-r--r--include/swaybar/bar.h37
-rw-r--r--include/swaybar/config.h5
-rw-r--r--include/swaybar/i3bar.h2
-rw-r--r--include/swaybar/ipc.h4
-rw-r--r--include/swaybar/status_line.h3
-rw-r--r--sway/commands/bar/hidden_state.c34
-rw-r--r--sway/commands/bar/mode.c34
-rw-r--r--sway/config/bar.c2
-rw-r--r--sway/input/keyboard.c28
-rw-r--r--sway/ipc-server.c18
-rw-r--r--sway/sway-bar.5.scd16
-rw-r--r--sway/sway.5.scd12
-rw-r--r--swaybar/bar.c102
-rw-r--r--swaybar/config.c4
-rw-r--r--swaybar/ipc.c128
-rw-r--r--swaybar/main.c8
-rw-r--r--swaybar/render.c32
-rw-r--r--swaybar/status_line.c14
21 files changed, 358 insertions, 130 deletions
diff --git a/include/ipc.h b/include/ipc.h
index a3f60e19..9063b933 100644
--- a/include/ipc.h
+++ b/include/ipc.h
@@ -30,6 +30,9 @@ enum ipc_command_type {
30 IPC_EVENT_BINDING = ((1<<31) | 5), 30 IPC_EVENT_BINDING = ((1<<31) | 5),
31 IPC_EVENT_SHUTDOWN = ((1<<31) | 6), 31 IPC_EVENT_SHUTDOWN = ((1<<31) | 6),
32 IPC_EVENT_TICK = ((1<<31) | 7), 32 IPC_EVENT_TICK = ((1<<31) | 7),
33
34 // sway-specific event types
35 IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20),
33}; 36};
34 37
35#endif 38#endif
diff --git a/include/sway/config.h b/include/sway/config.h
index f21ecbb1..be5a00b5 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -191,6 +191,7 @@ struct bar_config {
191 * In "show" mode, it will always be shown on top of the active workspace. 191 * In "show" mode, it will always be shown on top of the active workspace.
192 */ 192 */
193 char *hidden_state; 193 char *hidden_state;
194 bool visible_by_modifier; // only relevant in "hide" mode
194 /** 195 /**
195 * Id name used to identify the bar through IPC. 196 * Id name used to identify the bar through IPC.
196 * 197 *
diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h
index 80180ec4..3c43f74d 100644
--- a/include/sway/ipc-server.h
+++ b/include/sway/ipc-server.h
@@ -15,6 +15,7 @@ void ipc_event_workspace(struct sway_workspace *old,
15 struct sway_workspace *new, const char *change); 15 struct sway_workspace *new, const char *change);
16void ipc_event_window(struct sway_container *window, const char *change); 16void ipc_event_window(struct sway_container *window, const char *change);
17void ipc_event_barconfig_update(struct bar_config *bar); 17void ipc_event_barconfig_update(struct bar_config *bar);
18void ipc_event_bar_state_update(struct bar_config *bar);
18void ipc_event_mode(const char *mode, bool pango); 19void ipc_event_mode(const char *mode, bool pango);
19void ipc_event_shutdown(const char *reason); 20void ipc_event_shutdown(const char *reason);
20void ipc_event_binding(struct sway_binding *binding); 21void ipc_event_binding(struct sway_binding *binding);
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h
index de234111..9ff3fe7b 100644
--- a/include/swaybar/bar.h
+++ b/include/swaybar/bar.h
@@ -37,7 +37,7 @@ enum hotspot_event_handling {
37}; 37};
38 38
39struct swaybar_hotspot { 39struct swaybar_hotspot {
40 struct wl_list link; 40 struct wl_list link; // swaybar_output::hotspots
41 int x, y, width, height; 41 int x, y, width, height;
42 enum hotspot_event_handling (*callback)(struct swaybar_output *output, 42 enum hotspot_event_handling (*callback)(struct swaybar_output *output,
43 int x, int y, enum x11_button button, void *data); 43 int x, int y, enum x11_button button, void *data);
@@ -46,6 +46,15 @@ struct swaybar_hotspot {
46}; 46};
47 47
48struct swaybar { 48struct swaybar {
49 char *id;
50 char *mode;
51 bool mode_pango_markup;
52
53 // only relevant when bar is in "hide" mode
54 bool visible_by_modifier;
55 bool visible_by_urgency;
56 bool visible;
57
49 struct wl_display *display; 58 struct wl_display *display;
50 struct wl_compositor *compositor; 59 struct wl_compositor *compositor;
51 struct zwlr_layer_shell_v1 *layer_shell; 60 struct zwlr_layer_shell_v1 *layer_shell;
@@ -60,11 +69,11 @@ struct swaybar {
60 int ipc_event_socketfd; 69 int ipc_event_socketfd;
61 int ipc_socketfd; 70 int ipc_socketfd;
62 71
63 struct wl_list outputs; 72 struct wl_list outputs; // swaybar_output::link
64}; 73};
65 74
66struct swaybar_output { 75struct swaybar_output {
67 struct wl_list link; 76 struct wl_list link; // swaybar::outputs
68 struct swaybar *bar; 77 struct swaybar *bar;
69 struct wl_output *output; 78 struct wl_output *output;
70 struct zxdg_output_v1 *xdg_output; 79 struct zxdg_output_v1 *xdg_output;
@@ -72,8 +81,8 @@ struct swaybar_output {
72 struct zwlr_layer_surface_v1 *layer_surface; 81 struct zwlr_layer_surface_v1 *layer_surface;
73 uint32_t wl_name; 82 uint32_t wl_name;
74 83
75 struct wl_list workspaces; 84 struct wl_list workspaces; // swaybar_workspace::link
76 struct wl_list hotspots; 85 struct wl_list hotspots; // swaybar_hotspot::link
77 86
78 char *name; 87 char *name;
79 bool focused; 88 bool focused;
@@ -88,7 +97,7 @@ struct swaybar_output {
88}; 97};
89 98
90struct swaybar_workspace { 99struct swaybar_workspace {
91 struct wl_list link; 100 struct wl_list link; // swaybar_output::workspaces
92 int num; 101 int num;
93 char *name; 102 char *name;
94 bool focused; 103 bool focused;
@@ -96,10 +105,24 @@ struct swaybar_workspace {
96 bool urgent; 105 bool urgent;
97}; 106};
98 107
99bool bar_setup(struct swaybar *bar, const char *socket_path, const char *bar_id); 108bool bar_setup(struct swaybar *bar, const char *socket_path);
100void bar_run(struct swaybar *bar); 109void bar_run(struct swaybar *bar);
101void bar_teardown(struct swaybar *bar); 110void bar_teardown(struct swaybar *bar);
102 111
112/*
113 * Determines whether the bar should be visible and changes it to be so.
114 * If the current visibility of the bar is the different to what it should be,
115 * then it adds or destroys the layer surface as required,
116 * as well as sending the cont or stop signal to the status command.
117 * If the current visibility of the bar is already what it should be,
118 * then this function is a no-op, unless moving_layer is true, which occurs
119 * when the bar changes from "hide" to "dock" mode or vice versa, and the bar
120 * needs to be destroyed and re-added in order to change its layer.
121 *
122 * Returns true if the bar is now visible, otherwise false.
123 */
124bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
125void free_hotspots(struct wl_list *list);
103void free_workspaces(struct wl_list *list); 126void free_workspaces(struct wl_list *list);
104 127
105#endif 128#endif
diff --git a/include/swaybar/config.h b/include/swaybar/config.h
index d0336c27..5d40790a 100644
--- a/include/swaybar/config.h
+++ b/include/swaybar/config.h
@@ -13,7 +13,7 @@ struct box_colors {
13}; 13};
14 14
15struct config_output { 15struct config_output {
16 struct wl_list link; 16 struct wl_list link; // swaybar_config::outputs
17 char *name; 17 char *name;
18 size_t index; 18 size_t index;
19}; 19};
@@ -31,7 +31,8 @@ struct swaybar_config {
31 char *font; 31 char *font;
32 char *sep_symbol; 32 char *sep_symbol;
33 char *mode; 33 char *mode;
34 bool mode_pango_markup; 34 char *hidden_state;
35 char *modifier;
35 bool strip_workspace_numbers; 36 bool strip_workspace_numbers;
36 bool binding_mode_indicator; 37 bool binding_mode_indicator;
37 bool wrap_scroll; 38 bool wrap_scroll;
diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h
index 12d9b317..d4a48e07 100644
--- a/include/swaybar/i3bar.h
+++ b/include/swaybar/i3bar.h
@@ -5,7 +5,7 @@
5#include "status_line.h" 5#include "status_line.h"
6 6
7struct i3bar_block { 7struct i3bar_block {
8 struct wl_list link; 8 struct wl_list link; // status_link::blocks
9 int ref_count; 9 int ref_count;
10 char *full_text, *short_text, *align; 10 char *full_text, *short_text, *align;
11 bool urgent; 11 bool urgent;
diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h
index 8731dac2..d8cd0c76 100644
--- a/include/swaybar/ipc.h
+++ b/include/swaybar/ipc.h
@@ -3,9 +3,9 @@
3#include <stdbool.h> 3#include <stdbool.h>
4#include "swaybar/bar.h" 4#include "swaybar/bar.h"
5 5
6bool ipc_initialize(struct swaybar *bar, const char *bar_id); 6bool ipc_initialize(struct swaybar *bar);
7bool handle_ipc_readable(struct swaybar *bar); 7bool handle_ipc_readable(struct swaybar *bar);
8void ipc_get_workspaces(struct swaybar *bar); 8bool ipc_get_workspaces(struct swaybar *bar);
9void ipc_send_workspace_command(struct swaybar *bar, const char *ws); 9void ipc_send_workspace_command(struct swaybar *bar, const char *ws);
10void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind); 10void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind);
11 11
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h
index ca88b0c5..5e7e8771 100644
--- a/include/swaybar/status_line.h
+++ b/include/swaybar/status_line.h
@@ -22,6 +22,9 @@ struct status_line {
22 const char *text; 22 const char *text;
23 struct wl_list blocks; // i3bar_block::link 23 struct wl_list blocks; // i3bar_block::link
24 24
25 int stop_signal;
26 int cont_signal;
27
25 bool click_events; 28 bool click_events;
26 bool clicked; 29 bool clicked;
27 char *buffer; 30 char *buffer;
diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c
index 502ce2c4..28adf6c7 100644
--- a/sway/commands/bar/hidden_state.c
+++ b/sway/commands/bar/hidden_state.c
@@ -32,7 +32,7 @@ static struct cmd_results *bar_set_hidden_state(struct bar_config *bar,
32 } 32 }
33 // free old mode 33 // free old mode
34 free(old_state); 34 free(old_state);
35 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 35 return NULL;
36} 36}
37 37
38struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { 38struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
@@ -50,24 +50,20 @@ struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
50 50
51 const char *state = argv[0]; 51 const char *state = argv[0];
52 if (config->reading) { 52 if (config->reading) {
53 return bar_set_hidden_state(config->current_bar, state); 53 error = bar_set_hidden_state(config->current_bar, state);
54 } 54 } else {
55 55 const char *id = argc == 2 ? argv[1] : NULL;
56 const char *id = NULL; 56 for (int i = 0; i < config->bars->length; ++i) {
57 if (argc == 2) { 57 struct bar_config *bar = config->bars->items[i];
58 id = argv[1]; 58 if (id) {
59 } 59 if (strcmp(id, bar->id) == 0) {
60 struct bar_config *bar; 60 error = bar_set_hidden_state(bar, state);
61 for (int i = 0; i < config->bars->length; ++i) { 61 break;
62 bar = config->bars->items[i]; 62 }
63 if (id && strcmp(id, bar->id) == 0) { 63 } else if ((error = bar_set_hidden_state(bar, state))) {
64 return bar_set_hidden_state(bar, state); 64 break;
65 } 65 }
66
67 error = bar_set_hidden_state(bar, state);
68 if (error) {
69 return error;
70 } 66 }
71 } 67 }
72 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 68 return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
73} 69}
diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c
index 28e2d77b..dbdd3897 100644
--- a/sway/commands/bar/mode.c
+++ b/sway/commands/bar/mode.c
@@ -33,7 +33,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode
33 33
34 // free old mode 34 // free old mode
35 free(old_mode); 35 free(old_mode);
36 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 36 return NULL;
37} 37}
38 38
39struct cmd_results *bar_cmd_mode(int argc, char **argv) { 39struct cmd_results *bar_cmd_mode(int argc, char **argv) {
@@ -51,24 +51,20 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) {
51 51
52 const char *mode = argv[0]; 52 const char *mode = argv[0];
53 if (config->reading) { 53 if (config->reading) {
54 return bar_set_mode(config->current_bar, mode); 54 error = bar_set_mode(config->current_bar, mode);
55 } 55 } else {
56 56 const char *id = argc == 2 ? argv[1] : NULL;
57 const char *id = NULL; 57 for (int i = 0; i < config->bars->length; ++i) {
58 if (argc == 2) { 58 struct bar_config *bar = config->bars->items[i];
59 id = argv[1]; 59 if (id) {
60 } 60 if (strcmp(id, bar->id) == 0) {
61 61 error = bar_set_mode(bar, mode);
62 struct bar_config *bar; 62 break;
63 for (int i = 0; i < config->bars->length; ++i) { 63 }
64 bar = config->bars->items[i]; 64 } else if ((error = bar_set_mode(bar, mode))) {
65 if (id && strcmp(id, bar->id) == 0) { 65 break;
66 return bar_set_mode(bar, mode); 66 }
67 }
68 error = bar_set_mode(bar, mode);
69 if (error) {
70 return error;
71 } 67 }
72 } 68 }
73 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 69 return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
74} 70}
diff --git a/sway/config/bar.c b/sway/config/bar.c
index 5726e95b..8b88642e 100644
--- a/sway/config/bar.c
+++ b/sway/config/bar.c
@@ -16,6 +16,7 @@
16#include "stringop.h" 16#include "stringop.h"
17#include "list.h" 17#include "list.h"
18#include "log.h" 18#include "log.h"
19#include "util.h"
19 20
20static void terminate_swaybar(pid_t pid) { 21static void terminate_swaybar(pid_t pid) {
21 wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid); 22 wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid);
@@ -101,6 +102,7 @@ struct bar_config *default_bar_config(void) {
101 bar->binding_mode_indicator = true; 102 bar->binding_mode_indicator = true;
102 bar->verbose = false; 103 bar->verbose = false;
103 bar->pid = 0; 104 bar->pid = 0;
105 bar->modifier = get_modifier_mask_by_name("Mod4");
104 if (!(bar->mode = strdup("dock"))) { 106 if (!(bar->mode = strdup("dock"))) {
105 goto cleanup; 107 goto cleanup;
106 } 108 }
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index fb1fe7b5..2c8b41cd 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -9,6 +9,7 @@
9#include "sway/input/input-manager.h" 9#include "sway/input/input-manager.h"
10#include "sway/input/keyboard.h" 10#include "sway/input/keyboard.h"
11#include "sway/input/seat.h" 11#include "sway/input/seat.h"
12#include "sway/ipc-server.h"
12#include "log.h" 13#include "log.h"
13 14
14/** 15/**
@@ -66,10 +67,10 @@ static void update_shortcut_state(struct sway_shortcut_state *state,
66 bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers; 67 bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers;
67 state->last_raw_modifiers = raw_modifiers; 68 state->last_raw_modifiers = raw_modifiers;
68 69
69 if (last_key_was_a_modifier && state->last_keycode) { 70 if (last_key_was_a_modifier && state->last_keycode) {
70 // Last pressed key before this one was a modifier 71 // Last pressed key before this one was a modifier
71 state_erase_key(state, state->last_keycode); 72 state_erase_key(state, state->last_keycode);
72 } 73 }
73 74
74 if (event->state == WLR_KEY_PRESSED) { 75 if (event->state == WLR_KEY_PRESSED) {
75 // Add current key to set; there may be duplicates 76 // Add current key to set; there may be duplicates
@@ -235,7 +236,6 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
235 code_modifiers); 236 code_modifiers);
236 } 237 }
237 238
238
239 bool handled = false; 239 bool handled = false;
240 240
241 // Identify active release binding 241 // Identify active release binding
@@ -337,6 +337,19 @@ static int handle_keyboard_repeat(void *data) {
337 return 0; 337 return 0;
338} 338}
339 339
340static void determine_bar_visibility(uint32_t modifiers) {
341 for (int i = 0; i < config->bars->length; ++i) {
342 struct bar_config *bar = config->bars->items[i];
343 if (strcmp(bar->mode, bar->hidden_state) == 0) { // both are "hide"
344 bool should_be_visible = (~modifiers & bar->modifier) == 0;
345 if (bar->visible_by_modifier != should_be_visible) {
346 bar->visible_by_modifier = should_be_visible;
347 ipc_event_bar_state_update(bar);
348 }
349 }
350 }
351}
352
340static void handle_keyboard_modifiers(struct wl_listener *listener, 353static void handle_keyboard_modifiers(struct wl_listener *listener,
341 void *data) { 354 void *data) {
342 struct sway_keyboard *keyboard = 355 struct sway_keyboard *keyboard =
@@ -346,6 +359,9 @@ static void handle_keyboard_modifiers(struct wl_listener *listener,
346 keyboard->seat_device->input_device->wlr_device; 359 keyboard->seat_device->input_device->wlr_device;
347 wlr_seat_set_keyboard(wlr_seat, wlr_device); 360 wlr_seat_set_keyboard(wlr_seat, wlr_device);
348 wlr_seat_keyboard_notify_modifiers(wlr_seat, &wlr_device->keyboard->modifiers); 361 wlr_seat_keyboard_notify_modifiers(wlr_seat, &wlr_device->keyboard->modifiers);
362
363 uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard);
364 determine_bar_visibility(modifiers);
349} 365}
350 366
351struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, 367struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
@@ -464,7 +480,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
464 keyboard->keyboard_key.notify = handle_keyboard_key; 480 keyboard->keyboard_key.notify = handle_keyboard_key;
465 481
466 wl_list_remove(&keyboard->keyboard_modifiers.link); 482 wl_list_remove(&keyboard->keyboard_modifiers.link);
467 wl_signal_add( &wlr_device->keyboard->events.modifiers, 483 wl_signal_add(&wlr_device->keyboard->events.modifiers,
468 &keyboard->keyboard_modifiers); 484 &keyboard->keyboard_modifiers);
469 keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; 485 keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
470} 486}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 2d915502..63c95503 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -349,6 +349,22 @@ void ipc_event_barconfig_update(struct bar_config *bar) {
349 json_object_put(json); 349 json_object_put(json);
350} 350}
351 351
352void ipc_event_bar_state_update(struct bar_config *bar) {
353 if (!ipc_has_event_listeners(IPC_EVENT_BAR_STATE_UPDATE)) {
354 return;
355 }
356 wlr_log(WLR_DEBUG, "Sending bar_state_update event");
357
358 json_object *json = json_object_new_object();
359 json_object_object_add(json, "id", json_object_new_string(bar->id));
360 json_object_object_add(json, "visible_by_modifier",
361 json_object_new_boolean(bar->visible_by_modifier));
362
363 const char *json_string = json_object_to_json_string(json);
364 ipc_send_event(json_string, IPC_EVENT_BAR_STATE_UPDATE);
365 json_object_put(json);
366}
367
352void ipc_event_mode(const char *mode, bool pango) { 368void ipc_event_mode(const char *mode, bool pango) {
353 if (!ipc_has_event_listeners(IPC_EVENT_MODE)) { 369 if (!ipc_has_event_listeners(IPC_EVENT_MODE)) {
354 return; 370 return;
@@ -651,6 +667,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
651 client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE); 667 client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE);
652 } else if (strcmp(event_type, "barconfig_update") == 0) { 668 } else if (strcmp(event_type, "barconfig_update") == 0) {
653 client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); 669 client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE);
670 } else if (strcmp(event_type, "bar_state_update") == 0) {
671 client->subscribed_events |= event_mask(IPC_EVENT_BAR_STATE_UPDATE);
654 } else if (strcmp(event_type, "mode") == 0) { 672 } else if (strcmp(event_type, "mode") == 0) {
655 client->subscribed_events |= event_mask(IPC_EVENT_MODE); 673 client->subscribed_events |= event_mask(IPC_EVENT_MODE);
656 } else if (strcmp(event_type, "shutdown") == 0) { 674 } else if (strcmp(event_type, "shutdown") == 0) {
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd
index 6729c9ac..873741c0 100644
--- a/sway/sway-bar.5.scd
+++ b/sway/sway-bar.5.scd
@@ -65,6 +65,22 @@ Sway allows configuring swaybar in the sway configuration file.
65 is given, when mouse button _n_ has been released). To disable the default 65 is given, when mouse button _n_ has been released). To disable the default
66 behavior for a button, use the command _nop_. 66 behavior for a button, use the command _nop_.
67 67
68*mode* dock|hide|invisible
69 Specifies the visibility of the bar. In _dock_ mode, it is permanently
70 visible at one edge of the screen. In _hide_ mode, it is hidden unless the
71 modifier key is pressed, though this behaviour depends on the hidden state.
72 In _invisible_ mode, it is permanently hidden. Default is _dock_.
73
74*hidden\_state* hide|show
75 Specifies the behaviour of the bar when it is in _hide_ mode. When the
76 hidden state is _hide_, then it is normally hidden, and only unhidden by
77 pressing the modifier key or in case of urgency hints. When the hidden
78 state is _show_, then it is permanently visible, drawn on top of the
79 currently visible workspace. Default is _hide_.
80
81*modifier* <Modifier>|none
82 Specifies the modifier key that shows a hidden bar. Default is _Mod4_.
83
68## TRAY 84## TRAY
69 85
70Swaybar provides a system tray where third-party applications may place icons. 86Swaybar provides a system tray where third-party applications may place icons.
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 2e1d13a8..67cc1cb1 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -614,6 +614,18 @@ match any output by using the output name "\*".
614*workspace\_layout* default|stacking|tabbed 614*workspace\_layout* default|stacking|tabbed
615 Specifies the initial layout for new workspaces. 615 Specifies the initial layout for new workspaces.
616 616
617# BAR CONTROL
618
619*bar hidden\_state* hide|show|toggle [<bar\_id>]
620 Sets the hidden state of the bar (see *sway-bar*(5)), either individually,
621 by specifying a bar id, or if none is given, for all bar instances.
622 _toggle_ switches between _hide_ and _show_.
623
624*bar mode* dock|hide|invisible|toggle [<bar\_id>]
625 Sets the mode of the bar (see *sway-bar*(5)), either individually,
626 by specifying a bar id, or if none is given, for all bar instances.
627 _toggle_ switches between _dock_ and _hide_.
628
617# CRITERIA 629# CRITERIA
618 630
619A criteria is a string in the form of, for example: 631A criteria is a string in the form of, for example:
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 5b7fea71..9f72c94c 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -32,9 +32,21 @@
32 32
33static void bar_init(struct swaybar *bar) { 33static void bar_init(struct swaybar *bar) {
34 bar->config = init_config(); 34 bar->config = init_config();
35 bar->visible = true;
35 wl_list_init(&bar->outputs); 36 wl_list_init(&bar->outputs);
36} 37}
37 38
39void free_hotspots(struct wl_list *list) {
40 struct swaybar_hotspot *hotspot, *tmp;
41 wl_list_for_each_safe(hotspot, tmp, list, link) {
42 wl_list_remove(&hotspot->link);
43 if (hotspot->destroy) {
44 hotspot->destroy(hotspot->data);
45 }
46 free(hotspot);
47 }
48}
49
38void free_workspaces(struct wl_list *list) { 50void free_workspaces(struct wl_list *list) {
39 struct swaybar_workspace *ws, *tmp; 51 struct swaybar_workspace *ws, *tmp;
40 wl_list_for_each_safe(ws, tmp, list, link) { 52 wl_list_for_each_safe(ws, tmp, list, link) {
@@ -59,14 +71,8 @@ static void swaybar_output_free(struct swaybar_output *output) {
59 wl_output_destroy(output->output); 71 wl_output_destroy(output->output);
60 destroy_buffer(&output->buffers[0]); 72 destroy_buffer(&output->buffers[0]);
61 destroy_buffer(&output->buffers[1]); 73 destroy_buffer(&output->buffers[1]);
74 free_hotspots(&output->hotspots);
62 free_workspaces(&output->workspaces); 75 free_workspaces(&output->workspaces);
63 struct swaybar_hotspot *hotspot, *hotspot_tmp;
64 wl_list_for_each_safe(hotspot, hotspot_tmp, &output->hotspots, link) {
65 if (hotspot->destroy) {
66 hotspot->destroy(hotspot->data);
67 }
68 free(hotspot);
69 }
70 wl_list_remove(&output->link); 76 wl_list_remove(&output->link);
71 free(output->name); 77 free(output->name);
72 free(output); 78 free(output);
@@ -75,9 +81,7 @@ static void swaybar_output_free(struct swaybar_output *output) {
75static void set_output_dirty(struct swaybar_output *output) { 81static void set_output_dirty(struct swaybar_output *output) {
76 if (output->frame_scheduled) { 82 if (output->frame_scheduled) {
77 output->dirty = true; 83 output->dirty = true;
78 return; 84 } else if (output->surface) {
79 }
80 if (output->surface) {
81 render_frame(output); 85 render_frame(output);
82 } 86 }
83} 87}
@@ -335,21 +339,68 @@ const struct wl_seat_listener seat_listener = {
335}; 339};
336 340
337static void add_layer_surface(struct swaybar_output *output) { 341static void add_layer_surface(struct swaybar_output *output) {
338 if (output->surface != NULL) { 342 if (output->layer_surface) {
339 return; 343 return;
340 } 344 }
341 struct swaybar *bar = output->bar; 345 struct swaybar *bar = output->bar;
342 346
343 output->surface = wl_compositor_create_surface(bar->compositor); 347 struct swaybar_config *config = bar->config;
344 assert(output->surface); 348 bool hidden = strcmp(config->mode, "hide") == 0;
345 output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( 349 output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
346 bar->layer_shell, output->surface, output->output, 350 bar->layer_shell, output->surface, output->output,
351 hidden ? ZWLR_LAYER_SHELL_V1_LAYER_TOP :
347 ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); 352 ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
348 assert(output->layer_surface); 353 assert(output->layer_surface);
349 zwlr_layer_surface_v1_add_listener(output->layer_surface, 354 zwlr_layer_surface_v1_add_listener(output->layer_surface,
350 &layer_surface_listener, output); 355 &layer_surface_listener, output);
351 zwlr_layer_surface_v1_set_anchor(output->layer_surface, 356
352 bar->config->position); 357 zwlr_layer_surface_v1_set_anchor(output->layer_surface, config->position);
358 if (hidden) {
359 zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1);
360 }
361}
362
363static void destroy_layer_surface(struct swaybar_output *output) {
364 if (!output->layer_surface) {
365 return;
366 }
367 zwlr_layer_surface_v1_destroy(output->layer_surface);
368 wl_surface_attach(output->surface, NULL, 0, 0); // detach buffer
369 output->layer_surface = NULL;
370 output->width = 0;
371 output->frame_scheduled = false;
372}
373
374bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) {
375 struct swaybar_config *config = bar->config;
376 bool visible = !(strcmp(config->mode, "invisible") == 0 ||
377 (strcmp(config->mode, config->hidden_state) == 0 // both "hide"
378 && !bar->visible_by_modifier && !bar->visible_by_urgency));
379
380 struct swaybar_output *output;
381 if (visible == bar->visible) {
382 if (visible && moving_layer) {
383 // need to destroy layer surface to move to a different layer
384 wl_list_for_each(output, &bar->outputs, link) {
385 destroy_layer_surface(output);
386 add_layer_surface(output);
387 }
388 }
389 } else {
390 bar->visible = visible;
391 wl_list_for_each(output, &bar->outputs, link) {
392 if (visible) {
393 add_layer_surface(output);
394 } else {
395 destroy_layer_surface(output);
396 }
397 }
398 wlr_log(WLR_DEBUG, "Sending %s signal to status command",
399 visible ? "cont" : "stop");
400 kill(bar->status->pid,
401 visible ? bar->status->cont_signal : bar->status->stop_signal);
402 }
403 return visible;
353} 404}
354 405
355static bool bar_uses_output(struct swaybar *bar, const char *name) { 406static bool bar_uses_output(struct swaybar *bar, const char *name) {
@@ -420,8 +471,11 @@ static void xdg_output_handle_done(void *data,
420 wl_list_remove(&output->link); 471 wl_list_remove(&output->link);
421 wl_list_insert(&bar->outputs, &output->link); 472 wl_list_insert(&bar->outputs, &output->link);
422 473
423 add_layer_surface(output); 474 output->surface = wl_compositor_create_surface(bar->compositor);
424 set_output_dirty(output); 475 assert(output->surface);
476 if (bar->visible) {
477 add_layer_surface(output);
478 }
425 } 479 }
426} 480}
427 481
@@ -517,14 +571,13 @@ static void set_bar_dirty(struct swaybar *bar) {
517 } 571 }
518} 572}
519 573
520bool bar_setup(struct swaybar *bar, 574bool bar_setup(struct swaybar *bar, const char *socket_path) {
521 const char *socket_path, const char *bar_id) {
522 bar_init(bar); 575 bar_init(bar);
523 init_event_loop(); 576 init_event_loop();
524 577
525 bar->ipc_socketfd = ipc_open_socket(socket_path); 578 bar->ipc_socketfd = ipc_open_socket(socket_path);
526 bar->ipc_event_socketfd = ipc_open_socket(socket_path); 579 bar->ipc_event_socketfd = ipc_open_socket(socket_path);
527 if (!ipc_initialize(bar, bar_id)) { 580 if (!ipc_initialize(bar)) {
528 return false; 581 return false;
529 } 582 }
530 if (bar->config->status_command) { 583 if (bar->config->status_command) {
@@ -565,8 +618,11 @@ bool bar_setup(struct swaybar *bar,
565 pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); 618 pointer->cursor_surface = wl_compositor_create_surface(bar->compositor);
566 assert(pointer->cursor_surface); 619 assert(pointer->cursor_surface);
567 620
568 ipc_get_workspaces(bar); 621 if (bar->config->workspace_buttons) {
569 set_bar_dirty(bar); 622 if (ipc_get_workspaces(bar)) {
623 set_bar_dirty(bar);
624 }
625 }
570 return true; 626 return true;
571} 627}
572 628
@@ -625,4 +681,6 @@ void bar_teardown(struct swaybar *bar) {
625 if (bar->status) { 681 if (bar->status) {
626 status_line_free(bar->status); 682 status_line_free(bar->status);
627 } 683 }
684 free(bar->id);
685 free(bar->mode);
628} 686}
diff --git a/swaybar/config.c b/swaybar/config.c
index 09d40c24..eafb0b69 100644
--- a/swaybar/config.c
+++ b/swaybar/config.c
@@ -30,7 +30,8 @@ struct swaybar_config *init_config(void) {
30 config->pango_markup = false; 30 config->pango_markup = false;
31 config->position = parse_position("bottom"); 31 config->position = parse_position("bottom");
32 config->font = strdup("monospace 10"); 32 config->font = strdup("monospace 10");
33 config->mode = NULL; 33 config->mode = strdup("dock");
34 config->hidden_state = strdup("hide");
34 config->sep_symbol = NULL; 35 config->sep_symbol = NULL;
35 config->strip_workspace_numbers = false; 36 config->strip_workspace_numbers = false;
36 config->binding_mode_indicator = true; 37 config->binding_mode_indicator = true;
@@ -84,6 +85,7 @@ void free_config(struct swaybar_config *config) {
84 free(config->status_command); 85 free(config->status_command);
85 free(config->font); 86 free(config->font);
86 free(config->mode); 87 free(config->mode);
88 free(config->hidden_state);
87 free(config->sep_symbol); 89 free(config->sep_symbol);
88 for (int i = 0; i < config->bindings->length; i++) { 90 for (int i = 0; i < config->bindings->length; i++) {
89 struct swaybar_binding *binding = config->bindings->items[i]; 91 struct swaybar_binding *binding = config->bindings->items[i];
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index a67814c1..e1b30b52 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -152,12 +152,12 @@ static bool ipc_parse_config(
152 json_object_put(bar_config); 152 json_object_put(bar_config);
153 return false; 153 return false;
154 } 154 }
155 json_object *markup, *mode, *hidden_bar, *position, *status_command; 155 json_object *markup, *mode, *hidden_state, *position, *status_command;
156 json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers; 156 json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers;
157 json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; 157 json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
158 json_object *bindings; 158 json_object *bindings;
159 json_object_object_get_ex(bar_config, "mode", &mode); 159 json_object_object_get_ex(bar_config, "mode", &mode);
160 json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar); 160 json_object_object_get_ex(bar_config, "hidden_state", &hidden_state);
161 json_object_object_get_ex(bar_config, "position", &position); 161 json_object_object_get_ex(bar_config, "position", &position);
162 json_object_object_get_ex(bar_config, "status_command", &status_command); 162 json_object_object_get_ex(bar_config, "status_command", &status_command);
163 json_object_object_get_ex(bar_config, "font", &font); 163 json_object_object_get_ex(bar_config, "font", &font);
@@ -220,6 +220,14 @@ static bool ipc_parse_config(
220 list_add(config->bindings, binding); 220 list_add(config->bindings, binding);
221 } 221 }
222 } 222 }
223 if (hidden_state) {
224 free(config->hidden_state);
225 config->hidden_state = strdup(json_object_get_string(hidden_state));
226 }
227 if (mode) {
228 free(config->mode);
229 config->mode = strdup(json_object_get_string(mode));
230 }
223 231
224 struct config_output *output, *tmp; 232 struct config_output *output, *tmp;
225 wl_list_for_each_safe(output, tmp, &config->outputs, link) { 233 wl_list_for_each_safe(output, tmp, &config->outputs, link) {
@@ -254,7 +262,7 @@ static bool ipc_parse_config(
254 return true; 262 return true;
255} 263}
256 264
257void ipc_get_workspaces(struct swaybar *bar) { 265bool ipc_get_workspaces(struct swaybar *bar) {
258 struct swaybar_output *output; 266 struct swaybar_output *output;
259 wl_list_for_each(output, &bar->outputs, link) { 267 wl_list_for_each(output, &bar->outputs, link) {
260 free_workspaces(&output->workspaces); 268 free_workspaces(&output->workspaces);
@@ -266,8 +274,10 @@ void ipc_get_workspaces(struct swaybar *bar) {
266 json_object *results = json_tokener_parse(res); 274 json_object *results = json_tokener_parse(res);
267 if (!results) { 275 if (!results) {
268 free(res); 276 free(res);
269 return; 277 return false;
270 } 278 }
279
280 bar->visible_by_urgency = false;
271 size_t length = json_object_array_length(results); 281 size_t length = json_object_array_length(results);
272 json_object *ws_json; 282 json_object *ws_json;
273 json_object *num, *name, *visible, *focused, *out, *urgent; 283 json_object *num, *name, *visible, *focused, *out, *urgent;
@@ -294,12 +304,16 @@ void ipc_get_workspaces(struct swaybar *bar) {
294 output->focused = true; 304 output->focused = true;
295 } 305 }
296 ws->urgent = json_object_get_boolean(urgent); 306 ws->urgent = json_object_get_boolean(urgent);
307 if (ws->urgent) {
308 bar->visible_by_urgency = true;
309 }
297 wl_list_insert(&output->workspaces, &ws->link); 310 wl_list_insert(&output->workspaces, &ws->link);
298 } 311 }
299 } 312 }
300 } 313 }
301 json_object_put(results); 314 json_object_put(results);
302 free(res); 315 free(res);
316 return determine_bar_visibility(bar, false);
303} 317}
304 318
305static void ipc_get_outputs(struct swaybar *bar) { 319static void ipc_get_outputs(struct swaybar *bar) {
@@ -345,10 +359,10 @@ void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) {
345 IPC_COMMAND, bind->command, &len)); 359 IPC_COMMAND, bind->command, &len));
346} 360}
347 361
348bool ipc_initialize(struct swaybar *bar, const char *bar_id) { 362bool ipc_initialize(struct swaybar *bar) {
349 uint32_t len = strlen(bar_id); 363 uint32_t len = strlen(bar->id);
350 char *res = ipc_single_command(bar->ipc_socketfd, 364 char *res = ipc_single_command(bar->ipc_socketfd,
351 IPC_GET_BAR_CONFIG, bar_id, &len); 365 IPC_GET_BAR_CONFIG, bar->id, &len);
352 if (!ipc_parse_config(bar->config, res)) { 366 if (!ipc_parse_config(bar->config, res)) {
353 free(res); 367 free(res);
354 return false; 368 return false;
@@ -356,56 +370,108 @@ bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
356 free(res); 370 free(res);
357 ipc_get_outputs(bar); 371 ipc_get_outputs(bar);
358 372
359 const char *subscribe = "[ \"workspace\", \"mode\" ]"; 373 struct swaybar_config *config = bar->config;
360 len = strlen(subscribe); 374 char subscribe[128]; // suitably large buffer
375 len = snprintf(subscribe, 128,
376 "[ \"barconfig_update\" , \"bar_state_update\" %s %s ]",
377 config->binding_mode_indicator ? ", \"mode\"" : "",
378 config->workspace_buttons ? ", \"workspace\"" : "");
361 free(ipc_single_command(bar->ipc_event_socketfd, 379 free(ipc_single_command(bar->ipc_event_socketfd,
362 IPC_SUBSCRIBE, subscribe, &len)); 380 IPC_SUBSCRIBE, subscribe, &len));
363 return true; 381 return true;
364} 382}
365 383
384static bool handle_bar_state_update(struct swaybar *bar, json_object *event) {
385 json_object *json_id;
386 json_object_object_get_ex(event, "id", &json_id);
387 const char *id = json_object_get_string(json_id);
388 if (strcmp(id, bar->id) != 0) {
389 return false;
390 }
391
392 json_object *visible_by_modifier;
393 json_object_object_get_ex(event, "visible_by_modifier", &visible_by_modifier);
394 bar->visible_by_modifier = json_object_get_boolean(visible_by_modifier);
395 return determine_bar_visibility(bar, false);
396}
397
398static bool handle_barconfig_update(struct swaybar *bar,
399 json_object *json_config) {
400 json_object *json_id;
401 json_object_object_get_ex(json_config, "id", &json_id);
402 const char *id = json_object_get_string(json_id);
403 if (strcmp(id, bar->id) != 0) {
404 return false;
405 }
406
407 struct swaybar_config *config = bar->config;
408
409 json_object *json_state;
410 json_object_object_get_ex(json_config, "hidden_state", &json_state);
411 const char *new_state = json_object_get_string(json_state);
412 char *old_state = config->hidden_state;
413 if (strcmp(new_state, old_state) != 0) {
414 wlr_log(WLR_DEBUG, "Changing bar hidden state to %s", new_state);
415 free(old_state);
416 config->hidden_state = strdup(new_state);
417 return determine_bar_visibility(bar, false);
418 }
419
420 free(config->mode);
421 json_object *json_mode;
422 json_object_object_get_ex(json_config, "mode", &json_mode);
423 config->mode = strdup(json_object_get_string(json_mode));
424 wlr_log(WLR_DEBUG, "Changing bar mode to %s", config->mode);
425
426 return determine_bar_visibility(bar, true);
427}
428
366bool handle_ipc_readable(struct swaybar *bar) { 429bool handle_ipc_readable(struct swaybar *bar) {
367 struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); 430 struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
368 if (!resp) { 431 if (!resp) {
369 return false; 432 return false;
370 } 433 }
434
435 json_object *result = json_tokener_parse(resp->payload);
436 if (!result) {
437 wlr_log(WLR_ERROR, "failed to parse payload as json");
438 free_ipc_response(resp);
439 return false;
440 }
441
442 bool bar_is_dirty = true;
371 switch (resp->type) { 443 switch (resp->type) {
372 case IPC_EVENT_WORKSPACE: 444 case IPC_EVENT_WORKSPACE:
373 ipc_get_workspaces(bar); 445 bar_is_dirty = ipc_get_workspaces(bar);
374 break; 446 break;
375 case IPC_EVENT_MODE: { 447 case IPC_EVENT_MODE: {
376 json_object *result = json_tokener_parse(resp->payload);
377 if (!result) {
378 free_ipc_response(resp);
379 wlr_log(WLR_ERROR, "failed to parse payload as json");
380 return false;
381 }
382 json_object *json_change, *json_pango_markup; 448 json_object *json_change, *json_pango_markup;
383 if (json_object_object_get_ex(result, "change", &json_change)) { 449 if (json_object_object_get_ex(result, "change", &json_change)) {
384 const char *change = json_object_get_string(json_change); 450 const char *change = json_object_get_string(json_change);
385 free(bar->config->mode); 451 free(bar->mode);
386 if (strcmp(change, "default") == 0) { 452 bar->mode = strcmp(change, "default") != 0 ? strdup(change) : NULL;
387 bar->config->mode = NULL;
388 } else {
389 bar->config->mode = strdup(change);
390 }
391 } else { 453 } else {
392 wlr_log(WLR_ERROR, "failed to parse response"); 454 wlr_log(WLR_ERROR, "failed to parse response");
393 json_object_put(result); 455 bar_is_dirty = false;
394 free_ipc_response(resp); 456 break;
395 return false;
396 } 457 }
397 if (json_object_object_get_ex(result, 458 if (json_object_object_get_ex(result,
398 "pango_markup", &json_pango_markup)) { 459 "pango_markup", &json_pango_markup)) {
399 bar->config->mode_pango_markup = json_object_get_boolean( 460 bar->mode_pango_markup = json_object_get_boolean(json_pango_markup);
400 json_pango_markup);
401 } 461 }
402 json_object_put(result);
403 break; 462 break;
404 } 463 }
464 case IPC_EVENT_BARCONFIG_UPDATE:
465 bar_is_dirty = handle_barconfig_update(bar, result);
466 break;
467 case IPC_EVENT_BAR_STATE_UPDATE:
468 bar_is_dirty = handle_bar_state_update(bar, result);
469 break;
405 default: 470 default:
406 free_ipc_response(resp); 471 bar_is_dirty = false;
407 return false; 472 break;
408 } 473 }
474 json_object_put(result);
409 free_ipc_response(resp); 475 free_ipc_response(resp);
410 return true; 476 return bar_is_dirty;
411} 477}
diff --git a/swaybar/main.c b/swaybar/main.c
index db204f4a..2672abef 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -22,7 +22,6 @@ void sway_terminate(int code) {
22 22
23int main(int argc, char **argv) { 23int main(int argc, char **argv) {
24 char *socket_path = NULL; 24 char *socket_path = NULL;
25 char *bar_id = NULL;
26 bool debug = false; 25 bool debug = false;
27 26
28 static struct option long_options[] = { 27 static struct option long_options[] = {
@@ -59,7 +58,7 @@ int main(int argc, char **argv) {
59 socket_path = strdup(optarg); 58 socket_path = strdup(optarg);
60 break; 59 break;
61 case 'b': // Type 60 case 'b': // Type
62 bar_id = strdup(optarg); 61 swaybar.id = strdup(optarg);
63 break; 62 break;
64 case 'v': 63 case 'v':
65 fprintf(stdout, "swaybar version " SWAY_VERSION "\n"); 64 fprintf(stdout, "swaybar version " SWAY_VERSION "\n");
@@ -80,7 +79,7 @@ int main(int argc, char **argv) {
80 wlr_log_init(WLR_ERROR, NULL); 79 wlr_log_init(WLR_ERROR, NULL);
81 } 80 }
82 81
83 if (!bar_id) { 82 if (!swaybar.id) {
84 wlr_log(WLR_ERROR, "No bar_id passed. " 83 wlr_log(WLR_ERROR, "No bar_id passed. "
85 "Provide --bar_id or let sway start swaybar"); 84 "Provide --bar_id or let sway start swaybar");
86 return 1; 85 return 1;
@@ -96,13 +95,12 @@ int main(int argc, char **argv) {
96 95
97 signal(SIGTERM, sig_handler); 96 signal(SIGTERM, sig_handler);
98 97
99 if (!bar_setup(&swaybar, socket_path, bar_id)) { 98 if (!bar_setup(&swaybar, socket_path)) {
100 free(socket_path); 99 free(socket_path);
101 return 1; 100 return 1;
102 } 101 }
103 102
104 free(socket_path); 103 free(socket_path);
105 free(bar_id);
106 104
107 bar_run(&swaybar); 105 bar_run(&swaybar);
108 bar_teardown(&swaybar); 106 bar_teardown(&swaybar);
diff --git a/swaybar/render.c b/swaybar/render.c
index dc31a5ea..097eb462 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -296,11 +296,15 @@ static uint32_t render_status_line(cairo_t *cairo,
296 296
297static uint32_t render_binding_mode_indicator(cairo_t *cairo, 297static uint32_t render_binding_mode_indicator(cairo_t *cairo,
298 struct swaybar_output *output, double x) { 298 struct swaybar_output *output, double x) {
299 const char *mode = output->bar->mode;
300 if (!mode) {
301 return 0;
302 }
303
299 struct swaybar_config *config = output->bar->config; 304 struct swaybar_config *config = output->bar->config;
300 const char *mode = config->mode;
301 int text_width, text_height; 305 int text_width, text_height;
302 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 306 get_text_size(cairo, config->font, &text_width, &text_height, NULL,
303 output->scale, config->mode_pango_markup, 307 output->scale, output->bar->mode_pango_markup,
304 "%s", mode); 308 "%s", mode);
305 309
306 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 310 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale;
@@ -333,8 +337,8 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
333 double text_y = height / 2.0 - text_height / 2.0; 337 double text_y = height / 2.0 - text_height / 2.0;
334 cairo_set_source_u32(cairo, config->colors.binding_mode.text); 338 cairo_set_source_u32(cairo, config->colors.binding_mode.text);
335 cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); 339 cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
336 pango_printf(cairo, config->font, output->scale, config->mode_pango_markup, 340 pango_printf(cairo, config->font, output->scale,
337 "%s", mode); 341 output->bar->mode_pango_markup, "%s", mode);
338 return output->height; 342 return output->height;
339} 343}
340 344
@@ -465,7 +469,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
465 max_height = h > max_height ? h : max_height; 469 max_height = h > max_height ? h : max_height;
466 } 470 }
467 } 471 }
468 if (config->binding_mode_indicator && config->mode) { 472 if (config->binding_mode_indicator) {
469 uint32_t h = render_binding_mode_indicator(cairo, output, x); 473 uint32_t h = render_binding_mode_indicator(cairo, output, x);
470 max_height = h > max_height ? h : max_height; 474 max_height = h > max_height ? h : max_height;
471 } 475 }
@@ -490,16 +494,12 @@ static const struct wl_callback_listener output_frame_listener = {
490 494
491void render_frame(struct swaybar_output *output) { 495void render_frame(struct swaybar_output *output) {
492 assert(output->surface != NULL); 496 assert(output->surface != NULL);
493 497 if (!output->layer_surface) {
494 struct swaybar_hotspot *hotspot, *tmp; 498 return;
495 wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) {
496 if (hotspot->destroy) {
497 hotspot->destroy(hotspot->data);
498 }
499 wl_list_remove(&hotspot->link);
500 free(hotspot);
501 } 499 }
502 500
501 free_hotspots(&output->hotspots);
502
503 cairo_surface_t *recorder = cairo_recording_surface_create( 503 cairo_surface_t *recorder = cairo_recording_surface_create(
504 CAIRO_CONTENT_COLOR_ALPHA, NULL); 504 CAIRO_CONTENT_COLOR_ALPHA, NULL);
505 cairo_t *cairo = cairo_create(recorder); 505 cairo_t *cairo = cairo_create(recorder);
@@ -519,10 +519,12 @@ void render_frame(struct swaybar_output *output) {
519 if (config_height >= 0 && height < (uint32_t)config_height) { 519 if (config_height >= 0 && height < (uint32_t)config_height) {
520 height = config_height; 520 height = config_height;
521 } 521 }
522 if (height != output->height) { 522 if (height != output->height || output->width == 0) {
523 // Reconfigure surface 523 // Reconfigure surface
524 zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height); 524 zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height);
525 zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height); 525 if (strcmp(output->bar->config->mode, "dock") == 0) {
526 zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height);
527 }
526 // TODO: this could infinite loop if the compositor assigns us a 528 // TODO: this could infinite loop if the compositor assigns us a
527 // different height than what we asked for 529 // different height than what we asked for
528 wl_surface_commit(output->surface); 530 wl_surface_commit(output->surface);
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index ed6dc7c8..000609ce 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -83,6 +83,17 @@ bool status_handle_readable(struct status_line *status) {
83 return true; 83 return true;
84 } 84 }
85 } 85 }
86
87 json_object *signal;
88 if (json_object_object_get_ex(header, "stop_signal", &signal)) {
89 status->stop_signal = json_object_get_int(signal);
90 wlr_log(WLR_DEBUG, "Setting stop signal to %d", status->stop_signal);
91 }
92 if (json_object_object_get_ex(header, "cont_signal", &signal)) {
93 status->cont_signal = json_object_get_int(signal);
94 wlr_log(WLR_DEBUG, "Setting cont signal to %d", status->cont_signal);
95 }
96
86 json_object_put(header); 97 json_object_put(header);
87 98
88 wl_list_init(&status->blocks); 99 wl_list_init(&status->blocks);
@@ -121,6 +132,9 @@ bool status_handle_readable(struct status_line *status) {
121 132
122struct status_line *status_line_init(char *cmd) { 133struct status_line *status_line_init(char *cmd) {
123 struct status_line *status = calloc(1, sizeof(struct status_line)); 134 struct status_line *status = calloc(1, sizeof(struct status_line));
135 status->stop_signal = SIGSTOP;
136 status->cont_signal = SIGCONT;
137
124 status->buffer_size = 8192; 138 status->buffer_size = 8192;
125 status->buffer = malloc(status->buffer_size); 139 status->buffer = malloc(status->buffer_size);
126 140