Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Manuel Barrio Linares 2025-12-10 14:26:44 -03:00
commit fd6d62eaed
18 changed files with 248 additions and 75 deletions

View file

@ -51,9 +51,13 @@ Actions are used in menus and keyboard/mouse bindings.
another window or screen edge. If set to "no", only move to
the next screen edge. Default is yes.
*<action name="Resize" />*
*<action name="Resize" direction="value" />*
Begin interactive resize of window under cursor.
*direction* [up|down|left|right|up-left|up-right|down-left|down-right]
Edge or corner from which to start resizing. If this is not provided,
the direction is inferred from the cursor position.
*<action name="ResizeRelative" left="" right="" top="" bottom="" />*
Resize window relative to its current size. Values of left, right,
top or bottom tell how much to resize on that edge of window,

View file

@ -349,7 +349,7 @@ this is for compatibility with Openbox.
</windowSwitcher>
```
*<windowSwitcher preview="" outlines="" allWorkspaces="" unshade="">*
*<windowSwitcher preview="" outlines="" allWorkspaces="" unshade="" order="">*
*preview* [yes|no] Preview the contents of the selected window when
switching between windows. Default is yes.
@ -363,6 +363,11 @@ this is for compatibility with Openbox.
*unshade* [yes|no] Temporarily unshade windows when switching between
them and permanently unshade on the final selection. Default is yes.
*order* [focus|age] The order in which windows are cycled. *focus* cycles by
recent focus history, starting with the previously focused window. *age* cycles
by creation/open order, a stable taskbar-style ordering that doesnt change on
focus. Default is *focus*.
*<windowSwitcher><osd show="" style="" output="" thumbnailLabelFormat="" />*
*show* [yes|no] Draw the OnScreenDisplay when switching between
windows. Default is yes.
@ -498,13 +503,16 @@ activated with SnapToEdge actions or, optionally, by dragging windows to the
edges of an output. Edge snapping causes a window to occupy half of its output,
extending outward from the snapped edge.
*<snapping><range>*++
*<snapping><range><inner>*++
*<snapping><range><outer>*++
*<snapping><cornerRange>*
If an interactive move ends with the cursor within *<range>* pixels of an
output edge, the window is snapped to the edge. If it's also within
*<cornerRange>* pixels of an output corner, the window is snapped to the
corner instead. A *<range>* of 0 disables snapping.
Default is 10 for *<range>* and 50 for *<cornerRange>*.
If an interactive move ends with the cursor within *inner* or *outer* pixels
of an output edge, the window is snapped to the edge. *inner* edges are edges
with an adjacent output and *outer* edges are edges without an adjacent output.
If it's also within *<cornerRange>* pixels of an output corner, the window is
snapped to the corner instead.
If *inner* and *outer* is 0, snapping is disabled.
Default is 10 for *<range><inner>* and *<range><outer>*, and 50 for *<cornerRange>*.
*<snapping><overlay><enabled>* [yes|no]
Show an overlay when snapping to a window to an edge. Default is yes.
@ -700,6 +708,45 @@ extending outward from the snapped edge.
invisible zones just beyond the window that serve as click targets for
mouse actions. Default is 8.
# INPUT CONFIGURATION
This section describes configuration of input devices including:
- Keyboards
- Mice
- Touchpads (sometimes referred to as laptop trackpads)
- Touchscreens
- Tablets
- Tablet tools (like stylus pens)
It aims to clarify related terminology and separation of concerns.
Keyboards are configured in the *<keyboard>* section below and are simple in
this regard.
Touchpads and mice are harder. They are both considered to be *pointer* devices
by the compositor, and can be configured in the *<mouse>* and *<libinput>*
sections. Any setting that is supported by libinput is configured in the
*<libinput>* section, and anything else is in *<mouse>*. Touchpad devices can
generate gesture events, like swipe and pinch. There are some related settings
(e.g. *threeFingerDrag* and *twoFingerScroll*) in the *<libinput>* section.
In the Wayland Compositor domain, events associated with touchscreens are
sometimes simply referred to as *touch* events. Touchscreens can be configured
in both the *<touch>* and *<libinput>* sections. Note that touchscreen gestures
are not interpreted by libinput, nor labwc. Any touch point is passed to the
client (application) for any interpretation of gestures.
Tablets are considered special by libinput although in the eyes of the Wayland
protocol they are merely a *touch* capability. Tablets and associated tablet
tools are configured in the *<tablet>*, *<tablettool>* and *<libinput>*
sections. Note that the term *tablet* in libinput (and labwc) refers to graphics
tablets only (e.g. Wacom Intuos), not to tablet devices like the Apple iPad.
References:
- https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html
- https://wayland.freedesktop.org/libinput/doc/latest/gestures.html
## KEYBOARD
*<keyboard><numlock>* [on|off]
@ -808,6 +855,9 @@ extending outward from the snapped edge.
## MOUSE
This section relates to mice and touchpads - which are both considered pointer
input-devices by the Wayland protocol.
*<mouse><doubleClickTime>*
Set double click time in milliseconds. Default is 500.
@ -918,6 +968,11 @@ extending outward from the snapped edge.
## TOUCH
This section relates to touchscreens and *not* touchpads.
Note: To rotate touch events with output rotation, use the libinput
*calibrationMatrix* setting.
```
<touch deviceName="" mapToOutput="" mouseEmulation="no"/>
```
@ -1080,14 +1135,9 @@ extending outward from the snapped edge.
attribute is provided, a 'default' device profile will created that will
act as the fallback for all libinput devices. Category can be set to any
of the following types:
- *touch* - Devices which have a defined width/height, but do not
support multitouch (i.e. they cannot track multiple locations where
the screen has been touched). Drawing tablets typically fall into this
type.
- *touchpad* - Same as 'touch' but support multitouch. This typically
includes laptop track pads with two-finger scroll and swipe gestures.
- *non-touch* - Anything not described above, for example traditional
mouse pointers.
- *touch* - Includes touchscreens and drawing-tablets.
- *touchpad* - Includes touchpads (also known as laptop trackpads)
- *non-touch* - Includes traditional mice
- *default* - Defines a device-category applicable to all devices not
matched by anything else. This can be useful for a fallback, or if you
want the same settings to be applied to all devices.

View file

@ -6,7 +6,7 @@
<labwc_config>
<theme>
<name></name>
<name>Clearlooks-3.4</name>
<cornerRadius>8</cornerRadius>
<font name="sans" size="10" />
</theme>

View file

@ -33,8 +33,8 @@
<!-- <font><theme> can be defined without an attribute to set all places -->
<theme>
<name></name>
<icon></icon>
<!-- <name>Numix</name> -->
<!-- <icon>breeze</icon> -->
<fallbackAppIcon>labwc</fallbackAppIcon>
<titlebar>
<layout>icon:iconify,max,close</layout>
@ -161,8 +161,8 @@
</focus>
<snapping>
<!-- Set range to 0 to disable window snapping completely -->
<range>10</range>
<!-- Set inner and outer range to 0 to disable window snapping completely -->
<range inner="10" outer="10" />
<cornerRange>50</cornerRange>
<overlay enabled="yes">
<delay inner="500" outer="500" />
@ -218,9 +218,9 @@
space automatically, so <margin> is only intended for other, specialist
cases.
If output is left empty, the margin will be applied to all outputs.
If 'output' is not provided, the margin will be applied to all outputs.
<margin top="" bottom="" left="" right="" output="" />
<margin top="10" bottom="10" left="10" right="10" output="HDMI-A-1" />
-->
<!-- Percent based regions based on output usable area, % char is required -->
@ -525,7 +525,11 @@
If mouseEmulation is enabled, all touch up/down/motion events are
translated to mouse button and motion events.
-->
<touch deviceName="" mapToOutput="" mouseEmulation="no"/>
<touch>
<!-- <deviceName>ELAN2514:00 04F3:2AF1<deviceName> -->
<!-- <mapToOutput>HDMI-A-1</mapToOutput> -->
<mouseEmulation>no</mouseEmulation>
</touch>
<!--
The tablet cursor movement can be restricted to a single output.
@ -552,7 +556,8 @@
When using mouse emulation, the pen tip [tip] and the stylus buttons
can be set to any available mouse button [Left|Right|Middle|..|Task].
-->
<tablet mapToOutput="" rotate="0" mouseEmulation="no">
<tablet rotate="0" mouseEmulation="no">
<!-- <mapToOutput>HDMI-A-1</mapToOutput> -->
<!-- Active area dimensions are in mm -->
<area top="0.0" left="0.0" width="0.0" height="0.0" />
<map button="Tip" to="Left" />
@ -583,10 +588,11 @@
- accelProfile [flat|adaptive]
- tapButtonMap [lrm|lmr]
- clickMethod [none|buttonAreas|clickfinger]
- scrollMethod [twoFinger|edge|none]
- sendEventsMode [yes|no|disabledOnExternalMouse]
- calibrationMatrix [six float values split by space]
- scrollFactor [float]
The following <libinput>...</libinput> block may not be complete for
your requirements. Default values are device specific. Only set an option
if you require to override the default. Valid values must be inserted.
@ -595,21 +601,21 @@
<libinput>
<device category="default">
<naturalScroll></naturalScroll>
<leftHanded></leftHanded>
<pointerSpeed></pointerSpeed>
<accelProfile></accelProfile>
<!-- <naturalScroll>no</naturalScroll> -->
<!-- <leftHanded>no</leftHanded> -->
<!-- <pointerSpeed>0.0</pointerSpeed> -->
<!-- <accelProfile>adaptive</accelProfile> -->
<tap>yes</tap>
<tapButtonMap></tapButtonMap>
<tapAndDrag></tapAndDrag>
<dragLock></dragLock>
<threeFingerDrag></threeFingerDrag>
<middleEmulation></middleEmulation>
<disableWhileTyping></disableWhileTyping>
<clickMethod></clickMethod>
<scrollMethod></scrollMethod>
<sendEventsMode></sendEventsMode>
<calibrationMatrix></calibrationMatrix>
<!-- <tapButtonMap>lrm</tapButtonMap> -->
<!-- <tapAndDrag>yes</tapAndDrag> -->
<!-- <dragLock>yes</dragLock> -->
<!-- <threeFingerDrag>yes</threeFingerDrag> -->
<!-- <middleEmulation>no</middleEmulation> -->
<!-- <disableWhileTyping>yes</disableWhileTyping> -->
<!-- <clickMethod>buttonAreas</clickMethod> -->
<!-- <scrollMethod>twofinger</scrollMethod> -->
<!-- <sendEventsMode>yes</sendEventsMode> -->
<!-- <calibrationMatrix>1 0 0 0 1 0</calibrationMatrix> -->
<scrollFactor>1.0</scrollFactor>
</device>
</libinput>
@ -678,7 +684,7 @@
<height>400</height>
<initScale>2.0</initScale>
<increment>0.2</increment>
<useFilter>true</useFilter>
<useFilter>yes</useFilter>
</magnifier>
</labwc_config>

View file

@ -151,7 +151,8 @@ struct rcxml {
int unmaximize_threshold;
/* window snapping */
int snap_edge_range;
int snap_edge_range_inner;
int snap_edge_range_outer;
int snap_edge_corner_range;
bool snap_overlay_enabled;
int snap_overlay_delay_inner;
@ -185,6 +186,7 @@ struct rcxml {
enum cycle_osd_style style;
enum cycle_osd_output_criteria output_criteria;
char *thumbnail_label_format;
enum window_switcher_order order;
} window_switcher;
struct wl_list window_rules; /* struct window_rule.link */

View file

@ -107,6 +107,11 @@ enum lab_window_type {
LAB_WINDOW_TYPE_LEN
};
enum window_switcher_order {
WINDOW_SWITCHER_ORDER_FOCUS,
WINDOW_SWITCHER_ORDER_AGE,
};
enum cycle_osd_style {
CYCLE_OSD_STYLE_CLASSIC,
CYCLE_OSD_STYLE_THUMBNAIL,

View file

@ -188,6 +188,7 @@ struct server {
struct wl_listener xdg_toplevel_icon_set_icon;
struct wl_list views;
uint64_t next_view_creation_id;
struct wl_list unmanaged_surfaces;
struct seat seat;

View file

@ -24,6 +24,7 @@ struct node_descriptor {
* @type: node descriptor type
* @view: associated view
* @data: struct to point to as follows:
* - LAB_NODE_CYCLE_OSD_ITEM struct cycle_osd_item
* - LAB_NODE_LAYER_SURFACE struct lab_layer_surface
* - LAB_NODE_LAYER_POPUP struct lab_layer_popup
* - LAB_NODE_MENUITEM struct menuitem

View file

@ -174,6 +174,7 @@ struct view {
bool mapped;
bool been_mapped;
uint64_t creation_id;
enum lab_ssd_mode ssd_mode;
enum ssd_preference ssd_preference;
bool shaded;

View file

@ -414,6 +414,20 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
goto cleanup;
}
break;
case ACTION_TYPE_RESIZE:
if (!strcmp(argument, "direction")) {
enum lab_edge edge = lab_edge_parse(content,
/*tiled*/ true, /*any*/ false);
if (edge == LAB_EDGE_NONE || edge == LAB_EDGE_CENTER) {
wlr_log(WLR_ERROR,
"Invalid argument for action %s: '%s' (%s)",
action_names[action->type], argument, content);
} else {
action_arg_add_int(action, argument, edge);
}
goto cleanup;
}
break;
case ACTION_TYPE_RESIZE_RELATIVE:
if (!strcmp(argument, "left") || !strcmp(argument, "right") ||
!strcmp(argument, "top") || !strcmp(argument, "bottom")) {
@ -1223,8 +1237,17 @@ run_action(struct view *view, struct server *server, struct action *action,
break;
case ACTION_TYPE_RESIZE:
if (view) {
enum lab_edge resize_edges = cursor_get_resize_edges(
server->seat.cursor, ctx);
/*
* If a direction was specified in the config, honour it.
* Otherwise, fall back to determining the resize edges from
* the current cursor position (existing behaviour).
*/
enum lab_edge resize_edges =
action_get_int(action, "direction", LAB_EDGE_NONE);
if (resize_edges == LAB_EDGE_NONE) {
resize_edges = cursor_get_resize_edges(
server->seat.cursor, ctx);
}
interactive_begin(view, LAB_INPUT_STATE_RESIZE,
resize_edges);
}

View file

@ -714,6 +714,8 @@ fill_libinput_category(xmlNode *node)
char *key, *content;
LAB_XML_FOR_EACH(node, child, key, content) {
if (string_null_or_empty(content)) {
wlr_log(WLR_ERROR, "Empty string is not allowed for "
"<libinput><device><%s>. Ignoring.", key);
continue;
}
if (!strcmp(key, "category")) {
@ -1076,7 +1078,8 @@ entry(xmlNode *node, char *nodename, char *content)
return true;
} else if (str_space_only(content)) {
/* ignore empty leaf nodes other than above */
wlr_log(WLR_ERROR, "Empty string is not allowed for %s. "
"Ignoring.", nodename);
/* handle non-empty leaf nodes */
} else if (!strcmp(nodename, "decoration.core")) {
@ -1177,7 +1180,14 @@ entry(xmlNode *node, char *nodename, char *content)
} else if (!strcasecmp(nodename, "unMaximizeThreshold.resistance")) {
rc.unmaximize_threshold = atoi(content);
} else if (!strcasecmp(nodename, "range.snapping")) {
rc.snap_edge_range = atoi(content);
rc.snap_edge_range_inner = atoi(content);
rc.snap_edge_range_outer = atoi(content);
wlr_log(WLR_ERROR, "<snapping><range> is deprecated. "
"Use <snapping><range inner=\"\" outer=\"\"> instead.");
} else if (!strcasecmp(nodename, "inner.range.snapping")) {
rc.snap_edge_range_inner = atoi(content);
} else if (!strcasecmp(nodename, "outer.range.snapping")) {
rc.snap_edge_range_outer = atoi(content);
} else if (!strcasecmp(nodename, "cornerRange.snapping")) {
rc.snap_edge_corner_range = atoi(content);
} else if (!strcasecmp(nodename, "enabled.overlay.snapping")) {
@ -1230,6 +1240,15 @@ entry(xmlNode *node, char *nodename, char *content)
wlr_log(WLR_ERROR, "Invalid windowSwitcher output %s: "
"should be one of all|focused|cursor", content);
}
} else if (!strcasecmp(nodename, "order.windowSwitcher")) {
if (!strcasecmp(content, "focus")) {
rc.window_switcher.order = WINDOW_SWITCHER_ORDER_FOCUS;
} else if (!strcasecmp(content, "age")) {
rc.window_switcher.order = WINDOW_SWITCHER_ORDER_AGE;
} else {
wlr_log(WLR_ERROR, "Invalid windowSwitcher order %s: "
"should be one of focus|age", content);
}
/* The following two are for backward compatibility only. */
} else if (!strcasecmp(nodename, "show.windowSwitcher")) {
@ -1456,7 +1475,8 @@ rcxml_init(void)
rc.unsnap_threshold = 20;
rc.unmaximize_threshold = 150;
rc.snap_edge_range = 10;
rc.snap_edge_range_inner = 10;
rc.snap_edge_range_outer = 10;
rc.snap_edge_corner_range = 50;
rc.snap_overlay_enabled = true;
rc.snap_overlay_delay_inner = 500;
@ -1474,6 +1494,7 @@ rcxml_init(void)
rc.window_switcher.criteria = LAB_VIEW_CRITERIA_CURRENT_WORKSPACE
| LAB_VIEW_CRITERIA_ROOT_TOPLEVEL
| LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER;
rc.window_switcher.order = WINDOW_SWITCHER_ORDER_FOCUS;
rc.resize_indicator = LAB_RESIZE_INDICATOR_NEVER;
rc.resize_draw_contents = true;
@ -1648,9 +1669,8 @@ load_default_window_switcher_fields(void)
#endif
};
struct cycle_osd_field *field;
for (size_t i = 0; i < ARRAY_SIZE(fields); i++) {
field = znew(*field);
struct cycle_osd_field *field = znew(*field);
field->content = fields[i].content;
field->width = fields[i].width;
wl_list_append(&rc.window_switcher.fields, &field->link);

View file

@ -276,13 +276,31 @@ create_osd_on_output(struct output *output)
assert(output->cycle_osd.tree);
}
static void
insert_view_ordered_by_age(struct wl_list *views, struct view *new_view)
{
struct wl_list *link = views;
struct view *view;
wl_list_for_each(view, views, cycle_link) {
if (view->creation_id >= new_view->creation_id) {
break;
}
link = &view->cycle_link;
}
wl_list_insert(link, &new_view->cycle_link);
}
/* Return false on failure */
static bool
init_cycle(struct server *server)
{
struct view *view;
for_each_view(view, &server->views, rc.window_switcher.criteria) {
wl_list_append(&server->cycle.views, &view->cycle_link);
if (rc.window_switcher.order == WINDOW_SWITCHER_ORDER_AGE) {
insert_view_ordered_by_age(&server->cycle.views, view);
} else {
wl_list_append(&server->cycle.views, &view->cycle_link);
}
}
if (wl_list_empty(&server->cycle.views)) {
wlr_log(WLR_DEBUG, "no views to switch between");

View file

@ -144,7 +144,6 @@ cycle_osd_classic_create(struct output *output)
y += switcher_theme->item_height;
}
struct buf buf = BUF_INIT;
int nr_fields = wl_list_length(&rc.window_switcher.fields);
/* This is the width of the area available for text fields */
@ -194,9 +193,9 @@ cycle_osd_classic_create(struct output *output)
/* Highlight around selected window's item */
struct lab_scene_rect_options highlight_opts = {
.border_colors = (float *[1]) {active_border_color},
.bg_color = active_bg_color,
.nr_borders = 1,
.border_width = switcher_theme->item_active_border_width,
.bg_color = active_bg_color,
.width = w - 2 * padding,
.height = switcher_theme->item_height,
};
@ -216,7 +215,6 @@ cycle_osd_classic_create(struct output *output)
y += switcher_theme->item_height;
}
buf_reset(&buf);
error:;
/* Center OSD */

View file

@ -251,6 +251,9 @@ err:
* (e.g. "thunderbird" matches "org.mozilla.Thunderbird.desktop"
* and "XTerm" matches "xterm.desktop"). This is not per any spec
* but is needed to find icons for existing applications.
*
* The second loop tries to match more partial strings, for
* example "gimp-2.0" would match "org.something.gimp.desktop".
*/
static struct sfdo_desktop_entry *
get_db_entry_by_id_fuzzy(struct sfdo_desktop_db *db, const char *app_id)
@ -258,6 +261,7 @@ get_db_entry_by_id_fuzzy(struct sfdo_desktop_db *db, const char *app_id)
size_t n_entries;
struct sfdo_desktop_entry **entries = sfdo_desktop_db_get_entries(db, &n_entries);
/* Would match "org.foobar.xterm" when given app-id "XTerm" */
for (size_t i = 0; i < n_entries; i++) {
struct sfdo_desktop_entry *entry = entries[i];
const char *desktop_id = sfdo_desktop_entry_get_id(entry, NULL);
@ -266,6 +270,8 @@ get_db_entry_by_id_fuzzy(struct sfdo_desktop_db *db, const char *app_id)
const char *desktop_id_base = dot ? (dot + 1) : desktop_id;
if (!strcasecmp(app_id, desktop_id_base)) {
wlr_log(WLR_DEBUG, "'%s' to '%s.desktop' via case-insensitive match",
app_id, desktop_id);
return entry;
}
@ -278,20 +284,31 @@ get_db_entry_by_id_fuzzy(struct sfdo_desktop_db *db, const char *app_id)
const char *wm_class =
sfdo_desktop_entry_get_startup_wm_class(entry, NULL);
if (wm_class && !strcasecmp(app_id, wm_class)) {
wlr_log(WLR_DEBUG, "'%s' to '%s.desktop' via StartupWMClass",
app_id, desktop_id);
return entry;
}
}
/* Try matching partial strings - catches GIMP, among others */
/* Would match "org.foobar.xterm-unicode" when given app-id "XTerm" */
const int app_id_len = strlen(app_id);
for (size_t i = 0; i < n_entries; i++) {
struct sfdo_desktop_entry *entry = entries[i];
const char *desktop_id = sfdo_desktop_entry_get_id(entry, NULL);
const char *dot = strrchr(desktop_id, '.');
const char *desktop_id_base = dot ? (dot + 1) : desktop_id;
int alen = strlen(app_id);
int dlen = strlen(desktop_id_base);
if (!strncasecmp(app_id, desktop_id_base, alen > dlen ? dlen : alen)) {
const int dlen = strlen(desktop_id_base);
const int cmp_len = MIN(app_id_len, dlen);
if (cmp_len < 3) {
/*
* Without this check, app-id "foot" would match
* "something.f" and any app-id would match "R.E.P.O."
*/
continue;
}
if (!strncasecmp(app_id, desktop_id_base, cmp_len)) {
wlr_log(WLR_DEBUG, "'%s' to '%s.desktop' via partial match",
app_id, desktop_id);
return entry;
}
}
@ -304,10 +321,14 @@ get_desktop_entry(struct sfdo *sfdo, const char *app_id)
{
struct sfdo_desktop_entry *entry = sfdo_desktop_db_get_entry_by_id(
sfdo->desktop_db, app_id, SFDO_NT);
if (!entry) {
entry = get_db_entry_by_id_fuzzy(sfdo->desktop_db, app_id);
if (entry) {
wlr_log(WLR_DEBUG, "matched '%s.desktop' via exact match", app_id);
return entry;
}
entry = get_db_entry_by_id_fuzzy(sfdo->desktop_db, app_id);
if (!entry) {
wlr_log(WLR_DEBUG, "failed to find .desktop file for '%s'", app_id);
}
return entry;
}

View file

@ -840,10 +840,12 @@ apply_constraint(struct seat *seat, struct wlr_pointer *pointer, double *x, doub
if (!seat->server->active_view) {
return;
}
if (!seat->current_constraint || pointer->base.type != WLR_INPUT_DEVICE_POINTER) {
if (!seat->current_constraint
|| pointer->base.type != WLR_INPUT_DEVICE_POINTER
|| seat->current_constraint->type
!= WLR_POINTER_CONSTRAINT_V1_CONFINED) {
return;
}
assert(seat->current_constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED);
double sx = seat->cursor->x;
double sy = seat->cursor->y;
@ -866,7 +868,9 @@ cursor_locked(struct seat *seat, struct wlr_pointer *pointer)
{
return seat->current_constraint
&& pointer->base.type == WLR_INPUT_DEVICE_POINTER
&& seat->current_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED;
&& seat->current_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED
&& seat->current_constraint->surface
== seat->seat->pointer_state.focused_surface;
}
static void
@ -981,11 +985,6 @@ handle_motion_absolute(struct wl_listener *listener, void *data)
double dx = lx - seat->cursor->x;
double dy = ly - seat->cursor->y;
wlr_relative_pointer_manager_v1_send_relative_motion(
seat->server->relative_pointer_manager,
seat->seat, (uint64_t)event->time_msec * 1000,
dx, dy, dx, dy);
preprocess_cursor_motion(seat, event->pointer,
event->time_msec, dx, dy);
}

View file

@ -186,7 +186,7 @@ edge_from_cursor(struct seat *seat, struct output **dest_output,
return false;
}
if (rc.snap_edge_range == 0) {
if (rc.snap_edge_range_inner == 0 && rc.snap_edge_range_outer == 0) {
return false;
}
@ -197,9 +197,31 @@ edge_from_cursor(struct seat *seat, struct output **dest_output,
}
*dest_output = output;
/* Translate into output local coordinates */
double cursor_x = seat->cursor->x;
double cursor_y = seat->cursor->y;
int top_range = rc.snap_edge_range_outer;
int bottom_range = rc.snap_edge_range_outer;
int left_range = rc.snap_edge_range_outer;
int right_range = rc.snap_edge_range_outer;
if (wlr_output_layout_adjacent_output(seat->server->output_layout, WLR_DIRECTION_UP,
output->wlr_output, cursor_x, cursor_y)) {
top_range = rc.snap_edge_range_inner;
}
if (wlr_output_layout_adjacent_output(seat->server->output_layout, WLR_DIRECTION_DOWN,
output->wlr_output, cursor_x, cursor_y)) {
bottom_range = rc.snap_edge_range_inner;
}
if (wlr_output_layout_adjacent_output(seat->server->output_layout, WLR_DIRECTION_LEFT,
output->wlr_output, cursor_x, cursor_y)) {
left_range = rc.snap_edge_range_inner;
}
if (wlr_output_layout_adjacent_output(seat->server->output_layout, WLR_DIRECTION_RIGHT,
output->wlr_output, cursor_x, cursor_y)) {
right_range = rc.snap_edge_range_inner;
}
/* Translate into output local coordinates */
wlr_output_layout_output_coords(seat->server->output_layout,
output->wlr_output, &cursor_x, &cursor_y);
@ -210,13 +232,13 @@ edge_from_cursor(struct seat *seat, struct output **dest_output,
int left = cursor_x - area->x;
int right = area->x + area->width - cursor_x;
if (top < rc.snap_edge_range) {
if (top < top_range) {
*edge1 = LAB_EDGE_TOP;
} else if (bottom < rc.snap_edge_range) {
} else if (bottom < bottom_range) {
*edge1 = LAB_EDGE_BOTTOM;
} else if (left < rc.snap_edge_range) {
} else if (left < left_range) {
*edge1 = LAB_EDGE_LEFT;
} else if (right < rc.snap_edge_range) {
} else if (right < right_range) {
*edge1 = LAB_EDGE_RIGHT;
} else {
return false;

View file

@ -1085,6 +1085,7 @@ handle_new_xdg_toplevel(struct wl_listener *listener, void *data)
CONNECT_SIGNAL(xdg_surface, xdg_toplevel_view, new_popup);
wl_list_insert(&server->views, &view->link);
view->creation_id = server->next_view_creation_id++;
}
static void

View file

@ -1036,6 +1036,7 @@ xwayland_view_create(struct server *server,
CONNECT_SIGNAL(xsurface, xwayland_view, map_request);
wl_list_insert(&view->server->views, &view->link);
view->creation_id = view->server->next_view_creation_id++;
if (xsurface->surface) {
handle_associate(&xwayland_view->associate, NULL);