From eb5c8cfdad57b40762d868edd45c05ecd4615175 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Tue, 13 Sep 2022 08:15:33 +0200 Subject: [PATCH] SnapToRegion: Add dynamic overlay Either uses a half transparent single rect if running hardware accelerated or uses a solid struct multirect outline if not. --- include/labwc.h | 6 ++- include/regions.h | 16 +++++--- src/config/rcxml.c | 2 +- src/cursor.c | 2 +- src/interactive.c | 2 +- src/keyboard.c | 2 +- src/output.c | 2 +- src/regions.c | 98 +++++++++++++++++++++++++++++++--------------- src/server.c | 2 - src/view.c | 1 + 10 files changed, 88 insertions(+), 45 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index 230a6401..596bb0d7 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -47,6 +47,7 @@ #include "cursor.h" #include "config/keybind.h" #include "config/rcxml.h" +#include "regions.h" #if HAVE_NLS #include #include @@ -156,7 +157,9 @@ struct seat { struct wlr_scene_tree *icons; } drag; - struct wlr_scene_rect *region_overlay; + /* Private use by regions.c */ + struct region *region_active; + struct region_overlay region_overlay; struct wl_client *active_client_while_inhibited; struct wl_list inputs; @@ -312,6 +315,7 @@ struct output { struct wlr_box usable_area; struct wl_list regions; /* struct region.link */ + struct wlr_box regions_usable_area; struct lab_data_buffer *osd_buffer; diff --git a/include/regions.h b/include/regions.h index f583a310..87806123 100644 --- a/include/regions.h +++ b/include/regions.h @@ -2,14 +2,13 @@ #ifndef __LABWC_REGIONS_H #define __LABWC_REGIONS_H -//FIXME: ignore that there could be more than a single seat - struct seat; struct view; struct server; struct output; struct wl_list; struct wlr_box; +struct multi_rect; /* Double use: rcxml.c for config and output.c for usage */ struct region { @@ -23,17 +22,24 @@ struct region { } center; }; +struct region_overlay { + struct wlr_scene_tree *tree; + union { + struct wlr_scene_rect *overlay; + struct multi_rect *pixman_overlay; + }; +}; + /* Can be used as a cheap check to detect if there are any regions configured */ bool regions_available(void); -void regions_init(struct server *server, struct seat *seat); void regions_update(struct output *output); void regions_evacuate_output(struct output *output); -void regions_destroy(struct wl_list *regions); +void regions_destroy(struct seat *seat, struct wl_list *regions); struct region *regions_from_cursor(struct server *server); struct region *regions_from_name(const char *region_name, struct output *output); void regions_show_overlay(struct view *view, struct seat *seat, struct region *region); -void regions_hide_overlay(struct server *server, struct seat *seat); +void regions_hide_overlay(struct seat *seat); #endif /* __LABWC_REGIONS_H */ diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 4341bf5c..068e6d3c 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -868,7 +868,7 @@ rcxml_finish(void) zfree(w); } - regions_destroy(&rc.regions); + regions_destroy(NULL, &rc.regions); /* Reset state vars for starting fresh when Reload is triggered */ current_keybind = NULL; diff --git a/src/cursor.c b/src/cursor.c index 9b534e23..9be1e474 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -198,7 +198,7 @@ process_cursor_move(struct server *server, uint32_t time) if (region) { regions_show_overlay(view, &server->seat, region); } else { - regions_hide_overlay(server, &server->seat); + regions_hide_overlay(&server->seat); } } } diff --git a/src/interactive.c b/src/interactive.c index 3b3746f8..f1007441 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -163,7 +163,7 @@ interactive_finish(struct view *view) { if (view->server->grabbed_view == view) { enum input_mode mode = view->server->input_mode; - regions_hide_overlay(view->server, &view->server->seat); + regions_hide_overlay(&view->server->seat); view->server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; view->server->grabbed_view = NULL; if (mode == LAB_INPUT_STATE_MOVE) { diff --git a/src/keyboard.c b/src/keyboard.c index edac5ed8..39414cd8 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -71,7 +71,7 @@ keyboard_modifiers_notify(struct wl_listener *listener, void *data) workspaces_osd_hide(seat); } if (server->grabbed_view) { - regions_hide_overlay(server, seat); + regions_hide_overlay(seat); } } } diff --git a/src/output.c b/src/output.c index c28186ac..fa258ba9 100644 --- a/src/output.c +++ b/src/output.c @@ -42,7 +42,7 @@ output_destroy_notify(struct wl_listener *listener, void *data) { struct output *output = wl_container_of(listener, output, destroy); regions_evacuate_output(output); - regions_destroy(&output->regions); + regions_destroy(&output->server->seat, &output->regions); wl_list_remove(&output->link); wl_list_remove(&output->frame.link); wl_list_remove(&output->destroy.link); diff --git a/src/regions.c b/src/regions.c index 35937a2e..727a78c3 100644 --- a/src/regions.c +++ b/src/regions.c @@ -22,22 +22,30 @@ regions_available(void) return !wl_list_empty(&rc.regions); } -void -regions_init(struct server *server, struct seat *seat) +static void +overlay_create(struct seat *seat) { - assert(server); - assert(seat); + assert(!seat->region_overlay.tree); - float *color; - float solid[4] = { 0.5, 0.5, 0.7, 1 }; - float trans[4] = { 0.25, 0.25, 0.35, 0.5 }; - if (wlr_renderer_is_pixman(server->renderer)) { - color = solid; + struct server *server = seat->server; + struct wlr_scene_tree *parent = wlr_scene_tree_create(&server->scene->tree); + + seat->region_overlay.tree = parent; + wlr_scene_node_set_enabled(&parent->node, false); + if (!wlr_renderer_is_pixman(server->renderer)) { + /* Hardware assisted rendering: Half transparent overlay */ + float color[4] = { 0.25, 0.25, 0.35, 0.5 }; + seat->region_overlay.overlay = wlr_scene_rect_create(parent, 0, 0, color); } else { - color = trans; + /* Software rendering: Outlines */ + int line_width = server->theme->osd_border_width; + float *colors[3] = { + server->theme->osd_bg_color, + server->theme->osd_label_text_color, + server->theme->osd_bg_color + }; + seat->region_overlay.pixman_overlay = multi_rect_create(parent, colors, line_width); } - seat->region_overlay = wlr_scene_rect_create(&server->scene->tree, 0, 0, color); - wlr_scene_node_set_enabled(&seat->region_overlay->node, false); } struct region * @@ -91,36 +99,53 @@ regions_show_overlay(struct view *view, struct seat *seat, struct region *region assert(view); assert(seat); assert(region); - static struct region *old_region; - struct wlr_scene_rect *overlay = seat->region_overlay; - if (old_region != region) { - wlr_scene_rect_set_size(overlay, region->geo.width, region->geo.height); - wlr_scene_node_set_position(&overlay->node, region->geo.x, region->geo.y); - old_region = region; + /* Don't show active region */ + if (seat->region_active == region) { + return; } - if (overlay->node.parent != view->scene_tree->node.parent) { - wlr_scene_node_reparent(&overlay->node, view->scene_tree->node.parent); - wlr_scene_node_place_below(&overlay->node, &view->scene_tree->node); + + if (!seat->region_overlay.tree) { + overlay_create(seat); } - if (!overlay->node.enabled) { - wlr_scene_node_set_enabled(&overlay->node, true); + + /* Update overlay */ + struct server *server = seat->server; + struct wlr_scene_node *node = &seat->region_overlay.tree->node; + if (!wlr_renderer_is_pixman(server->renderer)) { + /* Hardware assisted rendering: Half transparent overlay */ + wlr_scene_rect_set_size(seat->region_overlay.overlay, + region->geo.width, region->geo.height); + } else { + /* Software rendering: Outlines */ + multi_rect_set_size(seat->region_overlay.pixman_overlay, + region->geo.width, region->geo.height); } + if (node->parent != view->scene_tree->node.parent) { + wlr_scene_node_reparent(node, view->scene_tree->node.parent); + wlr_scene_node_place_below(node, &view->scene_tree->node); + } + wlr_scene_node_set_position(node, region->geo.x, region->geo.y); + wlr_scene_node_set_enabled(node, true); + seat->region_active = region; } void -regions_hide_overlay(struct server *server, struct seat *seat) +regions_hide_overlay(struct seat *seat) { - assert(server); assert(seat); + if (!seat->region_active) { + return; + } - struct wlr_scene_rect *overlay = seat->region_overlay; - if (overlay->node.enabled) { - wlr_scene_node_set_enabled(&overlay->node, false); - } - if (overlay->node.parent != &server->scene->tree) { - wlr_scene_node_reparent(&overlay->node, &server->scene->tree); + struct server *server = seat->server; + struct wlr_scene_node *node = &seat->region_overlay.tree->node; + + wlr_scene_node_set_enabled(node, false); + if (node->parent != &server->scene->tree) { + wlr_scene_node_reparent(node, &server->scene->tree); } + seat->region_active = NULL; } void @@ -142,6 +167,12 @@ regions_update(struct output *output) } } + if (wlr_box_equal(&output->regions_usable_area, &usable)) { + /* Nothing changed */ + return; + } + output->regions_usable_area = usable; + /* Update regions */ struct wlr_box *perc, *geo; wl_list_for_each(region, &output->regions, link) { @@ -177,13 +208,16 @@ regions_evacuate_output(struct output *output) } void -regions_destroy(struct wl_list *regions) +regions_destroy(struct seat *seat, struct wl_list *regions) { assert(regions); struct region *region, *region_tmp; wl_list_for_each_safe(region, region_tmp, regions, link) { wl_list_remove(®ion->link); zfree(region->name); + if (seat && seat->region_active == region) { + seat->region_active = NULL; + } zfree(region); } } diff --git a/src/server.c b/src/server.c index e4c41e09..e36c2880 100644 --- a/src/server.c +++ b/src/server.c @@ -20,7 +20,6 @@ #include "labwc.h" #include "layers.h" #include "menu/menu.h" -#include "regions.h" #include "theme.h" #include "view.h" #include "workspaces.h" @@ -389,7 +388,6 @@ server_init(struct server *server) &server->output_power_manager_set_mode); layers_init(server); - regions_init(server, &server->seat); #if HAVE_XWAYLAND xwayland_server_init(server, compositor); diff --git a/src/view.c b/src/view.c index 4e572b3a..d8364ab6 100644 --- a/src/view.c +++ b/src/view.c @@ -993,6 +993,7 @@ view_destroy(struct view *view) server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; server->grabbed_view = NULL; need_cursor_update = true; + regions_hide_overlay(&server->seat); } if (server->focused_view == view) {