Add CycleInRegion action

CycleInRegion will cycle focus between all windows/views that are within
the given region, to support position-based focusing.

The window/region matching supports:
* when a window is explicitly assigned to a region
* an optional `windowOverlapPercentage` arg, when at least the given
  percentage of the window's geometry is within the region's geometry.
* an optional `regionOverlapPercentage` arg, when at least the given
  percentage of the region's geometry is within the window's geometry.

To support immediate focus cycling and to avoid ping-pong'ing between the
top two windows, we cycle through windows within a region in
reverse-order.  When we are not focused within a region, we instead focus
the top-most (first) window, as that is what the user will expect.

If the `region` arg is not specified, the action will cycle through all
windows on the given desktop instead.
This commit is contained in:
Robert M. Thomson 2024-05-22 07:43:57 +02:00
parent 16c5373be5
commit 6a4d937050
4 changed files with 225 additions and 1 deletions

View file

@ -2,6 +2,7 @@
#ifndef LABWC_H
#define LABWC_H
#include "config.h"
#include "config/types.h"
#include <wlr/util/box.h>
#include <wlr/util/log.h>
#include "common/set.h"
@ -359,6 +360,30 @@ void desktop_focus_output(struct output *output);
*/
void desktop_update_top_layer_visibility(struct server *server);
/**
* desktop_cycle_view_in_region() - return a view to "cycle" to,
* filtered to views that are mostly inside a region.
*
* @active_view: Reference point for finding the next view.
* @region: If non-NULL, only return views mostly inside this region.
* @criteria: Base filtering (e.g. current workspace).
* @view_threshold: Fraction of the view area that must lie inside @region.
* If <= 0, this check is disabled.
* @region_threshold: Fraction of the region area that must lie inside the
* view. If <= 0, this check is disabled.
*
* If both thresholds are disabled, a view only matches if it is explicitly
* assigned to the region (e.g. tiled to it).
*
* Note: If @active_view is not in-region, the topmost matching view is
* returned first. If @active_view is in-region, iteration reverses to
* avoid bouncing between the two most recent views when focusing raises.
*/
struct view *desktop_cycle_view_in_region(struct server *server,
struct view *active_view, struct region *region,
enum lab_view_criteria criteria, double view_threshold,
double region_threshold);
/**
* desktop_focus_topmost_view() - focus the topmost view on the current
* workspace, skipping views that claim not to want focus (those can