Merge branch 'master' of github.com:tmpm697/Swea

This commit is contained in:
Tuyen Pham 2021-07-17 11:55:19 +00:00
commit 23b94ca6d7
16 changed files with 401 additions and 17 deletions

16
contrib/borders/README.md Normal file
View file

@ -0,0 +1,16 @@
# Border Image Samples
This folder contains sample border images for anyone's use. A `testing.png` file also provides borders which can be used for easier debugging of incorrect border image rendering.
Feel free to add your own and make a PR, as long as they aren't _too_ similar to existing samples. Please keep them list in alphabetical order. Keep in mind that this directory will likely be removed once the contrib script for creating such images becomes available.
## Rounded
![](https://raw.githubusercontent.com/TheAvidDev/sway-borders/master/contrib/borders/rounded.png)
## Rounded and Shadows
![](https://raw.githubusercontent.com/TheAvidDev/sway-borders/master/contrib/borders/rounded_and_shadows.png)
## Shadows
![](https://raw.githubusercontent.com/TheAvidDev/sway-borders/master/contrib/borders/shadows.png)
## Testing
![](https://raw.githubusercontent.com/TheAvidDev/sway-borders/master/contrib/borders/testing.png)

BIN
contrib/borders/rounded.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
contrib/borders/shadows.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
contrib/borders/testing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

View file

@ -110,6 +110,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;

View file

@ -1,9 +1,11 @@
#ifndef _SWAY_CONFIG_H
#define _SWAY_CONFIG_H
#include <cairo.h>
#include <libinput.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <wlr/render/wlr_texture.h>
#include <wlr/interfaces/wlr_switch.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/util/box.h>
@ -397,6 +399,11 @@ struct border_colors {
float child_border[4];
};
struct border_textures {
cairo_surface_t *image_surface;
struct wlr_texture *texture;
};
enum edge_border_types {
E_NONE, /**< Don't hide edge borders */
E_VERTICAL, /**< hide vertical edge borders */
@ -506,8 +513,8 @@ struct sway_config {
enum focus_follows_mouse_mode focus_follows_mouse;
enum mouse_warping_mode mouse_warping;
enum focus_wrapping_mode focus_wrapping;
bool ttyaccess;
bool active;
bool ttyaccess;
bool failed;
bool reloading;
bool reading;
@ -548,6 +555,14 @@ 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;
} border_textures;
// floating view
int32_t floating_maximum_width;
int32_t floating_maximum_height;

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

@ -44,11 +44,15 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type
/* Keep alphabetized */
static const struct cmd_handler handlers[] = {
{ "assign", cmd_assign },
{ "ttyaccess", cmd_ttyaccess },
{ "ttyaccess", cmd_ttyaccess },
{ "bar", cmd_bar },
{ "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 },
@ -111,6 +115,10 @@ static const struct cmd_handler config_handlers[] = {
/* Runtime-only commands. Keep alphabetized */
static const 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 },

View file

@ -0,0 +1,76 @@
#define _POSIX_C_SOURCE 200809L
#include <wlr/render/wlr_renderer.h>
#include <drm_fourcc.h>
#include <string.h>
#include "cairo.h"
#include "log.h"
#include "stringop.h"
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
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);
class->texture = wlr_texture_from_pixels(renderer, DRM_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;
}
char *src = strdup(argv[0]);
if (!expand_path(&src)) {
error = cmd_results_new(CMD_INVALID, "Invalid syntax (%s)", src);
free(src);
src = NULL;
return error;
}
if (!src) {
sway_log(SWAY_ERROR, "Failed to allocate expanded path");
return cmd_results_new(CMD_FAILURE, "Unable to allocate resource");
}
bool can_access = access(src, F_OK) != -1;
if (!can_access) {
sway_log_errno(SWAY_ERROR, "Unable to access border images file '%s'",
src);
config_add_swaynag_warning("Unable to access border images file '%s'",
src);
}
class->image_surface = cairo_image_surface_create_from_png(src);
apply_border_textures_for_class(class);
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);
}

View file

@ -349,6 +349,7 @@ static void render_saved_view(struct sway_view *view,
// https://github.com/swaywm/sway/pull/4465#discussion_r321082059
}
/**
* Render a view's surface and left/bottom/right borders.
*/
@ -428,8 +429,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;
@ -711,6 +712,211 @@ 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_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);
float matrix[9];
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, &src_box, &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 wlr_texture *texture, float alpha) {
if (!texture) {
return;
}
struct wlr_box box;
struct wlr_fbox src_box;
int tw = texture->width;
int th = texture->height;
// 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);
}
/**
* Determines which border texture class to render for a given container.
*/
struct border_textures *get_border_textures_for_container(
struct sway_container *con) {
if (container_has_urgent_child(con)) {
return &config->border_textures.urgent;
}
if (container_has_focused_child(con) || con->current.focused) {
return &config->border_textures.focused;
}
if (!con->pending.children) {
return &config->border_textures.unfocused;
}
for (int i = 0; i < con->pending.children->length; ++i) {
struct sway_container *child = con->pending.children->items[i];
if (child == con->current.focused_inactive_child) {
return &config->border_textures.focused_inactive;
}
}
return &config->border_textures.unfocused;
}
/**
* Render all of the border textures for a container.
*/
static void render_border_textures_for_container(struct sway_container *con,
struct sway_output *output, pixman_region32_t *damage) {
if (!con->pending.workspace) {
return;
}
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->pending.parent;
}
enum sway_container_layout ws_layout = con->pending.workspace->layout;
if ((con->pending.layout == L_VERT || con->pending.layout == L_HORIZ) &&
(ws_layout == L_VERT || ws_layout == L_HORIZ)) {
return;
}
struct border_textures *textures = get_border_textures_for_container(con);;
struct sway_container_state *state = &con->current;
struct wlr_box box = {
.x = state->x,
.y = state->y,
.width = state->width,
.height = state->height,
};
render_border_textures(output, damage, &box, textures->texture, con->alpha);
}
/**
* Render the border textures for the overall layout of the container. A tabbed
* or stacked workspace layout means that all containers within the workspace
* are part of a single container, so a single border gets drawn.
*/
static void render_border_textures_for_workspace(struct sway_output *output,
pixman_region32_t *damage, struct sway_workspace *ws) {
if (ws->layout == L_TABBED || ws->layout == L_STACKED) {
struct wlr_box box;
workspace_get_box(ws, &box);
struct sway_container *con = ws->tiling->items[0];
if (ws->tiling->length == 0) {
return;
}
struct border_textures *textures = get_border_textures_for_container(con);
render_border_textures(output, damage, &box, textures->texture, con->alpha);
}
}
static void render_container(struct sway_output *output,
pixman_region32_t *damage, struct sway_container *con, bool parent_focused);
@ -762,6 +968,8 @@ static void render_containers_linear(struct sway_output *output,
render_container(output, damage, child,
parent->focused || child->current.focused);
}
render_border_textures_for_container(child, output, damage);
}
}
@ -819,6 +1027,8 @@ static void render_containers_tabbed(struct sway_output *output,
if (child == current) {
current_colors = colors;
}
render_border_textures_for_container(child, output, damage);
}
// Render surface and left/right/bottom borders
@ -873,11 +1083,14 @@ 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;
}
render_border_textures_for_container(child, output, damage);
}
// Render surface and left/right/bottom borders
@ -946,6 +1159,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,
@ -981,6 +1195,8 @@ static void render_floating_container(struct sway_output *soutput,
} else {
render_container(soutput, damage, con, con->current.focused);
}
render_border_textures_for_container(con, soutput, damage);
}
static void render_floating(struct sway_output *soutput,

View file

@ -231,6 +231,13 @@ static void apply_workspace_state(struct sway_workspace *ws,
static void apply_container_state(struct sway_container *container,
struct sway_container_state *state) {
int tw = 0, th = 0;
struct wlr_texture *texture = config->border_textures.focused.texture;
if (texture) {
tw = texture->width;
th = texture->height;
}
struct sway_view *view = container->view;
// Damage the old location
desktop_damage_whole_container(container);
@ -238,10 +245,10 @@ static void apply_container_state(struct sway_container *container,
struct sway_saved_buffer *saved_buf;
wl_list_for_each(saved_buf, &view->saved_buffers, link) {
struct wlr_box box = {
.x = saved_buf->x - view->saved_geometry.x,
.y = saved_buf->y - view->saved_geometry.y,
.width = saved_buf->width,
.height = saved_buf->height,
.x = saved_buf->x - view->saved_geometry.x - tw,
.y = saved_buf->y - view->saved_geometry.y - th,
.width = saved_buf->width + 2 * tw,
.height = saved_buf->height + 2 * th,
};
desktop_damage_box(&box);
}
@ -274,10 +281,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

@ -41,10 +41,11 @@ sway_sources = files(
'config/input.c',
'commands/assign.c',
'commands/ttyaccess.c',
'commands/ttyaccess.c',
'commands/bar.c',
'commands/bind.c',
'commands/border.c',
'commands/border_images.c',
'commands/client.c',
'commands/create_output.c',
'commands/default_border.c',

View file

@ -111,6 +111,30 @@ 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>* <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.
*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.
@ -154,9 +178,10 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
is now. If no argument is given, it does the same as _toggle_. If _global_
is specified, the view will be fullscreen across all outputs.
*ttyaccess* enable|disable
*ttyaccess* enable|disable|toggle
Do not switch VTs, block tty access.
*gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current
set|plus|minus <amount>
Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the

View file

@ -559,6 +559,7 @@ static void update_title_texture(struct sway_container *con,
output->wlr_output->backend);
*texture = wlr_texture_from_pixels(
renderer, DRM_FORMAT_ARGB8888, stride, width, height, data);
cairo_surface_destroy(surface);
g_object_unref(pango);
cairo_destroy(cairo);
@ -1036,6 +1037,14 @@ bool container_has_urgent_child(struct sway_container *container) {
return container_find_child(container, find_urgent_iterator, NULL);
}
static bool find_focused_iterator(struct sway_container *con, void *data) {
return con->current.focused;
}
bool container_has_focused_child(struct sway_container *container) {
return container_find_child(container, find_focused_iterator, NULL);
}
void container_end_mouse_operation(struct sway_container *container) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {

View file

@ -688,14 +688,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];