mirror of
https://github.com/labwc/labwc.git
synced 2026-02-05 04:06:33 -05:00
action.c: split actions_run()
This commit is contained in:
parent
6c50a62817
commit
15e3c32b5b
1 changed files with 483 additions and 476 deletions
959
src/action.c
959
src/action.c
|
|
@ -862,6 +862,488 @@ warp_cursor(struct server *server, struct view *view, const char *to, const char
|
|||
cursor_update_focus(server);
|
||||
}
|
||||
|
||||
static void
|
||||
run_action(struct view *view, struct server *server, struct action *action,
|
||||
struct cursor_context *ctx)
|
||||
{
|
||||
switch (action->type) {
|
||||
case ACTION_TYPE_CLOSE:
|
||||
if (view) {
|
||||
view_close(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_KILL:
|
||||
if (view) {
|
||||
/* Send SIGTERM to the process associated with the surface */
|
||||
assert(view->impl->get_pid);
|
||||
pid_t pid = view->impl->get_pid(view);
|
||||
if (pid == getpid()) {
|
||||
wlr_log(WLR_ERROR, "Preventing sending SIGTERM to labwc");
|
||||
} else if (pid > 0) {
|
||||
kill(pid, SIGTERM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_DEBUG:
|
||||
debug_dump_scene(server);
|
||||
break;
|
||||
case ACTION_TYPE_EXECUTE: {
|
||||
struct buf cmd = BUF_INIT;
|
||||
buf_add(&cmd, action_get_str(action, "command", NULL));
|
||||
buf_expand_tilde(&cmd);
|
||||
spawn_async_no_shell(cmd.data);
|
||||
buf_reset(&cmd);
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_EXIT:
|
||||
wl_display_terminate(server->wl_display);
|
||||
break;
|
||||
case ACTION_TYPE_MOVE_TO_EDGE:
|
||||
if (view) {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
bool snap_to_windows = action_get_bool(action, "snapWindows", true);
|
||||
view_move_to_edge(view, edge, snap_to_windows);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_SNAP_TO_EDGE:
|
||||
case ACTION_TYPE_SNAP_TO_EDGE:
|
||||
if (view) {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
if (action->type == ACTION_TYPE_TOGGLE_SNAP_TO_EDGE
|
||||
&& view->maximized == VIEW_AXIS_NONE
|
||||
&& !view->fullscreen
|
||||
&& view_is_tiled(view)
|
||||
&& view->tiled == edge) {
|
||||
view_set_untiled(view);
|
||||
view_apply_natural_geometry(view);
|
||||
break;
|
||||
}
|
||||
view_snap_to_edge(view, edge,
|
||||
/*across_outputs*/ true,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_GROW_TO_EDGE:
|
||||
if (view) {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
view_grow_to_edge(view, edge);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SHRINK_TO_EDGE:
|
||||
if (view) {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
view_shrink_to_edge(view, edge);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_NEXT_WINDOW:
|
||||
if (server->input_mode == LAB_INPUT_STATE_WINDOW_SWITCHER) {
|
||||
osd_cycle(server, LAB_CYCLE_DIR_FORWARD);
|
||||
} else {
|
||||
osd_begin(server, LAB_CYCLE_DIR_FORWARD);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_PREVIOUS_WINDOW:
|
||||
if (server->input_mode == LAB_INPUT_STATE_WINDOW_SWITCHER) {
|
||||
osd_cycle(server, LAB_CYCLE_DIR_BACKWARD);
|
||||
} else {
|
||||
osd_begin(server, LAB_CYCLE_DIR_BACKWARD);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RECONFIGURE:
|
||||
kill(getpid(), SIGHUP);
|
||||
break;
|
||||
case ACTION_TYPE_SHOW_MENU:
|
||||
show_menu(server, view, ctx,
|
||||
action_get_str(action, "menu", NULL),
|
||||
action_get_bool(action, "atCursor", true),
|
||||
action_get_str(action, "x.position", NULL),
|
||||
action_get_str(action, "y.position", NULL));
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_MAXIMIZE:
|
||||
if (view) {
|
||||
enum view_axis axis = action_get_int(action,
|
||||
"direction", VIEW_AXIS_BOTH);
|
||||
view_toggle_maximize(view, axis);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MAXIMIZE:
|
||||
if (view) {
|
||||
enum view_axis axis = action_get_int(action,
|
||||
"direction", VIEW_AXIS_BOTH);
|
||||
view_maximize(view, axis,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_UNMAXIMIZE:
|
||||
if (view) {
|
||||
enum view_axis axis = action_get_int(action,
|
||||
"direction", VIEW_AXIS_BOTH);
|
||||
view_maximize(view, view->maximized & ~axis,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_FULLSCREEN:
|
||||
if (view) {
|
||||
view_toggle_fullscreen(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SET_DECORATIONS:
|
||||
if (view) {
|
||||
enum ssd_mode mode = action_get_int(action,
|
||||
"decorations", LAB_SSD_MODE_FULL);
|
||||
bool force_ssd = action_get_bool(action,
|
||||
"forceSSD", false);
|
||||
view_set_decorations(view, mode, force_ssd);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_DECORATIONS:
|
||||
if (view) {
|
||||
view_toggle_decorations(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_ALWAYS_ON_TOP:
|
||||
if (view) {
|
||||
view_toggle_always_on_top(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_ALWAYS_ON_BOTTOM:
|
||||
if (view) {
|
||||
view_toggle_always_on_bottom(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_OMNIPRESENT:
|
||||
if (view) {
|
||||
view_toggle_visible_on_all_workspaces(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_FOCUS:
|
||||
if (view) {
|
||||
desktop_focus_view(view, /*raise*/ false);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_UNFOCUS:
|
||||
seat_focus_surface(&server->seat, NULL);
|
||||
break;
|
||||
case ACTION_TYPE_ICONIFY:
|
||||
if (view) {
|
||||
view_minimize(view, true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVE:
|
||||
if (view) {
|
||||
interactive_begin(view, LAB_INPUT_STATE_MOVE, 0);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RAISE:
|
||||
if (view) {
|
||||
view_move_to_front(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_LOWER:
|
||||
if (view) {
|
||||
view_move_to_back(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RESIZE:
|
||||
if (view) {
|
||||
uint32_t resize_edges = cursor_get_resize_edges(
|
||||
server->seat.cursor, ctx);
|
||||
interactive_begin(view, LAB_INPUT_STATE_RESIZE,
|
||||
resize_edges);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RESIZE_RELATIVE:
|
||||
if (view) {
|
||||
int left = action_get_int(action, "left", 0);
|
||||
int right = action_get_int(action, "right", 0);
|
||||
int top = action_get_int(action, "top", 0);
|
||||
int bottom = action_get_int(action, "bottom", 0);
|
||||
view_resize_relative(view, left, right, top, bottom);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVETO:
|
||||
if (view) {
|
||||
int x = action_get_int(action, "x", 0);
|
||||
int y = action_get_int(action, "y", 0);
|
||||
struct border margin = ssd_thickness(view);
|
||||
view_move(view, x + margin.left, y + margin.top);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RESIZETO:
|
||||
if (view) {
|
||||
int width = action_get_int(action, "width", 0);
|
||||
int height = action_get_int(action, "height", 0);
|
||||
|
||||
/*
|
||||
* To support only setting one of width/height
|
||||
* in <action name="ResizeTo" width="" height=""/>
|
||||
* we fall back to current dimension when unset.
|
||||
*/
|
||||
struct wlr_box box = {
|
||||
.x = view->pending.x,
|
||||
.y = view->pending.y,
|
||||
.width = width ? : view->pending.width,
|
||||
.height = height ? : view->pending.height,
|
||||
};
|
||||
view_set_shade(view, false);
|
||||
view_move_resize(view, box);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVE_RELATIVE:
|
||||
if (view) {
|
||||
int x = action_get_int(action, "x", 0);
|
||||
int y = action_get_int(action, "y", 0);
|
||||
view_move_relative(view, x, y);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVETO_CURSOR:
|
||||
wlr_log(WLR_ERROR,
|
||||
"Action MoveToCursor is deprecated. To ensure your config works in future labwc "
|
||||
"releases, please use <action name=\"AutoPlace\" policy=\"cursor\">");
|
||||
if (view) {
|
||||
view_move_to_cursor(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SEND_TO_DESKTOP:
|
||||
if (!view) {
|
||||
break;
|
||||
}
|
||||
/* Falls through to GoToDesktop */
|
||||
case ACTION_TYPE_GO_TO_DESKTOP: {
|
||||
bool follow = true;
|
||||
bool wrap = action_get_bool(action, "wrap", true);
|
||||
const char *to = action_get_str(action, "to", NULL);
|
||||
/*
|
||||
* `to` is always != NULL here because otherwise we would have
|
||||
* removed the action during the initial parsing step as it is
|
||||
* a required argument for both SendToDesktop and GoToDesktop.
|
||||
*/
|
||||
struct workspace *target_workspace = workspaces_find(
|
||||
server->workspaces.current, to, wrap);
|
||||
if (!target_workspace) {
|
||||
break;
|
||||
}
|
||||
if (action->type == ACTION_TYPE_SEND_TO_DESKTOP) {
|
||||
view_move_to_workspace(view, target_workspace);
|
||||
follow = action_get_bool(action, "follow", true);
|
||||
|
||||
/* Ensure that the focus is not on another desktop */
|
||||
if (!follow && server->active_view == view) {
|
||||
desktop_focus_topmost_view(server);
|
||||
}
|
||||
}
|
||||
if (follow) {
|
||||
workspaces_switch_to(target_workspace,
|
||||
/*update_focus*/ true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_MOVE_TO_OUTPUT: {
|
||||
if (!view) {
|
||||
break;
|
||||
}
|
||||
struct output *target_output =
|
||||
get_target_output(view->output, server, action);
|
||||
if (target_output) {
|
||||
view_move_to_output(view, target_output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_FIT_TO_OUTPUT:
|
||||
if (!view) {
|
||||
break;
|
||||
}
|
||||
view_constrain_size_to_that_of_usable_area(view);
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_SNAP_TO_REGION:
|
||||
case ACTION_TYPE_SNAP_TO_REGION: {
|
||||
if (!view) {
|
||||
break;
|
||||
}
|
||||
struct output *output = view->output;
|
||||
if (!output) {
|
||||
break;
|
||||
}
|
||||
const char *region_name = action_get_str(action, "region", NULL);
|
||||
struct region *region = regions_from_name(region_name, output);
|
||||
if (region) {
|
||||
if (action->type == ACTION_TYPE_TOGGLE_SNAP_TO_REGION
|
||||
&& view->maximized == VIEW_AXIS_NONE
|
||||
&& !view->fullscreen
|
||||
&& view_is_tiled(view)
|
||||
&& view->tiled_region == region) {
|
||||
view_set_untiled(view);
|
||||
view_apply_natural_geometry(view);
|
||||
break;
|
||||
}
|
||||
view_snap_to_region(view, region,
|
||||
/*store_natural_geometry*/ true);
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Invalid SnapToRegion id: '%s'", region_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_UNSNAP:
|
||||
if (view && !view->fullscreen && !view_is_floating(view)) {
|
||||
view_maximize(view, VIEW_AXIS_NONE,
|
||||
/* store_natural_geometry */ false);
|
||||
view_set_untiled(view);
|
||||
view_apply_natural_geometry(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_KEYBINDS:
|
||||
if (view) {
|
||||
view_toggle_keybinds(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_FOCUS_OUTPUT: {
|
||||
struct output *output = output_nearest_to_cursor(server);
|
||||
struct output *target_output =
|
||||
get_target_output(output, server, action);
|
||||
if (target_output) {
|
||||
desktop_focus_output(target_output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_IF:
|
||||
if (view) {
|
||||
run_if_action(view, server, action);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_FOR_EACH: {
|
||||
struct wl_array views;
|
||||
struct view **item;
|
||||
bool matches = false;
|
||||
wl_array_init(&views);
|
||||
view_array_append(server, &views, LAB_VIEW_CRITERIA_NONE);
|
||||
wl_array_for_each(item, &views) {
|
||||
matches |= run_if_action(*item, server, action);
|
||||
}
|
||||
wl_array_release(&views);
|
||||
if (!matches) {
|
||||
struct wl_list *child_actions;
|
||||
child_actions = action_get_actionlist(action, "none");
|
||||
if (child_actions) {
|
||||
actions_run(view, server, child_actions, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_VIRTUAL_OUTPUT_ADD: {
|
||||
/* TODO: rename this argument to "outputName" */
|
||||
const char *output_name =
|
||||
action_get_str(action, "output_name", NULL);
|
||||
output_virtual_add(server, output_name,
|
||||
/*store_wlr_output*/ NULL);
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE: {
|
||||
/* TODO: rename this argument to "outputName" */
|
||||
const char *output_name =
|
||||
action_get_str(action, "output_name", NULL);
|
||||
output_virtual_remove(server, output_name);
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_AUTO_PLACE:
|
||||
if (view) {
|
||||
enum view_placement_policy policy =
|
||||
action_get_int(action, "policy", LAB_PLACE_AUTOMATIC);
|
||||
view_place_by_policy(view,
|
||||
/* allow_cursor */ true, policy);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_TEARING:
|
||||
if (view) {
|
||||
switch (view->force_tearing) {
|
||||
case LAB_STATE_UNSPECIFIED:
|
||||
view->force_tearing =
|
||||
output_get_tearing_allowance(view->output)
|
||||
? LAB_STATE_DISABLED : LAB_STATE_ENABLED;
|
||||
break;
|
||||
case LAB_STATE_DISABLED:
|
||||
view->force_tearing = LAB_STATE_ENABLED;
|
||||
break;
|
||||
case LAB_STATE_ENABLED:
|
||||
view->force_tearing = LAB_STATE_DISABLED;
|
||||
break;
|
||||
}
|
||||
wlr_log(WLR_ERROR, "force tearing %sabled",
|
||||
view->force_tearing == LAB_STATE_ENABLED
|
||||
? "en" : "dis");
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_SHADE:
|
||||
if (view) {
|
||||
view_set_shade(view, !view->shaded);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SHADE:
|
||||
if (view) {
|
||||
view_set_shade(view, true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_UNSHADE:
|
||||
if (view) {
|
||||
view_set_shade(view, false);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_ENABLE_SCROLL_WHEEL_EMULATION:
|
||||
server->seat.cursor_scroll_wheel_emulation = true;
|
||||
break;
|
||||
case ACTION_TYPE_DISABLE_SCROLL_WHEEL_EMULATION:
|
||||
server->seat.cursor_scroll_wheel_emulation = false;
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_SCROLL_WHEEL_EMULATION:
|
||||
server->seat.cursor_scroll_wheel_emulation =
|
||||
!server->seat.cursor_scroll_wheel_emulation;
|
||||
break;
|
||||
case ACTION_TYPE_ENABLE_TABLET_MOUSE_EMULATION:
|
||||
rc.tablet.force_mouse_emulation = true;
|
||||
break;
|
||||
case ACTION_TYPE_DISABLE_TABLET_MOUSE_EMULATION:
|
||||
rc.tablet.force_mouse_emulation = false;
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_TABLET_MOUSE_EMULATION:
|
||||
rc.tablet.force_mouse_emulation = !rc.tablet.force_mouse_emulation;
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_MAGNIFY:
|
||||
magnifier_toggle(server);
|
||||
break;
|
||||
case ACTION_TYPE_ZOOM_IN:
|
||||
magnifier_set_scale(server, MAGNIFY_INCREASE);
|
||||
break;
|
||||
case ACTION_TYPE_ZOOM_OUT:
|
||||
magnifier_set_scale(server, MAGNIFY_DECREASE);
|
||||
break;
|
||||
case ACTION_TYPE_WARP_CURSOR: {
|
||||
const char *to = action_get_str(action, "to", "output");
|
||||
const char *x = action_get_str(action, "x", "center");
|
||||
const char *y = action_get_str(action, "y", "center");
|
||||
warp_cursor(server, view, to, x, y);
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_HIDE_CURSOR:
|
||||
cursor_set_visible(&server->seat, false);
|
||||
break;
|
||||
case ACTION_TYPE_INVALID:
|
||||
wlr_log(WLR_ERROR, "Not executing unknown action");
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* If we get here it must be a BUG caused most likely by
|
||||
* action_names and action_type being out of sync or by
|
||||
* adding a new action without installing a handler here.
|
||||
*/
|
||||
wlr_log(WLR_ERROR,
|
||||
"Not executing invalid action (%u)"
|
||||
" This is a BUG. Please report.", action->type);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
actions_run(struct view *activator, struct server *server,
|
||||
struct wl_list *actions, struct cursor_context *cursor_ctx)
|
||||
|
|
@ -898,481 +1380,6 @@ actions_run(struct view *activator, struct server *server,
|
|||
*/
|
||||
struct view *view = view_for_action(activator, server, action, &ctx);
|
||||
|
||||
switch (action->type) {
|
||||
case ACTION_TYPE_CLOSE:
|
||||
if (view) {
|
||||
view_close(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_KILL:
|
||||
if (view) {
|
||||
/* Send SIGTERM to the process associated with the surface */
|
||||
assert(view->impl->get_pid);
|
||||
pid_t pid = view->impl->get_pid(view);
|
||||
if (pid == getpid()) {
|
||||
wlr_log(WLR_ERROR, "Preventing sending SIGTERM to labwc");
|
||||
} else if (pid > 0) {
|
||||
kill(pid, SIGTERM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_DEBUG:
|
||||
debug_dump_scene(server);
|
||||
break;
|
||||
case ACTION_TYPE_EXECUTE: {
|
||||
struct buf cmd = BUF_INIT;
|
||||
buf_add(&cmd, action_get_str(action, "command", NULL));
|
||||
buf_expand_tilde(&cmd);
|
||||
spawn_async_no_shell(cmd.data);
|
||||
buf_reset(&cmd);
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_EXIT:
|
||||
wl_display_terminate(server->wl_display);
|
||||
break;
|
||||
case ACTION_TYPE_MOVE_TO_EDGE:
|
||||
if (view) {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
bool snap_to_windows = action_get_bool(action, "snapWindows", true);
|
||||
view_move_to_edge(view, edge, snap_to_windows);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_SNAP_TO_EDGE:
|
||||
case ACTION_TYPE_SNAP_TO_EDGE:
|
||||
if (view) {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
if (action->type == ACTION_TYPE_TOGGLE_SNAP_TO_EDGE
|
||||
&& view->maximized == VIEW_AXIS_NONE
|
||||
&& !view->fullscreen
|
||||
&& view_is_tiled(view)
|
||||
&& view->tiled == edge) {
|
||||
view_set_untiled(view);
|
||||
view_apply_natural_geometry(view);
|
||||
break;
|
||||
}
|
||||
view_snap_to_edge(view, edge,
|
||||
/*across_outputs*/ true,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_GROW_TO_EDGE:
|
||||
if (view) {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
view_grow_to_edge(view, edge);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SHRINK_TO_EDGE:
|
||||
if (view) {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
view_shrink_to_edge(view, edge);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_NEXT_WINDOW:
|
||||
if (server->input_mode == LAB_INPUT_STATE_WINDOW_SWITCHER) {
|
||||
osd_cycle(server, LAB_CYCLE_DIR_FORWARD);
|
||||
} else {
|
||||
osd_begin(server, LAB_CYCLE_DIR_FORWARD);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_PREVIOUS_WINDOW:
|
||||
if (server->input_mode == LAB_INPUT_STATE_WINDOW_SWITCHER) {
|
||||
osd_cycle(server, LAB_CYCLE_DIR_BACKWARD);
|
||||
} else {
|
||||
osd_begin(server, LAB_CYCLE_DIR_BACKWARD);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RECONFIGURE:
|
||||
kill(getpid(), SIGHUP);
|
||||
break;
|
||||
case ACTION_TYPE_SHOW_MENU:
|
||||
show_menu(server, view, &ctx,
|
||||
action_get_str(action, "menu", NULL),
|
||||
action_get_bool(action, "atCursor", true),
|
||||
action_get_str(action, "x.position", NULL),
|
||||
action_get_str(action, "y.position", NULL));
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_MAXIMIZE:
|
||||
if (view) {
|
||||
enum view_axis axis = action_get_int(action,
|
||||
"direction", VIEW_AXIS_BOTH);
|
||||
view_toggle_maximize(view, axis);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MAXIMIZE:
|
||||
if (view) {
|
||||
enum view_axis axis = action_get_int(action,
|
||||
"direction", VIEW_AXIS_BOTH);
|
||||
view_maximize(view, axis,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_UNMAXIMIZE:
|
||||
if (view) {
|
||||
enum view_axis axis = action_get_int(action,
|
||||
"direction", VIEW_AXIS_BOTH);
|
||||
view_maximize(view, view->maximized & ~axis,
|
||||
/*store_natural_geometry*/ true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_FULLSCREEN:
|
||||
if (view) {
|
||||
view_toggle_fullscreen(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SET_DECORATIONS:
|
||||
if (view) {
|
||||
enum ssd_mode mode = action_get_int(action,
|
||||
"decorations", LAB_SSD_MODE_FULL);
|
||||
bool force_ssd = action_get_bool(action,
|
||||
"forceSSD", false);
|
||||
view_set_decorations(view, mode, force_ssd);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_DECORATIONS:
|
||||
if (view) {
|
||||
view_toggle_decorations(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_ALWAYS_ON_TOP:
|
||||
if (view) {
|
||||
view_toggle_always_on_top(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_ALWAYS_ON_BOTTOM:
|
||||
if (view) {
|
||||
view_toggle_always_on_bottom(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_OMNIPRESENT:
|
||||
if (view) {
|
||||
view_toggle_visible_on_all_workspaces(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_FOCUS:
|
||||
if (view) {
|
||||
desktop_focus_view(view, /*raise*/ false);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_UNFOCUS:
|
||||
seat_focus_surface(&server->seat, NULL);
|
||||
break;
|
||||
case ACTION_TYPE_ICONIFY:
|
||||
if (view) {
|
||||
view_minimize(view, true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVE:
|
||||
if (view) {
|
||||
interactive_begin(view, LAB_INPUT_STATE_MOVE, 0);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RAISE:
|
||||
if (view) {
|
||||
view_move_to_front(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_LOWER:
|
||||
if (view) {
|
||||
view_move_to_back(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RESIZE:
|
||||
if (view) {
|
||||
uint32_t resize_edges = cursor_get_resize_edges(
|
||||
server->seat.cursor, &ctx);
|
||||
interactive_begin(view, LAB_INPUT_STATE_RESIZE,
|
||||
resize_edges);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RESIZE_RELATIVE:
|
||||
if (view) {
|
||||
int left = action_get_int(action, "left", 0);
|
||||
int right = action_get_int(action, "right", 0);
|
||||
int top = action_get_int(action, "top", 0);
|
||||
int bottom = action_get_int(action, "bottom", 0);
|
||||
view_resize_relative(view, left, right, top, bottom);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVETO:
|
||||
if (view) {
|
||||
int x = action_get_int(action, "x", 0);
|
||||
int y = action_get_int(action, "y", 0);
|
||||
struct border margin = ssd_thickness(view);
|
||||
view_move(view, x + margin.left, y + margin.top);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_RESIZETO:
|
||||
if (view) {
|
||||
int width = action_get_int(action, "width", 0);
|
||||
int height = action_get_int(action, "height", 0);
|
||||
|
||||
/*
|
||||
* To support only setting one of width/height
|
||||
* in <action name="ResizeTo" width="" height=""/>
|
||||
* we fall back to current dimension when unset.
|
||||
*/
|
||||
struct wlr_box box = {
|
||||
.x = view->pending.x,
|
||||
.y = view->pending.y,
|
||||
.width = width ? : view->pending.width,
|
||||
.height = height ? : view->pending.height,
|
||||
};
|
||||
view_set_shade(view, false);
|
||||
view_move_resize(view, box);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVE_RELATIVE:
|
||||
if (view) {
|
||||
int x = action_get_int(action, "x", 0);
|
||||
int y = action_get_int(action, "y", 0);
|
||||
view_move_relative(view, x, y);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_MOVETO_CURSOR:
|
||||
wlr_log(WLR_ERROR,
|
||||
"Action MoveToCursor is deprecated. To ensure your config works in future labwc "
|
||||
"releases, please use <action name=\"AutoPlace\" policy=\"cursor\">");
|
||||
if (view) {
|
||||
view_move_to_cursor(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SEND_TO_DESKTOP:
|
||||
if (!view) {
|
||||
break;
|
||||
}
|
||||
/* Falls through to GoToDesktop */
|
||||
case ACTION_TYPE_GO_TO_DESKTOP: {
|
||||
bool follow = true;
|
||||
bool wrap = action_get_bool(action, "wrap", true);
|
||||
const char *to = action_get_str(action, "to", NULL);
|
||||
/*
|
||||
* `to` is always != NULL here because otherwise we would have
|
||||
* removed the action during the initial parsing step as it is
|
||||
* a required argument for both SendToDesktop and GoToDesktop.
|
||||
*/
|
||||
struct workspace *target_workspace = workspaces_find(
|
||||
server->workspaces.current, to, wrap);
|
||||
if (!target_workspace) {
|
||||
break;
|
||||
}
|
||||
if (action->type == ACTION_TYPE_SEND_TO_DESKTOP) {
|
||||
view_move_to_workspace(view, target_workspace);
|
||||
follow = action_get_bool(action, "follow", true);
|
||||
|
||||
/* Ensure that the focus is not on another desktop */
|
||||
if (!follow && server->active_view == view) {
|
||||
desktop_focus_topmost_view(server);
|
||||
}
|
||||
}
|
||||
if (follow) {
|
||||
workspaces_switch_to(target_workspace,
|
||||
/*update_focus*/ true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_MOVE_TO_OUTPUT: {
|
||||
if (!view) {
|
||||
break;
|
||||
}
|
||||
struct output *target_output =
|
||||
get_target_output(view->output, server, action);
|
||||
if (target_output) {
|
||||
view_move_to_output(view, target_output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_FIT_TO_OUTPUT:
|
||||
if (!view) {
|
||||
break;
|
||||
}
|
||||
view_constrain_size_to_that_of_usable_area(view);
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_SNAP_TO_REGION:
|
||||
case ACTION_TYPE_SNAP_TO_REGION: {
|
||||
if (!view) {
|
||||
break;
|
||||
}
|
||||
struct output *output = view->output;
|
||||
if (!output) {
|
||||
break;
|
||||
}
|
||||
const char *region_name = action_get_str(action, "region", NULL);
|
||||
struct region *region = regions_from_name(region_name, output);
|
||||
if (region) {
|
||||
if (action->type == ACTION_TYPE_TOGGLE_SNAP_TO_REGION
|
||||
&& view->maximized == VIEW_AXIS_NONE
|
||||
&& !view->fullscreen
|
||||
&& view_is_tiled(view)
|
||||
&& view->tiled_region == region) {
|
||||
view_set_untiled(view);
|
||||
view_apply_natural_geometry(view);
|
||||
break;
|
||||
}
|
||||
view_snap_to_region(view, region,
|
||||
/*store_natural_geometry*/ true);
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Invalid SnapToRegion id: '%s'", region_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_UNSNAP:
|
||||
if (view && !view->fullscreen && !view_is_floating(view)) {
|
||||
view_maximize(view, VIEW_AXIS_NONE,
|
||||
/* store_natural_geometry */ false);
|
||||
view_set_untiled(view);
|
||||
view_apply_natural_geometry(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_KEYBINDS:
|
||||
if (view) {
|
||||
view_toggle_keybinds(view);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_FOCUS_OUTPUT: {
|
||||
struct output *output = output_nearest_to_cursor(server);
|
||||
struct output *target_output =
|
||||
get_target_output(output, server, action);
|
||||
if (target_output) {
|
||||
desktop_focus_output(target_output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_IF:
|
||||
if (view) {
|
||||
run_if_action(view, server, action);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_FOR_EACH: {
|
||||
struct wl_array views;
|
||||
struct view **item;
|
||||
bool matches = false;
|
||||
wl_array_init(&views);
|
||||
view_array_append(server, &views, LAB_VIEW_CRITERIA_NONE);
|
||||
wl_array_for_each(item, &views) {
|
||||
matches |= run_if_action(*item, server, action);
|
||||
}
|
||||
wl_array_release(&views);
|
||||
if (!matches) {
|
||||
struct wl_list *child_actions;
|
||||
child_actions = action_get_actionlist(action, "none");
|
||||
if (child_actions) {
|
||||
actions_run(view, server, child_actions, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_VIRTUAL_OUTPUT_ADD: {
|
||||
/* TODO: rename this argument to "outputName" */
|
||||
const char *output_name =
|
||||
action_get_str(action, "output_name", NULL);
|
||||
output_virtual_add(server, output_name,
|
||||
/*store_wlr_output*/ NULL);
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE: {
|
||||
/* TODO: rename this argument to "outputName" */
|
||||
const char *output_name =
|
||||
action_get_str(action, "output_name", NULL);
|
||||
output_virtual_remove(server, output_name);
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_AUTO_PLACE:
|
||||
if (view) {
|
||||
enum view_placement_policy policy =
|
||||
action_get_int(action, "policy", LAB_PLACE_AUTOMATIC);
|
||||
view_place_by_policy(view,
|
||||
/* allow_cursor */ true, policy);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_TEARING:
|
||||
if (view) {
|
||||
switch (view->force_tearing) {
|
||||
case LAB_STATE_UNSPECIFIED:
|
||||
view->force_tearing =
|
||||
output_get_tearing_allowance(view->output)
|
||||
? LAB_STATE_DISABLED : LAB_STATE_ENABLED;
|
||||
break;
|
||||
case LAB_STATE_DISABLED:
|
||||
view->force_tearing = LAB_STATE_ENABLED;
|
||||
break;
|
||||
case LAB_STATE_ENABLED:
|
||||
view->force_tearing = LAB_STATE_DISABLED;
|
||||
break;
|
||||
}
|
||||
wlr_log(WLR_ERROR, "force tearing %sabled",
|
||||
view->force_tearing == LAB_STATE_ENABLED
|
||||
? "en" : "dis");
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_SHADE:
|
||||
if (view) {
|
||||
view_set_shade(view, !view->shaded);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_SHADE:
|
||||
if (view) {
|
||||
view_set_shade(view, true);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_UNSHADE:
|
||||
if (view) {
|
||||
view_set_shade(view, false);
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_ENABLE_SCROLL_WHEEL_EMULATION:
|
||||
server->seat.cursor_scroll_wheel_emulation = true;
|
||||
break;
|
||||
case ACTION_TYPE_DISABLE_SCROLL_WHEEL_EMULATION:
|
||||
server->seat.cursor_scroll_wheel_emulation = false;
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_SCROLL_WHEEL_EMULATION:
|
||||
server->seat.cursor_scroll_wheel_emulation =
|
||||
!server->seat.cursor_scroll_wheel_emulation;
|
||||
break;
|
||||
case ACTION_TYPE_ENABLE_TABLET_MOUSE_EMULATION:
|
||||
rc.tablet.force_mouse_emulation = true;
|
||||
break;
|
||||
case ACTION_TYPE_DISABLE_TABLET_MOUSE_EMULATION:
|
||||
rc.tablet.force_mouse_emulation = false;
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_TABLET_MOUSE_EMULATION:
|
||||
rc.tablet.force_mouse_emulation = !rc.tablet.force_mouse_emulation;
|
||||
break;
|
||||
case ACTION_TYPE_TOGGLE_MAGNIFY:
|
||||
magnifier_toggle(server);
|
||||
break;
|
||||
case ACTION_TYPE_ZOOM_IN:
|
||||
magnifier_set_scale(server, MAGNIFY_INCREASE);
|
||||
break;
|
||||
case ACTION_TYPE_ZOOM_OUT:
|
||||
magnifier_set_scale(server, MAGNIFY_DECREASE);
|
||||
break;
|
||||
case ACTION_TYPE_WARP_CURSOR: {
|
||||
const char *to = action_get_str(action, "to", "output");
|
||||
const char *x = action_get_str(action, "x", "center");
|
||||
const char *y = action_get_str(action, "y", "center");
|
||||
warp_cursor(server, view, to, x, y);
|
||||
break;
|
||||
}
|
||||
case ACTION_TYPE_HIDE_CURSOR:
|
||||
cursor_set_visible(&server->seat, false);
|
||||
break;
|
||||
case ACTION_TYPE_INVALID:
|
||||
wlr_log(WLR_ERROR, "Not executing unknown action");
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* If we get here it must be a BUG caused most likely by
|
||||
* action_names and action_type being out of sync or by
|
||||
* adding a new action without installing a handler here.
|
||||
*/
|
||||
wlr_log(WLR_ERROR,
|
||||
"Not executing invalid action (%u)"
|
||||
" This is a BUG. Please report.", action->type);
|
||||
}
|
||||
run_action(view, server, action, &ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue