Fix border rendering for non-floating containers

This commit is contained in:
TheAvidDev 2020-08-23 01:26:39 -04:00
parent a09b0ee9fb
commit bb09fa197d
8 changed files with 214 additions and 159 deletions

View file

@ -1,5 +1,6 @@
#ifndef _SWAY_CONFIG_H
#define _SWAY_CONFIG_H
#include <cairo.h>
#include <libinput.h>
#include <stdint.h>
#include <string.h>
@ -376,14 +377,8 @@ struct border_colors {
};
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;
cairo_surface_t *image_surface;
struct wlr_texture *texture;
};
enum edge_border_types {
@ -542,7 +537,6 @@ struct sway_config {
struct border_textures focused_inactive;
struct border_textures unfocused;
struct border_textures urgent;
struct border_textures placeholder;
} border_textures;
// floating view

View file

@ -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);

View file

@ -48,6 +48,10 @@ static struct cmd_handler handlers[] = {
{ "bindcode", cmd_bindcode },
{ "bindswitch", cmd_bindswitch },
{ "bindsym", cmd_bindsym },
{ "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 },
{ "client.background", cmd_client_noop },
{ "client.focused", cmd_client_focused },
{ "client.focused_inactive", cmd_client_focused_inactive },

View file

@ -1,54 +1,32 @@
#include <string.h>
#include <wlr/render/wlr_renderer.h>
#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) {
static void apply_border_textures_for_class(struct border_textures *class) {
struct sway_output *output = root->outputs->items[0];
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));
class->texture = wlr_texture_from_pixels(renderer, WL_SHM_FORMAT_ARGB8888,
cairo_image_surface_get_width(class->image_surface) * 4,
cairo_image_surface_get_width(class->image_surface),
cairo_image_surface_get_height(class->image_surface),
cairo_image_surface_get_data(class->image_surface));
}
static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
struct border_textures *class) {
if (!config->active) return cmd_results_new(CMD_DEFER, NULL);
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.");
class->image_surface = cairo_image_surface_create_from_png(argv[0]);
apply_border_textures_for_class(class);
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -691,133 +691,196 @@ struct parent_data {
* Render a single border texture.
*/
static void render_border_texture(struct sway_output *output,
pixman_region32_t *damage, struct wlr_box box,
pixman_region32_t *damage, struct wlr_box box, struct wlr_fbox src_box,
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;
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);
wlr_output_damage_add(output->damage, &texture_damage);
render_texture(wlr_output, damage, texture, NULL, &box, matrix, alpha);
render_texture(wlr_output, damage, texture, &src_box, &box, matrix, alpha);
}
/**
* Render a view's border textures.
* 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 wlr_texture *texture, float alpha) {
if (!texture) {
return;
}
struct wlr_box box;
struct wlr_fbox src_box;
int tw, th;
wlr_texture_get_size(texture, &tw, &th);
// Top left corner
src_box.x = 0;
src_box.y = 0;
src_box.width = tw / 2;
src_box.height = th / 2;
box.x = full_box->x - src_box.width;
box.y = full_box->y - src_box.height;
box.width = src_box.width;
box.height = src_box.height;
render_border_texture(output, damage, box, src_box, texture, alpha);
// Top edge
src_box.x = tw / 2;
src_box.y = 0;
src_box.width = 1;
src_box.height = th / 2;
box.x = full_box->x;
box.y = full_box->y - src_box.height;
box.width = full_box->width;
box.height = src_box.height;
render_border_texture(output, damage, box, src_box, texture, alpha);
// Top right corner
src_box.x = tw / 2 + 1;
src_box.y = 0;
src_box.width = tw / 2;
src_box.height = th / 2;
box.x = full_box->x + full_box->width;
box.y = full_box->y - src_box.height;
box.width = src_box.width;
box.height = src_box.height;
render_border_texture(output, damage, box, src_box, texture, alpha);
// Right edge
src_box.x = tw / 2 + 1;
src_box.y = th / 2;
src_box.width = tw / 2;
src_box.height = 1;
box.x = full_box->x + full_box->width;
box.y = full_box->y;
box.width = src_box.width;
box.height = full_box->height;
render_border_texture(output, damage, box, src_box, texture, alpha);
// Bottom right corner
src_box.x = tw / 2 + 1;
src_box.y = th / 2 + 1;
src_box.width = tw / 2;
src_box.height = th / 2;
box.x = full_box->x + full_box->width;
box.y = full_box->y + full_box->height;
box.width = src_box.width;
box.height = src_box.height;
render_border_texture(output, damage, box, src_box, texture, alpha);
// Bottom edge
src_box.x = tw / 2;
src_box.y = th / 2 + 1;
src_box.width = 1;
src_box.height = th / 2;
box.x = full_box->x;
box.y = full_box->y + full_box->height;
box.width = full_box->width;
box.height = src_box.height;
render_border_texture(output, damage, box, src_box, texture, alpha);
// Bottom left corner
src_box.x = 0;
src_box.y = th / 2 + 1;
src_box.width = tw / 2;
src_box.height = th / 2;
box.x = full_box->x - src_box.width;
box.y = full_box->y + full_box->height;
box.width = src_box.width;
box.height = src_box.height;
render_border_texture(output, damage, box, src_box, texture, alpha);
// Left edge
src_box.x = 0;
src_box.y = th / 2;
src_box.width = tw / 2;
src_box.height = 1;
box.x = full_box->x - src_box.width;
box.y = full_box->y;
box.width = src_box.width;
box.height = full_box->height;
render_border_texture(output, damage, box, src_box, texture, alpha);
}
struct output_and_damage {
struct sway_output *output;
pixman_region32_t *damage;
};
/**
* Render all of the border textures for a container.
*/
static void render_border_textures_for_container(struct sway_container *con,
void *data) {
// TODO: Fix certain layouts causing double border draws like 'T[app app]'
sway_log(SWAY_INFO, "name: %s", con->title);
if (con->parent) {
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 (container_is_floating(con)) {
goto bypass_border_checks;
}
if (con->layout == L_VERT || con->layout == L_HORIZ) {
if (container_parent_layout(con) && con->layout) {
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;
}
enum sway_container_layout ws_layout = con->workspace->layout;
if ((con->layout == L_VERT || con->layout == L_HORIZ) &&
(ws_layout == L_VERT || ws_layout == L_HORIZ)) {
return;
}
struct border_textures *textures;
bypass_border_checks:
// TODO: Use the appropriate border_texture based on children
struct border_textures *textures = &config->border_textures.focused;
textures = &config->border_textures.focused;
struct sway_container_state *state = &con->current;
struct sway_output *output = con->workspace->output;
pixman_region32_t* damage = (pixman_region32_t *) data;
struct wlr_box box;
struct wlr_texture *texture;
texture = textures->left_edge;
if (texture) {
box.x = state->x - texture->width;
box.y = state->y;
box.width = texture->width;
box.height = state->height;
render_border_texture(output, damage, box, texture, con->alpha);
}
texture = textures->right_edge;
if (texture) {
box.x = state->x + state->width;
box.y = state->y;
box.width = texture->width;
box.height = state->height;
render_border_texture(output, damage, box, texture, con->alpha);
}
texture = textures->top_edge;
if (texture) {
box.x = state->x;
box.y = state->y - texture->height;
box.width = state->width;
box.height = texture->height;
render_border_texture(output, damage, box, texture, con->alpha);
}
texture = textures->top_left_corner;
if (texture) {
box.x = state->x - texture->width;
box.y = state->y - texture->height;
box.width = texture->width;
box.height = texture->height;
render_border_texture(output, damage, box, texture, con->alpha);
}
texture = textures->top_right_corner;
if (texture) {
box.x = state->x + state->width;
box.y = state->y - texture->height;
box.width = texture->width;
box.height = texture->height;
render_border_texture(output, damage, box, texture, con->alpha);
}
texture = textures->bottom_edge;
if (texture) {
box.x = state->x;
box.y = state->y + state->height;
box.width = state->width;
box.height = texture->height;
render_border_texture(output, damage, box, texture, con->alpha);
}
texture = textures->bottom_left_corner;
if (texture) {
box.x = state->x - texture->width;
box.y = state->y + state->height;
box.width = texture->width;
box.height = texture->height;
render_border_texture(output, damage, box, texture, con->alpha);
}
texture = textures->bottom_right_corner;
if (texture) {
box.x = state->x + state->width;
box.y = state->y + state->height;
box.width = texture->width;
box.height = texture->height;
render_border_texture(output, damage, box, texture, con->alpha);
}
box.x = state->x;
box.y = state->y;
box.width = state->width;
box.height = state->height;
struct output_and_damage *oad = (struct output_and_damage *) data;
render_border_textures(oad->output, oad->damage, &box, textures->texture, 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) {
workspace_for_each_container(ws, render_border_textures_for_container,
damage);
// 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->texture, con->alpha);
return;
}
struct output_and_damage data = {
.output = output,
.damage = damage,
};
workspace_for_each_tiling_container(ws,
render_border_textures_for_container, &data);
}
static void render_container(struct sway_output *output,
@ -1089,6 +1152,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);
}
@ -1109,6 +1173,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);
}
}
}

View file

@ -208,16 +208,18 @@ static void apply_workspace_state(struct sway_workspace *ws,
static void apply_container_state(struct sway_container *container,
struct sway_container_state *state) {
struct sway_view *view = container->view;
int tw, th;
wlr_texture_get_size(config->border_textures.focused.texture, &tw, &th);
// Damage the old location
desktop_damage_whole_container(container);
if (view && !wl_list_empty(&view->saved_buffers)) {
struct sway_saved_buffer *saved_buf;
wl_list_for_each(saved_buf, &view->saved_buffers, link) {
struct wlr_box box = {
.x = container->current.content_x - view->saved_geometry.x + saved_buf->x,
.y = container->current.content_y - view->saved_geometry.y + saved_buf->y,
.width = saved_buf->width,
.height = saved_buf->height,
.x = container->current.content_x - view->saved_geometry.x + saved_buf->x - tw,
.y = container->current.content_y - view->saved_geometry.y + saved_buf->y - th,
.width = saved_buf->width + 2 * tw,
.height = saved_buf->height + 2 * th,
};
desktop_damage_box(&box);
}
@ -243,10 +245,10 @@ static void apply_container_state(struct sway_container *container,
if (view && view->surface) {
struct wlr_surface *surface = view->surface;
struct wlr_box box = {
.x = container->current.content_x - view->geometry.x,
.y = container->current.content_y - view->geometry.y,
.width = surface->current.width,
.height = surface->current.height,
.x = container->current.content_x - view->geometry.x - tw,
.y = container->current.content_y - view->geometry.y - th,
.width = surface->current.width + 2 * tw,
.height = surface->current.height + 2 * th,
};
desktop_damage_box(&box);
}

View file

@ -111,15 +111,16 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
*border* toggle
Cycles through the available border styles.
*border-images.<class>* <folder_path>
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.<class>* <path>
Configures the images used for borders. The _path_ is expected to be an
absolute path to an image with an odd width and height which will be scaled to
container sizes. The edges are expected to be 1 pixel in width for top and
bottom edges, and 1 pixel in height for left edges as they will be stretched
across container edges.
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.

View file

@ -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];