feat: add round titlebars (#26)

This commit is contained in:
William McKinnon 2022-11-11 01:19:02 -05:00 committed by GitHub
parent 9ee7fa61af
commit 1930bd0d71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 291 additions and 67 deletions

View file

@ -4,7 +4,7 @@
Sway is an incredible window manager, and certainly one of the most well established wayland window managers. However, it is restricted to only include the functionality that existed in i3. This fork ditches the simple wlr_renderer, and extends it to render fancy GLES2 effects. This, along with a couple of minor changes, expands sway's featureset to include the following: Sway is an incredible window manager, and certainly one of the most well established wayland window managers. However, it is restricted to only include the functionality that existed in i3. This fork ditches the simple wlr_renderer, and extends it to render fancy GLES2 effects. This, along with a couple of minor changes, expands sway's featureset to include the following:
+ **Anti-aliased rounded corners and borders** + **Anti-aliased rounded corners, borders, and titlebars**
+ **Scratchpad treated as minimize**: Allows docks, or panels with a taskbar, to correctly interpret minimize / unminimize requests ([thanks to LCBCrion](https://github.com/swaywm/sway/issues/6457)) + **Scratchpad treated as minimize**: Allows docks, or panels with a taskbar, to correctly interpret minimize / unminimize requests ([thanks to LCBCrion](https://github.com/swaywm/sway/issues/6457))
+ **Add a nix flake to the repo**: Allows nixos users to easily contribute to and test this project + **Add a nix flake to the repo**: Allows nixos users to easily contribute to and test this project

View file

@ -4,7 +4,7 @@
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
#include <stdbool.h> #include <stdbool.h>
enum corner_location {NONE, TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT}; enum corner_location { NONE, TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT };
struct gles2_tex_shader { struct gles2_tex_shader {
GLuint program; GLuint program;
@ -16,6 +16,17 @@ struct gles2_tex_shader {
GLint size; GLint size;
GLint position; GLint position;
GLint radius; GLint radius;
GLint has_titlebar;
};
struct rounded_quad_shader {
GLuint program;
GLint proj;
GLint color;
GLint pos_attrib;
GLint size;
GLint position;
GLint radius;
}; };
struct fx_renderer { struct fx_renderer {
@ -31,6 +42,10 @@ struct fx_renderer {
GLint color; GLint color;
GLint pos_attrib; GLint pos_attrib;
} quad; } quad;
struct rounded_quad_shader rounded_tl_quad;
struct rounded_quad_shader rounded_tr_quad;
struct { struct {
GLuint program; GLuint program;
GLint proj; GLint proj;
@ -45,6 +60,7 @@ struct fx_renderer {
GLint half_size; GLint half_size;
GLint half_thickness; GLint half_thickness;
} corner; } corner;
struct gles2_tex_shader tex_rgba; struct gles2_tex_shader tex_rgba;
struct gles2_tex_shader tex_rgbx; struct gles2_tex_shader tex_rgbx;
struct gles2_tex_shader tex_ext; struct gles2_tex_shader tex_ext;
@ -63,14 +79,19 @@ void fx_renderer_scissor(struct wlr_box *box);
bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture, bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9], const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9],
float alpha, int radius); float alpha, int radius, const bool has_titlebar);
bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture, bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture,
const struct wlr_box *dst_box, const float matrix[static 9], float alpha, int radius); const struct wlr_box *dst_box, const float matrix[static 9], float alpha, int radius,
const bool has_titlebar);
void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9]); const float color[static 4], const float projection[static 9]);
void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9],
int radius, enum corner_location corner_location);
void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9], const float color[static 4], const float projection[static 9],
enum corner_location corner_location, int radius, int border_thickness); enum corner_location corner_location, int radius, int border_thickness);

View file

@ -20,6 +20,8 @@
// shaders // shaders
#include "quad_vert_src.h" #include "quad_vert_src.h"
#include "quad_frag_src.h" #include "quad_frag_src.h"
#include "quad_round_tl_frag_src.h"
#include "quad_round_tr_frag_src.h"
#include "corner_frag_src.h" #include "corner_frag_src.h"
#include "tex_vert_src.h" #include "tex_vert_src.h"
#include "tex_rgba_frag_src.h" #include "tex_rgba_frag_src.h"
@ -97,6 +99,22 @@ bool init_frag_shader(struct gles2_tex_shader *shader, GLuint prog) {
shader->size = glGetUniformLocation(prog, "size"); shader->size = glGetUniformLocation(prog, "size");
shader->position = glGetUniformLocation(prog, "position"); shader->position = glGetUniformLocation(prog, "position");
shader->radius = glGetUniformLocation(prog, "radius"); shader->radius = glGetUniformLocation(prog, "radius");
shader->has_titlebar = glGetUniformLocation(prog, "has_titlebar");
return true;
}
// initializes a provided rounded quad shader and returns false if unsuccessful
bool init_rounded_quad_shader(struct rounded_quad_shader *shader, GLuint prog) {
shader->program = prog;
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->color = glGetUniformLocation(prog, "color");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->size = glGetUniformLocation(prog, "size");
shader->position = glGetUniformLocation(prog, "position");
shader->radius = glGetUniformLocation(prog, "radius");
return true; return true;
} }
@ -133,6 +151,7 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
// init shaders // init shaders
GLuint prog; GLuint prog;
// quad fragment shader
prog = link_program(quad_vert_src, quad_frag_src); prog = link_program(quad_vert_src, quad_frag_src);
renderer->shaders.quad.program = prog; renderer->shaders.quad.program = prog;
if (!renderer->shaders.quad.program) { if (!renderer->shaders.quad.program) {
@ -142,7 +161,17 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
renderer->shaders.quad.color = glGetUniformLocation(prog, "color"); renderer->shaders.quad.color = glGetUniformLocation(prog, "color");
renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos"); renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos");
// Border corners // rounded quad fragment shaders
prog = link_program(quad_vert_src, quad_round_tl_frag_src);
if (!init_rounded_quad_shader(&renderer->shaders.rounded_tl_quad, prog)) {
goto error;
}
prog = link_program(quad_vert_src, quad_round_tr_frag_src);
if (!init_rounded_quad_shader(&renderer->shaders.rounded_tr_quad, prog)) {
goto error;
}
// Border corner shader
prog = link_program(quad_vert_src, corner_frag_src); prog = link_program(quad_vert_src, corner_frag_src);
renderer->shaders.corner.program = prog; renderer->shaders.corner.program = prog;
if (!renderer->shaders.corner.program) { if (!renderer->shaders.corner.program) {
@ -225,7 +254,7 @@ void fx_renderer_scissor(struct wlr_box *box) {
bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture, bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9], const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9],
float alpha, int radius) { float alpha, int radius, const bool has_titlebar) {
assert(wlr_texture_is_gles2(wlr_texture)); assert(wlr_texture_is_gles2(wlr_texture));
struct wlr_gles2_texture_attribs texture_attrs; struct wlr_gles2_texture_attribs texture_attrs;
@ -282,6 +311,7 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_t
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix);
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
glUniform1f(shader->alpha, alpha); glUniform1f(shader->alpha, alpha);
glUniform1f(shader->has_titlebar, has_titlebar);
// rounded corners // rounded corners
glUniform2f(shader->size, dst_box->width, dst_box->height); glUniform2f(shader->size, dst_box->width, dst_box->height);
@ -316,14 +346,15 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_t
} }
bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture, bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct wlr_texture *wlr_texture,
const struct wlr_box *dst_box, const float matrix[static 9], float alpha, int radius) { const struct wlr_box *dst_box, const float matrix[static 9], float alpha, int radius,
const bool has_titlebar) {
struct wlr_fbox src_box = { struct wlr_fbox src_box = {
.x = 0, .x = 0,
.y = 0, .y = 0,
.width = wlr_texture->width, .width = wlr_texture->width,
.height = wlr_texture->height, .height = wlr_texture->height,
}; };
return fx_render_subtexture_with_matrix(renderer, wlr_texture, &src_box, dst_box, matrix, alpha, radius); return fx_render_subtexture_with_matrix(renderer, wlr_texture, &src_box, dst_box, matrix, alpha, radius, has_titlebar);
} }
void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
@ -364,6 +395,61 @@ void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
glDisableVertexAttribArray(renderer->shaders.quad.pos_attrib); glDisableVertexAttribArray(renderer->shaders.quad.pos_attrib);
} }
void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9],
int radius, enum corner_location corner_location) {
if (box->width == 0 || box->height == 0) {
return;
}
assert(box->width > 0 && box->height > 0);
struct rounded_quad_shader *shader = NULL;
switch (corner_location) {
case TOP_LEFT:
shader = &renderer->shaders.rounded_tl_quad;
break;
case TOP_RIGHT:
shader = &renderer->shaders.rounded_tr_quad;
break;
default:
sway_log(SWAY_ERROR, "Invalid Corner Location. Aborting render");
abort();
}
float matrix[9];
wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, projection);
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
// TODO: investigate why matrix is flipped prior to this cmd
// wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix);
wlr_matrix_transpose(gl_matrix, gl_matrix);
glEnable(GL_BLEND);
glUseProgram(shader->program);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix);
glUniform4f(shader->color, color[0], color[1], color[2], color[3]);
// rounded corners
glUniform2f(shader->size, box->width, box->height);
glUniform2f(shader->position, box->x, box->y);
glUniform1f(shader->radius, radius);
glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE,
0, verts);
glEnableVertexAttribArray(shader->pos_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader->pos_attrib);
}
void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box, void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9], const float color[static 4], const float projection[static 9],
enum corner_location corner_location, int radius, int border_thickness) { enum corner_location corner_location, int radius, int border_thickness) {

View file

@ -33,6 +33,7 @@ struct render_data {
pixman_region32_t *damage; pixman_region32_t *damage;
float alpha; float alpha;
int corner_radius; int corner_radius;
bool has_titlebar;
struct wlr_box *clip_box; struct wlr_box *clip_box;
}; };
@ -102,7 +103,7 @@ static void set_scale_filter(struct wlr_output *wlr_output,
static void render_texture(struct wlr_output *wlr_output, static void render_texture(struct wlr_output *wlr_output,
pixman_region32_t *output_damage, struct wlr_texture *texture, pixman_region32_t *output_damage, struct wlr_texture *texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const struct wlr_fbox *src_box, const struct wlr_box *dst_box,
const float matrix[static 9], float alpha, int corner_radius) { const float matrix[static 9], float alpha, int corner_radius, bool has_titlebar) {
struct sway_output *output = wlr_output->data; struct sway_output *output = wlr_output->data;
struct fx_renderer *renderer = output->server->renderer; struct fx_renderer *renderer = output->server->renderer;
@ -122,9 +123,9 @@ static void render_texture(struct wlr_output *wlr_output,
scissor_output(wlr_output, &rects[i]); scissor_output(wlr_output, &rects[i]);
set_scale_filter(wlr_output, texture, output->scale_filter); set_scale_filter(wlr_output, texture, output->scale_filter);
if (src_box != NULL) { if (src_box != NULL) {
fx_render_subtexture_with_matrix(renderer, texture, src_box, dst_box, matrix, alpha, corner_radius); fx_render_subtexture_with_matrix(renderer, texture, src_box, dst_box, matrix, alpha, corner_radius, has_titlebar);
} else { } else {
fx_render_texture_with_matrix(renderer, texture, dst_box, matrix, alpha, corner_radius); fx_render_texture_with_matrix(renderer, texture, dst_box, matrix, alpha, corner_radius, has_titlebar);
} }
} }
@ -140,6 +141,7 @@ static void render_surface_iterator(struct sway_output *output,
pixman_region32_t *output_damage = data->damage; pixman_region32_t *output_damage = data->damage;
float alpha = data->alpha; float alpha = data->alpha;
int corner_radius = data->corner_radius; int corner_radius = data->corner_radius;
bool has_titlebar = data->has_titlebar;
struct wlr_texture *texture = wlr_surface_get_texture(surface); struct wlr_texture *texture = wlr_surface_get_texture(surface);
if (!texture) { if (!texture) {
@ -167,7 +169,7 @@ static void render_surface_iterator(struct sway_output *output,
scale_box(&dst_box, wlr_output->scale); scale_box(&dst_box, wlr_output->scale);
render_texture(wlr_output, output_damage, texture, &src_box, &dst_box, render_texture(wlr_output, output_damage, texture, &src_box, &dst_box,
matrix, alpha, corner_radius * wlr_output->scale); matrix, alpha, corner_radius * wlr_output->scale, has_titlebar);
wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_presentation_surface_sampled_on_output(server.presentation, surface,
wlr_output); wlr_output);
@ -179,6 +181,7 @@ static void render_layer_toplevel(struct sway_output *output,
.damage = damage, .damage = damage,
.alpha = 1.0f, .alpha = 1.0f,
.corner_radius = 0, .corner_radius = 0,
.has_titlebar = false,
}; };
output_layer_for_each_toplevel_surface(output, layer_surfaces, output_layer_for_each_toplevel_surface(output, layer_surfaces,
render_surface_iterator, &data); render_surface_iterator, &data);
@ -190,6 +193,7 @@ static void render_layer_popups(struct sway_output *output,
.damage = damage, .damage = damage,
.alpha = 1.0f, .alpha = 1.0f,
.corner_radius = 0, .corner_radius = 0,
.has_titlebar = false,
}; };
output_layer_for_each_popup_surface(output, layer_surfaces, output_layer_for_each_popup_surface(output, layer_surfaces,
render_surface_iterator, &data); render_surface_iterator, &data);
@ -202,6 +206,7 @@ static void render_unmanaged(struct sway_output *output,
.damage = damage, .damage = damage,
.alpha = 1.0f, .alpha = 1.0f,
.corner_radius = 0, .corner_radius = 0,
.has_titlebar = false,
}; };
output_unmanaged_for_each_surface(output, unmanaged, output_unmanaged_for_each_surface(output, unmanaged,
render_surface_iterator, &data); render_surface_iterator, &data);
@ -214,6 +219,7 @@ static void render_drag_icons(struct sway_output *output,
.damage = damage, .damage = damage,
.alpha = 1.0f, .alpha = 1.0f,
.corner_radius = 0, .corner_radius = 0,
.has_titlebar = false,
}; };
output_drag_icons_for_each_surface(output, drag_icons, output_drag_icons_for_each_surface(output, drag_icons,
render_surface_iterator, &data); render_surface_iterator, &data);
@ -246,8 +252,40 @@ void render_rect(struct sway_output *output,
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) { for (int i = 0; i < nrects; ++i) {
scissor_output(wlr_output, &rects[i]); scissor_output(wlr_output, &rects[i]);
fx_render_rect(renderer, &box, color, fx_render_rect(renderer, &box, color, wlr_output->transform_matrix);
wlr_output->transform_matrix); }
damage_finish:
pixman_region32_fini(&damage);
}
void render_rounded_rect(struct sway_output *output, pixman_region32_t *output_damage,
const struct wlr_box *_box, float color[static 4], int corner_radius,
enum corner_location corner_location) {
struct wlr_output *wlr_output = output->wlr_output;
struct fx_renderer *renderer = output->server->renderer;
struct wlr_box box;
memcpy(&box, _box, sizeof(struct wlr_box));
box.x -= output->lx * wlr_output->scale;
box.y -= output->ly * wlr_output->scale;
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_union_rect(&damage, &damage, box.x, box.y,
box.width, box.height);
pixman_region32_intersect(&damage, &damage, output_damage);
bool damaged = pixman_region32_not_empty(&damage);
if (!damaged) {
goto damage_finish;
}
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; ++i) {
scissor_output(wlr_output, &rects[i]);
fx_render_rounded_rect(renderer, &box, color, wlr_output->transform_matrix,
corner_radius, corner_location);
} }
damage_finish: damage_finish:
@ -257,7 +295,7 @@ damage_finish:
// _box.x and .y are expected to be layout-local // _box.x and .y are expected to be layout-local
// _box.width and .height are expected to be output-buffer-local // _box.width and .height are expected to be output-buffer-local
void render_border_corner(struct sway_output *output, pixman_region32_t *output_damage, void render_border_corner(struct sway_output *output, pixman_region32_t *output_damage,
const struct wlr_box *_box, float color[static 4], int corner_radius, const struct wlr_box *_box, const float color[static 4], int corner_radius,
int border_thickness, enum corner_location corner_location) { int border_thickness, enum corner_location corner_location) {
struct wlr_output *wlr_output = output->wlr_output; struct wlr_output *wlr_output = output->wlr_output;
struct fx_renderer *renderer = output->server->renderer; struct fx_renderer *renderer = output->server->renderer;
@ -296,12 +334,13 @@ void premultiply_alpha(float color[4], float opacity) {
color[2] *= color[3]; color[2] *= color[3];
} }
static void render_view_toplevels(struct sway_view *view, static void render_view_toplevels(struct sway_view *view, struct sway_output *output,
struct sway_output *output, pixman_region32_t *damage, float alpha, int corner_radius) { pixman_region32_t *damage, float alpha, int corner_radius, bool has_titlebar) {
struct render_data data = { struct render_data data = {
.damage = damage, .damage = damage,
.alpha = alpha, .alpha = alpha,
.corner_radius = corner_radius, .corner_radius = corner_radius,
.has_titlebar = has_titlebar,
}; };
struct wlr_box clip_box; struct wlr_box clip_box;
if (!container_is_current_floating(view->container)) { if (!container_is_current_floating(view->container)) {
@ -321,18 +360,19 @@ static void render_view_toplevels(struct sway_view *view,
} }
static void render_view_popups(struct sway_view *view, struct sway_output *output, static void render_view_popups(struct sway_view *view, struct sway_output *output,
pixman_region32_t *damage, float alpha, int corner_radius) { pixman_region32_t *damage, float alpha, int corner_radius, bool has_titlebar) {
struct render_data data = { struct render_data data = {
.damage = damage, .damage = damage,
.alpha = alpha, .alpha = alpha,
.corner_radius = corner_radius, .corner_radius = corner_radius,
.has_titlebar = has_titlebar,
}; };
output_view_for_each_popup_surface(output, view, output_view_for_each_popup_surface(output, view,
render_surface_iterator, &data); render_surface_iterator, &data);
} }
static void render_saved_view(struct sway_view *view, static void render_saved_view(struct sway_view *view, struct sway_output *output,
struct sway_output *output, pixman_region32_t *damage, float alpha, int corner_radius) { pixman_region32_t *damage, float alpha, int corner_radius, bool has_titlebar) {
struct wlr_output *wlr_output = output->wlr_output; struct wlr_output *wlr_output = output->wlr_output;
if (wl_list_empty(&view->saved_buffers)) { if (wl_list_empty(&view->saved_buffers)) {
@ -384,7 +424,7 @@ static void render_saved_view(struct sway_view *view,
scale_box(&dst_box, wlr_output->scale); scale_box(&dst_box, wlr_output->scale);
render_texture(wlr_output, damage, saved_buf->buffer->texture, render_texture(wlr_output, damage, saved_buf->buffer->texture,
&saved_buf->source_box, &dst_box, matrix, alpha, corner_radius * wlr_output->scale); &saved_buf->source_box, &dst_box, matrix, alpha, corner_radius * wlr_output->scale, has_titlebar);
} }
// FIXME: we should set the surface that this saved buffer originates from // FIXME: we should set the surface that this saved buffer originates from
@ -399,9 +439,9 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
struct sway_container *con, struct border_colors *colors, bool has_titlebar) { struct sway_container *con, struct border_colors *colors, bool has_titlebar) {
struct sway_view *view = con->view; struct sway_view *view = con->view;
if (!wl_list_empty(&view->saved_buffers)) { if (!wl_list_empty(&view->saved_buffers)) {
render_saved_view(view, output, damage, con->alpha, con->corner_radius); render_saved_view(view, output, damage, con->alpha, con->corner_radius, has_titlebar);
} else if (view->surface) { } else if (view->surface) {
render_view_toplevels(view, output, damage, con->alpha, con->corner_radius); render_view_toplevels(view, output, damage, con->alpha, con->corner_radius, has_titlebar);
} }
if (con->current.border == B_NONE || con->current.border == B_CSD) { if (con->current.border == B_NONE || con->current.border == B_CSD) {
@ -518,25 +558,30 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
*/ */
static void render_titlebar(struct sway_output *output, static void render_titlebar(struct sway_output *output,
pixman_region32_t *output_damage, struct sway_container *con, pixman_region32_t *output_damage, struct sway_container *con,
int x, int y, int width, int x, int y, int width, struct border_colors *colors,
struct border_colors *colors, struct wlr_texture *title_texture, struct wlr_texture *title_texture, struct wlr_texture *marks_texture) {
struct wlr_texture *marks_texture) {
struct wlr_box box; struct wlr_box box;
float color[4]; float color[4];
float output_scale = output->wlr_output->scale; float output_scale = output->wlr_output->scale;
double output_x = output->lx; double output_x = output->lx;
double output_y = output->ly; double output_y = output->ly;
int titlebar_border_thickness = config->titlebar_border_thickness; int titlebar_border_thickness = config->titlebar_border_thickness;
int titlebar_h_padding = config->titlebar_h_padding;
int titlebar_v_padding = config->titlebar_v_padding;
enum alignment title_align = config->title_align; enum alignment title_align = config->title_align;
int corner_radius = con->corner_radius;
// titlebar padding should account for corner radius
int titlebar_h_padding = corner_radius > config->titlebar_h_padding ?
corner_radius : config->titlebar_h_padding;
float titlebar_v_padding = corner_radius == (int)container_titlebar_height() ?
(container_titlebar_height() - config->font_height) / 2.0 : config->titlebar_v_padding;
// Single pixel bar above title // Single pixel bar above title
memcpy(&color, colors->border, sizeof(float) * 4); memcpy(&color, colors->border, sizeof(float) * 4);
premultiply_alpha(color, con->alpha); premultiply_alpha(color, con->alpha);
box.x = x; box.x = corner_radius ? x + corner_radius : x + titlebar_border_thickness;
box.y = y; box.y = y;
box.width = width; box.width = corner_radius ?
width - corner_radius * 2 : width - titlebar_border_thickness * 2;
box.height = titlebar_border_thickness; box.height = titlebar_border_thickness;
scale_box(&box, output_scale); scale_box(&box, output_scale);
render_rect(output, output_damage, &box, color); render_rect(output, output_damage, &box, color);
@ -549,22 +594,43 @@ static void render_titlebar(struct sway_output *output,
scale_box(&box, output_scale); scale_box(&box, output_scale);
render_rect(output, output_damage, &box, color); render_rect(output, output_damage, &box, color);
// Single pixel left edge // Single pixel bar left edge
box.x = x; box.x = x;
box.y = y + titlebar_border_thickness; box.y = y + corner_radius;
box.width = titlebar_border_thickness; box.width = titlebar_border_thickness;
box.height = container_titlebar_height() - titlebar_border_thickness * 2; box.height = container_titlebar_height() - titlebar_border_thickness - corner_radius;
scale_box(&box, output_scale); scale_box(&box, output_scale);
render_rect(output, output_damage, &box, color); render_rect(output, output_damage, &box, color);
// Single pixel right edge // Single pixel bar right edge
box.x = x + width - titlebar_border_thickness; box.x = x + width - titlebar_border_thickness;
box.y = y + titlebar_border_thickness; box.y = y + corner_radius;
box.width = titlebar_border_thickness; box.width = titlebar_border_thickness;
box.height = container_titlebar_height() - titlebar_border_thickness * 2; box.height = container_titlebar_height() - titlebar_border_thickness - corner_radius;
scale_box(&box, output_scale); scale_box(&box, output_scale);
render_rect(output, output_damage, &box, color); render_rect(output, output_damage, &box, color);
// if corner_radius: single pixel corners
if (corner_radius) {
// left corner
box.x = x;
box.y = y;
box.width = corner_radius * 2;
box.height = corner_radius * 2;
scale_box(&box, output_scale);
render_border_corner(output, output_damage, &box, color,
corner_radius, titlebar_border_thickness, TOP_LEFT);
// right corner
box.x = x + width - corner_radius * 2;
box.y = y;
box.width = corner_radius * 2;
box.height = corner_radius * 2;
scale_box(&box, output_scale);
render_border_corner(output, output_damage, &box, color,
corner_radius, titlebar_border_thickness, TOP_RIGHT);
}
int inner_x = x - output_x + titlebar_h_padding; int inner_x = x - output_x + titlebar_h_padding;
int bg_y = y + titlebar_border_thickness; int bg_y = y + titlebar_border_thickness;
size_t inner_width = width - titlebar_h_padding * 2; size_t inner_width = width - titlebar_h_padding * 2;
@ -613,7 +679,7 @@ static void render_titlebar(struct sway_output *output,
texture_box.width = ob_inner_width; texture_box.width = ob_inner_width;
} }
render_texture(output->wlr_output, output_damage, marks_texture, render_texture(output->wlr_output, output_damage, marks_texture,
NULL, &texture_box, matrix, con->alpha, 0); NULL, &texture_box, matrix, con->alpha, 0, false);
// Padding above // Padding above
memcpy(&color, colors->background, sizeof(float) * 4); memcpy(&color, colors->background, sizeof(float) * 4);
@ -689,7 +755,7 @@ static void render_titlebar(struct sway_output *output,
} }
render_texture(output->wlr_output, output_damage, title_texture, render_texture(output->wlr_output, output_damage, title_texture,
NULL, &texture_box, matrix, con->alpha, 0); NULL, &texture_box, matrix, con->alpha, 0, false);
// Padding above // Padding above
memcpy(&color, colors->background, sizeof(float) * 4); memcpy(&color, colors->background, sizeof(float) * 4);
@ -751,7 +817,11 @@ static void render_titlebar(struct sway_output *output,
if (box.x + box.width < left_x) { if (box.x + box.width < left_x) {
box.width += left_x - box.x - box.width; box.width += left_x - box.x - box.width;
} }
render_rect(output, output_damage, &box, color); if (corner_radius) {
render_rounded_rect(output, output_damage, &box, color, corner_radius, TOP_LEFT);
} else {
render_rect(output, output_damage, &box, color);
}
// Padding on right side // Padding on right side
box.x = x + width - titlebar_h_padding; box.x = x + width - titlebar_h_padding;
@ -765,7 +835,11 @@ static void render_titlebar(struct sway_output *output,
box.width += box.x - right_rx; box.width += box.x - right_rx;
box.x = right_rx; box.x = right_rx;
} }
render_rect(output, output_damage, &box, color); if (corner_radius) {
render_rounded_rect(output, output_damage, &box, color, corner_radius, TOP_RIGHT);
} else {
render_rect(output, output_damage, &box, color);
}
} }
/** /**
@ -1116,7 +1190,6 @@ static void render_floating_container(struct sway_output *soutput,
render_titlebar(soutput, damage, con, floor(con->current.x), render_titlebar(soutput, damage, con, floor(con->current.x),
floor(con->current.y), con->current.width, colors, floor(con->current.y), con->current.width, colors,
title_texture, marks_texture); title_texture, marks_texture);
has_titlebar = true;
} else if (con->current.border == B_PIXEL) { } else if (con->current.border == B_PIXEL) {
render_top_border(soutput, damage, con, colors); render_top_border(soutput, damage, con, colors);
} }
@ -1201,10 +1274,9 @@ void output_render(struct sway_output *output, struct timespec *when,
if (fullscreen_con->view) { if (fullscreen_con->view) {
if (!wl_list_empty(&fullscreen_con->view->saved_buffers)) { if (!wl_list_empty(&fullscreen_con->view->saved_buffers)) {
render_saved_view(fullscreen_con->view, output, damage, 1.0f, 0); render_saved_view(fullscreen_con->view, output, damage, 1.0f, 0, false);
} else if (fullscreen_con->view->surface) { } else if (fullscreen_con->view->surface) {
render_view_toplevels(fullscreen_con->view, render_view_toplevels(fullscreen_con->view, output, damage, 1.0f, 0, false);
output, damage, 1.0f, 0);
} }
} else { } else {
render_container(output, damage, fullscreen_con, render_container(output, damage, fullscreen_con,
@ -1257,7 +1329,8 @@ void output_render(struct sway_output *output, struct timespec *when,
struct sway_seat *seat = input_manager_current_seat(); struct sway_seat *seat = input_manager_current_seat();
struct sway_container *focus = seat_get_focused_container(seat); struct sway_container *focus = seat_get_focused_container(seat);
if (focus && focus->view) { if (focus && focus->view) {
render_view_popups(focus->view, output, damage, focus->alpha, focus->corner_radius); render_view_popups(focus->view, output, damage, focus->alpha,
focus->corner_radius, focus->current.border == B_NORMAL);
} }
render_overlay: render_overlay:

View file

@ -3,8 +3,10 @@ embed = find_program('./embed.sh', native: true)
shaders = [ shaders = [
'quad.vert', 'quad.vert',
'quad.frag', 'quad.frag',
'tex.vert', 'quad_round_tl.frag',
'quad_round_tr.frag',
'corner.frag', 'corner.frag',
'tex.vert',
'tex_rgba.frag', 'tex_rgba.frag',
'tex_rgbx.frag', 'tex_rgbx.frag',
'tex_external.frag', 'tex_external.frag',

View file

@ -0,0 +1,14 @@
precision mediump float;
varying vec4 v_color;
varying vec2 v_texcoord;
uniform vec2 size;
uniform vec2 position;
uniform float radius;
void main() {
vec2 q = abs(gl_FragCoord.xy - position - size) - size + radius;
float distance = min(max(q.x,q.y),0.0) + length(max(q,0.0)) - radius;
float smoothedAlpha = 1.0 - smoothstep(-1.0, 0.5, distance);
gl_FragColor = mix(vec4(0), v_color, smoothedAlpha);
}

View file

@ -0,0 +1,14 @@
precision mediump float;
varying vec4 v_color;
varying vec2 v_texcoord;
uniform vec2 size;
uniform vec2 position;
uniform float radius;
void main() {
vec2 q = abs(gl_FragCoord.xy - position - vec2(0, size.y)) - size + radius;
float distance = min(max(q.x,q.y),0.0) + length(max(q,0.0)) - radius;
float smoothedAlpha = 1.0 - smoothstep(-1.0, 0.5, distance);
gl_FragColor = mix(vec4(0), v_color, smoothedAlpha);
}

View file

@ -8,13 +8,16 @@ uniform float alpha;
uniform vec2 size; uniform vec2 size;
uniform vec2 position; uniform vec2 position;
uniform float radius; uniform float radius;
uniform bool has_titlebar;
void main() { void main() {
gl_FragColor = texture2D(texture0, v_texcoord) * alpha; gl_FragColor = texture2D(texture0, v_texcoord) * alpha;
vec2 corner_distance = min(gl_FragCoord.xy - position, position + size - gl_FragCoord.xy); if (!has_titlebar || gl_FragCoord.y - position.y > radius) {
if (max(corner_distance.x, corner_distance.y) < radius) { vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy);
float d = radius - distance(corner_distance, vec2(radius)); if (max(corner_distance.x, corner_distance.y) < radius) {
float smooth = smoothstep(-1.0f, 0.5f, d); float d = radius - distance(corner_distance, vec2(radius));
gl_FragColor = mix(vec4(0), gl_FragColor, smooth); float smooth = smoothstep(-1.0f, 0.5f, d);
} gl_FragColor = mix(vec4(0), gl_FragColor, smooth);
}
}
} }

View file

@ -6,13 +6,16 @@ uniform float alpha;
uniform vec2 size; uniform vec2 size;
uniform vec2 position; uniform vec2 position;
uniform float radius; uniform float radius;
uniform bool has_titlebar;
void main() { void main() {
gl_FragColor = texture2D(tex, v_texcoord) * alpha; gl_FragColor = texture2D(tex, v_texcoord) * alpha;
vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); if (!has_titlebar || gl_FragCoord.y - position.y > radius) {
if (max(corner_distance.x, corner_distance.y) < radius) { vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy);
float d = radius - distance(corner_distance, vec2(radius)); if (max(corner_distance.x, corner_distance.y) < radius) {
float smooth = smoothstep(-1.0f, 0.5f, d); float d = radius - distance(corner_distance, vec2(radius));
gl_FragColor = mix(vec4(0), gl_FragColor, smooth); float smooth = smoothstep(-1.0f, 0.5f, d);
} gl_FragColor = mix(vec4(0), gl_FragColor, smooth);
}
}
} }

View file

@ -6,13 +6,16 @@ uniform float alpha;
uniform vec2 size; uniform vec2 size;
uniform vec2 position; uniform vec2 position;
uniform float radius; uniform float radius;
uniform bool has_titlebar;
void main() { void main() {
gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha; gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;
vec2 corner_distance = min(gl_FragCoord.xy - position, position + size - gl_FragCoord.xy); if (!has_titlebar || gl_FragCoord.y - position.y > radius) {
if (max(corner_distance.x, corner_distance.y) < radius) { vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy);
float d = radius - distance(corner_distance, vec2(radius)); if (max(corner_distance.x, corner_distance.y) < radius) {
float smooth = smoothstep(-1.0f, 0.5f, d); float d = radius - distance(corner_distance, vec2(radius));
gl_FragColor = mix(vec4(0), gl_FragColor, smooth); float smooth = smoothstep(-1.0f, 0.5f, d);
} gl_FragColor = mix(vec4(0), gl_FragColor, smooth);
}
}
} }

View file

@ -663,7 +663,9 @@ The default colors are:
padding of the text while _vertical_ value affects vertical padding (space padding of the text while _vertical_ value affects vertical padding (space
above and below text). Padding includes titlebar borders so their value above and below text). Padding includes titlebar borders so their value
should be greater than titlebar_border_thickness. If _vertical_ value is should be greater than titlebar_border_thickness. If _vertical_ value is
not specified it is set to the _horizontal_ value. not specified it is set to the _horizontal_ value. If _corner_radius_ is set
to be greater than the _horizontal_ or _vertical_ value, the value will be
treated as that of _corner_radius_.
*for_window* <criteria> <command> *for_window* <criteria> <command>
Whenever a window that matches _criteria_ appears, run list of commands. Whenever a window that matches _criteria_ appears, run list of commands.
@ -960,3 +962,4 @@ The following attributes may be matched with:
# SEE ALSO # SEE ALSO
*sway*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) *sway-ipc*(7) *sway*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) *sway-ipc*(7)

View file

@ -675,7 +675,9 @@ void container_update_representation(struct sway_container *con) {
} }
size_t container_titlebar_height(void) { size_t container_titlebar_height(void) {
return config->font_height + config->titlebar_v_padding * 2; int config_titlebar_height = config->font_height + config->titlebar_v_padding * 2;
return config->corner_radius > config_titlebar_height ?
config->corner_radius : config_titlebar_height;
} }
void floating_calculate_constraints(int *min_width, int *max_width, void floating_calculate_constraints(int *min_width, int *max_width,