From 6ac590a00c1b0e6ac007be737e9d3f64d10650d2 Mon Sep 17 00:00:00 2001 From: TheAvidDev Date: Tue, 11 Aug 2020 01:30:53 -0400 Subject: [PATCH 1/4] Add basic border texture support --- contrib/split-border-image.py | 22 +++++ include/sway/commands.h | 4 + include/sway/config.h | 21 ++++ sway/commands.c | 4 + sway/commands/border_images.c | 74 ++++++++++++++ sway/desktop/render.c | 176 +++++++++++++++++++++++++++++++++- sway/meson.build | 1 + 7 files changed, 299 insertions(+), 3 deletions(-) create mode 100644 contrib/split-border-image.py create mode 100644 sway/commands/border_images.c diff --git a/contrib/split-border-image.py b/contrib/split-border-image.py new file mode 100644 index 0000000000..a200cbcdd8 --- /dev/null +++ b/contrib/split-border-image.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +from PIL import Image +import os +import sys + +fi = Image.open(sys.argv[1]) +image_dir = os.path.dirname(os.path.abspath(sys.argv[1])) +size = int(sys.argv[2]) + +# Split into images ordered as follows: +# 012 +# 7 3 +# 654 +fi.crop((0, 0, size, size)).save(os.path.join(image_dir, "0.png")) +fi.crop((size, 0, fi.width-size, size)).save(os.path.join(image_dir, "1.png")) +fi.crop((fi.width-size, 0, fi.width, size)).save(os.path.join(image_dir, "2.png")) +fi.crop((fi.width-size, size, fi.width, fi.height-size)).save(os.path.join(image_dir, "3.png")) +fi.crop((fi.width-size, fi.height-size, fi.width, fi.height)).save(os.path.join(image_dir, "4.png")) +fi.crop((size, fi.height-size, fi.width-size, fi.height)).save(os.path.join(image_dir, "5.png")) +fi.crop((0, fi.height-size, size, fi.height)).save(os.path.join(image_dir, "6.png")) +fi.crop((0, size, size, fi.height-size)).save(os.path.join(image_dir, "7.png")) diff --git a/include/sway/commands.h b/include/sway/commands.h index 4a2f8c20dd..04f917bf3f 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -103,6 +103,10 @@ sway_cmd cmd_bindcode; sway_cmd cmd_bindswitch; sway_cmd cmd_bindsym; sway_cmd cmd_border; +sway_cmd cmd_border_images_focused; +sway_cmd cmd_border_images_focused_inactive; +sway_cmd cmd_border_images_unfocused; +sway_cmd cmd_border_images_urgent; sway_cmd cmd_client_noop; sway_cmd cmd_client_focused; sway_cmd cmd_client_focused_inactive; diff --git a/include/sway/config.h b/include/sway/config.h index 5ad240d34f..3b69171e52 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -374,6 +375,17 @@ struct border_colors { float child_border[4]; }; +struct border_textures { + struct wlr_texture *top_edge; + struct wlr_texture *right_edge; + struct wlr_texture *bottom_edge; + struct wlr_texture *left_edge; + struct wlr_texture *top_left_corner; + struct wlr_texture *top_right_corner; + struct wlr_texture *bottom_right_corner; + struct wlr_texture *bottom_left_corner; +}; + enum edge_border_types { E_NONE, /**< Don't hide edge borders */ E_VERTICAL, /**< hide vertical edge borders */ @@ -524,6 +536,15 @@ struct sway_config { float background[4]; } border_colors; + // border textures + struct { + struct border_textures focused; + struct border_textures focused_inactive; + struct border_textures unfocused; + struct border_textures urgent; + struct border_textures placeholder; + } border_textures; + // floating view int32_t floating_maximum_width; int32_t floating_maximum_height; diff --git a/sway/commands.c b/sway/commands.c index fe1e98b539..615fbcebd6 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -110,6 +110,10 @@ static struct cmd_handler config_handlers[] = { /* Runtime-only commands. Keep alphabetized */ static struct cmd_handler command_handlers[] = { { "border", cmd_border }, + { "border_images.focused", cmd_border_images_focused }, + { "border_images.focused_inactive", cmd_border_images_focused_inactive }, + { "border_images.unfocused", cmd_border_images_unfocused }, + { "border_images.urgent", cmd_border_images_urgent }, { "create_output", cmd_create_output }, { "exit", cmd_exit }, { "floating", cmd_floating }, diff --git a/sway/commands/border_images.c b/sway/commands/border_images.c new file mode 100644 index 0000000000..209d5ac82e --- /dev/null +++ b/sway/commands/border_images.c @@ -0,0 +1,74 @@ +#include +#include +#include "cairo.h" +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/output.h" +#include "sway/tree/container.h" + +char* strcat_copy(const char *a, const char *b) { + char *out; + int a_len = strlen(a); + int b_len = strlen(b); + + out = malloc(a_len + b_len + 1); + + memcpy(out, a, a_len); + memcpy(out + a_len, b, b_len + 1); + return out; +} + +struct wlr_texture* wlr_texture_from_png(struct sway_output *output, char* folder_path, + char* filename) { + struct wlr_renderer *renderer = wlr_backend_get_renderer( + output->wlr_output->backend); + cairo_surface_t *image = cairo_image_surface_create_from_png(strcat_copy( + folder_path, filename)); + return wlr_texture_from_pixels(renderer, WL_SHM_FORMAT_ARGB8888, + cairo_image_surface_get_width(image) * 4, + cairo_image_surface_get_width(image), + cairo_image_surface_get_height(image), + cairo_image_surface_get_data(image)); +} + +static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name, + struct border_textures *class) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { + return error; + } + + struct sway_output *output = root->outputs->items[0]; + class->top_left_corner = wlr_texture_from_png(output, argv[0], "0.png"); + class->top_edge = wlr_texture_from_png(output, argv[0], "1.png"); + class->top_right_corner = wlr_texture_from_png(output, argv[0], "2.png"); + class->right_edge = wlr_texture_from_png(output, argv[0], "3.png"); + class->bottom_right_corner = wlr_texture_from_png(output, argv[0], "4.png"); + class->bottom_edge = wlr_texture_from_png(output, argv[0], "5.png"); + class->bottom_left_corner = wlr_texture_from_png(output, argv[0], "6.png"); + class->left_edge = wlr_texture_from_png(output, argv[0], "7.png"); + sway_log(SWAY_DEBUG, "Assigned all textures."); + + return cmd_results_new(CMD_SUCCESS, NULL); +} + +struct cmd_results *cmd_border_images_focused(int argc, char **argv) { + return handle_command(argc, argv, "border_images.focused", + &config->border_textures.focused); +} + +struct cmd_results *cmd_border_images_focused_inactive(int argc, char **argv) { + return handle_command(argc, argv, "border_images.focused_inactive", + &config->border_textures.focused_inactive); +} + +struct cmd_results *cmd_border_images_unfocused(int argc, char **argv) { + return handle_command(argc, argv, "border_images.unfocused", + &config->border_textures.unfocused); +} + +struct cmd_results *cmd_border_images_urgent(int argc, char **argv) { + return handle_command(argc, argv, "border_images.urgent", + &config->border_textures.urgent); +} diff --git a/sway/desktop/render.c b/sway/desktop/render.c index d3d927c838..db25ecb268 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -413,8 +413,8 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, static void render_titlebar(struct sway_output *output, pixman_region32_t *output_damage, struct sway_container *con, int x, int y, int width, - struct border_colors *colors, struct wlr_texture *title_texture, - struct wlr_texture *marks_texture) { + struct border_colors *colors, + struct wlr_texture *title_texture, struct wlr_texture *marks_texture) { struct wlr_box box; float color[4]; float output_scale = output->wlr_output->scale; @@ -686,6 +686,173 @@ struct parent_data { struct sway_container *active_child; }; +/** + * Render a single border texture. + */ +static void render_border_texture(struct sway_output *output, + pixman_region32_t *damage, struct wlr_box box, + struct wlr_texture *texture, float alpha) { + struct wlr_output *wlr_output = output->wlr_output; + + scale_box(&box, wlr_output->scale); + box.x -= output->lx * wlr_output->scale; + box.y -= output->ly * wlr_output->scale; + + // TODO: Fix texture drawing between outputs. + float matrix[9]; + memcpy(matrix, wlr_output->transform_matrix, sizeof(matrix)); + wlr_matrix_translate(matrix, box.x, box.y); + wlr_matrix_scale(matrix, box.width, box.height); + + pixman_region32_t texture_damage; + pixman_region32_init_rect(&texture_damage, box.x, box.y, box.width, box.height); + wlr_output_damage_add(output->damage, &texture_damage); + render_texture(wlr_output, damage, texture, NULL, &box, matrix, alpha); +} + +/** + * Render all border textures based on a given wlr_box. + */ +static void render_border_textures(struct sway_output *output, + pixman_region32_t *damage, struct wlr_box *full_box, + struct border_textures *textures, float alpha) { + + struct wlr_box box; + struct wlr_texture *texture; + texture = textures->left_edge; + if (texture) { + box.x = full_box->x - texture->width; + box.y = full_box->y; + box.width = texture->width; + box.height = full_box->height; + render_border_texture(output, damage, box, texture, alpha); + } + + texture = textures->right_edge; + if (texture) { + box.x = full_box->x + full_box->width; + box.y = full_box->y; + box.width = texture->width; + box.height = full_box->height; + render_border_texture(output, damage, box, texture, alpha); + } + + texture = textures->top_edge; + if (texture) { + box.x = full_box->x; + box.y = full_box->y - texture->height; + box.width = full_box->width; + box.height = texture->height; + render_border_texture(output, damage, box, texture, alpha); + } + + texture = textures->top_left_corner; + if (texture) { + box.x = full_box->x - texture->width; + box.y = full_box->y - texture->height; + box.width = texture->width; + box.height = texture->height; + render_border_texture(output, damage, box, texture, alpha); + } + + texture = textures->top_right_corner; + if (texture) { + box.x = full_box->x + full_box->width; + box.y = full_box->y - texture->height; + box.width = texture->width; + box.height = texture->height; + render_border_texture(output, damage, box, texture, alpha); + } + + texture = textures->bottom_edge; + if (texture) { + box.x = full_box->x; + box.y = full_box->y + full_box->height; + box.width = full_box->width; + box.height = texture->height; + render_border_texture(output, damage, box, texture, alpha); + } + + texture = textures->bottom_left_corner; + if (texture) { + box.x = full_box->x - texture->width; + box.y = full_box->y + full_box->height; + box.width = texture->width; + box.height = texture->height; + render_border_texture(output, damage, box, texture, alpha); + } + + texture = textures->bottom_right_corner; + if (texture) { + box.x = full_box->x + full_box->width; + box.y = full_box->y + full_box->height; + box.width = texture->width; + box.height = texture->height; + render_border_texture(output, damage, box, texture, alpha); + } +} + +/** + * Render all of the border textures for a container. + */ +static void render_border_textures_for_container(struct sway_container *con, + pixman_region32_t *damage) { + if (container_is_floating(con)) { + goto bypass_border_checks; + } + + struct sway_container *temp = con; + while (temp) { + enum sway_container_layout layout = container_parent_layout(temp); + if (layout == L_TABBED || layout == L_STACKED) { + return; + } + temp = temp->parent; + } + + if ((con->layout == L_VERT || con->layout == L_HORIZ) && + container_parent_layout(con) == con->layout) { + return; + } + + struct border_textures *textures; +bypass_border_checks: + // TODO: Use the appropriate border_texture based on children + textures = &config->border_textures.focused; + + struct sway_output *output = con->workspace->output; + struct sway_container_state *state = &con->current; + struct wlr_box box; + box.x = state->x; + box.y = state->y; + box.width = state->width; + box.height = state->height; + render_border_textures(output, damage, &box, textures, con->alpha); +} + +/** + * Render all of the border textures for tiling containers within a workspace + */ +static void render_border_textures_for_workspace(struct sway_output *output, + pixman_region32_t *damage, struct sway_workspace *ws) { + // If the workspace layout is tabbed or stacked, all containers within are + // part of a parent container so only one border needs to be drawn. + if (ws->layout == L_TABBED || ws->layout == L_STACKED) { + struct wlr_box box; + workspace_get_box(ws, &box); + + // TODO: Use the appropriate border_texture based on children + struct border_textures *textures = &config->border_textures.focused; + struct sway_container *con = ws->tiling->items[0]; + render_border_textures(output, damage, &box, textures, con->alpha); + return; + } + for (int i = 0; i < ws->tiling->length; ++i) { + struct sway_container *container = ws->tiling->items[i]; + render_border_textures_for_container(container, damage); + } +} + static void render_container(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, bool parent_focused); @@ -848,7 +1015,8 @@ static void render_containers_stacked(struct sway_output *output, int y = parent->box.y + titlebar_height * i; render_titlebar(output, damage, child, parent->box.x, y, - parent->box.width, colors, title_texture, marks_texture); + parent->box.width, colors, title_texture, + marks_texture); if (child == current) { current_colors = colors; @@ -921,6 +1089,7 @@ static void render_workspace(struct sway_output *output, .active_child = ws->current.focused_inactive_child, }; render_containers(output, damage, &data); + render_border_textures_for_workspace(output, damage, ws); } static void render_floating_container(struct sway_output *soutput, @@ -953,6 +1122,7 @@ static void render_floating_container(struct sway_output *soutput, render_top_border(soutput, damage, con, colors); } render_view(soutput, damage, con, colors); + render_border_textures_for_container(con, damage); } else { render_container(soutput, damage, con, con->current.focused); } diff --git a/sway/meson.build b/sway/meson.build index 0db458362d..4871c78b6d 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -43,6 +43,7 @@ sway_sources = files( 'commands/bar.c', 'commands/bind.c', 'commands/border.c', + 'commands/border_images.c', 'commands/client.c', 'commands/create_output.c', 'commands/default_border.c', From e34ef65fd904488a34660648175cc54726a3aa6b Mon Sep 17 00:00:00 2001 From: TheAvidDev Date: Sun, 23 Aug 2020 01:49:59 -0400 Subject: [PATCH 2/4] Add man page --- sway/sway.5.scd | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index f608ad2e9f..faeb945f8f 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -111,6 +111,29 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). *border* toggle Cycles through the available border styles. +*border-images.* + Configures the images used for borders. The _folder_path_ is expected to be + the full path, with a trailing slash, to a folder that contains 8 PNG images + named 0.png, 1.png, ..., 7.png. These images are used in clockwise order, + starting from the top-left corner, ending on the left edge. For the classes + below, _container_ refers to a container which has gaps around it. + + The available classes are: + + *border_images.focused* + The container which is focused or has a window that has focus. + + *border_images.focused_inactive* + The container which has the most recently focused view within a container + which is not focused. + + *border_images.unfocused* + A container with all of its views unfocused. + + *border_images.urgent* + A container which has view with an urgency hint. *Note*: Native Wayland windows do not + support urgency. Urgency only works for Xwayland windows. + *exit* Exit sway and end your Wayland session. From 2c49efc12c63dd8ac89e513b8c6538c130c8fa5c Mon Sep 17 00:00:00 2001 From: TheAvidDev Date: Sun, 23 Aug 2020 20:10:25 -0400 Subject: [PATCH 3/4] More container fixes --- include/sway/tree/workspace.h | 3 +++ sway/desktop/render.c | 21 ++++++++++----------- sway/tree/workspace.c | 8 ++++++-- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 1adbe68a28..255ace192a 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -92,6 +92,9 @@ struct sway_output *workspace_output_get_highest_available( void workspace_detect_urgent(struct sway_workspace *workspace); +void workspace_for_each_tiling_container(struct sway_workspace *ws, + void (*f)(struct sway_container *con, void *data), void *data); + void workspace_for_each_container(struct sway_workspace *ws, void (*f)(struct sway_container *con, void *data), void *data); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index db25ecb268..62667201c6 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -694,15 +694,14 @@ static void render_border_texture(struct sway_output *output, struct wlr_texture *texture, float alpha) { struct wlr_output *wlr_output = output->wlr_output; + box.x -= output->lx; + box.y -= output->ly; scale_box(&box, wlr_output->scale); - box.x -= output->lx * wlr_output->scale; - box.y -= output->ly * wlr_output->scale; // TODO: Fix texture drawing between outputs. float matrix[9]; - memcpy(matrix, wlr_output->transform_matrix, sizeof(matrix)); - wlr_matrix_translate(matrix, box.x, box.y); - wlr_matrix_scale(matrix, box.width, box.height); + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, + output->wlr_output->transform_matrix); pixman_region32_t texture_damage; pixman_region32_init_rect(&texture_damage, box.x, box.y, box.width, box.height); @@ -796,7 +795,7 @@ static void render_border_textures(struct sway_output *output, * Render all of the border textures for a container. */ static void render_border_textures_for_container(struct sway_container *con, - pixman_region32_t *damage) { + void *data) { if (container_is_floating(con)) { goto bypass_border_checks; } @@ -810,8 +809,9 @@ static void render_border_textures_for_container(struct sway_container *con, temp = temp->parent; } + enum sway_container_layout ws_layout = con->workspace->layout; if ((con->layout == L_VERT || con->layout == L_HORIZ) && - container_parent_layout(con) == con->layout) { + (ws_layout == L_VERT || ws_layout == L_HORIZ)) { return; } @@ -821,6 +821,7 @@ static void render_border_textures_for_container(struct sway_container *con, textures = &config->border_textures.focused; struct sway_output *output = con->workspace->output; + pixman_region32_t *damage = (pixman_region32_t *) data; struct sway_container_state *state = &con->current; struct wlr_box box; box.x = state->x; @@ -847,10 +848,8 @@ static void render_border_textures_for_workspace(struct sway_output *output, render_border_textures(output, damage, &box, textures, con->alpha); return; } - for (int i = 0; i < ws->tiling->length; ++i) { - struct sway_container *container = ws->tiling->items[i]; - render_border_textures_for_container(container, damage); - } + workspace_for_each_tiling_container(ws, + render_border_textures_for_container, damage); } static void render_container(struct sway_output *output, diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 3bcba8e546..3d7b2d8d01 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -585,14 +585,18 @@ void workspace_detect_urgent(struct sway_workspace *workspace) { } } -void workspace_for_each_container(struct sway_workspace *ws, +void workspace_for_each_tiling_container(struct sway_workspace *ws, void (*f)(struct sway_container *con, void *data), void *data) { - // Tiling for (int i = 0; i < ws->tiling->length; ++i) { struct sway_container *container = ws->tiling->items[i]; f(container, data); container_for_each_child(container, f, data); } +} + +void workspace_for_each_container(struct sway_workspace *ws, + void (*f)(struct sway_container *con, void *data), void *data) { + workspace_for_each_tiling_container(ws, f, data); // Floating for (int i = 0; i < ws->floating->length; ++i) { struct sway_container *container = ws->floating->items[i]; From b51640fdf22691742b79b64b9a8ed8ffa0597ba6 Mon Sep 17 00:00:00 2001 From: TheAvidDev Date: Mon, 24 Aug 2020 00:52:12 -0400 Subject: [PATCH 4/4] Fix rendering of floating containers across outputs --- sway/desktop/render.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 62667201c6..70ffe69fe8 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -698,7 +698,6 @@ static void render_border_texture(struct sway_output *output, box.y -= output->ly; scale_box(&box, wlr_output->scale); - // TODO: Fix texture drawing between outputs. float matrix[9]; wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, output->wlr_output->transform_matrix); @@ -791,6 +790,11 @@ static void render_border_textures(struct sway_output *output, } } +struct output_and_damage { + struct sway_output *output; + pixman_region32_t *damage; +}; + /** * Render all of the border textures for a container. */ @@ -820,15 +824,14 @@ static void render_border_textures_for_container(struct sway_container *con, // TODO: Use the appropriate border_texture based on children textures = &config->border_textures.focused; - struct sway_output *output = con->workspace->output; - pixman_region32_t *damage = (pixman_region32_t *) data; struct sway_container_state *state = &con->current; struct wlr_box box; box.x = state->x; box.y = state->y; box.width = state->width; box.height = state->height; - render_border_textures(output, damage, &box, textures, con->alpha); + struct output_and_damage *oad = (struct output_and_damage *) data; + render_border_textures(oad->output, oad->damage, &box, textures, con->alpha); } /** @@ -848,8 +851,13 @@ static void render_border_textures_for_workspace(struct sway_output *output, render_border_textures(output, damage, &box, textures, con->alpha); return; } + + struct output_and_damage data = { + .output = output, + .damage = damage, + }; workspace_for_each_tiling_container(ws, - render_border_textures_for_container, damage); + render_border_textures_for_container, &data); } static void render_container(struct sway_output *output, @@ -1121,7 +1129,6 @@ static void render_floating_container(struct sway_output *soutput, render_top_border(soutput, damage, con, colors); } render_view(soutput, damage, con, colors); - render_border_textures_for_container(con, damage); } else { render_container(soutput, damage, con, con->current.focused); } @@ -1142,6 +1149,11 @@ static void render_floating(struct sway_output *soutput, continue; } render_floating_container(soutput, damage, floater); + struct output_and_damage data = { + .output = soutput, + .damage = damage, + }; + render_border_textures_for_container(floater, &data); } } }