outlined rectangle is shown to indicate the geometry of resized window.
Default is yes.
+*<resize><cornerRange>*
+ The size of corner regions to which the 'TLCorner', 'TRCorner',
+ 'BLCorner' and 'RLCorner' mousebind contexts apply, as well as the size
+ of the border region for which mouse resizing will apply both
+ horizontally and vertically rather than one or the other. Default is
+ half the titlebar height.
+
## KEYBOARD
*<keyboard><numlock>* [on|off]
<popupShow>Never</popupShow>
<!-- Let client redraw its contents while resizing -->
<drawContents>yes</drawContents>
+ <cornerRange>8</cornerRange>
</resize>
<focus>
enum resize_indicator_mode resize_indicator;
bool resize_draw_contents;
+ int resize_corner_range;
struct {
int popuptime;
#include <wayland-server-core.h>
#include "common/border.h"
+struct wlr_cursor;
+
#define SSD_EXTENDED_AREA 8
/*
struct view *ssd_button_get_view(const struct ssd_button *button);
/* Public SSD helpers */
-enum ssd_part_type ssd_at(const struct ssd *ssd,
- struct wlr_scene *scene, double lx, double ly);
enum ssd_part_type ssd_get_part_type(const struct ssd *ssd,
- struct wlr_scene_node *node);
+ struct wlr_scene_node *node, struct wlr_cursor *cursor);
uint32_t ssd_resize_edges(enum ssd_part_type type);
bool ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate);
enum ssd_mode ssd_mode_parse(const char *mode);
}
} else if (!strcasecmp(nodename, "drawContents.resize")) {
set_bool(content, &rc.resize_draw_contents);
+ } else if (!strcasecmp(nodename, "cornerRange.resize")) {
+ rc.resize_corner_range = atoi(content);
} else if (!strcasecmp(nodename, "mouseEmulation.tablet")) {
set_bool(content, &rc.tablet.force_mouse_emulation);
} else if (!strcasecmp(nodename, "mapToOutput.tablet")) {
rc.resize_indicator = LAB_RESIZE_INDICATOR_NEVER;
rc.resize_draw_contents = true;
+ rc.resize_corner_range = -1;
rc.workspace_config.popuptime = INT_MIN;
rc.workspace_config.min_nr_workspaces = 1;
case LAB_NODE_DESC_VIEW:
case LAB_NODE_DESC_XDG_POPUP:
ret.view = desc->data;
- ret.type = ssd_get_part_type(ret.view->ssd, ret.node);
+ ret.type = ssd_get_part_type(
+ ret.view->ssd, ret.node, cursor);
if (ret.type == LAB_SSD_CLIENT) {
ret.surface = lab_wlr_surface_from_node(ret.node);
}
-(theme->border_width + extended_area),
-(ssd->titlebar.height + theme->border_width + extended_area));
- /* Top */
- add_extent(part_list, LAB_SSD_PART_CORNER_TOP_LEFT, parent);
add_extent(part_list, LAB_SSD_PART_TOP, parent);
- add_extent(part_list, LAB_SSD_PART_CORNER_TOP_RIGHT, parent);
- /* Sides */
add_extent(part_list, LAB_SSD_PART_LEFT, parent);
add_extent(part_list, LAB_SSD_PART_RIGHT, parent);
- /* Bottom */
- add_extent(part_list, LAB_SSD_PART_CORNER_BOTTOM_LEFT, parent);
add_extent(part_list, LAB_SSD_PART_BOTTOM, parent);
- add_extent(part_list, LAB_SSD_PART_CORNER_BOTTOM_RIGHT, parent);
/* Initial manual update to keep X11 applications happy */
ssd_extents_update(ssd);
int full_height = height + theme->border_width * 2 + ssd->titlebar.height;
int full_width = width + 2 * theme->border_width;
int extended_area = SSD_EXTENDED_AREA;
- int corner_width = ssd_get_corner_width();
- int corner_size = extended_area + theme->border_width +
- MIN(corner_width, width) / 2;
- int side_width = full_width + extended_area * 2 - corner_size * 2;
- int side_height = full_height + extended_area * 2 - corner_size * 2;
struct wlr_box part_box;
struct wlr_box result_box;
wl_list_for_each(part, &ssd->extents.parts, link) {
rect = wlr_scene_rect_from_node(part->node);
switch (part->type) {
- case LAB_SSD_PART_CORNER_TOP_LEFT:
- target.x = 0;
- target.y = 0;
- target.width = corner_size;
- target.height = corner_size;
- break;
case LAB_SSD_PART_TOP:
- target.x = corner_size;
+ target.x = 0;
target.y = 0;
- target.width = side_width;
+ target.width = full_width + extended_area * 2;
target.height = extended_area;
break;
- case LAB_SSD_PART_CORNER_TOP_RIGHT:
- target.x = corner_size + side_width;
- target.y = 0;
- target.width = corner_size;
- target.height = corner_size;
- break;
case LAB_SSD_PART_LEFT:
target.x = 0;
- target.y = corner_size;
+ target.y = extended_area;
target.width = extended_area;
- target.height = side_height;
+ target.height = full_height;
break;
case LAB_SSD_PART_RIGHT:
target.x = extended_area + full_width;
- target.y = corner_size;
+ target.y = extended_area;
target.width = extended_area;
- target.height = side_height;
- break;
- case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
- target.x = 0;
- target.y = corner_size + side_height;
- target.width = corner_size;
- target.height = corner_size;
+ target.height = full_height;
break;
case LAB_SSD_PART_BOTTOM:
- target.x = corner_size;
+ target.x = 0;
target.y = extended_area + full_height;
- target.width = side_width;
+ target.width = full_width + extended_area * 2;
target.height = extended_area;
break;
- case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
- target.x = corner_size + side_width;
- target.y = corner_size + side_height;
- target.width = corner_size;
- target.height = corner_size;
- break;
default:
/* not reached */
assert(false);
};
}
+/*
+ * Resizing and mouse contexts like 'Left', 'TLCorner', etc. in the vicinity of
+ * SSD borders, titlebars and extents can have effective "corner regions" that
+ * behave differently from single-edge contexts.
+ *
+ * Corner regions are active whenever the cursor is within a prescribed size
+ * (generally rc.resize_corner_range, but clipped to view size) of the view
+ * bounds, so check the cursor against the view here.
+ */
+static enum ssd_part_type
+get_resizing_type(const struct ssd *ssd, struct wlr_cursor *cursor)
+{
+ struct view *view = ssd ? ssd->view : NULL;
+ if (!view || !cursor || !view->ssd_enabled || view->fullscreen) {
+ return LAB_SSD_NONE;
+ }
+
+ struct wlr_box view_box = view->current;
+ view_box.height = view_effective_height(view, /* use_pending */ false);
+
+ if (!view->ssd_titlebar_hidden) {
+ /* If the titlebar is visible, consider it part of the view */
+ int titlebar_height = view->server->theme->titlebar_height;
+ view_box.y -= titlebar_height;
+ view_box.height += titlebar_height;
+ }
+
+ if (wlr_box_contains_point(&view_box, cursor->x, cursor->y)) {
+ /* A cursor in bounds of the view is never in an SSD context */
+ return LAB_SSD_NONE;
+ }
+
+ int corner_height = MAX(0, MIN(rc.resize_corner_range, view_box.height / 2));
+ int corner_width = MAX(0, MIN(rc.resize_corner_range, view_box.width / 2));
+ bool left = cursor->x < view_box.x + corner_width;
+ bool right = cursor->x > view_box.x + view_box.width - corner_width;
+ bool top = cursor->y < view_box.y + corner_height;
+ bool bottom = cursor->y > view_box.y + view_box.height - corner_height;
+
+ if (top && left) {
+ return LAB_SSD_PART_CORNER_TOP_LEFT;
+ } else if (top && right) {
+ return LAB_SSD_PART_CORNER_TOP_RIGHT;
+ } else if (bottom && left) {
+ return LAB_SSD_PART_CORNER_BOTTOM_LEFT;
+ } else if (bottom && right) {
+ return LAB_SSD_PART_CORNER_BOTTOM_RIGHT;
+ } else if (top) {
+ return LAB_SSD_PART_TOP;
+ } else if (bottom) {
+ return LAB_SSD_PART_BOTTOM;
+ } else if (left) {
+ return LAB_SSD_PART_LEFT;
+ } else if (right) {
+ return LAB_SSD_PART_RIGHT;
+ }
+
+ return LAB_SSD_NONE;
+}
+
enum ssd_part_type
-ssd_get_part_type(const struct ssd *ssd, struct wlr_scene_node *node)
+ssd_get_part_type(const struct ssd *ssd, struct wlr_scene_node *node,
+ struct wlr_cursor *cursor)
{
if (!node) {
return LAB_SSD_NONE;
part_list = &ssd->border.inactive.parts;
}
+ enum ssd_part_type part_type = LAB_SSD_NONE;
+
if (part_list) {
struct ssd_part *part;
wl_list_for_each(part, part_list, link) {
if (node == part->node) {
- return part->type;
+ part_type = part->type;
+ break;
}
}
}
- return LAB_SSD_NONE;
-}
-enum ssd_part_type
-ssd_at(const struct ssd *ssd, struct wlr_scene *scene, double lx, double ly)
-{
- assert(scene);
- double sx, sy;
- struct wlr_scene_node *node = wlr_scene_node_at(
- &scene->tree.node, lx, ly, &sx, &sy);
- return ssd_get_part_type(ssd, node);
+ if (part_type == LAB_SSD_NONE) {
+ return part_type;
+ }
+
+ /* Perform cursor-based context checks */
+ enum ssd_part_type resizing_type = get_resizing_type(ssd, cursor);
+ return resizing_type != LAB_SSD_NONE ? resizing_type : part_type;
}
uint32_t
rc.corner_radius = theme->titlebar_height - 1;
}
+ if (rc.resize_corner_range < 0) {
+ rc.resize_corner_range = theme->titlebar_height / 2;
+ }
+
int min_button_hover_radius =
MIN(theme->window_button_width, theme->window_button_height) / 2;
if (theme->window_button_hover_bg_corner_radius > min_button_hover_radius) {