diff --git a/include/sway/sway_text_node.h b/include/sway/sway_text_node.h index 0d4209bb..e488ef66 100644 --- a/include/sway/sway_text_node.h +++ b/include/sway/sway_text_node.h @@ -4,7 +4,7 @@ struct sway_text_node { int width; - int max_width; + double max_width; int height; int baseline; bool pango_markup; @@ -21,7 +21,7 @@ void sway_text_node_set_color(struct sway_text_node *node, float color[4]); void sway_text_node_set_text(struct sway_text_node *node, char *text); -void sway_text_node_set_max_width(struct sway_text_node *node, int max_width); +void sway_text_node_set_max_width(struct sway_text_node *node, double max_width); void sway_text_node_set_background(struct sway_text_node *node, float background[4]); diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index e18fd00a..9a671678 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -102,7 +102,7 @@ struct sway_container { char *title; // The view's title (unformatted) char *formatted_title; // The title displayed in the title bar - int title_width; + double title_width; char *title_format; @@ -360,6 +360,8 @@ bool container_is_sticky_or_child(struct sway_container *con); */ int container_squash(struct sway_container *con); +float container_scale_factor(struct sway_container *con); + void container_arrange_title_bar(struct sway_container *con); void container_update(struct sway_container *con); diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 8c54d71a..f136db26 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -334,7 +334,7 @@ static void popup_unconstrain(struct sway_layer_popup *popup) { return; } - int lx, ly; + double lx, ly; wlr_scene_node_coords(&popup->toplevel->scene->tree->node, &lx, &ly); // the output box expressed in the coordinate system of the toplevel parent diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 12dc9cc7..de5ca9cf 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -144,7 +144,7 @@ static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_surface } static void send_frame_done_iterator(struct wlr_scene_buffer *buffer, - int x, int y, void *user_data) { + double x, double y, void *user_data) { struct send_frame_done_data *data = user_data; struct sway_output *output = data->output; int view_max_render_time = 0; diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 325a3022..9af67451 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -254,7 +254,7 @@ static void apply_container_state(struct sway_container *container, } static void arrange_title_bar(struct sway_container *con, - int x, int y, int width, int height) { + double x, double y, double width, double height) { container_update(con); bool has_title_bar = height > 0; @@ -283,13 +283,17 @@ static void disable_container(struct sway_container *con) { } } +static double align_to_fractional(float scale, double value) { + return round(value * scale) / scale; +} + static void arrange_container(struct sway_container *con, - int width, int height, bool title_bar, int gaps); + double width, double height, bool title_bar, double gaps); static void arrange_children(enum sway_container_layout layout, list_t *children, struct sway_container *active, struct wlr_scene_tree *content, - int width, int height, int gaps) { - int title_bar_height = container_titlebar_height(); + double width, double height, double gaps, float scale) { + double title_bar_height = align_to_fractional(scale, container_titlebar_height()); if (layout == L_TABBED) { struct sway_container *first = children->length == 1 ? @@ -299,28 +303,27 @@ static void arrange_children(enum sway_container_layout layout, list_t *children title_bar_height = 0; } - double w = (double) width / children->length; - int title_offset = 0; + double w = align_to_fractional(scale, width / children->length); + double title_offset = 0; for (int i = 0; i < children->length; i++) { struct sway_container *child = children->items[i]; bool activated = child == active; - int next_title_offset = round(w * i + w); arrange_title_bar(child, title_offset, -title_bar_height, - next_title_offset - title_offset, title_bar_height); + (i == children->length - 1) ? width - title_offset : w, title_bar_height); wlr_scene_node_set_enabled(&child->border.tree->node, activated); wlr_scene_node_set_enabled(&child->scene_tree->node, true); wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height); wlr_scene_node_reparent(&child->scene_tree->node, content); - int net_height = height - title_bar_height; + double net_height = height - title_bar_height; if (activated && width > 0 && net_height > 0) { arrange_container(child, width, net_height, title_bar_height == 0, 0); } else { disable_container(child); } - title_offset = next_title_offset; + title_offset += w; } } else if (layout == L_STACKED) { struct sway_container *first = children->length == 1 ? @@ -330,9 +333,9 @@ static void arrange_children(enum sway_container_layout layout, list_t *children title_bar_height = 0; } - int title_height = title_bar_height * children->length; + double title_height = title_bar_height * children->length; - int y = 0; + double y = 0; for (int i = 0; i < children->length; i++) { struct sway_container *child = children->items[i]; bool activated = child == active; @@ -343,7 +346,7 @@ static void arrange_children(enum sway_container_layout layout, list_t *children wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height); wlr_scene_node_reparent(&child->scene_tree->node, content); - int net_height = height - title_height; + double net_height = height - title_height; if (activated && width > 0 && net_height > 0) { arrange_container(child, width, net_height, title_bar_height == 0, 0); } else { @@ -353,10 +356,10 @@ static void arrange_children(enum sway_container_layout layout, list_t *children y += title_bar_height; } } else if (layout == L_VERT) { - int off = 0; + double off = 0; for (int i = 0; i < children->length; i++) { struct sway_container *child = children->items[i]; - int cheight = child->current.height; + double cheight = align_to_fractional(scale, child->current.height); wlr_scene_node_set_enabled(&child->border.tree->node, true); wlr_scene_node_set_position(&child->scene_tree->node, 0, off); @@ -369,10 +372,10 @@ static void arrange_children(enum sway_container_layout layout, list_t *children } } } else if (layout == L_HORIZ) { - int off = 0; + double off = 0; for (int i = 0; i < children->length; i++) { struct sway_container *child = children->items[i]; - int cwidth = child->current.width; + double cwidth = align_to_fractional(scale, child->current.width); wlr_scene_node_set_enabled(&child->border.tree->node, true); wlr_scene_node_set_position(&child->scene_tree->node, off, 0); @@ -390,7 +393,9 @@ static void arrange_children(enum sway_container_layout layout, list_t *children } static void arrange_container(struct sway_container *con, - int width, int height, bool title_bar, int gaps) { + double width, double height, bool title_bar, double gaps) { + float scale = container_scale_factor(con); + // this container might have previously been in the scratchpad, // make sure it's enabled for viewing wlr_scene_node_set_enabled(&con->scene_tree->node, true); @@ -400,8 +405,8 @@ static void arrange_container(struct sway_container *con, } if (con->view) { - int border_top = container_titlebar_height(); - int border_width = con->current.border_thickness; + double border_top = container_titlebar_height(); + double border_width = con->current.border_thickness; if (title_bar && con->current.border != B_NORMAL) { wlr_scene_node_set_enabled(&con->title_bar.tree->node, false); @@ -431,10 +436,21 @@ static void arrange_container(struct sway_container *con, sway_assert(false, "unreachable"); } - int border_bottom = con->current.border_bottom ? border_width : 0; - int border_left = con->current.border_left ? border_width : 0; - int border_right = con->current.border_right ? border_width : 0; - int vert_border_height = MAX(0, height - border_top - border_bottom); + border_top = align_to_fractional(scale, border_top); + border_width = align_to_fractional(scale, border_width); + + double content_width = align_to_fractional(scale, con->current.content_width); + double content_height = align_to_fractional(scale, con->current.content_height); + + double border_bottom = con->current.border_bottom ? border_width : 0; + double border_left = con->current.border_left ? border_width : 0; + double border_right = con->current.border_right ? border_width : 0; + + width = border_left + content_width + border_right; + height = border_top + content_height + border_bottom; + + double vert_border_height = MAX(0, height - border_top - border_bottom); + vert_border_height = align_to_fractional(scale, vert_border_height); wlr_scene_rect_set_size(con->border.top, width, border_top); wlr_scene_rect_set_size(con->border.bottom, width, border_bottom); @@ -464,7 +480,7 @@ static void arrange_container(struct sway_container *con, arrange_children(con->current.layout, con->current.children, con->current.focused_inactive_child, con->content_tree, - width, height, gaps); + width, height, gaps, scale); } } @@ -488,7 +504,7 @@ static int container_get_gaps(struct sway_container *con) { static void arrange_fullscreen(struct wlr_scene_tree *tree, struct sway_container *fs, struct sway_workspace *ws, - int width, int height) { + double width, double height) { struct wlr_scene_node *fs_node; if (fs->view) { fs_node = &fs->view->scene_tree->node; @@ -497,7 +513,9 @@ static void arrange_fullscreen(struct wlr_scene_tree *tree, wlr_scene_node_set_enabled(&fs->scene_tree->node, false); } else { fs_node = &fs->scene_tree->node; - arrange_container(fs, width, height, true, container_get_gaps(fs)); + float scale = container_scale_factor(fs); + double gaps = align_to_fractional(scale, container_get_gaps(fs)); + arrange_container(fs, width, height, true, gaps); } wlr_scene_node_reparent(fs_node, tree); @@ -506,6 +524,9 @@ static void arrange_fullscreen(struct wlr_scene_tree *tree, } static void arrange_workspace_floating(struct sway_workspace *ws) { + float scale = ws->output->wlr_output->scale; + double gaps = align_to_fractional(scale, ws->gaps_inner); + for (int i = 0; i < ws->current.floating->length; i++) { struct sway_container *floater = ws->current.floating->items[i]; struct wlr_scene_tree *layer = root->layers.floating; @@ -531,21 +552,27 @@ static void arrange_workspace_floating(struct sway_workspace *ws) { } wlr_scene_node_reparent(&floater->scene_tree->node, layer); - wlr_scene_node_set_position(&floater->scene_tree->node, - floater->current.x, floater->current.y); + + double x = align_to_fractional(scale, floater->current.x); + double y = align_to_fractional(scale, floater->current.y); + wlr_scene_node_set_position(&floater->scene_tree->node, x, y); wlr_scene_node_set_enabled(&floater->scene_tree->node, true); wlr_scene_node_set_enabled(&floater->border.tree->node, true); - arrange_container(floater, floater->current.width, floater->current.height, - true, ws->gaps_inner); + double width = align_to_fractional(scale, floater->current.width); + double height = align_to_fractional(scale, floater->current.height); + arrange_container(floater, width, height, true, gaps); } } static void arrange_workspace_tiling(struct sway_workspace *ws, - int width, int height) { + double width, double height) { + float scale = ws->output->wlr_output->scale; + double gaps = align_to_fractional(scale, ws->gaps_inner); + arrange_children(ws->current.layout, ws->current.tiling, ws->current.focused_inactive_child, ws->layers.tiling, - width, height, ws->gaps_inner); + width, height, gaps, scale); } static void disable_workspace(struct sway_workspace *ws) { @@ -584,6 +611,8 @@ static void arrange_output(struct sway_output *output, int width, int height) { if (activated) { struct sway_container *fs = child->current.fullscreen; + double scale = output->wlr_output->scale; + wlr_scene_node_set_enabled(&child->layers.tiling->node, !fs); wlr_scene_node_set_enabled(&child->layers.fullscreen->node, fs); @@ -604,11 +633,12 @@ static void arrange_output(struct sway_output *output, int width, int height) { struct side_gaps *gaps = &child->current_gaps; wlr_scene_node_set_position(&child->layers.tiling->node, - gaps->left + area->x, gaps->top + area->y); + align_to_fractional(scale, gaps->left + area->x), + align_to_fractional(scale, gaps->top + area->y)); arrange_workspace_tiling(child, - area->width - gaps->left - gaps->right, - area->height - gaps->top - gaps->bottom); + align_to_fractional(scale, area->width - gaps->left - gaps->right), + align_to_fractional(scale, area->height - gaps->top - gaps->bottom)); arrange_workspace_floating(child); } } else { @@ -627,7 +657,7 @@ void arrange_popups(struct wlr_scene_tree *popups) { SWAY_SCENE_DESC_POPUP); if (popup) { - int lx, ly; + double lx, ly; wlr_scene_node_coords(popup->relative, &lx, &ly); wlr_scene_node_set_position(node, lx, ly); } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 696a45ad..e71afeca 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -375,7 +375,7 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { return; } - int lx, ly; + double lx, ly; wlr_scene_node_coords(&popup->view->content_tree->node, &lx, &ly); wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly); } diff --git a/sway/input/text_input.c b/sway/input/text_input.c index e496bff1..a7d0719e 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -132,7 +132,10 @@ static void constrain_popup(struct sway_input_popup *popup) { } struct wlr_box parent = {0}; - wlr_scene_node_coords(&popup->desc.relative->parent->node, &parent.x, &parent.y); + double lx, ly; + wlr_scene_node_coords(&popup->desc.relative->parent->node, &lx, &ly); + parent.x = lx; + parent.y = ly; struct wlr_box geo = {0}; struct wlr_output *output; diff --git a/sway/sway_text_node.c b/sway/sway_text_node.c index 89ece91e..f808b47d 100644 --- a/sway/sway_text_node.c +++ b/sway/sway_text_node.c @@ -56,8 +56,8 @@ struct text_buffer { struct wl_listener destroy; }; -static int get_text_width(struct sway_text_node *props) { - int width = props->width; +static double get_text_width(struct sway_text_node *props) { + double width = props->width; if (props->max_width >= 0) { width = MIN(width, props->max_width); } @@ -136,14 +136,14 @@ static void render_backing_buffer(struct text_buffer *buffer) { wlr_scene_buffer_set_buffer(buffer->buffer_node, &cairo_buffer->base); wlr_buffer_drop(&cairo_buffer->base); - pixman_region32_t opaque; - pixman_region32_init(&opaque); + pixman_region64f_t opaque; + pixman_region64f_init(&opaque); if (background[3] == 1) { - pixman_region32_union_rect(&opaque, &opaque, 0, 0, + pixman_region64f_union_rectf(&opaque, &opaque, 0, 0, get_text_width(&buffer->props), buffer->props.height); } wlr_scene_buffer_set_opaque_region(buffer->buffer_node, &opaque); - pixman_region32_fini(&opaque); + pixman_region64f_fini(&opaque); err: if (pango) g_object_unref(pango); @@ -279,7 +279,7 @@ void sway_text_node_set_text(struct sway_text_node *node, char *text) { render_backing_buffer(buffer); } -void sway_text_node_set_max_width(struct sway_text_node *node, int max_width) { +void sway_text_node_set_max_width(struct sway_text_node *node, double max_width) { struct text_buffer *buffer = wl_container_of(node, buffer, props); if (max_width == buffer->props.max_width) { return; diff --git a/sway/tree/container.c b/sway/tree/container.c index c9ec852f..cd4e2046 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -103,6 +103,7 @@ struct sway_container *container_create(struct sway_view *view) { // - buffer used for output enter/leave events for foreign_toplevel bool failed = false; c->scene_tree = alloc_scene_tree(root->staging, &failed); + c->scene_tree->node.scaling_group = true; c->title_bar.tree = alloc_scene_tree(c->scene_tree, &failed); c->title_bar.border = alloc_scene_tree(c->title_bar.tree, &failed); @@ -316,9 +317,9 @@ void container_update_itself_and_parents(struct sway_container *con) { } } -static void update_rect_list(struct wlr_scene_tree *tree, pixman_region32_t *region) { +static void update_rect_list(struct wlr_scene_tree *tree, pixman_region64f_t *region) { int len; - const pixman_box32_t *rects = pixman_region32_rectangles(region, &len); + const pixman_box64f_t *rects = pixman_region64f_rectangles(region, &len); wlr_scene_node_set_enabled(&tree->node, len > 0); if (len == 0) { @@ -332,27 +333,42 @@ static void update_rect_list(struct wlr_scene_tree *tree, pixman_region32_t *reg wlr_scene_node_set_enabled(&rect->node, i < len); if (i < len) { - const pixman_box32_t *box = &rects[i++]; + const pixman_box64f_t *box = &rects[i++]; wlr_scene_node_set_position(&rect->node, box->x1, box->y1); wlr_scene_rect_set_size(rect, box->x2 - box->x1, box->y2 - box->y1); } } } +float container_scale_factor(struct sway_container *con) { + struct sway_workspace *ws = con->pending.workspace + ? con->pending.workspace + : con->current.workspace; + if (ws) { + return ws->output->wlr_output->scale; + } + return 1.0f; +} + +static double align_to_fractional(double scale, double value) { + return round(value * scale) / scale; +} + void container_arrange_title_bar(struct sway_container *con) { enum alignment title_align = config->title_align; + float scale = container_scale_factor(con); int marks_buffer_width = 0; - int width = con->title_width; - int height = container_titlebar_height(); + double width = align_to_fractional(scale, con->title_width); + double height = align_to_fractional(scale, container_titlebar_height()); - pixman_region32_t text_area; - pixman_region32_init(&text_area); + pixman_region64f_t text_area; + pixman_region64f_init(&text_area); if (con->title_bar.marks_text) { struct sway_text_node *node = con->title_bar.marks_text; marks_buffer_width = node->width; - int h_padding; + double h_padding; if (title_align == ALIGN_RIGHT) { h_padding = config->titlebar_h_padding; } else { @@ -360,68 +376,93 @@ void container_arrange_title_bar(struct sway_container *con) { } h_padding = MAX(h_padding, config->titlebar_h_padding); + h_padding = align_to_fractional(scale, h_padding); - int alloc_width = MIN((int)node->width, + double v_padding = (height - node->height) / 2.0; + v_padding = align_to_fractional(scale, v_padding); + + double alloc_width = MIN(node->width, width - h_padding - config->titlebar_h_padding); alloc_width = MAX(alloc_width, 0); - sway_text_node_set_max_width(node, alloc_width); - wlr_scene_node_set_position(node->node, - h_padding, (height - node->height) >> 1); + double text_width = align_to_fractional(scale, alloc_width); + double text_height = align_to_fractional(scale, node->height); - pixman_region32_union_rect(&text_area, &text_area, - node->node->x, node->node->y, alloc_width, node->height); + sway_text_node_set_max_width(node, text_width); + wlr_scene_node_set_position(node->node, h_padding, v_padding); + + pixman_region64f_union_rectf(&text_area, &text_area, + node->node->x, node->node->y, text_width, text_height); } if (con->title_bar.title_text) { struct sway_text_node *node = con->title_bar.title_text; - int h_padding; + double h_padding; if (title_align == ALIGN_RIGHT) { h_padding = width - config->titlebar_h_padding - node->width; } else if (title_align == ALIGN_CENTER) { - h_padding = ((int)width - marks_buffer_width - node->width) >> 1; + h_padding = (width - marks_buffer_width - node->width) / 2.0; } else { h_padding = config->titlebar_h_padding; } h_padding = MAX(h_padding, config->titlebar_h_padding); + h_padding = align_to_fractional(scale, h_padding); - int alloc_width = MIN((int) node->width, + double v_padding = (height - node->height) / 2.0; + v_padding = align_to_fractional(scale, v_padding); + + double alloc_width = MIN(node->width, width - h_padding - config->titlebar_h_padding); alloc_width = MAX(alloc_width, 0); - sway_text_node_set_max_width(node, alloc_width); - wlr_scene_node_set_position(node->node, - h_padding, (height - node->height) >> 1); + double text_width = align_to_fractional(scale, alloc_width); + double text_height = align_to_fractional(scale, node->height); - pixman_region32_union_rect(&text_area, &text_area, - node->node->x, node->node->y, alloc_width, node->height); + sway_text_node_set_max_width(node, text_width); + wlr_scene_node_set_position(node->node, h_padding, v_padding); + + pixman_region64f_union_rectf(&text_area, &text_area, + node->node->x, node->node->y, text_width, text_height); } // silence pixman errors if (width <= 0 || height <= 0) { - pixman_region32_fini(&text_area); + pixman_region64f_fini(&text_area); return; } - pixman_region32_t background, border; - int thickness = config->titlebar_border_thickness; - pixman_region32_init_rect(&background, - thickness, thickness, - width - thickness * 2, height - thickness * 2); - pixman_region32_init_rect(&border, 0, 0, width, height); - pixman_region32_subtract(&border, &border, &background); - pixman_region32_subtract(&background, &background, &text_area); - pixman_region32_fini(&text_area); + double border_x1 = 0, + border_y1 = 0; + double border_size = align_to_fractional(scale, thickness); + double background_x1 = align_to_fractional(scale, border_x1 + border_size), + background_y1 = align_to_fractional(scale, border_y1 + border_size); + double background_x2 = align_to_fractional(scale, width - border_size), + background_y2 = align_to_fractional(scale, height - border_size); + double border_x2 = align_to_fractional(scale, width), + border_y2 = align_to_fractional(scale, height); + + pixman_region64f_t background, border; + + pixman_region64f_init_rectf(&background, + background_x1, background_y1, + background_x2 - background_x1, background_y2 - background_y1); + pixman_region64f_init_rectf(&border, + border_x1, border_y1, + border_x2 - border_x1, border_y2 - border_y1); + pixman_region64f_subtract(&border, &border, &background); + + pixman_region64f_subtract(&background, &background, &text_area); + pixman_region64f_fini(&text_area); update_rect_list(con->title_bar.background, &background); - pixman_region32_fini(&background); + pixman_region64f_fini(&background); update_rect_list(con->title_bar.border, &border); - pixman_region32_fini(&border); + pixman_region64f_fini(&border); container_update(con); } diff --git a/sway/tree/view.c b/sway/tree/view.c index 3d621124..0503b0da 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1194,7 +1194,7 @@ void view_remove_saved_buffer(struct sway_view *view) { } static void view_save_buffer_iterator(struct wlr_scene_buffer *buffer, - int sx, int sy, void *data) { + double sx, double sy, void *data) { struct wlr_scene_tree *tree = data; struct wlr_scene_buffer *sbuf = wlr_scene_buffer_create(tree, NULL); @@ -1258,7 +1258,7 @@ bool view_can_tear(struct sway_view *view) { } static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer, - int x, int y, void *data) { + double x, double y, void *data) { struct timespec *when = data; struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer); if (scene_surface == NULL) {