mirror of
https://github.com/labwc/labwc.git
synced 2026-04-07 08:21:20 -04:00
Merge 6a4d937050 into 50bb882cf0
This commit is contained in:
commit
afe4c6c840
4 changed files with 225 additions and 1 deletions
|
|
@ -125,6 +125,23 @@ Actions are used in menus and keyboard/mouse bindings.
|
||||||
Resize and move the active window back to its untiled or unmaximized
|
Resize and move the active window back to its untiled or unmaximized
|
||||||
position if it had been maximized or tiled to a direction or region.
|
position if it had been maximized or tiled to a direction or region.
|
||||||
|
|
||||||
|
*<action name="CycleInRegion" region="value" windowOverlapPercent="value" regionOverlapPercent="value" />*
|
||||||
|
Cycle focus to the next window in the given region.
|
||||||
|
|
||||||
|
If _windowOverlapPercent_ is set and > 0, it is the minimum percentage of
|
||||||
|
the window area that must lie inside the region.
|
||||||
|
|
||||||
|
If _regionOverlapPercent_ is set and > 0, it is the minimum percentage of
|
||||||
|
the region area that must lie inside the window.
|
||||||
|
|
||||||
|
If both are omitted or set to 0, a window matches only if it is explicitly
|
||||||
|
assigned to the region (e.g. tiled to it), regardless of window size.
|
||||||
|
|
||||||
|
If _region_ is omitted, cycle focus to the next window on the entire
|
||||||
|
screen (still honoring the standard window-switcher criteria such as
|
||||||
|
current-workspace filtering).
|
||||||
|
See labwc-config(5) for further information on how to define regions.
|
||||||
|
|
||||||
*<action name="NextWindow" workspace="current" output="all" identifier="all" />*++
|
*<action name="NextWindow" workspace="current" output="all" identifier="all" />*++
|
||||||
*<action name="PreviousWindow" workspace="current" output="all" identifier="all" />*
|
*<action name="PreviousWindow" workspace="current" output="all" identifier="all" />*
|
||||||
Cycle focus to next/previous window, respectively.
|
Cycle focus to next/previous window, respectively.
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#ifndef LABWC_H
|
#ifndef LABWC_H
|
||||||
#define LABWC_H
|
#define LABWC_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "config/types.h"
|
||||||
#include <wlr/util/box.h>
|
#include <wlr/util/box.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include "common/set.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);
|
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
|
* desktop_focus_topmost_view() - focus the topmost view on the current
|
||||||
* workspace, skipping views that claim not to want focus (those can
|
* workspace, skipping views that claim not to want focus (those can
|
||||||
|
|
|
||||||
57
src/action.c
57
src/action.c
|
|
@ -112,6 +112,7 @@ enum action_type {
|
||||||
ACTION_TYPE_TOGGLE_SNAP_TO_REGION,
|
ACTION_TYPE_TOGGLE_SNAP_TO_REGION,
|
||||||
ACTION_TYPE_SNAP_TO_REGION,
|
ACTION_TYPE_SNAP_TO_REGION,
|
||||||
ACTION_TYPE_UNSNAP,
|
ACTION_TYPE_UNSNAP,
|
||||||
|
ACTION_TYPE_CYCLE_IN_REGION,
|
||||||
ACTION_TYPE_TOGGLE_KEYBINDS,
|
ACTION_TYPE_TOGGLE_KEYBINDS,
|
||||||
ACTION_TYPE_FOCUS_OUTPUT,
|
ACTION_TYPE_FOCUS_OUTPUT,
|
||||||
ACTION_TYPE_MOVE_TO_OUTPUT,
|
ACTION_TYPE_MOVE_TO_OUTPUT,
|
||||||
|
|
@ -182,6 +183,7 @@ const char *action_names[] = {
|
||||||
"ToggleSnapToRegion",
|
"ToggleSnapToRegion",
|
||||||
"SnapToRegion",
|
"SnapToRegion",
|
||||||
"UnSnap",
|
"UnSnap",
|
||||||
|
"CycleInRegion",
|
||||||
"ToggleKeybinds",
|
"ToggleKeybinds",
|
||||||
"FocusOutput",
|
"FocusOutput",
|
||||||
"MoveToOutput",
|
"MoveToOutput",
|
||||||
|
|
@ -516,6 +518,17 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ACTION_TYPE_CYCLE_IN_REGION:
|
||||||
|
if (!strcasecmp(argument, "region")) {
|
||||||
|
action_arg_add_str(action, argument, content);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(argument, "windowOverlapPercent")
|
||||||
|
|| !strcasecmp(argument, "regionOverlapPercent")) {
|
||||||
|
action_arg_add_int(action, argument, atoi(content));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ACTION_TYPE_FOCUS_OUTPUT:
|
case ACTION_TYPE_FOCUS_OUTPUT:
|
||||||
case ACTION_TYPE_MOVE_TO_OUTPUT:
|
case ACTION_TYPE_MOVE_TO_OUTPUT:
|
||||||
if (!strcmp(argument, "output")) {
|
if (!strcmp(argument, "output")) {
|
||||||
|
|
@ -1249,6 +1262,50 @@ run_action(struct view *view, struct server *server, struct action *action,
|
||||||
view_toggle_visible_on_all_workspaces(view);
|
view_toggle_visible_on_all_workspaces(view);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ACTION_TYPE_CYCLE_IN_REGION:
|
||||||
|
{
|
||||||
|
struct view *active_view = view ? view : server->active_view;
|
||||||
|
enum lab_view_criteria criteria =
|
||||||
|
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER
|
||||||
|
| LAB_VIEW_CRITERIA_NO_DIALOG;
|
||||||
|
int window_overlap_percent = action_get_int(action, "windowOverlapPercent", 0);
|
||||||
|
int region_overlap_percent = action_get_int(action, "regionOverlapPercent", 0);
|
||||||
|
|
||||||
|
if (rc.window_switcher.workspace_filter == CYCLE_WORKSPACE_CURRENT) {
|
||||||
|
criteria |= LAB_VIEW_CRITERIA_CURRENT_WORKSPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_overlap_percent = CLAMP(window_overlap_percent, 0, 100);
|
||||||
|
region_overlap_percent = CLAMP(region_overlap_percent, 0, 100);
|
||||||
|
|
||||||
|
double view_threshold = (double)window_overlap_percent / 100.0;
|
||||||
|
double region_threshold = (double)region_overlap_percent / 100.0;
|
||||||
|
|
||||||
|
const char *region_name = action_get_str(action, "region", NULL);
|
||||||
|
struct region *region = NULL;
|
||||||
|
if (region_name) {
|
||||||
|
if (!active_view) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
struct output *output = active_view->output;
|
||||||
|
if (!output_is_usable(output)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
region = regions_from_name(region_name, output);
|
||||||
|
if (!region) {
|
||||||
|
wlr_log(WLR_ERROR, "Invalid CycleInRegion region: '%s'",
|
||||||
|
region_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct view *new_view = desktop_cycle_view_in_region(
|
||||||
|
server, active_view, region, criteria, view_threshold, region_threshold);
|
||||||
|
if (new_view) {
|
||||||
|
desktop_focus_view(new_view, /*raise*/ true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ACTION_TYPE_FOCUS:
|
case ACTION_TYPE_FOCUS:
|
||||||
if (view) {
|
if (view) {
|
||||||
desktop_focus_view(view, /*raise*/ false);
|
desktop_focus_view(view, /*raise*/ false);
|
||||||
|
|
|
||||||
127
src/desktop.c
127
src/desktop.c
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
|
@ -8,6 +9,7 @@
|
||||||
#include <wlr/types/wlr_seat.h>
|
#include <wlr/types/wlr_seat.h>
|
||||||
#include <wlr/types/wlr_subcompositor.h>
|
#include <wlr/types/wlr_subcompositor.h>
|
||||||
#include <wlr/types/wlr_xdg_shell.h>
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
|
#include "common/macros.h"
|
||||||
#include "common/scene-helpers.h"
|
#include "common/scene-helpers.h"
|
||||||
#include "dnd.h"
|
#include "dnd.h"
|
||||||
#include "labwc.h"
|
#include "labwc.h"
|
||||||
|
|
@ -16,6 +18,7 @@
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
#include "ssd.h"
|
#include "ssd.h"
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
|
#include "regions.h"
|
||||||
#include "workspaces.h"
|
#include "workspaces.h"
|
||||||
|
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
|
|
@ -134,6 +137,129 @@ desktop_focus_view_or_surface(struct seat *seat, struct view *view,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
view_is_assigned_to_region(struct view *view, struct region *region)
|
||||||
|
{
|
||||||
|
if (!view || !region) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view->tiled_region && view->tiled_region->name
|
||||||
|
&& !strcmp(view->tiled_region->name, region->name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view->tiled_region_evacuate
|
||||||
|
&& !strcmp(view->tiled_region_evacuate, region->name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
view_matches_region(struct view *view, struct region *region,
|
||||||
|
double view_threshold, double region_threshold)
|
||||||
|
{
|
||||||
|
if (!view || !region) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view_is_assigned_to_region(view, region)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view_threshold <= 0 && region_threshold <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_box overlap;
|
||||||
|
wlr_box_intersection(&overlap, &view->current, ®ion->geo);
|
||||||
|
double overlap_area = (double)overlap.height * (double)overlap.width;
|
||||||
|
if (overlap_area <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view_threshold > 0) {
|
||||||
|
double view_area = (double)view->current.height * (double)view->current.width;
|
||||||
|
if (view_area > 0 && overlap_area >= view_threshold * view_area) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region_threshold > 0) {
|
||||||
|
double region_area = (double)region->geo.height * (double)region->geo.width;
|
||||||
|
if (region_area > 0 && overlap_area >= region_threshold * region_area) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct view *
|
||||||
|
cycle_prev_wrap(struct wl_list *head, struct view *from,
|
||||||
|
enum lab_view_criteria criteria)
|
||||||
|
{
|
||||||
|
struct view *view = view_prev(head, from, criteria);
|
||||||
|
return view ? view : view_prev(head, NULL, criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (!active_view) {
|
||||||
|
struct view *cur;
|
||||||
|
for_each_view(cur, &server->views, criteria) {
|
||||||
|
if (cur->minimized) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!region || view_matches_region(cur, region,
|
||||||
|
view_threshold, region_threshold)) {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region && (!active_view
|
||||||
|
|| !view_matches_region(active_view, region,
|
||||||
|
view_threshold, region_threshold))) {
|
||||||
|
/*
|
||||||
|
* If the currently focused view is not in-region, always focus the
|
||||||
|
* topmost matching view first.
|
||||||
|
*/
|
||||||
|
struct view *cur;
|
||||||
|
for_each_view(cur, &server->views, criteria) {
|
||||||
|
if (!cur->minimized && view_matches_region(cur, region,
|
||||||
|
view_threshold, region_threshold)) {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the currently active/focused window is already in-region, cycle
|
||||||
|
* through in reverse order so that we cycle through all windows, and
|
||||||
|
* not just the two most recent (focusing raises).
|
||||||
|
*/
|
||||||
|
struct view *start = active_view;
|
||||||
|
struct view *cur = cycle_prev_wrap(&server->views, start, criteria);
|
||||||
|
while (cur && cur != start) {
|
||||||
|
if (!cur->minimized
|
||||||
|
&& (!region
|
||||||
|
|| view_matches_region(cur, region,
|
||||||
|
view_threshold, region_threshold))) {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
cur = cycle_prev_wrap(&server->views, cur, criteria);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct view *
|
static struct view *
|
||||||
desktop_topmost_focusable_view(struct server *server)
|
desktop_topmost_focusable_view(struct server *server)
|
||||||
{
|
{
|
||||||
|
|
@ -384,4 +510,3 @@ get_cursor_context(struct server *server)
|
||||||
*/
|
*/
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue