swaybar: handle mode/hidden_state changes

As well as adding the hidden_state property to the bar config struct,
this commit handles barconfig_update events when the mode or
hidden_state changes, and uses a new function determine_bar_visibility
to hide or show the bar as required, using, respectively,
destroy_layer_surface, which is also newly added, and add_layer_surface,
which has been changed to allow dynamically adding the surface.
This commit is contained in:
Ian Fan 2018-10-12 20:32:48 +01:00
parent 55ca16f2d8
commit bcc61e5147
6 changed files with 127 additions and 11 deletions

View file

@ -50,6 +50,11 @@ struct swaybar {
char *mode; char *mode;
bool mode_pango_markup; bool mode_pango_markup;
// only relevant when bar is in "hide" mode
bool visible_by_modifier;
bool visible_by_urgency;
bool visible;
struct wl_display *display; struct wl_display *display;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct zwlr_layer_shell_v1 *layer_shell; struct zwlr_layer_shell_v1 *layer_shell;
@ -104,6 +109,19 @@ bool bar_setup(struct swaybar *bar, const char *socket_path);
void bar_run(struct swaybar *bar); void bar_run(struct swaybar *bar);
void bar_teardown(struct swaybar *bar); void bar_teardown(struct swaybar *bar);
/*
* Determines whether the bar should be visible and changes it to be so.
* If the current visibility of the bar is the different to what it should be,
* then it adds or destroys the layer surface as required,
* as well as sending the cont or stop signal to the status command.
* If the current visibility of the bar is already what it should be,
* then this function is a no-op, unless moving_layer is true, which occurs
* when the bar changes from "hide" to "dock" mode or vice versa, and the bar
* needs to be destroyed and re-added in order to change its layer.
*
* Returns true if the bar is now visible, otherwise false.
*/
bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
void free_hotspots(struct wl_list *list); void free_hotspots(struct wl_list *list);
void free_workspaces(struct wl_list *list); void free_workspaces(struct wl_list *list);

View file

@ -31,6 +31,7 @@ struct swaybar_config {
char *font; char *font;
char *sep_symbol; char *sep_symbol;
char *mode; char *mode;
char *hidden_state;
bool strip_workspace_numbers; bool strip_workspace_numbers;
bool binding_mode_indicator; bool binding_mode_indicator;
bool wrap_scroll; bool wrap_scroll;

View file

@ -32,6 +32,7 @@
static void bar_init(struct swaybar *bar) { static void bar_init(struct swaybar *bar) {
bar->config = init_config(); bar->config = init_config();
bar->visible = true;
wl_list_init(&bar->outputs); wl_list_init(&bar->outputs);
} }
@ -338,21 +339,65 @@ const struct wl_seat_listener seat_listener = {
}; };
static void add_layer_surface(struct swaybar_output *output) { static void add_layer_surface(struct swaybar_output *output) {
if (output->surface != NULL) { if (output->layer_surface) {
return; return;
} }
struct swaybar *bar = output->bar; struct swaybar *bar = output->bar;
output->surface = wl_compositor_create_surface(bar->compositor); struct swaybar_config *config = bar->config;
assert(output->surface); bool hidden = strcmp(config->mode, "hide") == 0;
output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
bar->layer_shell, output->surface, output->output, bar->layer_shell, output->surface, output->output,
hidden ? ZWLR_LAYER_SHELL_V1_LAYER_TOP :
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
assert(output->layer_surface); assert(output->layer_surface);
zwlr_layer_surface_v1_add_listener(output->layer_surface, zwlr_layer_surface_v1_add_listener(output->layer_surface,
&layer_surface_listener, output); &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->height = 0;
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);
}
}
}
return visible;
} }
static bool bar_uses_output(struct swaybar *bar, const char *name) { static bool bar_uses_output(struct swaybar *bar, const char *name) {
@ -423,8 +468,11 @@ static void xdg_output_handle_done(void *data,
wl_list_remove(&output->link); wl_list_remove(&output->link);
wl_list_insert(&bar->outputs, &output->link); wl_list_insert(&bar->outputs, &output->link);
output->surface = wl_compositor_create_surface(bar->compositor);
assert(output->surface);
if (bar->visible) {
add_layer_surface(output); add_layer_surface(output);
set_output_dirty(output); }
} }
} }

View file

@ -30,7 +30,8 @@ struct swaybar_config *init_config(void) {
config->pango_markup = false; config->pango_markup = false;
config->position = parse_position("bottom"); config->position = parse_position("bottom");
config->font = strdup("monospace 10"); config->font = strdup("monospace 10");
config->mode = NULL; config->mode = strdup("dock");
config->hidden_state = strdup("hide");
config->sep_symbol = NULL; config->sep_symbol = NULL;
config->strip_workspace_numbers = false; config->strip_workspace_numbers = false;
config->binding_mode_indicator = true; config->binding_mode_indicator = true;
@ -84,6 +85,7 @@ void free_config(struct swaybar_config *config) {
free(config->status_command); free(config->status_command);
free(config->font); free(config->font);
free(config->mode); free(config->mode);
free(config->hidden_state);
free(config->sep_symbol); free(config->sep_symbol);
for (int i = 0; i < config->bindings->length; i++) { for (int i = 0; i < config->bindings->length; i++) {
struct swaybar_binding *binding = config->bindings->items[i]; struct swaybar_binding *binding = config->bindings->items[i];

View file

@ -152,12 +152,12 @@ static bool ipc_parse_config(
json_object_put(bar_config); json_object_put(bar_config);
return false; 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 *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers;
json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
json_object *bindings; json_object *bindings;
json_object_object_get_ex(bar_config, "mode", &mode); 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, "position", &position);
json_object_object_get_ex(bar_config, "status_command", &status_command); json_object_object_get_ex(bar_config, "status_command", &status_command);
json_object_object_get_ex(bar_config, "font", &font); json_object_object_get_ex(bar_config, "font", &font);
@ -220,6 +220,14 @@ static bool ipc_parse_config(
list_add(config->bindings, binding); 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; struct config_output *output, *tmp;
wl_list_for_each_safe(output, tmp, &config->outputs, link) { wl_list_for_each_safe(output, tmp, &config->outputs, link) {
@ -367,6 +375,37 @@ bool ipc_initialize(struct swaybar *bar) {
return true; return true;
} }
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) { bool handle_ipc_readable(struct swaybar *bar) {
struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
if (!resp) { if (!resp) {
@ -402,6 +441,9 @@ bool handle_ipc_readable(struct swaybar *bar) {
} }
break; break;
} }
case IPC_EVENT_BARCONFIG_UPDATE:
bar_is_dirty = handle_barconfig_update(bar, result);
break;
default: default:
bar_is_dirty = false; bar_is_dirty = false;
break; break;

View file

@ -494,6 +494,9 @@ static const struct wl_callback_listener output_frame_listener = {
void render_frame(struct swaybar_output *output) { void render_frame(struct swaybar_output *output) {
assert(output->surface != NULL); assert(output->surface != NULL);
if (!output->layer_surface) {
return;
}
free_hotspots(&output->hotspots); free_hotspots(&output->hotspots);
@ -519,7 +522,9 @@ void render_frame(struct swaybar_output *output) {
if (height != output->height) { if (height != output->height) {
// Reconfigure surface // Reconfigure surface
zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height); zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height);
if (strcmp(output->bar->config->mode, "dock") == 0) {
zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height); zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height);
}
// TODO: this could infinite loop if the compositor assigns us a // TODO: this could infinite loop if the compositor assigns us a
// different height than what we asked for // different height than what we asked for
wl_surface_commit(output->surface); wl_surface_commit(output->surface);