drag working, good callback arguments for moving and resizing views

This commit is contained in:
Harrison DiAmbrosio 2026-01-06 22:21:30 -05:00
parent 9d8463255c
commit 973ea9d509
3 changed files with 142 additions and 99 deletions

View file

@ -275,14 +275,29 @@ local master = function()
end
mez.input.add_mousemap("alt", "BTN_LEFT", {
press = function()
print("pressed mouse")
mez.input.del_mousemap("alt", "BTN_LEFT");
drag = function(pos, drag)
if drag.view ~= nil then
mez.view.set_position(drag.view.id, pos.x - drag.view.offset.x, pos.y - drag.view.offset.y)
end
end,
release = function() print("released mouse") end,
drag = function() print("dragging mouse") end
})
mez.input.add_mousemap("alt", "BTN_RIGHT", {
drag = function(pos, drag)
if drag.view ~= nil then
mez.view.set_size(
drag.view.id,
(pos.x - drag.start.x) + drag.view.offset.x,
(pos.y - drag.start.y) + drag.view.offset.y
)
-- mez.view.set_size(
-- drag.view.id,
-- (pos.x - drag.start.x) + drag.view.offset.x + (drag.view.dims.width - drag.view.offset.x),
-- (pos.y - drag.start.y) + drag.view.offset.y + (drag.view.dims.height - drag.view.offset.y)
-- )
end
end,
})
end
master()

View file

@ -29,12 +29,17 @@ hold_end: wl.Listener(*wlr.Pointer.event.HoldEnd) = .init(handleHoldEnd),
mode: enum { normal, drag } = .normal,
// Drag information
drag: struct {
start_x: c_int,
start_y: c_int,
view: ?*View,
view_offset_x: ?c_int,
view_offset_y: ?c_int,
drag: ?struct {
event_code: u32,
start: struct {
x: c_int,
y: c_int
},
view: ?struct {
view: *View,
dims: struct { width: c_int, height: c_int },
offset: struct { x: c_int, y: c_int, }
},
},
pub fn init(self: *Cursor) void {
@ -43,13 +48,7 @@ pub fn init(self: *Cursor) void {
self.* = .{
.wlr_cursor = try wlr.Cursor.create(),
.x_cursor_manager = try wlr.XcursorManager.create(null, 24),
.drag = .{
.start_x = 0,
.start_y = 0,
.view = null,
.view_offset_x = null,
.view_offset_y = null,
}
.drag = null
};
try self.x_cursor_manager.load(1);
@ -79,55 +78,57 @@ pub fn deinit(self: *Cursor) void {
}
pub fn processCursorMotion(self: *Cursor, time_msec: u32) void {
server.events.exec("PointerMotion", .{self.wlr_cursor.x, self.wlr_cursor.y});
switch (self.mode) {
.normal => {
const output = server.seat.focused_output;
// Exit the switch if no focused output exists
if (output == null) return;
const surfaceAtResult = output.?.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y);
if (surfaceAtResult == null) {
self.wlr_cursor.setXcursor(self.x_cursor_manager, "default");
server.seat.wlr_seat.pointerClearFocus();
// This is gonna be fun
// server.seat.wlr_seat.keyboardSendKey(time_msec: u32, key: u32, state: u32);
// server.seat.wlr_seat.pointerSendMotion(time_msec: u32, sx: f64, sy: f64)
// server.seat.wlr_seat.pointerSendButton(time_msec: u32, button: u32, state: ButtonState)
return;
var handled = false;
if (self.mode == .drag) {
const modifiers = server.seat.keyboard_group.keyboard.getModifiers();
std.debug.assert(self.drag != null);
// Proceed if mousemap for current mouse and modifier state's exist
if (server.mousemaps.get(Mousemap.hash(modifiers, @bitCast(self.drag.?.event_code)))) |map| {
if(map.options.lua_drag_ref_idx > 0) {
handled = true;
map.callback(.drag, .{
.{
.x = @as(c_int, @intFromFloat(self.wlr_cursor.x)),
.y = @as(c_int, @intFromFloat(self.wlr_cursor.y))
},
.{
.start = self.drag.?.start,
.view = if (self.drag.?.view != null) .{
.id = self.drag.?.view.?.view.id,
.dims = self.drag.?.view.?.dims,
.offset = self.drag.?.view.?.offset
} else null
}
});
}
}
}
switch (surfaceAtResult.?.scene_node_data.*) {
.view => {
// TODO: If serious performance issues arise from this, we need to be able to disable unused hooks
// Perhaps after the config is executed, if no callbacks are present on this hook, we disable it entirely
server.events.exec("ViewPointerMotion", .{surfaceAtResult.?.scene_node_data.view.id, self.wlr_cursor.x, self.wlr_cursor.y});
},
.layer_surface => { },
else => unreachable
if(!handled) {
const output = server.seat.focused_output;
// Exit the switch if no focused output exists
std.debug.assert(output != null);
const surfaceAtResult = output.?.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y);
if (surfaceAtResult) |surface| {
if(surface.scene_node_data.* == .view) {
server.events.exec("ViewPointerMotion", .{
surface.scene_node_data.view.id,
@as(c_int, @intFromFloat(self.wlr_cursor.x)),
@as(c_int, @intFromFloat(self.wlr_cursor.y))
});
}
server.seat.wlr_seat.pointerNotifyEnter(surfaceAtResult.?.surface, surfaceAtResult.?.sx, surfaceAtResult.?.sy);
server.seat.wlr_seat.pointerNotifyMotion(time_msec, surfaceAtResult.?.sx, surfaceAtResult.?.sy);
},
.drag => {
// @hook PointerDragMotion
// @param button string // TODO Translate a button to a string or smth
// @param state string - "pressed" or "released"
// @param time_msecs number // TODO idk what the hell msecs is
server.events.exec("PointerDragMotion", .{
self.wlr_cursor.x,
self.wlr_cursor.y,
self.drag.start_x,
self.drag.start_y,
self.drag.view.?.id,
self.drag.view_offset_x,
self.drag.view_offset_y
});
} else {
// This may not be necessary, remove if no bugs
server.seat.wlr_seat.pointerClearFocus();
}
}
}
@ -157,45 +158,49 @@ fn handleButton(
switch (event.state) {
.pressed => {
cursor.drag.start_x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x));
cursor.drag.start_y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y));
if(server.seat.focused_surface) |fs| {
cursor.mode = .drag;
cursor.drag = .{
.event_code = event.button,
.start = .{
.x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)),
.y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y))
},
.view = null
};
// Keep track of where the drag started
if(server.seat.focused_surface) |fs| {
if(fs == .view) {
cursor.drag.view = fs.view;
cursor.drag.view_offset_x = cursor.drag.start_x - fs.view.scene_tree.node.x;
cursor.drag.view_offset_y = cursor.drag.start_y - fs.view.scene_tree.node.y;
cursor.drag.?.view = .{
.view = fs.view,
.dims = .{
.width = fs.view.xdg_toplevel.base.geometry.width,
.height = fs.view.xdg_toplevel.base.geometry.height
},
.offset = .{
.x = cursor.drag.?.start.x - fs.view.scene_tree.node.x,
.y = cursor.drag.?.start.y - fs.view.scene_tree.node.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")) {
// if(fs == .view) {
// cursor.mode = .resize;
// _ = fs.view.xdg_toplevel.setResizing(true);
// }
// }
}
},
.released => {
cursor.mode = .normal;
if(cursor.drag.view) |view| {
_ = view.xdg_toplevel.setResizing(false);
}
// How do we do this on the lua side
// if(cursor.drag.view) |view| {
// _ = view.xdg_toplevel.setResizing(false);
// }
cursor.drag.view = null;
cursor.drag.view_offset_x = null;
cursor.drag.view_offset_y = null;
cursor.drag.?.view = null;
},
else => {
std.log.err("Invalid/Unimplemented pointer button event type", .{});
}
}
var handled = false;
const modifiers = server.seat.keyboard_group.keyboard.getModifiers();
@ -205,13 +210,23 @@ fn handleButton(
.pressed => {
// Only make callback if a callback function exists
if(map.options.lua_press_ref_idx > 0) {
map.callback(.press);
map.callback(.press, .{
.{
.x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)),
.y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y))
},
});
handled = true;
}
},
.released => {
if(map.options.lua_press_ref_idx > 0) {
map.callback(.release);
map.callback(.release, .{
.{
.x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)),
.y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y))
},
});
handled = true;
}
},
@ -227,8 +242,8 @@ fn handleButton(
}
fn handleHoldBegin(
listener: *wl.Listener(*wlr.Pointer.event.HoldBegin),
event: *wlr.Pointer.event.HoldBegin
listener: *wl.Listener(*wlr.Pointer.event.HoldBegin),
event: *wlr.Pointer.event.HoldBegin
) void {
_ = listener;
_ = event;
@ -236,8 +251,8 @@ event: *wlr.Pointer.event.HoldBegin
}
fn handleHoldEnd(
listener: *wl.Listener(*wlr.Pointer.event.HoldEnd),
event: *wlr.Pointer.event.HoldEnd
listener: *wl.Listener(*wlr.Pointer.event.HoldEnd),
event: *wlr.Pointer.event.HoldEnd
) void {
_ = listener;
_ = event;
@ -245,8 +260,8 @@ event: *wlr.Pointer.event.HoldEnd
}
fn handleAxis(
_: *wl.Listener(*wlr.Pointer.event.Axis),
event: *wlr.Pointer.event.Axis,
_: *wl.Listener(*wlr.Pointer.event.Axis),
event: *wlr.Pointer.event.Axis,
) void {
server.seat.wlr_seat.pointerNotifyAxis(
event.time_msec,
@ -255,7 +270,7 @@ event: *wlr.Pointer.event.Axis,
event.delta_discrete,
event.source,
event.relative_direction,
);
);
}
fn handleFrame(_: *wl.Listener(*wlr.Cursor), _: *wlr.Cursor) void {

View file

@ -24,7 +24,13 @@ options: struct {
pub const MousemapState = enum { press, drag, release };
pub fn callback(self: *const Mousemap, state: MousemapState) void {
pub fn callback(self: *const Mousemap, state: MousemapState, args: anytype) void {
const ArgsType = @TypeOf(args);
const args_type_info = @typeInfo(ArgsType);
if (args_type_info != .@"struct") {
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
}
const lua_ref_idx = switch(state) {
.press => self.options.lua_press_ref_idx,
.release => self.options.lua_release_ref_idx,
@ -38,7 +44,14 @@ pub fn callback(self: *const Mousemap, state: MousemapState) void {
return;
}
Lua.state.protectedCall(.{ .args = 0, .results = 0 }) catch {
// allow passing any arguments to the lua hook
var i: u8 = 0;
inline for (args, 1..) |field, k| {
try Lua.state.pushAny(field);
i = k;
}
Lua.state.protectedCall(.{ .args = i, .results = 0 }) catch {
RemoteLua.sendNewLogEntry(Lua.state.toString(-1) catch unreachable);
};
Lua.state.pop(-1);