action: make "FocusOutput" behave like "MoveToOutput"

This commit is contained in:
Orfeas 2024-08-21 07:38:44 +03:00 committed by Andrew J. Hesford
parent f2b6661db4
commit dda47a5e14
10 changed files with 172 additions and 128 deletions

View file

@ -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
View 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;
}
}

View file

@ -1,5 +1,6 @@
labwc_sources += files(
'box.c',
'direction.c',
'box.c',
'buf.c',
'dir.c',
'fd-util.c',

View file

@ -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;
}
}

View file

@ -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)
{

View file

@ -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) {
/*