diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index b5fc6ef4..99b86983 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -54,6 +54,10 @@ Actions are used in menus and keyboard/mouse bindings. ** Move to position (x, y) +** + Move to be centered on cursor. + Tries to prevent any part of the window from going off-screen. + ** Move window relative to its current position. Positive value of x moves it right, negative left. Positive value of y moves it down, negative up. diff --git a/include/view.h b/include/view.h index 9379d1e6..0fb10a22 100644 --- a/include/view.h +++ b/include/view.h @@ -306,6 +306,7 @@ void view_resize_relative(struct view *view, int left, int right, int top, int bottom); void view_move_relative(struct view *view, int x, int y); void view_move(struct view *view, int x, int y); +void view_move_to_cursor(struct view *view); void view_moved(struct view *view); void view_minimize(struct view *view, bool minimized); void view_store_natural_geometry(struct view *view); diff --git a/src/action.c b/src/action.c index 43c3ddec..fe0a6438 100644 --- a/src/action.c +++ b/src/action.c @@ -84,6 +84,7 @@ enum action_type { ACTION_TYPE_RESIZE, ACTION_TYPE_RESIZE_RELATIVE, ACTION_TYPE_MOVETO, + ACTION_TYPE_MOVETO_CURSOR, ACTION_TYPE_MOVE_RELATIVE, ACTION_TYPE_SEND_TO_DESKTOP, ACTION_TYPE_GO_TO_DESKTOP, @@ -122,6 +123,7 @@ const char *action_names[] = { "Resize", "ResizeRelative", "MoveTo", + "MoveToCursor", "MoveRelative", "SendToDesktop", "GoToDesktop", @@ -746,6 +748,11 @@ actions_run(struct view *activator, struct server *server, view_move_relative(view, x, y); } break; + case ACTION_TYPE_MOVETO_CURSOR: + if (view) { + view_move_to_cursor(view); + } + break; case ACTION_TYPE_SEND_TO_DESKTOP: if (!view) { break; diff --git a/src/view.c b/src/view.c index 94f2d82a..7a390d11 100644 --- a/src/view.c +++ b/src/view.c @@ -351,6 +351,50 @@ view_move_relative(struct view *view, int x, int y) view_move(view, view->pending.x + x, view->pending.y + y); } +void +view_move_to_cursor(struct view *view) +{ + assert(view); + + struct output *pending_output = output_nearest_to_cursor(view->server); + if (!output_is_usable(pending_output)) { + return; + } + if (view->fullscreen) { + view_set_fullscreen(view, false); + } + if (view->maximized) { + view_maximize(view, false, /*store_natural_geometry*/ false); + } + if (view_is_tiled(view)) { + view_set_untiled(view); + view_restore_to(view, view->natural_geometry); + } + + struct border margin = ssd_thickness(view); + struct wlr_box geo = view->pending; + geo.width += margin.left + margin.right; + geo.height += margin.top + margin.bottom; + + int x = view->server->seat.cursor->x - (geo.width / 2); + int y = view->server->seat.cursor->y - (geo.height / 2); + + struct wlr_box usable = output_usable_area_in_layout_coords(pending_output); + if (x + geo.width > usable.x + usable.width) { + x = usable.x + usable.width - geo.width; + } + x = MAX(x, usable.x); + + if (y + geo.height > usable.y + usable.height) { + y = usable.y + usable.height - geo.height; + } + y = MAX(y, usable.y); + + x += margin.left; + y += margin.top; + view_move(view, x, y); +} + struct view_size_hints view_get_size_hints(struct view *view) {