mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
action: make "FocusOutput" behave like "MoveToOutput"
This commit is contained in:
parent
f2b6661db4
commit
dda47a5e14
10 changed files with 172 additions and 128 deletions
|
|
@ -194,10 +194,20 @@ Actions are used in menus and keyboard/mouse bindings.
|
|||
to 'fullscreen' or 'fullscreenForced', tearing will still only be
|
||||
enabled if the active window is in fullscreen mode.
|
||||
|
||||
*<action name="FocusOutput" output="HDMI-A-1" />*
|
||||
Give focus to topmost window on given output and warp the cursor
|
||||
to the center of the window. If the given output does not contain
|
||||
any windows, the cursor is centered on the given output.
|
||||
*<action name="FocusOutput" output="HDMI-A-1" direction="value" wrap="no" />*
|
||||
Give focus to topmost window on other output and warp the cursor
|
||||
to the center of the window.
|
||||
|
||||
If *output* is specified, the focus is given to the specified output and
|
||||
*direction* is ignored. If *output* is omitted, *direction* may be one
|
||||
of "left", "right", "up" or "down" to indicate that the focus should be
|
||||
given to the next output in that direction (if one exists).
|
||||
|
||||
*wrap* [yes|no] When using the direction attribute, wrap around
|
||||
from right-to-left or top-to-bottom, and vice versa. Default is no.
|
||||
|
||||
If the target output does not contain any windows, the cursor will
|
||||
be centered on the output.
|
||||
|
||||
*<action name="MoveToOutput" output="HDMI-A-1" direction="value" wrap="no" />*
|
||||
Moves active window to other output, unless the window state is
|
||||
|
|
|
|||
10
include/common/direction.h
Normal file
10
include/common/direction.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef LABWC_DIRECTION_H
|
||||
#define LABWC_DIRECTION_H
|
||||
|
||||
#include "view.h"
|
||||
|
||||
enum wlr_direction direction_from_view_edge(enum view_edge edge);
|
||||
enum wlr_direction direction_get_opposite(enum wlr_direction direction);
|
||||
|
||||
#endif /* LABWC_DIRECTION_H */
|
||||
|
|
@ -460,6 +460,7 @@ void desktop_focus_view_or_surface(struct seat *seat, struct view *view,
|
|||
|
||||
void desktop_arrange_all_views(struct server *server);
|
||||
void desktop_focus_output(struct output *output);
|
||||
void warp_cursor(struct view *view);
|
||||
struct view *desktop_topmost_focusable_view(struct server *server);
|
||||
|
||||
/**
|
||||
|
|
@ -539,6 +540,21 @@ struct output *output_from_wlr_output(struct server *server,
|
|||
struct output *output_from_name(struct server *server, const char *name);
|
||||
struct output *output_nearest_to(struct server *server, int lx, int ly);
|
||||
struct output *output_nearest_to_cursor(struct server *server);
|
||||
|
||||
/**
|
||||
* output_get_adjacent() - get next output, in a given direction,
|
||||
* from a given output
|
||||
*
|
||||
* @output: reference output
|
||||
* @edge: direction in which to look for the nearest output
|
||||
* @wrap: if true, wrap around at layout edge
|
||||
*
|
||||
* Note: if output is NULL, the output nearest the cursor will be used as the
|
||||
* reference instead.
|
||||
*/
|
||||
struct output *output_get_adjacent(struct output *output,
|
||||
enum view_edge edge, bool wrap);
|
||||
|
||||
bool output_is_usable(struct output *output);
|
||||
void output_update_usable_area(struct output *output);
|
||||
void output_update_all_usable_areas(struct server *server, bool layout_changed);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#ifndef LABWC_VIEW_H
|
||||
#define LABWC_VIEW_H
|
||||
|
||||
#include "config/rcxml.h"
|
||||
#include "config.h"
|
||||
#include "ssd.h"
|
||||
#include <stdbool.h>
|
||||
|
|
@ -482,7 +483,7 @@ void view_center(struct view *view, const struct wlr_box *ref);
|
|||
* @policy: placement policy to apply
|
||||
*/
|
||||
void view_place_by_policy(struct view *view, bool allow_cursor,
|
||||
enum view_placement_policy);
|
||||
enum view_placement_policy policy);
|
||||
void view_constrain_size_to_that_of_usable_area(struct view *view);
|
||||
|
||||
void view_restore_to(struct view *view, struct wlr_box geometry);
|
||||
|
|
@ -548,8 +549,6 @@ void view_on_output_destroy(struct view *view);
|
|||
void view_connect_map(struct view *view, struct wlr_surface *surface);
|
||||
void view_destroy(struct view *view);
|
||||
|
||||
struct output *view_get_adjacent_output(struct view *view, enum view_edge edge,
|
||||
bool wrap);
|
||||
enum view_axis view_axis_parse(const char *direction);
|
||||
enum view_edge view_edge_parse(const char *direction);
|
||||
enum view_placement_policy view_placement_parse(const char *policy);
|
||||
|
|
|
|||
65
src/action.c
65
src/action.c
|
|
@ -19,7 +19,6 @@
|
|||
#include "menu/menu.h"
|
||||
#include "osd.h"
|
||||
#include "output-virtual.h"
|
||||
#include "placement.h"
|
||||
#include "regions.h"
|
||||
#include "ssd.h"
|
||||
#include "view.h"
|
||||
|
|
@ -413,11 +412,6 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
|
|||
}
|
||||
break;
|
||||
case ACTION_TYPE_FOCUS_OUTPUT:
|
||||
if (!strcmp(argument, "output")) {
|
||||
action_arg_add_str(action, argument, content);
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVE_TO_OUTPUT:
|
||||
if (!strcmp(argument, "output")) {
|
||||
action_arg_add_str(action, argument, content);
|
||||
|
|
@ -552,9 +546,6 @@ action_is_valid(struct action *action)
|
|||
case ACTION_TYPE_SNAP_TO_REGION:
|
||||
arg_name = "region";
|
||||
break;
|
||||
case ACTION_TYPE_FOCUS_OUTPUT:
|
||||
arg_name = "output";
|
||||
break;
|
||||
case ACTION_TYPE_IF:
|
||||
case ACTION_TYPE_FOR_EACH:
|
||||
; /* works around "a label can only be part of a statement" */
|
||||
|
|
@ -725,6 +716,29 @@ start_window_cycling(struct server *server, enum lab_cycle_dir direction)
|
|||
osd_update(server);
|
||||
}
|
||||
|
||||
static struct output *
|
||||
get_target_output(struct output *output, struct server *server,
|
||||
struct action *action)
|
||||
{
|
||||
const char *output_name = action_get_str(action, "output", NULL);
|
||||
struct output *target = NULL;
|
||||
|
||||
if (output_name) {
|
||||
target = output_from_name(server, output_name);
|
||||
} else {
|
||||
enum view_edge edge =
|
||||
action_get_int(action, "direction", VIEW_EDGE_INVALID);
|
||||
bool wrap = action_get_bool(action, "wrap", false);
|
||||
target = output_get_adjacent(output, edge, wrap);
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
wlr_log(WLR_DEBUG, "Invalid output");
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
void
|
||||
actions_run(struct view *activator, struct server *server,
|
||||
struct wl_list *actions, uint32_t resize_edges)
|
||||
|
|
@ -739,6 +753,9 @@ actions_run(struct view *activator, struct server *server,
|
|||
|
||||
struct view *view;
|
||||
struct action *action;
|
||||
struct output *output;
|
||||
struct output *target;
|
||||
|
||||
wl_list_for_each(action, actions, link) {
|
||||
wlr_log(WLR_DEBUG, "Handling action %u: %s", action->type,
|
||||
action_names[action->type]);
|
||||
|
|
@ -1009,25 +1026,10 @@ actions_run(struct view *activator, struct server *server,
|
|||
if (!view) {
|
||||
break;
|
||||
}
|
||||
const char *output_name = action_get_str(action, "output", NULL);
|
||||
struct output *target = NULL;
|
||||
if (output_name) {
|
||||
target = output_from_name(view->server, output_name);
|
||||
} else {
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
bool wrap = action_get_bool(action, "wrap", false);
|
||||
target = view_get_adjacent_output(view, edge, wrap);
|
||||
target = get_target_output(view->output, server, action);
|
||||
if (target) {
|
||||
view_move_to_output(view, target);
|
||||
}
|
||||
if (!target) {
|
||||
/*
|
||||
* Most likely because we're already on the
|
||||
* output furthest in the requested direction
|
||||
* or the output or direction was invalid.
|
||||
*/
|
||||
wlr_log(WLR_DEBUG, "Invalid output");
|
||||
break;
|
||||
}
|
||||
view_move_to_output(view, target);
|
||||
break;
|
||||
case ACTION_TYPE_FIT_TO_OUTPUT:
|
||||
if (!view) {
|
||||
|
|
@ -1039,7 +1041,7 @@ actions_run(struct view *activator, struct server *server,
|
|||
if (!view) {
|
||||
break;
|
||||
}
|
||||
struct output *output = view->output;
|
||||
output = view->output;
|
||||
if (!output) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -1058,9 +1060,10 @@ actions_run(struct view *activator, struct server *server,
|
|||
}
|
||||
break;
|
||||
case ACTION_TYPE_FOCUS_OUTPUT:
|
||||
{
|
||||
const char *output_name = action_get_str(action, "output", NULL);
|
||||
desktop_focus_output(output_from_name(server, output_name));
|
||||
output = output_nearest_to_cursor(server);
|
||||
target = get_target_output(output, server, action);
|
||||
if (target) {
|
||||
desktop_focus_output(target);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_IF:
|
||||
|
|
|
|||
42
src/common/direction.c
Normal file
42
src/common/direction.c
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <assert.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include "common/direction.h"
|
||||
#include "view.h"
|
||||
|
||||
enum wlr_direction
|
||||
direction_from_view_edge(enum view_edge edge)
|
||||
{
|
||||
switch (edge) {
|
||||
case VIEW_EDGE_LEFT:
|
||||
return WLR_DIRECTION_LEFT;
|
||||
case VIEW_EDGE_RIGHT:
|
||||
return WLR_DIRECTION_RIGHT;
|
||||
case VIEW_EDGE_UP:
|
||||
return WLR_DIRECTION_UP;
|
||||
case VIEW_EDGE_DOWN:
|
||||
return WLR_DIRECTION_DOWN;
|
||||
case VIEW_EDGE_CENTER:
|
||||
case VIEW_EDGE_INVALID:
|
||||
default:
|
||||
return WLR_DIRECTION_UP;
|
||||
}
|
||||
}
|
||||
|
||||
enum wlr_direction
|
||||
direction_get_opposite(enum wlr_direction direction)
|
||||
{
|
||||
switch (direction) {
|
||||
case WLR_DIRECTION_RIGHT:
|
||||
return WLR_DIRECTION_LEFT;
|
||||
case WLR_DIRECTION_LEFT:
|
||||
return WLR_DIRECTION_RIGHT;
|
||||
case WLR_DIRECTION_DOWN:
|
||||
return WLR_DIRECTION_UP;
|
||||
case WLR_DIRECTION_UP:
|
||||
return WLR_DIRECTION_DOWN;
|
||||
default:
|
||||
assert(0); /* Unreachable */
|
||||
return WLR_DIRECTION_UP;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
labwc_sources += files(
|
||||
'box.c',
|
||||
'direction.c',
|
||||
'box.c',
|
||||
'buf.c',
|
||||
'dir.c',
|
||||
'fd-util.c',
|
||||
|
|
|
|||
|
|
@ -197,10 +197,10 @@ desktop_focus_output(struct output *output)
|
|||
if (wlr_output_layout_intersects(layout,
|
||||
output->wlr_output, &view->current)) {
|
||||
desktop_focus_view(view, /*raise*/ false);
|
||||
wlr_cursor_warp(output->server->seat.cursor, NULL,
|
||||
wlr_cursor_warp(view->server->seat.cursor, NULL,
|
||||
view->current.x + view->current.width / 2,
|
||||
view->current.y + view->current.height / 2);
|
||||
cursor_update_focus(output->server);
|
||||
cursor_update_focus(view->server);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
48
src/output.c
48
src/output.c
|
|
@ -18,6 +18,7 @@
|
|||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/util/region.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "common/direction.h"
|
||||
#include "common/macros.h"
|
||||
#include "common/mem.h"
|
||||
#include "common/scene-helpers.h"
|
||||
|
|
@ -880,6 +881,53 @@ output_nearest_to_cursor(struct server *server)
|
|||
server->seat.cursor->y);
|
||||
}
|
||||
|
||||
struct output *
|
||||
output_get_adjacent(struct output *output, enum view_edge edge, bool wrap)
|
||||
{
|
||||
if (!output_is_usable(output)) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"output is not usable, cannot find adjacent output");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_box box = output_usable_area_in_layout_coords(output);
|
||||
int lx = box.x + box.width / 2;
|
||||
int ly = box.y + box.height / 2;
|
||||
|
||||
/* Determine any adjacent output in the appropriate direction */
|
||||
struct wlr_output *new_output = NULL;
|
||||
struct wlr_output *current_output = output->wlr_output;
|
||||
struct wlr_output_layout *layout = output->server->output_layout;
|
||||
enum wlr_direction direction = direction_from_view_edge(edge);
|
||||
new_output = wlr_output_layout_adjacent_output(layout, direction,
|
||||
current_output, lx, ly);
|
||||
|
||||
/*
|
||||
* Optionally wrap around from top-to-bottom or left-to-right, and vice
|
||||
* versa.
|
||||
*/
|
||||
if (wrap && !new_output) {
|
||||
new_output = wlr_output_layout_farthest_output(layout,
|
||||
direction_get_opposite(direction), current_output, lx, ly);
|
||||
}
|
||||
|
||||
/*
|
||||
* When "adjacent" output is the same as the original, there is no
|
||||
* adjacent
|
||||
*/
|
||||
if (!new_output || new_output == current_output) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output = output_from_wlr_output(output->server, new_output);
|
||||
if (!output_is_usable(output)) {
|
||||
wlr_log(WLR_ERROR, "invalid output in layout");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool
|
||||
output_is_usable(struct output *output)
|
||||
{
|
||||
|
|
|
|||
89
src/view.c
89
src/view.c
|
|
@ -1790,91 +1790,6 @@ view_on_output_destroy(struct view *view)
|
|||
view->output = NULL;
|
||||
}
|
||||
|
||||
static enum wlr_direction
|
||||
opposite_direction(enum wlr_direction direction)
|
||||
{
|
||||
switch (direction) {
|
||||
case WLR_DIRECTION_RIGHT:
|
||||
return WLR_DIRECTION_LEFT;
|
||||
case WLR_DIRECTION_LEFT:
|
||||
return WLR_DIRECTION_RIGHT;
|
||||
case WLR_DIRECTION_DOWN:
|
||||
return WLR_DIRECTION_UP;
|
||||
case WLR_DIRECTION_UP:
|
||||
return WLR_DIRECTION_DOWN;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static enum wlr_direction
|
||||
get_wlr_direction(enum view_edge edge)
|
||||
{
|
||||
switch (edge) {
|
||||
case VIEW_EDGE_LEFT:
|
||||
return WLR_DIRECTION_LEFT;
|
||||
case VIEW_EDGE_RIGHT:
|
||||
return WLR_DIRECTION_RIGHT;
|
||||
case VIEW_EDGE_UP:
|
||||
return WLR_DIRECTION_UP;
|
||||
case VIEW_EDGE_DOWN:
|
||||
return WLR_DIRECTION_DOWN;
|
||||
case VIEW_EDGE_CENTER:
|
||||
case VIEW_EDGE_INVALID:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct output *
|
||||
view_get_adjacent_output(struct view *view, enum view_edge edge, bool wrap)
|
||||
{
|
||||
assert(view);
|
||||
struct output *output = view->output;
|
||||
if (!output_is_usable(output)) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"view has no output, cannot find adjacent output");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_box box = output_usable_area_in_layout_coords(output);
|
||||
int lx = box.x + box.width / 2;
|
||||
int ly = box.y + box.height / 2;
|
||||
|
||||
/* Determine any adjacent output in the appropriate direction */
|
||||
struct wlr_output *new_output = NULL;
|
||||
struct wlr_output *current_output = output->wlr_output;
|
||||
struct wlr_output_layout *layout = view->server->output_layout;
|
||||
enum wlr_direction direction = get_wlr_direction(edge);
|
||||
new_output = wlr_output_layout_adjacent_output(layout, direction,
|
||||
current_output, lx, ly);
|
||||
|
||||
/*
|
||||
* Optionally wrap around from top-to-bottom or left-to-right, and vice
|
||||
* versa.
|
||||
*/
|
||||
if (wrap && !new_output) {
|
||||
new_output = wlr_output_layout_farthest_output(layout,
|
||||
opposite_direction(direction), current_output, lx, ly);
|
||||
}
|
||||
|
||||
/*
|
||||
* When "adjacent" output is the same as the original, there is no
|
||||
* adjacent
|
||||
*/
|
||||
if (!new_output || new_output == current_output) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output = output_from_wlr_output(view->server, new_output);
|
||||
if (!output_is_usable(output)) {
|
||||
wlr_log(WLR_ERROR, "invalid output in layout");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static int
|
||||
shift_view_to_usable_1d(int size,
|
||||
int cur_pos, int cur_lo, int cur_extent,
|
||||
|
|
@ -1936,7 +1851,7 @@ view_move_to_edge(struct view *view, enum view_edge direction, bool snap_to_wind
|
|||
|
||||
/* Otherwise, move to edge of next adjacent display, if possible */
|
||||
struct output *output =
|
||||
view_get_adjacent_output(view, direction, /* wrap */ false);
|
||||
output_get_adjacent(view->output, direction, /* wrap */ false);
|
||||
if (!output) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2115,7 +2030,7 @@ view_snap_to_edge(struct view *view, enum view_edge edge,
|
|||
|
||||
if (across_outputs && view->tiled == edge && view->maximized == VIEW_AXIS_NONE) {
|
||||
/* We are already tiled for this edge; try to switch outputs */
|
||||
output = view_get_adjacent_output(view, edge, /* wrap */ false);
|
||||
output = output_get_adjacent(view->output, edge, /* wrap */ false);
|
||||
|
||||
if (!output) {
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue