aboutsummaryrefslogtreecommitdiff
path: root/swaybar
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar')
-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
6 files changed, 214 insertions, 74 deletions
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 @@
static void bar_init(struct swaybar *bar) {
bar->config = init_config();
+ bar->visible = true;
wl_list_init(&bar->outputs);
}
+void free_hotspots(struct wl_list *list) {
+ struct swaybar_hotspot *hotspot, *tmp;
+ wl_list_for_each_safe(hotspot, tmp, list, link) {
+ wl_list_remove(&hotspot->link);
+ if (hotspot->destroy) {
+ hotspot->destroy(hotspot->data);
+ }
+ free(hotspot);
+ }
+}
+
void free_workspaces(struct wl_list *list) {
struct swaybar_workspace *ws, *tmp;
wl_list_for_each_safe(ws, tmp, list, link) {
@@ -59,14 +71,8 @@ static void swaybar_output_free(struct swaybar_output *output) {
wl_output_destroy(output->output);
destroy_buffer(&output->buffers[0]);
destroy_buffer(&output->buffers[1]);
+ free_hotspots(&output->hotspots);
free_workspaces(&output->workspaces);
- struct swaybar_hotspot *hotspot, *hotspot_tmp;
- wl_list_for_each_safe(hotspot, hotspot_tmp, &output->hotspots, link) {
- if (hotspot->destroy) {
- hotspot->destroy(hotspot->data);
- }
- free(hotspot);
- }
wl_list_remove(&output->link);
free(output->name);
free(output);
@@ -75,9 +81,7 @@ static void swaybar_output_free(struct swaybar_output *output) {
static void set_output_dirty(struct swaybar_output *output) {
if (output->frame_scheduled) {
output->dirty = true;
- return;
- }
- if (output->surface) {
+ } else if (output->surface) {
render_frame(output);
}
}
@@ -335,21 +339,68 @@ const struct wl_seat_listener seat_listener = {
};
static void add_layer_surface(struct swaybar_output *output) {
- if (output->surface != NULL) {
+ if (output->layer_surface) {
return;
}
struct swaybar *bar = output->bar;
- output->surface = wl_compositor_create_surface(bar->compositor);
- assert(output->surface);
+ struct swaybar_config *config = bar->config;
+ bool hidden = strcmp(config->mode, "hide") == 0;
output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
bar->layer_shell, output->surface, output->output,
+ hidden ? ZWLR_LAYER_SHELL_V1_LAYER_TOP :
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
assert(output->layer_surface);
zwlr_layer_surface_v1_add_listener(output->layer_surface,
&layer_surface_listener, output);
- zwlr_layer_surface_v1_set_anchor(output->layer_surface,
- bar->config->position);
+
+ zwlr_layer_surface_v1_set_anchor(output->layer_surface, config->position);
+ if (hidden) {
+ zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1);
+ }
+}
+
+static void destroy_layer_surface(struct swaybar_output *output) {
+ if (!output->layer_surface) {
+ return;
+ }
+ zwlr_layer_surface_v1_destroy(output->layer_surface);
+ wl_surface_attach(output->surface, NULL, 0, 0); // detach buffer
+ output->layer_surface = NULL;
+ output->width = 0;
+ output->frame_scheduled = false;
+}
+
+bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) {
+ struct swaybar_config *config = bar->config;
+ bool visible = !(strcmp(config->mode, "invisible") == 0 ||
+ (strcmp(config->mode, config->hidden_state) == 0 // both "hide"
+ && !bar->visible_by_modifier && !bar->visible_by_urgency));
+
+ struct swaybar_output *output;
+ if (visible == bar->visible) {
+ if (visible && moving_layer) {
+ // need to destroy layer surface to move to a different layer
+ wl_list_for_each(output, &bar->outputs, link) {
+ destroy_layer_surface(output);
+ add_layer_surface(output);
+ }
+ }
+ } else {
+ bar->visible = visible;
+ wl_list_for_each(output, &bar->outputs, link) {
+ if (visible) {
+ add_layer_surface(output);
+ } else {
+ destroy_layer_surface(output);
+ }
+ }
+ wlr_log(WLR_DEBUG, "Sending %s signal to status command",
+ visible ? "cont" : "stop");
+ kill(bar->status->pid,
+ visible ? bar->status->cont_signal : bar->status->stop_signal);
+ }
+ return visible;
}
static bool bar_uses_output(struct swaybar *bar, const char *name) {
@@ -420,8 +471,11 @@ static void xdg_output_handle_done(void *data,
wl_list_remove(&output->link);
wl_list_insert(&bar->outputs, &output->link);
- add_layer_surface(output);
- set_output_dirty(output);
+ output->surface = wl_compositor_create_surface(bar->compositor);
+ assert(output->surface);
+ if (bar->visible) {
+ add_layer_surface(output);
+ }
}
}
@@ -517,14 +571,13 @@ static void set_bar_dirty(struct swaybar *bar) {
}
}
-bool bar_setup(struct swaybar *bar,
- const char *socket_path, const char *bar_id) {
+bool bar_setup(struct swaybar *bar, const char *socket_path) {
bar_init(bar);
init_event_loop();
bar->ipc_socketfd = ipc_open_socket(socket_path);
bar->ipc_event_socketfd = ipc_open_socket(socket_path);
- if (!ipc_initialize(bar, bar_id)) {
+ if (!ipc_initialize(bar)) {
return false;
}
if (bar->config->status_command) {
@@ -565,8 +618,11 @@ bool bar_setup(struct swaybar *bar,
pointer->cursor_surface = wl_compositor_create_surface(bar->compositor);
assert(pointer->cursor_surface);
- ipc_get_workspaces(bar);
- set_bar_dirty(bar);
+ if (bar->config->workspace_buttons) {
+ if (ipc_get_workspaces(bar)) {
+ set_bar_dirty(bar);
+ }
+ }
return true;
}
@@ -625,4 +681,6 @@ void bar_teardown(struct swaybar *bar) {
if (bar->status) {
status_line_free(bar->status);
}
+ free(bar->id);
+ free(bar->mode);
}
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) {
config->pango_markup = false;
config->position = parse_position("bottom");
config->font = strdup("monospace 10");
- config->mode = NULL;
+ config->mode = strdup("dock");
+ config->hidden_state = strdup("hide");
config->sep_symbol = NULL;
config->strip_workspace_numbers = false;
config->binding_mode_indicator = true;
@@ -84,6 +85,7 @@ void free_config(struct swaybar_config *config) {
free(config->status_command);
free(config->font);
free(config->mode);
+ free(config->hidden_state);
free(config->sep_symbol);
for (int i = 0; i < config->bindings->length; i++) {
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(
json_object_put(bar_config);
return false;
}
- json_object *markup, *mode, *hidden_bar, *position, *status_command;
+ json_object *markup, *mode, *hidden_state, *position, *status_command;
json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers;
json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
json_object *bindings;
json_object_object_get_ex(bar_config, "mode", &mode);
- json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar);
+ json_object_object_get_ex(bar_config, "hidden_state", &hidden_state);
json_object_object_get_ex(bar_config, "position", &position);
json_object_object_get_ex(bar_config, "status_command", &status_command);
json_object_object_get_ex(bar_config, "font", &font);
@@ -220,6 +220,14 @@ static bool ipc_parse_config(
list_add(config->bindings, binding);
}
}
+ if (hidden_state) {
+ free(config->hidden_state);
+ config->hidden_state = strdup(json_object_get_string(hidden_state));
+ }
+ if (mode) {
+ free(config->mode);
+ config->mode = strdup(json_object_get_string(mode));
+ }
struct config_output *output, *tmp;
wl_list_for_each_safe(output, tmp, &config->outputs, link) {
@@ -254,7 +262,7 @@ static bool ipc_parse_config(
return true;
}
-void ipc_get_workspaces(struct swaybar *bar) {
+bool ipc_get_workspaces(struct swaybar *bar) {
struct swaybar_output *output;
wl_list_for_each(output, &bar->outputs, link) {
free_workspaces(&output->workspaces);
@@ -266,8 +274,10 @@ void ipc_get_workspaces(struct swaybar *bar) {
json_object *results = json_tokener_parse(res);
if (!results) {
free(res);
- return;
+ return false;
}
+
+ bar->visible_by_urgency = false;
size_t length = json_object_array_length(results);
json_object *ws_json;
json_object *num, *name, *visible, *focused, *out, *urgent;
@@ -294,12 +304,16 @@ void ipc_get_workspaces(struct swaybar *bar) {
output->focused = true;
}
ws->urgent = json_object_get_boolean(urgent);
+ if (ws->urgent) {
+ bar->visible_by_urgency = true;
+ }
wl_list_insert(&output->workspaces, &ws->link);
}
}
}
json_object_put(results);
free(res);
+ return determine_bar_visibility(bar, false);
}
static void ipc_get_outputs(struct swaybar *bar) {
@@ -345,10 +359,10 @@ void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) {
IPC_COMMAND, bind->command, &len));
}
-bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
- uint32_t len = strlen(bar_id);
+bool ipc_initialize(struct swaybar *bar) {
+ uint32_t len = strlen(bar->id);
char *res = ipc_single_command(bar->ipc_socketfd,
- IPC_GET_BAR_CONFIG, bar_id, &len);
+ IPC_GET_BAR_CONFIG, bar->id, &len);
if (!ipc_parse_config(bar->config, res)) {
free(res);
return false;
@@ -356,56 +370,108 @@ bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
free(res);
ipc_get_outputs(bar);
- const char *subscribe = "[ \"workspace\", \"mode\" ]";
- len = strlen(subscribe);
+ struct swaybar_config *config = bar->config;
+ char subscribe[128]; // suitably large buffer
+ len = snprintf(subscribe, 128,
+ "[ \"barconfig_update\" , \"bar_state_update\" %s %s ]",
+ config->binding_mode_indicator ? ", \"mode\"" : "",
+ config->workspace_buttons ? ", \"workspace\"" : "");
free(ipc_single_command(bar->ipc_event_socketfd,
IPC_SUBSCRIBE, subscribe, &len));
return true;
}
+static bool handle_bar_state_update(struct swaybar *bar, json_object *event) {
+ json_object *json_id;
+ json_object_object_get_ex(event, "id", &json_id);
+ const char *id = json_object_get_string(json_id);
+ if (strcmp(id, bar->id) != 0) {
+ return false;
+ }
+
+ json_object *visible_by_modifier;
+ json_object_object_get_ex(event, "visible_by_modifier", &visible_by_modifier);
+ bar->visible_by_modifier = json_object_get_boolean(visible_by_modifier);
+ return determine_bar_visibility(bar, false);
+}
+
+static bool handle_barconfig_update(struct swaybar *bar,
+ json_object *json_config) {
+ json_object *json_id;
+ json_object_object_get_ex(json_config, "id", &json_id);
+ const char *id = json_object_get_string(json_id);
+ if (strcmp(id, bar->id) != 0) {
+ return false;
+ }
+
+ struct swaybar_config *config = bar->config;
+
+ json_object *json_state;
+ json_object_object_get_ex(json_config, "hidden_state", &json_state);
+ const char *new_state = json_object_get_string(json_state);
+ char *old_state = config->hidden_state;
+ if (strcmp(new_state, old_state) != 0) {
+ wlr_log(WLR_DEBUG, "Changing bar hidden state to %s", new_state);
+ free(old_state);
+ config->hidden_state = strdup(new_state);
+ return determine_bar_visibility(bar, false);
+ }
+
+ free(config->mode);
+ json_object *json_mode;
+ json_object_object_get_ex(json_config, "mode", &json_mode);
+ config->mode = strdup(json_object_get_string(json_mode));
+ wlr_log(WLR_DEBUG, "Changing bar mode to %s", config->mode);
+
+ return determine_bar_visibility(bar, true);
+}
+
bool handle_ipc_readable(struct swaybar *bar) {
struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
if (!resp) {
return false;
}
+
+ json_object *result = json_tokener_parse(resp->payload);
+ if (!result) {
+ wlr_log(WLR_ERROR, "failed to parse payload as json");
+ free_ipc_response(resp);
+ return false;
+ }
+
+ bool bar_is_dirty = true;
switch (resp->type) {
case IPC_EVENT_WORKSPACE:
- ipc_get_workspaces(bar);
+ bar_is_dirty = ipc_get_workspaces(bar);
break;
case IPC_EVENT_MODE: {
- json_object *result = json_tokener_parse(resp->payload);
- if (!result) {
- free_ipc_response(resp);
- wlr_log(WLR_ERROR, "failed to parse payload as json");
- return false;
- }
json_object *json_change, *json_pango_markup;
if (json_object_object_get_ex(result, "change", &json_change)) {
const char *change = json_object_get_string(json_change);
- free(bar->config->mode);
- if (strcmp(change, "default") == 0) {
- bar->config->mode = NULL;
- } else {
- bar->config->mode = strdup(change);
- }
+ free(bar->mode);
+ bar->mode = strcmp(change, "default") != 0 ? strdup(change) : NULL;
} else {
wlr_log(WLR_ERROR, "failed to parse response");
- json_object_put(result);
- free_ipc_response(resp);
- return false;
+ bar_is_dirty = false;
+ break;
}
if (json_object_object_get_ex(result,
"pango_markup", &json_pango_markup)) {
- bar->config->mode_pango_markup = json_object_get_boolean(
- json_pango_markup);
+ bar->mode_pango_markup = json_object_get_boolean(json_pango_markup);
}
- json_object_put(result);
break;
}
+ case IPC_EVENT_BARCONFIG_UPDATE:
+ bar_is_dirty = handle_barconfig_update(bar, result);
+ break;
+ case IPC_EVENT_BAR_STATE_UPDATE:
+ bar_is_dirty = handle_bar_state_update(bar, result);
+ break;
default:
- free_ipc_response(resp);
- return false;
+ bar_is_dirty = false;
+ break;
}
+ json_object_put(result);
free_ipc_response(resp);
- return true;
+ return bar_is_dirty;
}
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) {
int main(int argc, char **argv) {
char *socket_path = NULL;
- char *bar_id = NULL;
bool debug = false;
static struct option long_options[] = {
@@ -59,7 +58,7 @@ int main(int argc, char **argv) {
socket_path = strdup(optarg);
break;
case 'b': // Type
- bar_id = strdup(optarg);
+ swaybar.id = strdup(optarg);
break;
case 'v':
fprintf(stdout, "swaybar version " SWAY_VERSION "\n");
@@ -80,7 +79,7 @@ int main(int argc, char **argv) {
wlr_log_init(WLR_ERROR, NULL);
}
- if (!bar_id) {
+ if (!swaybar.id) {
wlr_log(WLR_ERROR, "No bar_id passed. "
"Provide --bar_id or let sway start swaybar");
return 1;
@@ -96,13 +95,12 @@ int main(int argc, char **argv) {
signal(SIGTERM, sig_handler);
- if (!bar_setup(&swaybar, socket_path, bar_id)) {
+ if (!bar_setup(&swaybar, socket_path)) {
free(socket_path);
return 1;
}
free(socket_path);
- free(bar_id);
bar_run(&swaybar);
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,
static uint32_t render_binding_mode_indicator(cairo_t *cairo,
struct swaybar_output *output, double x) {
+ const char *mode = output->bar->mode;
+ if (!mode) {
+ return 0;
+ }
+
struct swaybar_config *config = output->bar->config;
- const char *mode = config->mode;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
- output->scale, config->mode_pango_markup,
+ output->scale, output->bar->mode_pango_markup,
"%s", mode);
int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale;
@@ -333,8 +337,8 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
double text_y = height / 2.0 - text_height / 2.0;
cairo_set_source_u32(cairo, config->colors.binding_mode.text);
cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
- pango_printf(cairo, config->font, output->scale, config->mode_pango_markup,
- "%s", mode);
+ pango_printf(cairo, config->font, output->scale,
+ output->bar->mode_pango_markup, "%s", mode);
return output->height;
}
@@ -465,7 +469,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
max_height = h > max_height ? h : max_height;
}
}
- if (config->binding_mode_indicator && config->mode) {
+ if (config->binding_mode_indicator) {
uint32_t h = render_binding_mode_indicator(cairo, output, x);
max_height = h > max_height ? h : max_height;
}
@@ -490,16 +494,12 @@ static const struct wl_callback_listener output_frame_listener = {
void render_frame(struct swaybar_output *output) {
assert(output->surface != NULL);
-
- struct swaybar_hotspot *hotspot, *tmp;
- wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) {
- if (hotspot->destroy) {
- hotspot->destroy(hotspot->data);
- }
- wl_list_remove(&hotspot->link);
- free(hotspot);
+ if (!output->layer_surface) {
+ return;
}
+ free_hotspots(&output->hotspots);
+
cairo_surface_t *recorder = cairo_recording_surface_create(
CAIRO_CONTENT_COLOR_ALPHA, NULL);
cairo_t *cairo = cairo_create(recorder);
@@ -519,10 +519,12 @@ void render_frame(struct swaybar_output *output) {
if (config_height >= 0 && height < (uint32_t)config_height) {
height = config_height;
}
- if (height != output->height) {
+ if (height != output->height || output->width == 0) {
// Reconfigure surface
zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height);
- zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height);
+ if (strcmp(output->bar->config->mode, "dock") == 0) {
+ zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height);
+ }
// TODO: this could infinite loop if the compositor assigns us a
// different height than what we asked for
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) {
return true;
}
}
+
+ json_object *signal;
+ if (json_object_object_get_ex(header, "stop_signal", &signal)) {
+ status->stop_signal = json_object_get_int(signal);
+ wlr_log(WLR_DEBUG, "Setting stop signal to %d", status->stop_signal);
+ }
+ if (json_object_object_get_ex(header, "cont_signal", &signal)) {
+ status->cont_signal = json_object_get_int(signal);
+ wlr_log(WLR_DEBUG, "Setting cont signal to %d", status->cont_signal);
+ }
+
json_object_put(header);
wl_list_init(&status->blocks);
@@ -121,6 +132,9 @@ bool status_handle_readable(struct status_line *status) {
struct status_line *status_line_init(char *cmd) {
struct status_line *status = calloc(1, sizeof(struct status_line));
+ status->stop_signal = SIGSTOP;
+ status->cont_signal = SIGCONT;
+
status->buffer_size = 8192;
status->buffer = malloc(status->buffer_size);