diff options
author | William McKinnon <[email protected]> | 2022-11-11 01:19:02 -0500 |
---|---|---|
committer | GitHub <[email protected]> | 2022-11-11 01:19:02 -0500 |
commit | 1930bd0d7136d84900fe1541e4317cbcd7a85ef6 (patch) | |
tree | 0953eb462206e0c52c5206370abfd3b33898e1ac /sway/desktop/render.c | |
parent | 9ee7fa61af58de3dab3d60e325ef1d0c6f40f9fd (diff) |
feat: add round titlebars (#26)
Diffstat (limited to 'sway/desktop/render.c')
-rw-r--r-- | sway/desktop/render.c | 147 |
1 files changed, 110 insertions, 37 deletions
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index d27eb46f..83fe8ca6 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -33,6 +33,7 @@ struct render_data { pixman_region32_t *damage; float alpha; int corner_radius; + bool has_titlebar; 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, pixman_region32_t *output_damage, struct wlr_texture *texture, 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 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]); set_scale_filter(wlr_output, texture, output->scale_filter); 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 { - 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; float alpha = data->alpha; int corner_radius = data->corner_radius; + bool has_titlebar = data->has_titlebar; struct wlr_texture *texture = wlr_surface_get_texture(surface); if (!texture) { @@ -167,7 +169,7 @@ 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 * wlr_output->scale); + matrix, alpha, corner_radius * wlr_output->scale, has_titlebar); wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_output); @@ -179,6 +181,7 @@ static void render_layer_toplevel(struct sway_output *output, .damage = damage, .alpha = 1.0f, .corner_radius = 0, + .has_titlebar = false, }; output_layer_for_each_toplevel_surface(output, layer_surfaces, render_surface_iterator, &data); @@ -190,6 +193,7 @@ static void render_layer_popups(struct sway_output *output, .damage = damage, .alpha = 1.0f, .corner_radius = 0, + .has_titlebar = false, }; output_layer_for_each_popup_surface(output, layer_surfaces, render_surface_iterator, &data); @@ -202,6 +206,7 @@ static void render_unmanaged(struct sway_output *output, .damage = damage, .alpha = 1.0f, .corner_radius = 0, + .has_titlebar = false, }; output_unmanaged_for_each_surface(output, unmanaged, render_surface_iterator, &data); @@ -214,6 +219,7 @@ static void render_drag_icons(struct sway_output *output, .damage = damage, .alpha = 1.0f, .corner_radius = 0, + .has_titlebar = false, }; output_drag_icons_for_each_surface(output, drag_icons, render_surface_iterator, &data); @@ -246,8 +252,40 @@ void render_rect(struct sway_output *output, pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(wlr_output, &rects[i]); - fx_render_rect(renderer, &box, color, - wlr_output->transform_matrix); + fx_render_rect(renderer, &box, color, 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: @@ -257,7 +295,7 @@ damage_finish: // _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 corner_radius, + const struct wlr_box *_box, const float color[static 4], int corner_radius, int border_thickness, enum corner_location corner_location) { struct wlr_output *wlr_output = output->wlr_output; struct fx_renderer *renderer = output->server->renderer; @@ -296,12 +334,13 @@ void premultiply_alpha(float color[4], float opacity) { color[2] *= color[3]; } -static void render_view_toplevels(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha, int corner_radius) { +static void render_view_toplevels(struct sway_view *view, struct sway_output *output, + pixman_region32_t *damage, float alpha, int corner_radius, bool has_titlebar) { struct render_data data = { .damage = damage, .alpha = alpha, .corner_radius = corner_radius, + .has_titlebar = has_titlebar, }; struct wlr_box clip_box; 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, - 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 = { .damage = damage, .alpha = alpha, .corner_radius = corner_radius, + .has_titlebar = has_titlebar, }; output_view_for_each_popup_surface(output, view, render_surface_iterator, &data); } -static void render_saved_view(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha, int corner_radius) { +static void render_saved_view(struct sway_view *view, struct sway_output *output, + pixman_region32_t *damage, float alpha, int corner_radius, bool has_titlebar) { struct wlr_output *wlr_output = output->wlr_output; 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); 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 @@ -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_view *view = con->view; 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) { - 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) { @@ -518,25 +558,30 @@ 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) { + int x, int y, int width, 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; double output_x = output->lx; double output_y = output->ly; 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; + 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 memcpy(&color, colors->border, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = x; + box.x = corner_radius ? x + corner_radius : x + titlebar_border_thickness; box.y = y; - box.width = width; + box.width = corner_radius ? + width - corner_radius * 2 : width - titlebar_border_thickness * 2; box.height = titlebar_border_thickness; scale_box(&box, output_scale); render_rect(output, output_damage, &box, color); @@ -549,22 +594,43 @@ static void render_titlebar(struct sway_output *output, scale_box(&box, output_scale); render_rect(output, output_damage, &box, color); - // Single pixel left edge + // Single pixel bar left edge box.x = x; - box.y = y + titlebar_border_thickness; + box.y = y + corner_radius; 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); render_rect(output, output_damage, &box, color); - // Single pixel right edge + // Single pixel bar right edge box.x = x + width - titlebar_border_thickness; - box.y = y + titlebar_border_thickness; + box.y = y + corner_radius; 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); 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 bg_y = y + titlebar_border_thickness; 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; } 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 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, - NULL, &texture_box, matrix, con->alpha, 0); + NULL, &texture_box, matrix, con->alpha, 0, false); // Padding above 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) { 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 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.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), 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); } @@ -1201,10 +1274,9 @@ void output_render(struct sway_output *output, struct timespec *when, if (fullscreen_con->view) { 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) { - render_view_toplevels(fullscreen_con->view, - output, damage, 1.0f, 0); + render_view_toplevels(fullscreen_con->view, output, damage, 1.0f, 0, false); } } else { 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_container *focus = seat_get_focused_container(seat); 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: |