diff --git a/include/labwc.h b/include/labwc.h index 0af693ea..09413391 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -435,6 +435,8 @@ void view_adjust_for_layout_change(struct view *view); void view_discover_output(struct view *view); void view_move_to_edge(struct view *view, const char *direction); void view_snap_to_edge(struct view *view, const char *direction); +void view_rel_move_resize_to(struct view *view, struct wlr_box *rel_box); + const char *view_get_string_prop(struct view *view, const char *prop); void view_update_title(struct view *view); void view_update_app_id(struct view *view); diff --git a/src/action.c b/src/action.c index 15970df1..63c91c10 100644 --- a/src/action.c +++ b/src/action.c @@ -2,6 +2,7 @@ #define _POSIX_C_SOURCE 200809L #include #include +#include #include #include #include @@ -38,6 +39,7 @@ enum action_type { ACTION_TYPE_RESIZE, ACTION_TYPE_GO_TO_DESKTOP, ACTION_TYPE_SEND_TO_DESKTOP, + ACTION_TYPE_MOVE_RESIZE_TO, }; const char *action_names[] = { @@ -63,6 +65,7 @@ const char *action_names[] = { "Resize", "GoToDesktop", "SendToDesktop", + "MoveResizeTo", NULL }; @@ -336,6 +339,16 @@ actions_run(struct view *activator, struct server *server, } } break; + case ACTION_TYPE_MOVE_RESIZE_TO: + if (!arg) { + wlr_log(WLR_ERROR, "Missing argument for MoveResizeTo"); + break; + } + if (view) { + struct wlr_box *box = action_box_from_arg(arg); + view_rel_move_resize_to(view, box); + } + break; case ACTION_TYPE_NONE: wlr_log(WLR_ERROR, "Not executing unknown action"); break; diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 1d950f7a..14168bcd 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -32,6 +32,7 @@ static struct libinput_category *current_libinput_category; static const char *current_mouse_context; static struct action *current_keybind_action; static struct action *current_mousebind_action; +static struct wlr_box *current_action_box; enum font_place { FONT_PLACE_UNKNOWN = 0, @@ -43,6 +44,21 @@ enum font_place { static void load_default_key_bindings(void); +static void +fill_geo(char *key, char *content) +{ + assert(current_action_box); + if (!strcmp(key, "x.action")) { + current_action_box->x = atoi(content); + } else if (!strcmp(key, "y.action")) { + current_action_box->y = atoi(content); + } else if (!strcmp(key, "width.action")) { + current_action_box->width = atoi(content); + } else if (!strcmp(key, "height.action")) { + current_action_box->height = atoi(content); + } +} + static void fill_keybind(char *nodename, char *content) { @@ -68,6 +84,12 @@ fill_keybind(char *nodename, char *content) current_keybind_action = action_create(content); wl_list_insert(current_keybind->actions.prev, ¤t_keybind_action->link); + if (!strcmp(content, "MoveResizeTo")) { + current_action_box = action_arg_add_box( + current_keybind_action, NULL); + } else { + current_action_box = NULL; + } } else if (!current_keybind_action) { wlr_log(WLR_ERROR, "expect element first. " "nodename: '%s' content: '%s'", nodename, content); @@ -83,6 +105,9 @@ fill_keybind(char *nodename, char *content) } else if (!strcmp(nodename, "to.action")) { /* GoToDesktop, SendToDesktop */ action_arg_add_str(current_keybind_action, NULL, content); + } else if (current_action_box) { + /* MoveResizeTo */ + fill_geo(nodename, content); } } diff --git a/src/view.c b/src/view.c index 6288d671..6f0c9c7b 100644 --- a/src/view.c +++ b/src/view.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include #include #include @@ -658,6 +659,41 @@ view_edge_parse(const char *direction) } } +/* Move and resize view based on percent output local values in rel_box */ +void +view_rel_move_resize_to(struct view *view, struct wlr_box *rel_box) +{ + assert(view); + assert(rel_box); + + struct output *output = view_output(view); + if (!output) { + return; + } + struct wlr_box usable = output_usable_area_in_layout_coords(output); + + /* Calculate new size and position */ + struct wlr_box new_geo = { view->x, view->y, view->w, view->h }; + if (rel_box->x != INT_MIN) { + new_geo.x = usable.width * rel_box->x / 100; + new_geo.x += usable.x + view->margin.left; + } + if (rel_box->y != INT_MIN) { + new_geo.y = usable.height * rel_box->y / 100; + new_geo.y += usable.y + view->margin.top; + } + if (rel_box->width != INT_MIN) { + new_geo.width = usable.width * rel_box->width / 100; + new_geo.width -= view->margin.left + view->margin.right; + } + if (rel_box->height != INT_MIN) { + new_geo.height = usable.height * rel_box->height / 100; + new_geo.height -= view->margin.top + view->margin.bottom; + } + + view_move_resize(view, new_geo); +} + void view_snap_to_edge(struct view *view, const char *direction) {