diff options
Diffstat (limited to 'sway')
-rw-r--r-- | sway/desktop/fx_renderer.c | 89 | ||||
-rw-r--r-- | sway/desktop/render.c | 132 |
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); } |