diff --git a/2 b/2 new file mode 100644 index 0000000..ce39e5f --- /dev/null +++ b/2 @@ -0,0 +1,244 @@ +//! Maintains state related to cursor position, rendering, and +//! events such as button presses and dragging + +pub const Cursor = @This(); + +const std = @import("std"); +const wl = @import("wayland").server.wl; +const wlr = @import("wlroots"); +const xkb = @import("xkbcommon"); + +const View = @import("view.zig"); +const Utils = @import("utils.zig"); + +const c = @import("c.zig").c; + +const server = &@import("main.zig").server; +const linux = std.os.linux; + +wlr_cursor: *wlr.Cursor, +x_cursor_manager: *wlr.XcursorManager, + +motion: wl.Listener(*wlr.Pointer.event.Motion) = .init(handleMotion), +motion_absolute: wl.Listener(*wlr.Pointer.event.MotionAbsolute) = .init(handleMotionAbsolute), +button: wl.Listener(*wlr.Pointer.event.Button) = .init(handleButton), +axis: wl.Listener(*wlr.Pointer.event.Axis) = .init(handleAxis), +frame: wl.Listener(*wlr.Cursor) = .init(handleFrame), +hold_begin: wl.Listener(*wlr.Pointer.event.HoldBegin) = .init(handleHoldBegin), +hold_end: wl.Listener(*wlr.Pointer.event.HoldEnd) = .init(handleHoldEnd), + +mode: enum { passthrough, move, resize } = .passthrough, + +// Drag information +selected_view: ?*View = null, +drag_start_x: c_int = 0, +drag_start_y: c_int = 0, +drag_view_offset_x: c_int = 0, +drag_view_offset_y: c_int = 0, + +pub fn init(self: *Cursor) void { + errdefer Utils.oomPanic(); + + self.* = .{ + .wlr_cursor = try wlr.Cursor.create(), + .x_cursor_manager = try wlr.XcursorManager.create(null, 24), + }; + + try self.x_cursor_manager.load(1); + + self.wlr_cursor.attachOutputLayout(server.root.output_layout); + + self.wlr_cursor.events.motion.add(&self.motion); + self.wlr_cursor.events.motion_absolute.add(&self.motion_absolute); + self.wlr_cursor.events.button.add(&self.button); + self.wlr_cursor.events.axis.add(&self.axis); + self.wlr_cursor.events.frame.add(&self.frame); + self.wlr_cursor.events.hold_begin.add(&self.hold_begin); + self.wlr_cursor.events.hold_end.add(&self.hold_end); +} + +pub fn deinit(self: *Cursor) void { + self.wlr_cursor.destroy(); + self.x_cursor_manager.destroy(); + + self.motion.link.remove(); + self.motion_absolute.link.remove(); + self.button.link.remove(); + self.axis.link.remove(); + self.frame.link.remove(); +} + +fn updateDrag(self: *Cursor) void { + self.drag_box.width = @as(c_int, @intFromFloat(self.wlr_cursor.x)) - self.drag_box.x; + self.drag_box.height = @as(c_int, @intFromFloat(self.wlr_cursor.y)) - self.drag_box.y; + + std.log.debug("{d}, {d}, {d}, {d}", .{self.drag_box.x, self.drag_box.y, self.drag_box.width, self.drag_box.height}); +} + +pub fn processCursorMotion(self: *Cursor, time_msec: u32) void { + switch (self.mode) { + .passthrough => { + if (server.root.viewAt(self.wlr_cursor.x, self.wlr_cursor.y)) |res| { + server.seat.wlr_seat.pointerNotifyEnter(res.surface, res.sx, res.sy); + server.seat.wlr_seat.pointerNotifyMotion(time_msec, res.sx, res.sy); + } else { + self.wlr_cursor.setXcursor(self.x_cursor_manager, "default"); + server.seat.wlr_seat.pointerClearFocus(); + } + }, + .move => { + const view = self.selected_view.?; + self.updateDrag(); + + // const half_width = @divFloor(view.xdg_surface.geometry.width, 2); + // const half_height = @divFloor(view.xdg_surface.geometry.width, 2); + + view.scene_tree.node.setPosition( + self.drag_box.x + @divFloor(self.drag_box.width, 2), + self.drag_box.y + @divFloor(self.drag_box.height, 2) + ); + }, + .resize => { + self.updateDrag(); + // Fix this resize + // + // REDOING RESIZING AND MOVING TOPLEVELS + // REDOING RESIZING AND MOVING TOPLEVELS + // REDOING RESIZING AND MOVING TOPLEVELS + // REDOING RESIZING AND MOVING TOPLEVELS + // + // const view = self.grabbed_view.?; + // const border_x = @as(i32, @intFromFloat(self.wlr_cursor.x - self.grab_x)); + // const border_y = @as(i32, @intFromFloat(self.wlr_cursor.y - self.grab_y)); + // + // var new_left = self.grab_box.x; + // var new_right = self.grab_box.x + self.grab_box.width; + // var new_top = self.grab_box.y; + // var new_bottom = self.grab_box.y + self.grab_box.height; + // + // if (self.resize_edges.top) { + // new_top = border_y; + // if (new_top >= new_bottom) + // new_top = new_bottom - 1; + // } else if (self.resize_edges.bottom) { + // new_bottom = border_y; + // if (new_bottom <= new_top) + // new_bottom = new_top + 1; + // } + // + // if (self.resize_edges.left) { + // new_left = border_x; + // if (new_left >= new_right) + // new_left = new_right - 1; + // } else if (self.resize_edges.right) { + // new_right = border_x; + // if (new_right <= new_left) + // new_right = new_left + 1; + // } + // + // // view.x = new_left - view.xdg_toplevel.base.geometry.x; + // // view.y = new_top - view.xdg_toplevel.base.geometry.y; + // view.scene_tree.node.setPosition(view.geometry.x, view.geometry.y); + // + // const new_width = new_right - new_left; + // const new_height = new_bottom - new_top; + // _ = view.xdg_toplevel.setSize(new_width, new_height); + }, + } +} + +// --------- WLR Cursor event handlers --------- +fn handleMotion( + _: *wl.Listener(*wlr.Pointer.event.Motion), + event: *wlr.Pointer.event.Motion, +) void { + server.cursor.wlr_cursor.move(event.device, event.delta_x, event.delta_y); + server.cursor.processCursorMotion(event.time_msec); +} + +fn handleMotionAbsolute( + _: *wl.Listener(*wlr.Pointer.event.MotionAbsolute), + event: *wlr.Pointer.event.MotionAbsolute, +) void { + server.cursor.wlr_cursor.warpAbsolute(event.device, event.x, event.y); + server.cursor.processCursorMotion(event.time_msec); +} + +fn handleButton( + listener: *wl.Listener(*wlr.Pointer.event.Button), + event: *wlr.Pointer.event.Button +) void { + const cursor: *Cursor = @fieldParentPtr("button", listener); + + _ = server.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state); + + const view_at_result = server.root.viewAt(cursor.wlr_cursor.x, cursor.wlr_cursor.y); + if (view_at_result) |res| { + server.root.focusView(res.view); + } + + std.log.debug("Button pressed {}", .{event.button}); + + switch (event.state) { + .pressed => { + if(server.keyboard.wlr_keyboard.getModifiers().alt) { + // Can be BTN_RIGHT, BTN_LEFT, or BTN_MIDDLE + if(view_at_result) |res| { + // Keep track of where the drag started + cursor.selected_view = res.view; + cursor.drag_box.x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)); + cursor.drag_box.y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)); + + // Maybe comptime this for later reference + if(event.button == c.libevdev_event_code_from_name(c.EV_KEY, "BTN_LEFT")) { + cursor.mode = .move; + } else if(event.button == c.libevdev_event_code_from_name(c.EV_KEY, "BTN_RIGHT")) { + cursor.mode = .resize; + } + } + } + }, + .released => { + cursor.mode = .passthrough; + }, + else => { + std.log.err("Invalid/Unimplemented pointer button event type", .{}); + } + } +} + +fn handleHoldBegin( + listener: *wl.Listener(*wlr.Pointer.event.HoldBegin), + event: *wlr.Pointer.event.HoldBegin +) void { + _ = listener; + _ = event; + std.log.err("Unimplemented cursor start hold", .{}); +} + +fn handleHoldEnd( + listener: *wl.Listener(*wlr.Pointer.event.HoldEnd), + event: *wlr.Pointer.event.HoldEnd +) void { + _ = listener; + _ = event; + std.log.err("Unimplemented cursor end hold", .{}); +} + +fn handleAxis( + _: *wl.Listener(*wlr.Pointer.event.Axis), + event: *wlr.Pointer.event.Axis, +) void { + server.seat.wlr_seat.pointerNotifyAxis( + event.time_msec, + event.orientation, + event.delta, + event.delta_discrete, + event.source, + event.relative_direction, + ); +} + +fn handleFrame(_: *wl.Listener(*wlr.Cursor), _: *wlr.Cursor) void { + server.seat.wlr_seat.pointerNotifyFrame(); +} diff --git a/src/cursor.zig b/src/cursor.zig index bb46963..d26ad4a 100644 --- a/src/cursor.zig +++ b/src/cursor.zig @@ -28,8 +28,15 @@ hold_begin: wl.Listener(*wlr.Pointer.event.HoldBegin) = .init(handleHoldBegin), hold_end: wl.Listener(*wlr.Pointer.event.HoldEnd) = .init(handleHoldEnd), mode: enum { passthrough, move, resize } = .passthrough, + +// Drag information selected_view: ?*View = null, -grab_box: wlr.Box = undefined, +drag_start_x: c_int = 0, +drag_start_y: c_int = 0, +drag_view_offset_x: c_int = 0, +drag_view_offset_y: c_int = 0, +drag_view_width: c_int = 0, +drag_view_height: c_int = 0, pub fn init(self: *Cursor) void { errdefer Utils.oomPanic(); @@ -63,16 +70,6 @@ pub fn deinit(self: *Cursor) void { self.frame.link.remove(); } -pub fn moveView(self: *Cursor, view: *View, _: *wlr.Pointer.event.Button) void { - self.mode = .move; - self.selected_view = view; -} - -pub fn resizeView(self: *Cursor, view: *View, _: *wlr.Pointer.event.Button) void { - self.mode = .resize; - self.selected_view = view; -} - pub fn processCursorMotion(self: *Cursor, time_msec: u32) void { switch (self.mode) { .passthrough => { @@ -86,55 +83,22 @@ pub fn processCursorMotion(self: *Cursor, time_msec: u32) void { }, .move => { const view = self.selected_view.?; + view.scene_tree.node.setPosition( - @as(i32, @intFromFloat(self.wlr_cursor.x)), - @as(i32, @intFromFloat(self.wlr_cursor.y)) + std.math.clamp(@as(c_int, @intFromFloat(self.wlr_cursor.x)) - self.drag_view_offset_x, 0, std.math.maxInt(u32)), + std.math.clamp(@as(c_int, @intFromFloat(self.wlr_cursor.y)) - self.drag_view_offset_y, 0, std.math.maxInt(u32)) ); }, .resize => { // Fix this resize - // - // REDOING RESIZING AND MOVING TOPLEVELS - // REDOING RESIZING AND MOVING TOPLEVELS - // REDOING RESIZING AND MOVING TOPLEVELS - // REDOING RESIZING AND MOVING TOPLEVELS - // - // const view = self.grabbed_view.?; - // const border_x = @as(i32, @intFromFloat(self.wlr_cursor.x - self.grab_x)); - // const border_y = @as(i32, @intFromFloat(self.wlr_cursor.y - self.grab_y)); - // - // var new_left = self.grab_box.x; - // var new_right = self.grab_box.x + self.grab_box.width; - // var new_top = self.grab_box.y; - // var new_bottom = self.grab_box.y + self.grab_box.height; - // - // if (self.resize_edges.top) { - // new_top = border_y; - // if (new_top >= new_bottom) - // new_top = new_bottom - 1; - // } else if (self.resize_edges.bottom) { - // new_bottom = border_y; - // if (new_bottom <= new_top) - // new_bottom = new_top + 1; - // } - // - // if (self.resize_edges.left) { - // new_left = border_x; - // if (new_left >= new_right) - // new_left = new_right - 1; - // } else if (self.resize_edges.right) { - // new_right = border_x; - // if (new_right <= new_left) - // new_right = new_left + 1; - // } - // - // // view.x = new_left - view.xdg_toplevel.base.geometry.x; - // // view.y = new_top - view.xdg_toplevel.base.geometry.y; - // view.scene_tree.node.setPosition(view.geometry.x, view.geometry.y); - // - // const new_width = new_right - new_left; - // const new_height = new_bottom - new_top; - // _ = view.xdg_toplevel.setSize(new_width, new_height); + const view = self.selected_view.?; + + + + _ = view.xdg_toplevel.setSize( + @intCast(@as(c_int, @intFromFloat(self.wlr_cursor.x)) - view.scene_tree.node.x), + @intCast(@as(c_int, @intFromFloat(self.wlr_cursor.y)) - view.scene_tree.node.y) + ); }, } } @@ -176,16 +140,32 @@ fn handleButton( if(server.keyboard.wlr_keyboard.getModifiers().alt) { // Can be BTN_RIGHT, BTN_LEFT, or BTN_MIDDLE if(view_at_result) |res| { + // Keep track of where the drag started + cursor.selected_view = res.view; + cursor.drag_start_x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)); + cursor.drag_start_y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)); + cursor.drag_view_offset_x = cursor.drag_start_x - res.view.scene_tree.node.x; + cursor.drag_view_offset_y = cursor.drag_start_y - res.view.scene_tree.node.y; + cursor.drag_view_width = res.view.xdg_surface.geometry.width; + cursor.drag_view_height = res.view.xdg_surface.geometry.height; + + // Maybe comptime this for later reference if(event.button == c.libevdev_event_code_from_name(c.EV_KEY, "BTN_LEFT")) { - cursor.moveView(res.view, event); + cursor.mode = .move; } else if(event.button == c.libevdev_event_code_from_name(c.EV_KEY, "BTN_RIGHT")) { - cursor.resizeView(res.view, event); + cursor.mode = .resize; + _ = res.view.xdg_toplevel.setResizing(true); } } } }, .released => { cursor.mode = .passthrough; + + if(cursor.selected_view) |view| { + _ = view.xdg_toplevel.setResizing(false); + } + cursor.selected_view = null; }, else => { std.log.err("Invalid/Unimplemented pointer button event type", .{});