summaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/desktop/fx_renderer.c89
-rw-r--r--sway/desktop/render.c132
2 files changed, 211 insertions, 10 deletions
diff --git a/sway/desktop/fx_renderer.c b/sway/desktop/fx_renderer.c
index 1bd68359..7dddc7ff 100644
--- a/sway/desktop/fx_renderer.c
+++ b/sway/desktop/fx_renderer.c
@@ -130,6 +130,25 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
renderer->shaders.quad.color = glGetUniformLocation(prog, "color");
renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos");
+ // Border corners
+ prog = link_program(quad_vertex_src, corner_fragment_src);
+ renderer->shaders.corner.program = prog;
+ if (!renderer->shaders.corner.program) {
+ goto error;
+ }
+ renderer->shaders.corner.proj = glGetUniformLocation(prog, "proj");
+ renderer->shaders.corner.color = glGetUniformLocation(prog, "color");
+ renderer->shaders.corner.pos_attrib = glGetAttribLocation(prog, "pos");
+ renderer->shaders.corner.is_top_left = glGetUniformLocation(prog, "is_top_left");
+ renderer->shaders.corner.is_top_right = glGetUniformLocation(prog, "is_top_right");
+ renderer->shaders.corner.is_bottom_left = glGetUniformLocation(prog, "is_bottom_left");
+ renderer->shaders.corner.is_bottom_right = glGetUniformLocation(prog, "is_bottom_right");
+ renderer->shaders.corner.width = glGetUniformLocation(prog, "width");
+ renderer->shaders.corner.height = glGetUniformLocation(prog, "height");
+ renderer->shaders.corner.position = glGetUniformLocation(prog, "position");
+ renderer->shaders.corner.radius = glGetUniformLocation(prog, "radius");
+ renderer->shaders.corner.thickness = glGetUniformLocation(prog, "thickness");
+
prog = link_program(tex_vertex_src, tex_fragment_src_rgba);
renderer->shaders.tex_rgba.program = prog;
if (!renderer->shaders.tex_rgba.program) {
@@ -183,6 +202,7 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
error:
glDeleteProgram(renderer->shaders.quad.program);
+ glDeleteProgram(renderer->shaders.corner.program);
glDeleteProgram(renderer->shaders.tex_rgba.program);
glDeleteProgram(renderer->shaders.tex_rgbx.program);
glDeleteProgram(renderer->shaders.tex_ext.program);
@@ -332,7 +352,8 @@ bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct wlr_text
return fx_render_subtexture_with_matrix(renderer, wlr_texture, &src_box, dst_box, matrix, alpha, radius);
}
-void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, const float color[static 4], const float projection[static 9]) {
+void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
+ const float color[static 4], const float projection[static 9]) {
if (box->width == 0 || box->height == 0) {
return;
}
@@ -368,3 +389,69 @@ void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, con
glDisableVertexAttribArray(renderer->shaders.quad.pos_attrib);
}
+
+void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box,
+ const float color[static 4], const float projection[static 9],
+ enum corner_location corner_location, int radius, int border_thickness) {
+ if (box->width == 0 || box->height == 0) {
+ return;
+ }
+ assert(box->width > 0 && box->height > 0);
+ 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);
+
+ if (color[3] == 1.0 && !radius) {
+ glDisable(GL_BLEND);
+ } else {
+ glEnable(GL_BLEND);
+ }
+
+ glUseProgram(renderer->shaders.corner.program);
+
+ glUniformMatrix3fv(renderer->shaders.corner.proj, 1, GL_FALSE, gl_matrix);
+ glUniform4f(renderer->shaders.corner.color, color[0], color[1], color[2], color[3]);
+
+ glUniform1f(renderer->shaders.corner.is_top_left, false);
+ glUniform1f(renderer->shaders.corner.is_top_right, false);
+ glUniform1f(renderer->shaders.corner.is_bottom_left, false);
+ glUniform1f(renderer->shaders.corner.is_bottom_right, false);
+ switch (corner_location) {
+ case TOP_LEFT:
+ glUniform1f(renderer->shaders.corner.is_top_left, true);
+ break;
+ case TOP_RIGHT:
+ glUniform1f(renderer->shaders.corner.is_top_right, true);
+ break;
+ case BOTTOM_LEFT:
+ glUniform1f(renderer->shaders.corner.is_bottom_left, true);
+ break;
+ case BOTTOM_RIGHT:
+ glUniform1f(renderer->shaders.corner.is_bottom_right, true);
+ break;
+ default:
+ return;
+ }
+
+ glUniform1f(renderer->shaders.corner.width, box->width);
+ glUniform1f(renderer->shaders.corner.height, box->height);
+ glUniform2f(renderer->shaders.corner.position, box->x, box->y);
+ glUniform1f(renderer->shaders.corner.radius, radius);
+ glUniform1f(renderer->shaders.corner.thickness, border_thickness);
+
+ glVertexAttribPointer(renderer->shaders.corner.pos_attrib, 2, GL_FLOAT, GL_FALSE,
+ 0, verts);
+
+ glEnableVertexAttribArray(renderer->shaders.corner.pos_attrib);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glDisableVertexAttribArray(renderer->shaders.corner.pos_attrib);
+}
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 09a99e02..422991f7 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -166,7 +166,8 @@ static void render_surface_iterator(struct sway_output *output,
}
scale_box(&dst_box, wlr_output->scale);
- render_texture(wlr_output, output_damage, texture, &src_box, &dst_box, matrix, alpha, corner_radius);
+ render_texture(wlr_output, output_damage, texture, &src_box, &dst_box,
+ matrix, alpha, corner_radius * wlr_output->scale);
wlr_presentation_surface_sampled_on_output(server.presentation, surface,
wlr_output);
@@ -253,6 +254,41 @@ damage_finish:
pixman_region32_fini(&damage);
}
+// _box.x and .y are expected to be layout-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,
+ const struct wlr_box *_box, float color[static 4], int border_thickness,
+ 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_border_corner(renderer, &box, color, wlr_output->transform_matrix,
+ corner_location, config->corner_radius * wlr_output->scale, border_thickness);
+ }
+
+damage_finish:
+ pixman_region32_fini(&damage);
+}
+
void premultiply_alpha(float color[4], float opacity) {
color[3] *= opacity;
color[0] *= color[3];
@@ -348,7 +384,7 @@ static void render_saved_view(struct sway_view *view,
scale_box(&dst_box, wlr_output->scale);
render_texture(wlr_output, damage, saved_buf->buffer->texture,
- &saved_buf->source_box, &dst_box, matrix, alpha, corner_radius);
+ &saved_buf->source_box, &dst_box, matrix, alpha, corner_radius * wlr_output->scale);
}
// FIXME: we should set the surface that this saved buffer originates from
@@ -360,7 +396,7 @@ static void render_saved_view(struct sway_view *view,
* Render a view's surface and left/bottom/right borders.
*/
static void render_view(struct sway_output *output, pixman_region32_t *damage,
- struct sway_container *con, struct border_colors *colors) {
+ struct sway_container *con, struct border_colors *colors, bool has_titlebar) {
struct sway_view *view = con->view;
if (!wl_list_empty(&view->saved_buffers)) {
render_saved_view(view, output, damage, view->container->alpha, config->corner_radius);
@@ -384,6 +420,15 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
box.y = floor(state->content_y);
box.width = state->border_thickness;
box.height = state->content_height;
+ // adjust sizing for rounded border corners
+ if (config->corner_radius) {
+ if (!has_titlebar) {
+ box.y += config->corner_radius;
+ box.height -= 2 * config->corner_radius;
+ } else {
+ box.height -= config->corner_radius;
+ }
+ }
scale_box(&box, output_scale);
render_rect(output, damage, &box, color);
}
@@ -403,6 +448,15 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
box.y = floor(state->content_y);
box.width = state->border_thickness;
box.height = state->content_height;
+ // adjust sizing for rounded border corners
+ if (config->corner_radius) {
+ if (!has_titlebar) {
+ box.y += config->corner_radius;
+ box.height -= 2 * config->corner_radius;
+ } else {
+ box.height -= config->corner_radius;
+ }
+ }
scale_box(&box, output_scale);
render_rect(output, damage, &box, color);
}
@@ -418,8 +472,35 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
box.y = floor(state->content_y + state->content_height);
box.width = state->width;
box.height = state->border_thickness;
+ // adjust sizing for rounded border corners
+ if (config->corner_radius) {
+ box.x += config->corner_radius;
+ box.width -= 2 * config->corner_radius;
+ }
scale_box(&box, output_scale);
render_rect(output, damage, &box, color);
+
+ // rounded bottom left & bottom right border corners
+ if (config->corner_radius) {
+ int size = 2 * (config->corner_radius + state->border_thickness);
+ int scaled_thickness = state->border_thickness * output_scale;
+ if (state->border_left) {
+ box.width = size;
+ box.height = size;
+ box.x = floor(state->x);
+ box.y = floor(state->y + state->height - size);
+ scale_box(&box, output_scale);
+ render_border_corner(output, damage, &box, color, scaled_thickness, BOTTOM_LEFT);
+ }
+ if (state->border_right) {
+ box.width = size;
+ box.height = size;
+ box.x = floor(state->x + state->width - size);
+ box.y = floor(state->y + state->height - size);
+ scale_box(&box, output_scale);
+ render_border_corner(output, damage, &box, color, scaled_thickness, BOTTOM_RIGHT);
+ }
+ }
}
}
@@ -705,8 +786,38 @@ static void render_top_border(struct sway_output *output,
box.y = floor(state->y);
box.width = state->width;
box.height = state->border_thickness;
+ // adjust sizing for rounded border corners
+ if (config->corner_radius) {
+ box.x += config->corner_radius;
+ box.width -= 2 * config->corner_radius;
+ }
scale_box(&box, output_scale);
render_rect(output, output_damage, &box, color);
+
+ // render rounded top corner borders if corner_radius is set > 0
+ if (config->corner_radius) {
+ int size = 2 * (config->corner_radius + state->border_thickness);
+ int scaled_thickness = state->border_thickness * output_scale;
+
+ // top left
+ if (state->border_left) {
+ box.width = size;
+ box.height = size;
+ box.x = floor(state->x);
+ box.y = floor(state->y);
+ scale_box(&box, output_scale);
+ render_border_corner(output, output_damage, &box, color, scaled_thickness, TOP_LEFT);
+ }
+ // top right
+ if (state->border_right) {
+ box.width = size;
+ box.height = size;
+ box.x = floor(state->x + state->width - size);
+ box.y = floor(state->y);
+ scale_box(&box, output_scale);
+ render_border_corner(output, output_damage, &box, color, scaled_thickness, TOP_RIGHT);
+ }
+ }
}
struct parent_data {
@@ -756,14 +867,15 @@ static void render_containers_linear(struct sway_output *output,
marks_texture = child->marks_unfocused;
}
- if (state->border == B_NORMAL) {
+ bool has_titlebar = state->border == B_NORMAL;
+ render_view(output, damage, child, colors, has_titlebar);
+ if (has_titlebar) {
render_titlebar(output, damage, child, floor(state->x),
floor(state->y), state->width, colors,
title_texture, marks_texture);
} else if (state->border == B_PIXEL) {
render_top_border(output, damage, child, colors);
}
- render_view(output, damage, child, colors);
} else {
render_container(output, damage, child,
parent->focused || child->current.focused);
@@ -841,7 +953,7 @@ static void render_containers_tabbed(struct sway_output *output,
// Render surface and left/right/bottom borders
if (current->view) {
- render_view(output, damage, current, current_colors);
+ render_view(output, damage, current, current_colors, true);
} else {
render_container(output, damage, current,
parent->focused || current->current.focused);
@@ -904,7 +1016,7 @@ static void render_containers_stacked(struct sway_output *output,
// Render surface and left/right/bottom borders
if (current->view) {
- render_view(output, damage, current, current_colors);
+ render_view(output, damage, current, current_colors, true);
} else {
render_container(output, damage, current,
parent->focused || current->current.focused);
@@ -992,14 +1104,16 @@ static void render_floating_container(struct sway_output *soutput,
marks_texture = con->marks_unfocused;
}
- if (con->current.border == B_NORMAL) {
+ bool has_titlebar = con->current.border == B_NORMAL;
+ render_view(soutput, damage, con, colors, has_titlebar);
+ if (has_titlebar) {
render_titlebar(soutput, damage, con, floor(con->current.x),
floor(con->current.y), con->current.width, colors,
title_texture, marks_texture);
+ has_titlebar = true;
} else if (con->current.border == B_PIXEL) {
render_top_border(soutput, damage, con, colors);
}
- render_view(soutput, damage, con, colors);
} else {
render_container(soutput, damage, con, con->current.focused);
}