diff --git a/README.md b/README.md index 5057d88f..4a285283 100644 --- a/README.md +++ b/README.md @@ -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: -+ **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)) + **Add a nix flake to the repo**: Allows nixos users to easily contribute to and test this project diff --git a/include/sway/desktop/fx_renderer.h b/include/sway/desktop/fx_renderer.h index 889d8a82..e3b23411 100644 --- a/include/sway/desktop/fx_renderer.h +++ b/include/sway/desktop/fx_renderer.h @@ -4,7 +4,7 @@ #include #include -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 { GLuint program; @@ -16,6 +16,17 @@ struct gles2_tex_shader { GLint size; GLint position; 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 { @@ -31,6 +42,10 @@ struct fx_renderer { GLint color; GLint pos_attrib; } quad; + + struct rounded_quad_shader rounded_tl_quad; + struct rounded_quad_shader rounded_tr_quad; + struct { GLuint program; GLint proj; @@ -45,6 +60,7 @@ struct fx_renderer { GLint half_size; GLint half_thickness; } corner; + struct gles2_tex_shader tex_rgba; struct gles2_tex_shader tex_rgbx; 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, 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, - 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, 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, const float color[static 4], const float projection[static 9], enum corner_location corner_location, int radius, int border_thickness); diff --git a/sway/desktop/fx_renderer.c b/sway/desktop/fx_renderer.c index 7af4a313..2b5ba060 100644 --- a/sway/desktop/fx_renderer.c +++ b/sway/desktop/fx_renderer.c @@ -20,6 +20,8 @@ // shaders #include "quad_vert_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 "tex_vert_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->position = glGetUniformLocation(prog, "position"); 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; } @@ -133,6 +151,7 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) { // init shaders GLuint prog; + // quad fragment shader prog = link_program(quad_vert_src, quad_frag_src); renderer->shaders.quad.program = prog; 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.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); renderer->shaders.corner.program = prog; 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, 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)); 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); glUniform1i(shader->tex, 0); glUniform1f(shader->alpha, alpha); + glUniform1f(shader->has_titlebar, has_titlebar); // rounded corners 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, - 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 = { .x = 0, .y = 0, .width = wlr_texture->width, .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, @@ -364,6 +395,61 @@ void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box, 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, const float color[static 4], const float projection[static 9], enum corner_location corner_location, int radius, int border_thickness) { 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: diff --git a/sway/desktop/shaders/meson.build b/sway/desktop/shaders/meson.build index 8eb12079..661ccc35 100644 --- a/sway/desktop/shaders/meson.build +++ b/sway/desktop/shaders/meson.build @@ -3,8 +3,10 @@ embed = find_program('./embed.sh', native: true) shaders = [ 'quad.vert', 'quad.frag', - 'tex.vert', + 'quad_round_tl.frag', + 'quad_round_tr.frag', 'corner.frag', + 'tex.vert', 'tex_rgba.frag', 'tex_rgbx.frag', 'tex_external.frag', diff --git a/sway/desktop/shaders/quad_round_tl.frag b/sway/desktop/shaders/quad_round_tl.frag new file mode 100644 index 00000000..6fd0119c --- /dev/null +++ b/sway/desktop/shaders/quad_round_tl.frag @@ -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); +} diff --git a/sway/desktop/shaders/quad_round_tr.frag b/sway/desktop/shaders/quad_round_tr.frag new file mode 100644 index 00000000..ff580045 --- /dev/null +++ b/sway/desktop/shaders/quad_round_tr.frag @@ -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); +} diff --git a/sway/desktop/shaders/tex_external.frag b/sway/desktop/shaders/tex_external.frag index 404688c2..0703a05f 100644 --- a/sway/desktop/shaders/tex_external.frag +++ b/sway/desktop/shaders/tex_external.frag @@ -8,13 +8,16 @@ uniform float alpha; uniform vec2 size; uniform vec2 position; uniform float radius; +uniform bool has_titlebar; void main() { gl_FragColor = texture2D(texture0, v_texcoord) * alpha; - vec2 corner_distance = min(gl_FragCoord.xy - position, position + size - gl_FragCoord.xy); - if (max(corner_distance.x, corner_distance.y) < radius) { - float d = radius - distance(corner_distance, vec2(radius)); - float smooth = smoothstep(-1.0f, 0.5f, d); - gl_FragColor = mix(vec4(0), gl_FragColor, smooth); - } + if (!has_titlebar || gl_FragCoord.y - position.y > radius) { + vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); + if (max(corner_distance.x, corner_distance.y) < radius) { + float d = radius - distance(corner_distance, vec2(radius)); + float smooth = smoothstep(-1.0f, 0.5f, d); + gl_FragColor = mix(vec4(0), gl_FragColor, smooth); + } + } } diff --git a/sway/desktop/shaders/tex_rgba.frag b/sway/desktop/shaders/tex_rgba.frag index 1886fab4..95f58987 100644 --- a/sway/desktop/shaders/tex_rgba.frag +++ b/sway/desktop/shaders/tex_rgba.frag @@ -6,13 +6,16 @@ uniform float alpha; uniform vec2 size; uniform vec2 position; uniform float radius; +uniform bool has_titlebar; void main() { - gl_FragColor = texture2D(tex, v_texcoord) * alpha; - vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); - if (max(corner_distance.x, corner_distance.y) < radius) { - float d = radius - distance(corner_distance, vec2(radius)); - float smooth = smoothstep(-1.0f, 0.5f, d); - gl_FragColor = mix(vec4(0), gl_FragColor, smooth); - } + gl_FragColor = texture2D(tex, v_texcoord) * alpha; + if (!has_titlebar || gl_FragCoord.y - position.y > radius) { + vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); + if (max(corner_distance.x, corner_distance.y) < radius) { + float d = radius - distance(corner_distance, vec2(radius)); + float smooth = smoothstep(-1.0f, 0.5f, d); + gl_FragColor = mix(vec4(0), gl_FragColor, smooth); + } + } } diff --git a/sway/desktop/shaders/tex_rgbx.frag b/sway/desktop/shaders/tex_rgbx.frag index cb6f1432..4a8b3756 100644 --- a/sway/desktop/shaders/tex_rgbx.frag +++ b/sway/desktop/shaders/tex_rgbx.frag @@ -6,13 +6,16 @@ uniform float alpha; uniform vec2 size; uniform vec2 position; uniform float radius; +uniform bool has_titlebar; void main() { 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 (max(corner_distance.x, corner_distance.y) < radius) { - float d = radius - distance(corner_distance, vec2(radius)); - float smooth = smoothstep(-1.0f, 0.5f, d); - gl_FragColor = mix(vec4(0), gl_FragColor, smooth); - } + if (!has_titlebar || gl_FragCoord.y - position.y > radius) { + vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); + if (max(corner_distance.x, corner_distance.y) < radius) { + float d = radius - distance(corner_distance, vec2(radius)); + float smooth = smoothstep(-1.0f, 0.5f, d); + gl_FragColor = mix(vec4(0), gl_FragColor, smooth); + } + } } diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 86f250d0..a245ae14 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -663,7 +663,9 @@ The default colors are: padding of the text while _vertical_ value affects vertical padding (space above and below text). Padding includes titlebar borders so their value 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* Whenever a window that matches _criteria_ appears, run list of commands. @@ -960,3 +962,4 @@ The following attributes may be matched with: # SEE ALSO *sway*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) *sway-ipc*(7) + diff --git a/sway/tree/container.c b/sway/tree/container.c index afc6d685..a2aa130b 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -675,7 +675,9 @@ void container_update_representation(struct sway_container *con) { } 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,