From 8a7bb48e75885cbb7c2dcc27ba3f3eb9b49620de Mon Sep 17 00:00:00 2001 From: Erik Reider Date: Tue, 2 May 2023 18:12:01 +0200 Subject: [PATCH] Made layer_effects syntax similar to the for_window command Example: `layer_effects "waybar" blur on; shadows on; corner_radius 6`. --- README.md | 7 +- include/sway/commands.h | 7 ++ include/sway/config.h | 5 +- .../sway/desktop/fx_renderer/fx_renderer.h | 12 +++ sway/commands/blur.c | 6 +- sway/commands/corner_radius.c | 15 +++- sway/commands/layer_effects.c | 79 +++++++++++++++---- sway/commands/shadows.c | 6 +- sway/desktop/output.c | 7 +- sway/desktop/render.c | 17 +--- sway/ipc-json.c | 10 +-- sway/sway.5.scd | 10 ++- 12 files changed, 127 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 13280110..9c9551d6 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,12 @@ Sway is an incredible window manager, and certainly one of the most well establi - `blur_passes ` - `blur_radius ` + LayerShell effects: *ONLY ON SWAYFX-GIT, NOT YET RELEASED* - - `layer_effects blur shadow corner_radius` + - `layer_effects ` + - Example: `layer_effects "waybar" blur enable; shadows enable; corner_radius 6` + - Available Effects: + - `blur ` + - `shadows ` + - `corner_radius ` + Dim unfocused windows: - `default_dim_inactive ` - `for_window [CRITERIA_HERE] dim_inactive ` diff --git a/include/sway/commands.h b/include/sway/commands.h index 924297ae..4cde776e 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -97,6 +97,13 @@ void container_resize_tiled(struct sway_container *parent, uint32_t axis, struct sway_container *container_find_resize_parent(struct sway_container *con, uint32_t edge); +/** + * Effect handlers value parsers + */ +bool cmd_blur_parse_value(char *arg); +bool cmd_corner_radius_parse_value(char *arg, int* result); +bool cmd_shadows_parse_value(char *arg); + /** * Handlers shared by exec and exec_always. */ diff --git a/include/sway/config.h b/include/sway/config.h index b49f735d..ef23c233 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -12,6 +12,7 @@ #include "../include/config.h" #include "gesture.h" #include "list.h" +#include "sway/desktop/fx_renderer/fx_renderer.h" #include "swaynag.h" #include "tree/container.h" #include "sway/input/tablet.h" @@ -477,9 +478,7 @@ struct blur_parameters { struct layer_effects { char *namespace; - bool blur; - bool shadow; - bool corner_rounding; + struct decoration_data deco_data; }; /** diff --git a/include/sway/desktop/fx_renderer/fx_renderer.h b/include/sway/desktop/fx_renderer/fx_renderer.h index 51f60557..2e78357c 100644 --- a/include/sway/desktop/fx_renderer/fx_renderer.h +++ b/include/sway/desktop/fx_renderer/fx_renderer.h @@ -9,6 +9,18 @@ #include "sway/desktop/fx_renderer/fx_framebuffer.h" #include "sway/desktop/fx_renderer/fx_texture.h" +#define get_undecorated_decoration_data() \ + (struct decoration_data) { \ + .alpha = 1.0f, \ + .dim = 0.0f, \ + .dim_color = config->dim_inactive_colors.unfocused, \ + .corner_radius = 0, \ + .saturation = 1.0f, \ + .has_titlebar = false, \ + .blur = false, \ + .shadow = false, \ + } + enum corner_location { TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, ALL, NONE }; enum fx_tex_shader_source { diff --git a/sway/commands/blur.c b/sway/commands/blur.c index 15dd985d..c9ef6860 100644 --- a/sway/commands/blur.c +++ b/sway/commands/blur.c @@ -3,6 +3,10 @@ #include "sway/output.h" #include "util.h" +bool cmd_blur_parse_value(char *arg) { + return parse_boolean(arg, true); +} + struct cmd_results *cmd_blur(int argc, char **argv) { struct cmd_results *error = checkarg(argc, "blur", EXPECTED_AT_LEAST, 1); @@ -12,7 +16,7 @@ struct cmd_results *cmd_blur(int argc, char **argv) { struct sway_container *con = config->handler_context.container; - bool result = parse_boolean(argv[0], config->blur_enabled); + bool result = cmd_blur_parse_value(argv[0]); if (con == NULL) { config->blur_enabled = result; } else { diff --git a/sway/commands/corner_radius.c b/sway/commands/corner_radius.c index ab216f6e..fe8b458f 100644 --- a/sway/commands/corner_radius.c +++ b/sway/commands/corner_radius.c @@ -4,15 +4,24 @@ #include "sway/tree/container.h" #include "log.h" +bool cmd_corner_radius_parse_value(char *arg, int* result) { + char *inv; + int value = strtol(arg, &inv, 10); + if (*inv != '\0' || value < 0 || value > 99) { + return false; + } + *result = value; + return true; +} + struct cmd_results *cmd_corner_radius(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "corner_radius", EXPECTED_EQUAL_TO, 1))) { return error; } - char *inv; - int value = strtol(argv[0], &inv, 10); - if (*inv != '\0' || value < 0 || value > 99) { + int value = 0; + if (!cmd_corner_radius_parse_value(argv[0], &value)) { return cmd_results_new(CMD_FAILURE, "Invalid size specified"); } diff --git a/sway/commands/layer_effects.c b/sway/commands/layer_effects.c index 66ec8571..0aadd684 100644 --- a/sway/commands/layer_effects.c +++ b/sway/commands/layer_effects.c @@ -1,8 +1,59 @@ +#include +#include "log.h" +#include "stringop.h" #include "sway/commands.h" #include "sway/config.h" #include "sway/output.h" #include "util.h" +struct cmd_results *parse_effects(int argc, char **argv, struct layer_effects *effect) { + char matched_delim = ';'; + char *head = join_args(argv + 1, argc - 1); + do { + // Trim leading whitespaces + for (; isspace(*head); ++head) {} + // Split command list + char *cmd = argsep(&head, ";,", &matched_delim); + for (; isspace(*cmd); ++cmd) {} + + if (strcmp(cmd, "") == 0) { + sway_log(SWAY_INFO, "Ignoring empty layer effect."); + continue; + } + sway_log(SWAY_INFO, "Handling layer effect '%s'", cmd); + + int argc; + char **argv = split_args(cmd, &argc); + // Strip all quotes from each token + for (int i = 1; i < argc; ++i) { + if (*argv[i] == '\"' || *argv[i] == '\'') { + strip_quotes(argv[i]); + } + } + if (strcmp(argv[0], "blur") == 0) { + effect->deco_data.blur = cmd_blur_parse_value(argv[1]); + continue; + } else if (strcmp(argv[0], "shadows") == 0) { + effect->deco_data.shadow = cmd_shadows_parse_value(argv[1]); + continue; + } else if (strcmp(argv[0], "corner_radius") == 0) { + int value; + if (cmd_corner_radius_parse_value(argv[1], &value)) { + effect->deco_data.corner_radius = value; + continue; + } + return cmd_results_new(CMD_INVALID, + "Invalid layer_effects corner_radius size! Got \"%s\"", + argv[1]); + } else { + return cmd_results_new(CMD_INVALID, + "Invalid layer_effects effect! Got \"%s\"", + cmd); + } + } while(head); + return NULL; +} + struct cmd_results *cmd_layer_effects(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "layer_effects", EXPECTED_AT_LEAST, 2))) { @@ -13,27 +64,21 @@ struct cmd_results *cmd_layer_effects(int argc, char **argv) { size_t len = sizeof(argv[0]); effect->namespace = malloc(len + 1); memcpy(effect->namespace, argv[0], len); - effect->blur = false; - effect->shadow = false; - effect->corner_rounding = false; + effect->deco_data = get_undecorated_decoration_data(); // Parse the commands - for (int i = 1; i < argc; i++) { - char *arg = argv[i]; - if (strcmp(arg, "blur") == 0) { - effect->blur = true; - continue; - } else if (strcmp(arg, "shadow") == 0) { - effect->shadow = true; - continue; - } else if (strcmp(arg, "corner_rounding") == 0) { - effect->corner_rounding = true; - continue; - } - return cmd_results_new(CMD_INVALID, "Invalid layer_effects effect! Got \"%s\"", arg); + if ((error = parse_effects(argc, argv, effect))) { + return error; } - if (!effect->blur && !effect->shadow && !effect->corner_rounding) { + // Ignore if nothing has changed + // TODO: Add deco_data cmp function? + if (!effect->deco_data.blur + && !effect->deco_data.shadow + && effect->deco_data.corner_radius < 1) { + sway_log(SWAY_ERROR, + "Ignoring layer effect \"%s\". Nothing changed\n", + join_args(argv + 1, argc - 1)); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/shadows.c b/sway/commands/shadows.c index 2b57b2e6..37a54618 100644 --- a/sway/commands/shadows.c +++ b/sway/commands/shadows.c @@ -8,6 +8,10 @@ #include "stringop.h" #include "util.h" +bool cmd_shadows_parse_value(char *arg) { + return parse_boolean(arg, true); +} + struct cmd_results *cmd_shadows(int argc, char **argv) { struct cmd_results *error = checkarg(argc, "shadows", EXPECTED_AT_LEAST, 1); @@ -17,7 +21,7 @@ struct cmd_results *cmd_shadows(int argc, char **argv) { struct sway_container *con = config->handler_context.container; - bool result = parse_boolean(argv[0], config->shadow_enabled); + bool result = cmd_shadows_parse_value(argv[0]); if (con == NULL) { config->shadow_enabled = result; } else { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 3b22bc79..85fbee9f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -200,11 +200,8 @@ void output_layer_for_each_toplevel_surface(struct sway_output *output, struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = layer_surface->layer_surface; struct render_data *data = user_data; - struct layer_effects *effects = layer_surface->effects; - if (effects) { - data->deco_data.blur = effects->blur; - data->deco_data.shadow = effects->shadow; - data->deco_data.corner_radius = effects->corner_rounding? config->corner_radius: 0; + if (layer_surface->effects) { + data->deco_data = layer_surface->effects->deco_data; } output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, diff --git a/sway/desktop/render.c b/sway/desktop/render.c index d8c6267d..04b34f30 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -39,19 +39,6 @@ struct workspace_effect_info { int expanded_size; }; -struct decoration_data get_undecorated_decoration_data() { - return (struct decoration_data) { - .alpha = 1.0f, - .dim = 0.0f, - .dim_color = config->dim_inactive_colors.unfocused, - .corner_radius = 0, - .saturation = 1.0f, - .has_titlebar = false, - .blur = false, - .shadow = false, - }; -} - int get_blur_size() { return pow(2, config->blur_params.num_passes) * config->blur_params.radius; } @@ -1865,14 +1852,14 @@ static struct workspace_effect_info get_workspace_effect_info(struct sway_output wl_list_for_each(lsurface, &sway_output->layers[i], link) { struct layer_effects *layer_effects = lsurface->effects; if (layer_effects) { - if (layer_effects->blur && !lsurface->layer_surface->surface->opaque) { + if (layer_effects->deco_data.blur && !lsurface->layer_surface->surface->opaque) { effect_info.container_wants_blur = true; // Check if we should render optimized blur if (renderer->blur_buffer_dirty && config->blur_xray) { effect_info.should_render_optimized_blur = true; } } - if (layer_effects->shadow) { + if (layer_effects->deco_data.shadow) { effect_info.container_wants_shadow = true; } } diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 9491e68b..7c9ed82c 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -376,14 +376,14 @@ static void ipc_json_describe_enabled_output(struct sway_output *output, json_object *effects = json_object_new_array(); struct layer_effects *layer_effects = lsurface->effects; if (layer_effects) { - if (layer_effects->blur) { + if (layer_effects->deco_data.blur) { json_object_array_add(effects, json_object_new_string("blur")); } - if (layer_effects->shadow) { - json_object_array_add(effects, json_object_new_string("shadow")); + if (layer_effects->deco_data.shadow) { + json_object_array_add(effects, json_object_new_string("shadows")); } - if (layer_effects->corner_rounding) { - json_object_array_add(effects, json_object_new_string("corner_rounding")); + if (layer_effects->deco_data.corner_radius > 0) { + json_object_array_add(effects, json_object_new_string("corner_radius")); } } json_object_object_add(layer, "effects", effects); diff --git a/sway/sway.5.scd b/sway/sway.5.scd index c77bbf03..8d23a265 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -78,9 +78,13 @@ The following commands may only be used in the configuration file. layers can use these effects. Effects: - - *blur* - - *shadow* - - *corner_rounding* + - *blur* + - *shadows* + - *corner_radius* + + Example: + + layer_effects "waybar" blur enable; shadows enable; corner_radius 6 *scratchpad_minimize* enable|disable Adjusts if minimized windows should be moved into the scratchpad.