From 5b1a03ae6996979f27e4c9259c9991c0c0aa6002 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Sun, 24 Mar 2024 11:46:34 +0900 Subject: [PATCH] [fixup] cache previous state & some refactoring --- include/overlay.h | 17 +++++- src/overlay.c | 142 ++++++++++++++++++++++++++-------------------- src/regions.c | 3 + 3 files changed, 96 insertions(+), 66 deletions(-) diff --git a/include/overlay.h b/include/overlay.h index e5035c7b..bd9b0050 100644 --- a/include/overlay.h +++ b/include/overlay.h @@ -4,6 +4,8 @@ #include #include "common/graphic-helpers.h" +#include "regions.h" +#include "view.h" struct overlay { struct wlr_scene_tree *tree; @@ -12,14 +14,23 @@ struct overlay { struct multi_rect *pixman_rect; }; - /* For delayed overlay */ - struct view *view; - struct wlr_box box; + /* For caching previously shown overlay */ + struct { + struct region *region; + enum view_edge edge; + } active; + + /* For delayed snap-to-edge overlay */ struct wl_event_source *timer; + struct { + struct view *view; + struct wlr_box box; + } pending; }; /* Calls overlay_hide() internally if the view is not to be snapped */ void overlay_show(struct seat *seat, struct view *view); +/* This function must be called when grabbed view is destroyed */ void overlay_hide(struct seat *seat); #endif diff --git a/src/overlay.c b/src/overlay.c index c9007e69..f2bc373a 100644 --- a/src/overlay.c +++ b/src/overlay.c @@ -34,13 +34,11 @@ create_overlay(struct seat *seat) static void cancel_pending_overlay(struct overlay *overlay) { - if (!overlay->timer) { - return; + if (overlay->timer) { + wl_event_source_timer_update(overlay->timer, 0); } - wl_event_source_remove(overlay->timer); - overlay->timer = NULL; - overlay->view = NULL; - overlay->box = (struct wlr_box){0}; + overlay->pending.view = NULL; + overlay->pending.box = (struct wlr_box){0}; } static void @@ -72,28 +70,71 @@ show_overlay(struct seat *seat, struct view *view, struct wlr_box *box) cancel_pending_overlay(&seat->overlay); } +static void +show_region_overlay(struct seat *seat, struct view *view, struct region *region) +{ + if (region == seat->overlay.active.region) { + return; + } + seat->overlay.active.region = region; + seat->overlay.active.edge = VIEW_EDGE_INVALID; + show_overlay(seat, view, ®ion->geo); +} + +/* TODO: share logic with view_get_edge_snap_box() */ +static struct wlr_box get_edge_snap_box(enum view_edge edge, struct output *output) +{ + struct wlr_box box = output_usable_area_in_layout_coords(output); + switch (edge) { + case VIEW_EDGE_RIGHT: + box.x += box.width / 2; + /* fallthrough */ + case VIEW_EDGE_LEFT: + box.width /= 2; + break; + case VIEW_EDGE_DOWN: + box.y += box.height / 2; + /* fallthrough */ + case VIEW_EDGE_UP: + box.height /= 2; + break; + case VIEW_EDGE_CENTER: + /* */ + break; + default: + /* not reached */ + assert(false); + } + return box; +} + static int handle_overlay_timeout(void *data) { struct seat *seat = data; - show_overlay(seat, seat->overlay.view, &seat->overlay.box); + show_overlay(seat, seat->overlay.pending.view, + &seat->overlay.pending.box); return 0; } static void -show_overlay_delayed(struct seat *seat, struct view *view, struct wlr_box *box) +show_edge_overlay_delayed(struct seat *seat, struct view *view, + enum view_edge edge, struct output *output) { - if (seat->overlay.timer - && seat->overlay.view == view - && wlr_box_equal(box, &seat->overlay.box)) { + if (seat->overlay.active.edge == edge) { return; } - cancel_pending_overlay(&seat->overlay); - seat->overlay.view = view; - seat->overlay.box = *box; - seat->overlay.timer = wl_event_loop_add_timer( - seat->server->wl_event_loop, - handle_overlay_timeout, seat); + seat->overlay.active.edge = edge; + seat->overlay.active.region = NULL; + + seat->overlay.pending.view = view; + seat->overlay.pending.box = get_edge_snap_box(edge, output); + if (!seat->overlay.timer) { + seat->overlay.timer = wl_event_loop_add_timer( + seat->server->wl_event_loop, + handle_overlay_timeout, seat); + } + /* Delay for 150ms */ wl_event_source_timer_update(seat->overlay.timer, 150); } @@ -102,55 +143,28 @@ overlay_show(struct seat *seat, struct view *view) { struct server *server = seat->server; - /* - * TODO: cache return value of regions_from_cursor() or - * edge_from_cursor() to eliminate duplicated calls to show_overlay() / - * show_overlay_delayed(). - */ + /* Region overlay */ if (regions_should_snap(server)) { - /* Region overlay */ struct region *region = regions_from_cursor(server); if (region) { - show_overlay(seat, view, ®ion->geo); - return; - } - } else { - /* Snap-to-edge overlay */ - struct output *output; - enum view_edge edge = edge_from_cursor(seat, &output); - if (edge != VIEW_EDGE_INVALID) { - /* TODO: share logic with view_get_edge_snap_box() */ - struct wlr_box box = - output_usable_area_in_layout_coords(output); - switch (edge) { - case VIEW_EDGE_RIGHT: - box.x += box.width / 2; - /* fallthrough */ - case VIEW_EDGE_LEFT: - box.width /= 2; - break; - case VIEW_EDGE_DOWN: - box.y += box.height / 2; - /* fallthrough */ - case VIEW_EDGE_UP: - box.height /= 2; - break; - case VIEW_EDGE_CENTER: - /* */ - break; - case VIEW_EDGE_INVALID: - /* not reached */ - assert(false); - } - /* - * Delay showing overlay to prevent flickering when - * dragging view across output edges in multi-monitor - * setup - */ - show_overlay_delayed(seat, view, &box); + show_region_overlay(seat, view, region); return; } } + + /* Snap-to-edge overlay */ + struct output *output; + enum view_edge edge = edge_from_cursor(seat, &output); + if (edge != VIEW_EDGE_INVALID) { + /* + * Snap-to-edge overlay is delayed for 150ms to prevent + * flickering when dragging view across output edges in + * multi-monitor setup. + */ + show_edge_overlay_delayed(seat, view, edge, output); + return; + } + overlay_hide(seat); } @@ -158,12 +172,14 @@ void overlay_hide(struct seat *seat) { cancel_pending_overlay(&seat->overlay); + seat->overlay.active.edge = VIEW_EDGE_INVALID; + seat->overlay.active.region = NULL; - struct server *server = seat->server; - struct wlr_scene_node *node = &seat->overlay.tree->node; - if (!node) { + if (!seat->overlay.tree) { return; } + struct server *server = seat->server; + struct wlr_scene_node *node = &seat->overlay.tree->node; wlr_scene_node_set_enabled(node, false); if (node->parent != &server->scene->tree) { diff --git a/src/regions.c b/src/regions.c index 3add5870..159d82d9 100644 --- a/src/regions.c +++ b/src/regions.c @@ -163,6 +163,9 @@ regions_destroy(struct seat *seat, struct wl_list *regions) struct region *region, *region_tmp; wl_list_for_each_safe(region, region_tmp, regions, link) { wl_list_remove(®ion->link); + if (seat && seat->overlay.active.region == region) { + seat->overlay.active.region = NULL; + } zfree(region->name); zfree(region); }