aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaac Freund <mail@isaacfreund.com>2021-12-29 06:19:37 +0000
committerIsaac Freund <mail@isaacfreund.com>2021-12-29 06:19:37 +0000
commitea4bd5e54b594c9524ee0522309faeb9c99d830c (patch)
tree40c7d09d68fd731e71b8e5e5bdbd635f5418de40
parent9c2e3b6738097dd38abea69a59c700c1ec0bc53f (diff)
downloadriver-ea4bd5e54b594c9524ee0522309faeb9c99d830c.tar.gz
river-ea4bd5e54b594c9524ee0522309faeb9c99d830c.tar.xz
Cursor: fix down mode motion events for subsurfaces
There are a couple of TODOs here that are not worth resolving until after moving to the scene graph api.
-rw-r--r--river/Cursor.zig139
1 files changed, 77 insertions, 62 deletions
diff --git a/river/Cursor.zig b/river/Cursor.zig
index 95bf7d6..2e53202 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -42,7 +42,19 @@ const XwaylandUnmanaged = @import("XwaylandUnmanaged.zig");
const Mode = union(enum) {
passthrough: void,
- down: *View,
+ down: struct {
+ // TODO: To handle the surface with pointer focus being moved during
+ // down mode we need to store the starting location of the surface as
+ // well and take that into account. This is currently not at all easy
+ // to do, but moing to the wlroots scene graph will allow us to fix this.
+
+ // Initial cursor position in layout coordinates
+ lx: f64,
+ ly: f64,
+ // Initial cursor position in surface-local coordinates
+ sx: f64,
+ sy: f64,
+ },
move: struct {
view: *View,
/// View coordinates are stored as i32s as they are in logical pixels.
@@ -204,8 +216,7 @@ pub fn setTheme(self: *Self, theme: ?[*:0]const u8, _size: ?u32) !void {
pub fn handleViewUnmap(self: *Self, view: *View) void {
if (switch (self.mode) {
- .passthrough => false,
- .down => |target_view| target_view == view,
+ .passthrough, .down => false,
.move => |data| data.view == view,
.resize => |data| data.view == view,
}) {
@@ -255,29 +266,33 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
self.seat.handleActivity();
- if (event.state == .pressed) {
- self.pressed_count += 1;
- } else {
+ if (event.state == .released) {
std.debug.assert(self.pressed_count > 0);
self.pressed_count -= 1;
if (self.pressed_count == 0 and self.mode != .passthrough) {
self.leaveMode(event);
- return;
+ } else {
+ _ = self.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
}
+ return;
+ }
+
+ assert(event.state == .pressed);
+ self.pressed_count += 1;
+
+ if (self.pressed_count > 1) {
+ _ = self.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
+ return;
}
if (self.surfaceAt()) |result| {
switch (result.parent) {
.view => |view| {
- // If a view has been clicked on, give that view keyboard focus and
- // perhaps enter move/resize mode.
- if (event.state == .pressed and self.pressed_count == 1) {
- // If there is an active mapping for this button which is
- // handled we are done here
- if (self.handlePointerMapping(event, view)) return;
- // Otherwise enter cursor down mode, giving keyboard focus
- self.enterMode(.down, view);
- }
+ // If there is an active mapping for this button which is
+ // handled we are done here
+ if (self.handlePointerMapping(event, view)) return;
+ // Otherwise focus the view
+ self.seat.focus(view);
},
.layer_surface => |layer_surface| {
self.seat.focusOutput(layer_surface.output);
@@ -288,11 +303,21 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
} else {
self.seat.focus(null);
}
- server.root.startTransaction();
},
.xwayland_unmanaged => assert(build_options.xwayland),
}
_ = self.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
+
+ self.mode = .{
+ .down = .{
+ .lx = self.wlr_cursor.x,
+ .ly = self.wlr_cursor.y,
+ .sx = result.sx,
+ .sy = result.sy,
+ },
+ };
+
+ server.root.startTransaction();
} else if (server.root.output_layout.outputAt(self.wlr_cursor.x, self.wlr_cursor.y)) |wlr_output| {
// If the user clicked on empty space of an output, focus it.
const output = @intToPtr(*Output, wlr_output.data);
@@ -680,52 +705,42 @@ fn surfaceAtFilter(view: *View, filter_tags: u32) bool {
return view.surface != null and view.current.tags & filter_tags != 0;
}
-pub fn enterMode(self: *Self, mode: std.meta.Tag((Mode)), view: *View) void {
+pub fn enterMode(self: *Self, mode: enum { move, resize }, view: *View) void {
log.debug("enter {s} cursor mode", .{@tagName(mode)});
self.seat.focus(view);
switch (mode) {
- .passthrough => unreachable,
- .down => {
- self.mode = .{ .down = view };
- server.root.startTransaction();
+ .move => self.mode = .{ .move = .{ .view = view } },
+ .resize => {
+ const cur_box = &view.current.box;
+ self.mode = .{ .resize = .{
+ .view = view,
+ .offset_x = cur_box.x + @intCast(i32, cur_box.width) - @floatToInt(i32, self.wlr_cursor.x),
+ .offset_y = cur_box.y + @intCast(i32, cur_box.height) - @floatToInt(i32, self.wlr_cursor.y),
+ } };
+ view.setResizing(true);
},
- .move, .resize => {
- switch (mode) {
- .passthrough, .down => unreachable,
- .move => self.mode = .{ .move = .{ .view = view } },
- .resize => {
- const cur_box = &view.current.box;
- self.mode = .{ .resize = .{
- .view = view,
- .offset_x = cur_box.x + @intCast(i32, cur_box.width) - @floatToInt(i32, self.wlr_cursor.x),
- .offset_y = cur_box.y + @intCast(i32, cur_box.height) - @floatToInt(i32, self.wlr_cursor.y),
- } };
- view.setResizing(true);
- },
- }
+ }
- // Automatically float all views being moved by the pointer, if
- // their dimensions are set by a layout generator. If however the views
- // are unarranged, leave them as non-floating so the next active
- // layout can affect them.
- if (!view.current.float and view.output.current.layout != null) {
- view.pending.float = true;
- view.float_box = view.current.box;
- view.applyPending();
- } else {
- // The View.applyPending() call in the other branch starts
- // the transaction needed after the seat.focus() call above.
- server.root.startTransaction();
- }
+ // Automatically float all views being moved by the pointer, if
+ // their dimensions are set by a layout generator. If however the views
+ // are unarranged, leave them as non-floating so the next active
+ // layout can affect them.
+ if (!view.current.float and view.output.current.layout != null) {
+ view.pending.float = true;
+ view.float_box = view.current.box;
+ view.applyPending();
+ } else {
+ // The View.applyPending() call in the other branch starts
+ // the transaction needed after the seat.focus() call above.
+ server.root.startTransaction();
+ }
- // Clear cursor focus, so that the surface does not receive events
- self.seat.wlr_seat.pointerNotifyClearFocus();
+ // Clear cursor focus, so that the surface does not receive events
+ self.seat.wlr_seat.pointerNotifyClearFocus();
- self.setImage(if (mode == .move) .move else .@"se-resize");
- },
- }
+ self.setImage(if (mode == .move) .move else .@"se-resize");
}
/// Return from down/move/resize to passthrough
@@ -783,14 +798,12 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64,
self.checkFocusFollowsCursor();
self.passthrough(time);
},
- .down => |view| {
+ .down => |down| {
self.wlr_cursor.move(device, dx, dy);
- // This takes surface-local coordinates
- const output_box = server.root.output_layout.getBox(view.output.wlr_output).?;
self.seat.wlr_seat.pointerNotifyMotion(
time,
- self.wlr_cursor.x - @intToFloat(f64, output_box.x + view.current.box.x - view.surface_box.x),
- self.wlr_cursor.y - @intToFloat(f64, output_box.y + view.current.box.y - view.surface_box.y),
+ down.sx + (self.wlr_cursor.x - down.lx),
+ down.sy + (self.wlr_cursor.y - down.ly),
);
},
.move => |*data| {
@@ -882,9 +895,11 @@ fn shouldPassthrough(self: Self) bool {
// target view.
return true;
},
- .down => |target| {
- // The target view is no longer visible
- return target.current.tags & target.output.current.tags == 0;
+ .down => {
+ // TODO: It's hard to determine from the target surface alone whether
+ // the surface is visible or not currently. Switching to the wlroots
+ // scene graph will fix this, but for now just don't bother.
+ return false;
},
.resize, .move => {
const target = if (self.mode == .resize) self.mode.resize.view else self.mode.move.view;