diff --git a/include/sway/config.h b/include/sway/config.h index 35f8d5f7e..06df00f90 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -110,7 +110,7 @@ struct bar_config { * Always visible in dock mode. Visible only when modifier key is held in hide mode. * Never visible in invisible mode. */ - char *mode; + char *display_mode; /** * One of "show" or "hide". * @@ -225,9 +225,10 @@ enum ipc_feature { IPC_FEATURE_EVENT_WINDOW = 2048, IPC_FEATURE_EVENT_BINDING = 4096, IPC_FEATURE_EVENT_INPUT = 8192, + IPC_FEATURE_EVENT_MODIFIER = 16384, IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, - IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, + IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192 | 16384, IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS, }; diff --git a/include/sway/extensions.h b/include/sway/extensions.h index f6b0c00ec..e1fbbb9f6 100644 --- a/include/sway/extensions.h +++ b/include/sway/extensions.h @@ -27,6 +27,9 @@ struct panel_config { struct wl_client *client; // wlc handle for this panel's surface, not set until panel is created wlc_handle handle; + + enum desktop_shell_hide_modes hide_mode; + enum desktop_shell_hide_state hide; }; struct desktop_shell_state { diff --git a/include/swaybar/config.h b/include/swaybar/config.h index 04b12cd4b..e2653c37c 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h @@ -16,6 +16,17 @@ struct box_colors { uint32_t text; }; +enum display_mode_types { + MODE_HIDE, + MODE_DOCK, + MODE_INVISIBLE +}; + +enum hidden_states { + BAR_HIDDEN, + BAR_SHOW +}; + /** * Swaybar config. */ @@ -26,6 +37,8 @@ struct config { char *font; char *sep_symbol; char *mode; + enum display_mode_types display_mode; + enum hidden_states hidden_state; bool strip_workspace_numbers; bool binding_mode_indicator; bool wrap_scroll; @@ -62,6 +75,16 @@ uint32_t parse_position(const char *position); */ char *parse_font(const char *font); +/** + * Parse display mode dock|hide|invisible. + */ +enum display_mode_types parse_display_mode(const char *display_mode); + +/** + * Parse hidden state show|hide. + */ +enum hidden_states parse_hidden_state(const char *hidden_state); + /** * Initialize default sway config. */ diff --git a/protocols/desktop-shell.xml b/protocols/desktop-shell.xml index 581f0c5d3..1b2f8b30d 100644 --- a/protocols/desktop-shell.xml +++ b/protocols/desktop-shell.xml @@ -116,6 +116,32 @@ + + + + + + + + + + + + + + Tell the shell whether or not panel is in hide mode + i.e. whether to allocate a fixed amount of space + for the panel (hide mode false) or not (hide mode true) + + + + + + + Tell the shell whether or not panel is currently hidden + + + diff --git a/security.d/00-defaults.in b/security.d/00-defaults.in index 05098dea0..e9bdbb3d1 100644 --- a/security.d/00-defaults.in +++ b/security.d/00-defaults.in @@ -33,6 +33,7 @@ ipc __PREFIX__/bin/swaybar { events { workspace enabled mode enabled + modifier enabled } } diff --git a/sway/commands.c b/sway/commands.c index 342184914..0eca5f1b6 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -322,6 +322,7 @@ static struct cmd_handler ipc_event_handlers[] = { { "binding", cmd_ipc_event_cmd }, { "input", cmd_ipc_event_cmd }, { "mode", cmd_ipc_event_cmd }, + { "modifier", cmd_ipc_event_cmd }, { "output", cmd_ipc_event_cmd }, { "window", cmd_ipc_event_cmd }, { "workspace", cmd_ipc_event_cmd }, diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c index 36816b939..9ba9a1487 100644 --- a/sway/commands/bar/mode.c +++ b/sway/commands/bar/mode.c @@ -7,31 +7,31 @@ #include "log.h" static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode) { - char *old_mode = bar->mode; + char *old_mode = bar->display_mode; if (strcasecmp("toggle", mode) == 0 && !config->reading) { - if (strcasecmp("dock", bar->mode) == 0) { - bar->mode = strdup("hide"); - } else if (strcasecmp("hide", bar->mode) == 0) { - bar->mode = strdup("dock"); + if (strcasecmp("dock", bar->display_mode) == 0) { + bar->display_mode = strdup("hide"); + } else if (strcasecmp("hide", bar->display_mode) == 0) { + bar->display_mode = strdup("dock"); } } else if (strcasecmp("dock", mode) == 0) { - bar->mode = strdup("dock"); + bar->display_mode = strdup("dock"); } else if (strcasecmp("hide", mode) == 0) { - bar->mode = strdup("hide"); + bar->display_mode = strdup("hide"); } else if (strcasecmp("invisible", mode) == 0) { - bar->mode = strdup("invisible"); + bar->display_mode = strdup("invisible"); } else { return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode); } - if (strcmp(old_mode, bar->mode) != 0) { + if (strcmp(old_mode, bar->display_mode) != 0) { if (!config->reading) { ipc_event_barconfig_update(bar); // active bar modifiers might have changed. update_active_bar_modifiers(); } - sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); + sway_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->display_mode, bar->id); } // free old mode diff --git a/sway/commands/ipc.c b/sway/commands/ipc.c index f0b3035af..3c1add315 100644 --- a/sway/commands/ipc.c +++ b/sway/commands/ipc.c @@ -138,6 +138,7 @@ struct cmd_results *cmd_ipc_event_cmd(int argc, char **argv) { { "window", IPC_FEATURE_EVENT_WINDOW }, { "binding", IPC_FEATURE_EVENT_BINDING }, { "input", IPC_FEATURE_EVENT_INPUT }, + { "modifier", IPC_FEATURE_EVENT_MODIFIER } }; uint32_t type = 0; diff --git a/sway/config.c b/sway/config.c index 85823953c..8ccdd4732 100644 --- a/sway/config.c +++ b/sway/config.c @@ -67,7 +67,7 @@ static void free_bar(struct bar_config *bar) { if (!bar) { return; } - free(bar->mode); + free(bar->display_mode); free(bar->hidden_state); free(bar->status_command); free(bar->font); @@ -414,7 +414,7 @@ void update_active_bar_modifiers() { int i; for (i = 0; i < config->bars->length; ++i) { bar = config->bars->items[i]; - if (strcmp(bar->mode, "hide") == 0 && strcmp(bar->hidden_state, "hide") == 0) { + if (strcmp(bar->display_mode, "hide") == 0 && strcmp(bar->hidden_state, "hide") == 0) { if (list_seq_find(config->active_bar_modifiers, compare_modifiers, &bar->modifier) < 0) { list_add(config->active_bar_modifiers, &bar->modifier); } @@ -1370,7 +1370,7 @@ struct bar_config *default_bar_config(void) { if (!bar) { return NULL; } - if (!(bar->mode = strdup("dock"))) goto cleanup; + if (!(bar->display_mode = strdup("dock"))) goto cleanup; if (!(bar->hidden_state = strdup("hide"))) goto cleanup; bar->modifier = WLC_BIT_MOD_LOGO; bar->outputs = NULL; diff --git a/sway/extensions.c b/sway/extensions.c index 96957dbff..89afb8484 100644 --- a/sway/extensions.c +++ b/sway/extensions.c @@ -133,6 +133,34 @@ static void set_panel(struct wl_client *client, struct wl_resource *resource, wlc_output_schedule_render(config->output); } +static void set_panel_hide_mode(struct wl_client *client, struct wl_resource *resource, + uint32_t mode) { + struct panel_config *config = find_or_create_panel_config(resource); + config->hide_mode = mode; + if (mode == 0) { + wlc_view_set_mask(wlc_handle_from_wl_surface_resource(config->wl_surface_res), false); + } else { + wlc_view_set_mask(wlc_handle_from_wl_surface_resource(config->wl_surface_res), true); + } + arrange_windows(&root_container, -1, -1); + wlc_output_schedule_render(config->output); +} + +static void set_panel_hide(struct wl_client *client, struct wl_resource *resource, + uint32_t hide) { + sway_log(L_ERROR, "Attempting to find panel %p", resource); + struct panel_config *config = find_or_create_panel_config(resource); + config->hide = hide; + if (hide == 0) { + sway_log(L_ERROR, "Hiding panel %p", resource); + wlc_view_set_mask(wlc_handle_from_wl_surface_resource(config->wl_surface_res), false); + } else if (hide == 1) { + sway_log(L_ERROR, "Showing panel %p", resource); + wlc_view_set_mask(wlc_handle_from_wl_surface_resource(config->wl_surface_res), true); + } + wlc_output_schedule_render(config->output); +} + static void desktop_set_lock_surface(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) { sway_log(L_ERROR, "desktop_set_lock_surface is not currently supported"); } @@ -169,7 +197,9 @@ static struct desktop_shell_interface desktop_shell_implementation = { .unlock = desktop_unlock, .set_grab_surface = set_grab_surface, .desktop_ready = desktop_ready, - .set_panel_position = set_panel_position + .set_panel_position = set_panel_position, + .set_panel_hide_mode = set_panel_hide_mode, + .set_panel_hide = set_panel_hide }; static void desktop_shell_bind(struct wl_client *client, void *data, diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 512144a4a..f0edff5e7 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -328,7 +328,7 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { json_object *json = json_object_new_object(); json_object_object_add(json, "id", json_object_new_string(bar->id)); json_object_object_add(json, "tray_output", NULL); - json_object_object_add(json, "mode", json_object_new_string(bar->mode)); + json_object_object_add(json, "mode", json_object_new_string(bar->display_mode)); json_object_object_add(json, "hidden_state", json_object_new_string(bar->hidden_state)); json_object_object_add(json, "modifier", json_object_new_string(get_modifier_name_by_mask(bar->modifier))); switch (bar->position) { diff --git a/sway/ipc-server.c b/sway/ipc-server.c index dca881fa5..66895a87c 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -643,7 +643,8 @@ void ipc_send_event(const char *json_string, enum ipc_command_type event) { { IPC_EVENT_MODE, IPC_FEATURE_EVENT_MODE }, { IPC_EVENT_WINDOW, IPC_FEATURE_EVENT_WINDOW }, { IPC_EVENT_BINDING, IPC_FEATURE_EVENT_BINDING }, - { IPC_EVENT_INPUT, IPC_FEATURE_EVENT_INPUT } + { IPC_EVENT_INPUT, IPC_FEATURE_EVENT_INPUT }, + { IPC_EVENT_MODIFIER, IPC_FEATURE_EVENT_MODIFIER} }; uint32_t security_mask = 0; diff --git a/sway/layout.c b/sway/layout.c index 69291dafd..f61402afd 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -1006,19 +1006,21 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { if (config->output == output->handle) { struct wlc_size size = *wlc_surface_get_size(config->surface); sway_log(L_DEBUG, "-> Found panel for this workspace: %ux%u, position: %u", size.w, size.h, config->panel_position); - switch (config->panel_position) { - case DESKTOP_SHELL_PANEL_POSITION_TOP: - y += size.h; height -= size.h; - break; - case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: - height -= size.h; - break; - case DESKTOP_SHELL_PANEL_POSITION_LEFT: - x += size.w; width -= size.w; - break; - case DESKTOP_SHELL_PANEL_POSITION_RIGHT: - width -= size.w; - break; + if (config->hide_mode == DESKTOP_SHELL_HIDE_MODES_SHOW) { + switch (config->panel_position) { + case DESKTOP_SHELL_PANEL_POSITION_TOP: + y += size.h; height -= size.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: + height -= size.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_LEFT: + x += size.w; width -= size.w; + break; + case DESKTOP_SHELL_PANEL_POSITION_RIGHT: + width -= size.w; + break; + } } } } diff --git a/swaybar/bar.c b/swaybar/bar.c index 5ed0d266b..50cef9605 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -164,6 +164,15 @@ void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { output->output, bar_output->window->surface); desktop_shell_set_panel_position(bar_output->registry->desktop_shell, bar->config->position); + switch (bar->config->display_mode) { + case MODE_HIDE: + case MODE_INVISIBLE: + desktop_shell_set_panel_hide_mode(bar_output->registry->desktop_shell, DESKTOP_SHELL_HIDE_MODES_HIDE); + break; + case MODE_DOCK: + desktop_shell_set_panel_hide_mode(bar_output->registry->desktop_shell, DESKTOP_SHELL_HIDE_MODES_SHOW); + break; + } window_make_shell(bar_output->window); diff --git a/swaybar/config.c b/swaybar/config.c index 1d8020223..38704a4ea 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -30,6 +30,28 @@ char *parse_font(const char *font) { return new_font; } +enum display_mode_types parse_display_mode(const char *display_mode) { + if (strcmp("hide", display_mode) == 0) { + return MODE_HIDE; + } else if (strcmp("dock", display_mode) == 0) { + return MODE_DOCK; + } else if (strcmp("invisible", display_mode) == 0) { + return MODE_INVISIBLE; + } else { + return MODE_DOCK; + } +} + +enum hidden_states parse_hidden_state(const char *hidden_state) { + if (strcmp("show", hidden_state) == 0) { + return BAR_SHOW; + } else if (strcmp("hide", hidden_state) == 0) { + return BAR_HIDDEN; + } else { + return BAR_SHOW; + } +} + struct config *init_config() { struct config *config = calloc(1, sizeof(struct config)); config->status_command = NULL; @@ -37,6 +59,8 @@ struct config *init_config() { config->position = DESKTOP_SHELL_PANEL_POSITION_BOTTOM; config->font = strdup("monospace 10"); config->mode = NULL; + config->display_mode = MODE_DOCK; + config->hidden_state = BAR_SHOW; config->sep_symbol = NULL; config->strip_workspace_numbers = false; config->binding_mode_indicator = true; diff --git a/swaybar/ipc.c b/swaybar/ipc.c index b08eeea89..34a9abe99 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -7,6 +7,7 @@ #include "ipc-client.h" #include "list.h" #include "log.h" +#include "util.h" void ipc_send_workspace_command(const char *workspace_name) { uint32_t size = strlen("workspace \"\"") + strlen(workspace_name) + 1; @@ -19,13 +20,15 @@ void ipc_send_workspace_command(const char *workspace_name) { static void ipc_parse_config(struct config *config, const char *payload) { json_object *bar_config = json_tokener_parse(payload); - json_object *tray_output, *mode, *hidden_bar, *position, *status_command; + json_object *tray_output, *display_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 *markup; json_object_object_get_ex(bar_config, "tray_output", &tray_output); - json_object_object_get_ex(bar_config, "mode", &mode); - json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar); + // "mode" as in the bar's display mode and "mode" as in binding mode + // should be distinguished more carefully + json_object_object_get_ex(bar_config, "mode", &display_mode); + 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); @@ -44,6 +47,14 @@ static void ipc_parse_config(struct config *config, const char *payload) { free(config->status_command); config->status_command = strdup(json_object_get_string(status_command)); } + + if (display_mode) { + config->display_mode = parse_display_mode(strdup(json_object_get_string(display_mode))); + } + + if (hidden_state) { + config->hidden_state = parse_hidden_state(strdup(json_object_get_string(hidden_state))); + } if (position) { config->position = parse_position(json_object_get_string(position)); @@ -322,10 +333,17 @@ void ipc_bar_init(struct bar *bar, const char *bar_id) { } free(res); json_object_put(outputs); - - const char *subscribe_json = "[ \"workspace\", \"mode\" ]"; - len = strlen(subscribe_json); - res = ipc_single_command(bar->ipc_event_socketfd, IPC_SUBSCRIBE, subscribe_json, &len); + // Will need to be redone for display mode toggling compatibility + // Will require setting bar->config->hidden_state to "show" as default + json_object *subscribe_json = json_object_new_array(); + json_object_array_add(subscribe_json, json_object_new_string("workspace")); + json_object_array_add(subscribe_json, json_object_new_string("mode")); + if (bar->config->display_mode == MODE_HIDE) { + json_object_array_add(subscribe_json, json_object_new_string("modifier")); + } + const char *subscribe_json_string = json_object_to_json_string(subscribe_json); + len = strlen(subscribe_json_string); + res = ipc_single_command(bar->ipc_event_socketfd, IPC_SUBSCRIBE, subscribe_json_string, &len); free(res); ipc_update_workspaces(bar); @@ -364,6 +382,44 @@ bool handle_ipc_event(struct bar *bar) { json_object_put(result); break; } + case IPC_EVENT_MODIFIER: { + if (bar->config->display_mode == MODE_HIDE) { + json_object *result = json_tokener_parse(resp->payload); + if (!result) { + free_ipc_response(resp); + sway_log(L_ERROR, "failed to parse payload as json"); + return false; + } + json_object *json_change; + if (json_object_object_get_ex(result, "change", &json_change)) { + const char *change = json_object_get_string(json_change); + if (strcmp(change, "pressed") == 0) { + bar->config->hidden_state = BAR_SHOW; + sway_log(L_ERROR, "Showing bar on %d outputs", bar->outputs->length); + int i; + for (i = 0; i < bar->outputs->length; ++i) { + struct output *bar_output = bar->outputs->items[i]; + sway_log(L_ERROR, "showing bar on input %d, with registry %p", i, bar_output->registry); + desktop_shell_set_panel_hide(bar_output->registry->desktop_shell, DESKTOP_SHELL_HIDE_STATE_SHOW); + } + } else { //must be "released" + bar->config->hidden_state = BAR_HIDDEN; + sway_log(L_ERROR, "Hiding bar"); + int i; + for (i = 0; i < bar->outputs->length; ++i) { + struct output *bar_output = bar->outputs->items[i]; + desktop_shell_set_panel_hide(bar_output->registry->desktop_shell, DESKTOP_SHELL_HIDE_STATE_HIDE); + } + } + + } else { + sway_log(L_ERROR, "failed to parse response"); + } + + json_object_put(result); + break; + } + } default: free_ipc_response(resp); return false; diff --git a/swaybar/render.c b/swaybar/render.c index 2eae997fc..2b53aa453 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -286,9 +286,8 @@ void render(struct output *output, struct config *config, struct status_line *li cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); cairo_paint(cairo); cairo_restore(cairo); - cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); - + // Background if (is_focused) { cairo_set_source_u32(cairo, config->colors.focused_background);