mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
ssd: fix resizing on border corners and add <resize><cornerRange>
Eliminate corner extents and instead use cursor position to map SSD borders and extents to corner contexts, with a size configurable by the <resize><cornerRange> parameter. This simplifies extent handling, eliminates bugs in the detection of corner context, and allows users to expand corner targets if they wish. Co-authored-by: Andrew J. Hesford <ajh@sideband.org>
This commit is contained in:
parent
9ad6e3c68c
commit
950337b895
9 changed files with 102 additions and 60 deletions
|
|
@ -576,6 +576,13 @@ extending outward from the snapped edge.
|
||||||
outlined rectangle is shown to indicate the geometry of resized window.
|
outlined rectangle is shown to indicate the geometry of resized window.
|
||||||
Default is yes.
|
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
|
||||||
|
|
||||||
*<keyboard><numlock>* [on|off]
|
*<keyboard><numlock>* [on|off]
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@
|
||||||
<popupShow>Never</popupShow>
|
<popupShow>Never</popupShow>
|
||||||
<!-- Let client redraw its contents while resizing -->
|
<!-- Let client redraw its contents while resizing -->
|
||||||
<drawContents>yes</drawContents>
|
<drawContents>yes</drawContents>
|
||||||
|
<cornerRange>8</cornerRange>
|
||||||
</resize>
|
</resize>
|
||||||
|
|
||||||
<focus>
|
<focus>
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,7 @@ struct rcxml {
|
||||||
|
|
||||||
enum resize_indicator_mode resize_indicator;
|
enum resize_indicator_mode resize_indicator;
|
||||||
bool resize_draw_contents;
|
bool resize_draw_contents;
|
||||||
|
int resize_corner_range;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int popuptime;
|
int popuptime;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include "common/border.h"
|
#include "common/border.h"
|
||||||
|
|
||||||
|
struct wlr_cursor;
|
||||||
|
|
||||||
#define SSD_EXTENDED_AREA 8
|
#define SSD_EXTENDED_AREA 8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -107,10 +109,8 @@ enum ssd_part_type ssd_button_get_type(const struct ssd_button *button);
|
||||||
struct view *ssd_button_get_view(const struct ssd_button *button);
|
struct view *ssd_button_get_view(const struct ssd_button *button);
|
||||||
|
|
||||||
/* Public SSD helpers */
|
/* 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,
|
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);
|
uint32_t ssd_resize_edges(enum ssd_part_type type);
|
||||||
bool ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate);
|
bool ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate);
|
||||||
enum ssd_mode ssd_mode_parse(const char *mode);
|
enum ssd_mode ssd_mode_parse(const char *mode);
|
||||||
|
|
|
||||||
|
|
@ -1223,6 +1223,8 @@ entry(xmlNode *node, char *nodename, char *content, struct parser_state *state)
|
||||||
}
|
}
|
||||||
} else if (!strcasecmp(nodename, "drawContents.resize")) {
|
} else if (!strcasecmp(nodename, "drawContents.resize")) {
|
||||||
set_bool(content, &rc.resize_draw_contents);
|
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")) {
|
} else if (!strcasecmp(nodename, "mouseEmulation.tablet")) {
|
||||||
set_bool(content, &rc.tablet.force_mouse_emulation);
|
set_bool(content, &rc.tablet.force_mouse_emulation);
|
||||||
} else if (!strcasecmp(nodename, "mapToOutput.tablet")) {
|
} else if (!strcasecmp(nodename, "mapToOutput.tablet")) {
|
||||||
|
|
@ -1498,6 +1500,7 @@ rcxml_init(void)
|
||||||
|
|
||||||
rc.resize_indicator = LAB_RESIZE_INDICATOR_NEVER;
|
rc.resize_indicator = LAB_RESIZE_INDICATOR_NEVER;
|
||||||
rc.resize_draw_contents = true;
|
rc.resize_draw_contents = true;
|
||||||
|
rc.resize_corner_range = -1;
|
||||||
|
|
||||||
rc.workspace_config.popuptime = INT_MIN;
|
rc.workspace_config.popuptime = INT_MIN;
|
||||||
rc.workspace_config.min_nr_workspaces = 1;
|
rc.workspace_config.min_nr_workspaces = 1;
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,8 @@ get_cursor_context(struct server *server)
|
||||||
case LAB_NODE_DESC_VIEW:
|
case LAB_NODE_DESC_VIEW:
|
||||||
case LAB_NODE_DESC_XDG_POPUP:
|
case LAB_NODE_DESC_XDG_POPUP:
|
||||||
ret.view = desc->data;
|
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) {
|
if (ret.type == LAB_SSD_CLIENT) {
|
||||||
ret.surface = lab_wlr_surface_from_node(ret.node);
|
ret.surface = lab_wlr_surface_from_node(ret.node);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,17 +37,10 @@ ssd_extents_create(struct ssd *ssd)
|
||||||
-(theme->border_width + extended_area),
|
-(theme->border_width + extended_area),
|
||||||
-(ssd->titlebar.height + 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_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_LEFT, parent);
|
||||||
add_extent(part_list, LAB_SSD_PART_RIGHT, 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_BOTTOM, parent);
|
||||||
add_extent(part_list, LAB_SSD_PART_CORNER_BOTTOM_RIGHT, parent);
|
|
||||||
|
|
||||||
/* Initial manual update to keep X11 applications happy */
|
/* Initial manual update to keep X11 applications happy */
|
||||||
ssd_extents_update(ssd);
|
ssd_extents_update(ssd);
|
||||||
|
|
@ -76,11 +69,6 @@ ssd_extents_update(struct ssd *ssd)
|
||||||
int full_height = height + theme->border_width * 2 + ssd->titlebar.height;
|
int full_height = height + theme->border_width * 2 + ssd->titlebar.height;
|
||||||
int full_width = width + 2 * theme->border_width;
|
int full_width = width + 2 * theme->border_width;
|
||||||
int extended_area = SSD_EXTENDED_AREA;
|
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 part_box;
|
||||||
struct wlr_box result_box;
|
struct wlr_box result_box;
|
||||||
|
|
@ -120,54 +108,30 @@ ssd_extents_update(struct ssd *ssd)
|
||||||
wl_list_for_each(part, &ssd->extents.parts, link) {
|
wl_list_for_each(part, &ssd->extents.parts, link) {
|
||||||
rect = wlr_scene_rect_from_node(part->node);
|
rect = wlr_scene_rect_from_node(part->node);
|
||||||
switch (part->type) {
|
switch (part->type) {
|
||||||
case LAB_SSD_PART_CORNER_TOP_LEFT:
|
case LAB_SSD_PART_TOP:
|
||||||
target.x = 0;
|
target.x = 0;
|
||||||
target.y = 0;
|
target.y = 0;
|
||||||
target.width = corner_size;
|
target.width = full_width + extended_area * 2;
|
||||||
target.height = corner_size;
|
|
||||||
break;
|
|
||||||
case LAB_SSD_PART_TOP:
|
|
||||||
target.x = corner_size;
|
|
||||||
target.y = 0;
|
|
||||||
target.width = side_width;
|
|
||||||
target.height = extended_area;
|
target.height = extended_area;
|
||||||
break;
|
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:
|
case LAB_SSD_PART_LEFT:
|
||||||
target.x = 0;
|
target.x = 0;
|
||||||
target.y = corner_size;
|
target.y = extended_area;
|
||||||
target.width = extended_area;
|
target.width = extended_area;
|
||||||
target.height = side_height;
|
target.height = full_height;
|
||||||
break;
|
break;
|
||||||
case LAB_SSD_PART_RIGHT:
|
case LAB_SSD_PART_RIGHT:
|
||||||
target.x = extended_area + full_width;
|
target.x = extended_area + full_width;
|
||||||
target.y = corner_size;
|
target.y = extended_area;
|
||||||
target.width = extended_area;
|
target.width = extended_area;
|
||||||
target.height = side_height;
|
target.height = full_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;
|
|
||||||
break;
|
break;
|
||||||
case LAB_SSD_PART_BOTTOM:
|
case LAB_SSD_PART_BOTTOM:
|
||||||
target.x = corner_size;
|
target.x = 0;
|
||||||
target.y = extended_area + full_height;
|
target.y = extended_area + full_height;
|
||||||
target.width = side_width;
|
target.width = full_width + extended_area * 2;
|
||||||
target.height = extended_area;
|
target.height = extended_area;
|
||||||
break;
|
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:
|
default:
|
||||||
/* not reached */
|
/* not reached */
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,69 @@ ssd_max_extents(struct view *view)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
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) {
|
if (!node) {
|
||||||
return LAB_SSD_NONE;
|
return LAB_SSD_NONE;
|
||||||
|
|
@ -121,25 +182,25 @@ ssd_get_part_type(const struct ssd *ssd, struct wlr_scene_node *node)
|
||||||
part_list = &ssd->border.inactive.parts;
|
part_list = &ssd->border.inactive.parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ssd_part_type part_type = LAB_SSD_NONE;
|
||||||
|
|
||||||
if (part_list) {
|
if (part_list) {
|
||||||
struct ssd_part *part;
|
struct ssd_part *part;
|
||||||
wl_list_for_each(part, part_list, link) {
|
wl_list_for_each(part, part_list, link) {
|
||||||
if (node == part->node) {
|
if (node == part->node) {
|
||||||
return part->type;
|
part_type = part->type;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return LAB_SSD_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ssd_part_type
|
if (part_type == LAB_SSD_NONE) {
|
||||||
ssd_at(const struct ssd *ssd, struct wlr_scene *scene, double lx, double ly)
|
return part_type;
|
||||||
{
|
}
|
||||||
assert(scene);
|
|
||||||
double sx, sy;
|
/* Perform cursor-based context checks */
|
||||||
struct wlr_scene_node *node = wlr_scene_node_at(
|
enum ssd_part_type resizing_type = get_resizing_type(ssd, cursor);
|
||||||
&scene->tree.node, lx, ly, &sx, &sy);
|
return resizing_type != LAB_SSD_NONE ? resizing_type : part_type;
|
||||||
return ssd_get_part_type(ssd, node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
|
|
|
||||||
|
|
@ -1388,6 +1388,10 @@ post_processing(struct theme *theme)
|
||||||
rc.corner_radius = theme->titlebar_height - 1;
|
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 =
|
int min_button_hover_radius =
|
||||||
MIN(theme->window_button_width, theme->window_button_height) / 2;
|
MIN(theme->window_button_width, theme->window_button_height) / 2;
|
||||||
if (theme->window_button_hover_bg_corner_radius > min_button_hover_radius) {
|
if (theme->window_button_hover_bg_corner_radius > min_button_hover_radius) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue