diff --git a/include/common/graphic-helpers.h b/include/common/graphic-helpers.h index 067da644..e1986d4e 100644 --- a/include/common/graphic-helpers.h +++ b/include/common/graphic-helpers.h @@ -3,41 +3,9 @@ #define LABWC_GRAPHIC_HELPERS_H #include -#include -struct wlr_scene_tree; -struct wlr_scene_rect; struct wlr_fbox; -struct multi_rect { - struct wlr_scene_tree *tree; - int line_width; /* read-only */ - - /* Private */ - struct wlr_scene_rect *top[3]; - struct wlr_scene_rect *bottom[3]; - struct wlr_scene_rect *left[3]; - struct wlr_scene_rect *right[3]; - struct wl_listener destroy; -}; - -/** - * Create a new multi_rect. - * A multi_rect consists of 3 nested rectangular outlines. - * Each of the rectangular outlines is using the same @line_width - * but its own color based on the @colors argument. - * - * The multi-rect can be positioned by positioning multi_rect->tree->node. - * - * It can be destroyed by destroying its tree node (or one of its - * parent nodes). Once the tree node has been destroyed the struct - * will be free'd automatically. - */ -struct multi_rect *multi_rect_create(struct wlr_scene_tree *parent, - float *colors[3], int line_width); - -void multi_rect_set_size(struct multi_rect *rect, int width, int height); - /** * Sets the cairo color. * Splits a float[4] single color array into its own arguments diff --git a/include/common/lab-scene-rect.h b/include/common/lab-scene-rect.h new file mode 100644 index 00000000..5005fbb3 --- /dev/null +++ b/include/common/lab-scene-rect.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LABWC_LAB_SCENE_RECT_H +#define LABWC_LAB_SCENE_RECT_H +#include + +struct wlr_scene_tree; + +struct lab_scene_rect_options { + float **border_colors; + int nr_borders; + int border_width; + float *bg_color; /* can be NULL */ + int width; + int height; +}; + +struct lab_scene_rect { + struct wlr_scene_tree *tree; + int border_width; + int nr_borders; + struct border_scene *borders; + struct wlr_scene_rect *fill; + + struct wl_listener node_destroy; +}; + +/** + * Create a new rectangle with borders. + * + * The rectangle can be positioned by positioning border_rect->tree->node. + * + * It can be destroyed by destroying its tree node (or one of its parent nodes). + * Once the tree node has been destroyed the struct will be free'd automatically. + */ +struct lab_scene_rect *lab_scene_rect_create(struct wlr_scene_tree *parent, + struct lab_scene_rect_options *opts); + +void lab_scene_rect_set_size(struct lab_scene_rect *rect, int width, int height); + +#endif /* LABWC_LAB_SCENE_RECT_H */ diff --git a/include/labwc.h b/include/labwc.h index 837ebc74..af451140 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -392,7 +392,7 @@ struct server { struct wlr_scene_node *preview_node; struct wlr_scene_tree *preview_parent; struct wlr_scene_node *preview_anchor; - struct multi_rect *preview_outline; + struct lab_scene_rect *preview_outline; } osd_state; struct theme *theme; diff --git a/include/overlay.h b/include/overlay.h index ebcaabcc..6a0ee020 100644 --- a/include/overlay.h +++ b/include/overlay.h @@ -7,6 +7,7 @@ #include "regions.h" #include "view.h" +/* TODO: replace this with single lab_scene_rect */ struct overlay_rect { struct wlr_scene_tree *tree; @@ -14,7 +15,7 @@ struct overlay_rect { struct wlr_scene_rect *bg_rect; bool border_enabled; - struct multi_rect *border_rect; + struct lab_scene_rect *border_rect; }; struct overlay { diff --git a/include/view.h b/include/view.h index 613f9160..cf0c0471 100644 --- a/include/view.h +++ b/include/view.h @@ -264,7 +264,7 @@ struct view { } resize_indicator; struct resize_outlines { struct wlr_box view_geo; - struct multi_rect *rect; + struct lab_scene_rect *rect; } resize_outlines; struct mappable mappable; diff --git a/src/common/graphic-helpers.c b/src/common/graphic-helpers.c index 4739b899..29ba8ddb 100644 --- a/src/common/graphic-helpers.c +++ b/src/common/graphic-helpers.c @@ -1,85 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only -#include #include -#include -#include #include -#include -#include "buffer.h" #include "common/graphic-helpers.h" -#include "common/macros.h" -#include "common/mem.h" - -static void -multi_rect_destroy_notify(struct wl_listener *listener, void *data) -{ - struct multi_rect *rect = wl_container_of(listener, rect, destroy); - wl_list_remove(&rect->destroy.link); - free(rect); -} - -struct multi_rect * -multi_rect_create(struct wlr_scene_tree *parent, float *colors[3], int line_width) -{ - struct multi_rect *rect = znew(*rect); - rect->line_width = line_width; - rect->tree = wlr_scene_tree_create(parent); - rect->destroy.notify = multi_rect_destroy_notify; - wl_signal_add(&rect->tree->node.events.destroy, &rect->destroy); - for (size_t i = 0; i < 3; i++) { - rect->top[i] = wlr_scene_rect_create(rect->tree, 0, 0, colors[i]); - rect->right[i] = wlr_scene_rect_create(rect->tree, 0, 0, colors[i]); - rect->bottom[i] = wlr_scene_rect_create(rect->tree, 0, 0, colors[i]); - rect->left[i] = wlr_scene_rect_create(rect->tree, 0, 0, colors[i]); - wlr_scene_node_set_position(&rect->top[i]->node, - i * line_width, i * line_width); - wlr_scene_node_set_position(&rect->left[i]->node, - i * line_width, (i + 1) * line_width); - } - return rect; -} - -void -multi_rect_set_size(struct multi_rect *rect, int width, int height) -{ - assert(rect); - int line_width = rect->line_width; - - /* - * The outmost outline is drawn like below: - * - * |--width--| - * - * +---------+ --- - * +-+-----+-+ | - * | | | | height - * | | | | | - * +-+-----+-+ | - * +---------+ --- - */ - for (int i = 0; i < 3; i++) { - /* Reposition, top and left don't ever change */ - wlr_scene_node_set_position(&rect->right[i]->node, - width - (i + 1) * line_width, (i + 1) * line_width); - wlr_scene_node_set_position(&rect->bottom[i]->node, - i * line_width, height - (i + 1) * line_width); - - /* Update sizes */ - wlr_scene_rect_set_size(rect->top[i], - MAX(width - i * line_width * 2, 0), - line_width); - wlr_scene_rect_set_size(rect->bottom[i], - MAX(width - i * line_width * 2, 0), - line_width); - wlr_scene_rect_set_size(rect->left[i], - line_width, - MAX(height - (i + 1) * line_width * 2, 0)); - wlr_scene_rect_set_size(rect->right[i], - line_width, - MAX(height - (i + 1) * line_width * 2, 0)); - } -} /* Draws a border with a specified line width */ void diff --git a/src/common/lab-scene-rect.c b/src/common/lab-scene-rect.c new file mode 100644 index 00000000..bc23422d --- /dev/null +++ b/src/common/lab-scene-rect.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include "common/lab-scene-rect.h" +#include "common/mem.h" + +struct border_scene { + struct wlr_scene_tree *tree; + struct wlr_scene_rect *top, *bottom, *left, *right; +}; + +static void +handle_node_destroy(struct wl_listener *listener, void *data) +{ + struct lab_scene_rect *rect = wl_container_of(listener, rect, node_destroy); + wl_list_remove(&rect->node_destroy.link); + free(rect->borders); + free(rect); +} + +struct lab_scene_rect * +lab_scene_rect_create(struct wlr_scene_tree *parent, + struct lab_scene_rect_options *opts) +{ + struct lab_scene_rect *rect = znew(*rect); + rect->border_width = opts->border_width; + rect->nr_borders = opts->nr_borders; + rect->borders = znew_n(rect->borders[0], opts->nr_borders); + rect->tree = wlr_scene_tree_create(parent); + + if (opts->bg_color) { + rect->fill = wlr_scene_rect_create(rect->tree, 0, 0, opts->bg_color); + } + + for (int i = 0; i < rect->nr_borders; i++) { + struct border_scene *border = &rect->borders[i]; + float *color = opts->border_colors[i]; + border->tree = wlr_scene_tree_create(rect->tree); + border->top = wlr_scene_rect_create(border->tree, 0, 0, color); + border->right = wlr_scene_rect_create(border->tree, 0, 0, color); + border->bottom = wlr_scene_rect_create(border->tree, 0, 0, color); + border->left = wlr_scene_rect_create(border->tree, 0, 0, color); + } + + rect->node_destroy.notify = handle_node_destroy; + wl_signal_add(&rect->tree->node.events.destroy, &rect->node_destroy); + + lab_scene_rect_set_size(rect, opts->width, opts->height); + + return rect; +} + +static void +resize_border(struct border_scene *border, int border_width, int width, int height) +{ + /* + * The border is drawn like below: + * + * <--width--> + * +---------+ ^ + * +-+-----+-+ | + * | | | | height + * | | | | | + * +-+-----+-+ | + * +---------+ v + */ + + if ((width < border_width * 2) || (height < border_width * 2)) { + wlr_scene_node_set_enabled(&border->tree->node, false); + return; + } + wlr_scene_node_set_enabled(&border->tree->node, true); + + wlr_scene_node_set_position(&border->top->node, 0, 0); + wlr_scene_node_set_position(&border->bottom->node, 0, height - border_width); + wlr_scene_node_set_position(&border->left->node, 0, border_width); + wlr_scene_node_set_position(&border->right->node, width - border_width, border_width); + + wlr_scene_rect_set_size(border->top, width, border_width); + wlr_scene_rect_set_size(border->bottom, width, border_width); + wlr_scene_rect_set_size(border->left, border_width, height - border_width * 2); + wlr_scene_rect_set_size(border->right, border_width, height - border_width * 2); +} + +void +lab_scene_rect_set_size(struct lab_scene_rect *rect, int width, int height) +{ + assert(rect); + int border_width = rect->border_width; + + for (int i = 0; i < rect->nr_borders; i++) { + struct border_scene *border = &rect->borders[i]; + resize_border(border, border_width, + width - 2 * border_width * i, + height - 2 * border_width * i); + wlr_scene_node_set_position(&border->tree->node, + i * border_width, i * border_width); + } + + if (rect->fill) { + wlr_scene_rect_set_size(rect->fill, width, height); + } +} diff --git a/src/common/meson.build b/src/common/meson.build index 15910f32..74dd6ef6 100644 --- a/src/common/meson.build +++ b/src/common/meson.build @@ -8,6 +8,7 @@ labwc_sources += files( 'font.c', 'grab-file.c', 'graphic-helpers.c', + 'lab-scene-rect.c', 'match.c', 'mem.c', 'nodename.c', diff --git a/src/debug.c b/src/debug.c index 43ae0c06..4123187b 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include -#include "common/graphic-helpers.h" +#include "common/lab-scene-rect.h" #include "common/scene-helpers.h" #include "common/string-helpers.h" #include "debug.h" @@ -220,11 +220,11 @@ dump_tree(struct server *server, struct wlr_scene_node *node, } printf("%.*s %*c %4d %4d [%p]\n", max_width - 1, type, padding, ' ', x, y, node); - struct multi_rect *osd_preview_outline = + struct lab_scene_rect *osd_preview_outline = server->osd_state.preview_outline; - struct multi_rect *region_snapping_overlay_outline = + struct lab_scene_rect *region_snapping_overlay_outline = server->seat.overlay.region_rect.border_rect; - struct multi_rect *edge_snapping_overlay_outline = + struct lab_scene_rect *edge_snapping_overlay_outline = server->seat.overlay.edge_rect.border_rect; if ((IGNORE_MENU && node == &server->menu_tree->node) || (IGNORE_SSD && last_view diff --git a/src/osd.c b/src/osd.c index 45b4b2de..7348af8b 100644 --- a/src/osd.c +++ b/src/osd.c @@ -6,6 +6,7 @@ #include "common/array.h" #include "common/buf.h" #include "common/font.h" +#include "common/lab-scene-rect.h" #include "common/macros.h" #include "common/scaled-font-buffer.h" #include "common/scaled-icon-buffer.h" @@ -46,21 +47,25 @@ osd_update_preview_outlines(struct view *view) { /* Create / Update preview outline tree */ struct server *server = view->server; - struct multi_rect *rect = view->server->osd_state.preview_outline; + struct theme *theme = server->theme; + struct lab_scene_rect *rect = view->server->osd_state.preview_outline; if (!rect) { - int line_width = server->theme->osd_window_switcher_preview_border_width; - float *colors[] = { - server->theme->osd_window_switcher_preview_border_color[0], - server->theme->osd_window_switcher_preview_border_color[1], - server->theme->osd_window_switcher_preview_border_color[2], + struct lab_scene_rect_options opts = { + .border_colors = (float *[3]) { + theme->osd_window_switcher_preview_border_color[0], + theme->osd_window_switcher_preview_border_color[1], + theme->osd_window_switcher_preview_border_color[2], + }, + .nr_borders = 3, + .border_width = theme->osd_window_switcher_preview_border_width, }; - rect = multi_rect_create(&server->scene->tree, colors, line_width); + rect = lab_scene_rect_create(&server->scene->tree, &opts); wlr_scene_node_place_above(&rect->tree->node, &server->menu_tree->node); server->osd_state.preview_outline = rect; } struct wlr_box geo = ssd_max_extents(view); - multi_rect_set_size(rect, geo.width, geo.height); + lab_scene_rect_set_size(rect, geo.width, geo.height); wlr_scene_node_set_position(&rect->tree->node, geo.x, geo.y); } diff --git a/src/overlay.c b/src/overlay.c index ba2cab3b..354f5ad9 100644 --- a/src/overlay.c +++ b/src/overlay.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include "common/lab-scene-rect.h" #include "labwc.h" #include "overlay.h" #include "view.h" @@ -23,13 +24,16 @@ create_overlay_rect(struct seat *seat, struct overlay_rect *rect, if (rect->border_enabled) { /* Create outlines */ - float *colors[3] = { - theme->border_color[0], - theme->border_color[1], - theme->border_color[2], + struct lab_scene_rect_options opts = { + .border_colors = (float *[3]) { + theme->border_color[0], + theme->border_color[1], + theme->border_color[2], + }, + .nr_borders = 3, + .border_width = theme->border_width, }; - rect->border_rect = multi_rect_create( - rect->tree, colors, theme->border_width); + rect->border_rect = lab_scene_rect_create(rect->tree, &opts); } wlr_scene_node_set_enabled(&rect->tree->node, false); @@ -67,7 +71,7 @@ show_overlay(struct seat *seat, struct overlay_rect *rect, struct wlr_box *box) wlr_scene_rect_set_size(rect->bg_rect, box->width, box->height); } if (rect->border_enabled) { - multi_rect_set_size(rect->border_rect, box->width, box->height); + lab_scene_rect_set_size(rect->border_rect, box->width, box->height); } struct wlr_scene_node *node = &rect->tree->node; diff --git a/src/resize-outlines.c b/src/resize-outlines.c index fbb10c73..9186bc6f 100644 --- a/src/resize-outlines.c +++ b/src/resize-outlines.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include -#include "common/graphic-helpers.h" +#include "common/lab-scene-rect.h" #include "ssd.h" #include "resize-outlines.h" #include "labwc.h" @@ -19,14 +19,16 @@ resize_outlines_update(struct view *view, struct wlr_box new_geo) struct resize_outlines *outlines = &view->resize_outlines; if (!outlines->rect) { - float *colors[3] = { - view->server->theme->osd_bg_color, - view->server->theme->osd_label_text_color, - view->server->theme->osd_bg_color, + struct lab_scene_rect_options opts = { + .border_colors = (float *[3]) { + view->server->theme->osd_bg_color, + view->server->theme->osd_label_text_color, + view->server->theme->osd_bg_color, + }, + .nr_borders = 3, + .border_width = 1, }; - int width = 1; - outlines->rect = multi_rect_create( - view->scene_tree, colors, width); + outlines->rect = lab_scene_rect_create(view->scene_tree, &opts); } struct border margin = ssd_get_margin(view->ssd); @@ -36,7 +38,7 @@ resize_outlines_update(struct view *view, struct wlr_box new_geo) .width = new_geo.width + margin.left + margin.right, .height = new_geo.height + margin.top + margin.bottom, }; - multi_rect_set_size(outlines->rect, box.width, box.height); + lab_scene_rect_set_size(outlines->rect, box.width, box.height); wlr_scene_node_set_position(&outlines->rect->tree->node, box.x - view->current.x, box.y - view->current.y); wlr_scene_node_set_enabled(