aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--completions/fish/riverctl.fish2
-rw-r--r--completions/zsh/_riverctl2
-rw-r--r--doc/riverctl.1.scd8
-rwxr-xr-xexample/init3
-rw-r--r--river/Cursor.zig4
-rw-r--r--river/PointerMapping.zig53
-rw-r--r--river/Seat.zig9
-rw-r--r--river/command/map.zig33
8 files changed, 89 insertions, 25 deletions
diff --git a/completions/fish/riverctl.fish b/completions/fish/riverctl.fish
index aabf99c..f24f32a 100644
--- a/completions/fish/riverctl.fish
+++ b/completions/fish/riverctl.fish
@@ -44,7 +44,7 @@ complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'send-to-previous
complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'declare-mode' -d 'Create a new mode'
complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'enter-mode' -d 'Switch to given mode if it exists'
complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'map' -d 'Run command when key is pressed while modifiers are held down and in the specified mode'
-complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'map-pointer' -d 'Move or resize views when button and modifers are held down while in the specified mode'
+complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'map-pointer' -d 'Move or resize views or run command when button and modifers are held down while in the specified mode'
complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'map-switch ' -d 'Run command when river receives a switch event in the specified mode'
complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'unmap' -d 'Remove the mapping defined by the arguments'
complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'unmap-pointer' -d 'Remove the pointer mapping defined by the arguments'
diff --git a/completions/zsh/_riverctl b/completions/zsh/_riverctl
index f5cd125..f303e5e 100644
--- a/completions/zsh/_riverctl
+++ b/completions/zsh/_riverctl
@@ -38,7 +38,7 @@ _riverctl_subcommands()
'declare-mode:Create a new mode'
'enter-mode:Switch to given mode if it exists'
'map:Run command when key is pressed while modifiers are held down and in the specified mode'
- 'map-pointer:Move or resize views when button and modifiers are held down while in the specified mode'
+ 'map-pointer:Move or resize views or run command when button and modifiers are held down while in the specified mode'
'map-switch:Run command when river receives a switch event in the specified mode'
'unmap:Remove the mapping defined by the arguments'
'unmap-pointer:Remove the pointer mapping defined by the arguments'
diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd
index d936308..b75fcae 100644
--- a/doc/riverctl.1.scd
+++ b/doc/riverctl.1.scd
@@ -212,9 +212,10 @@ A complete list may be found in _/usr/include/linux/input-event-codes.h_
- _key_: an XKB keysym name as described above
- _command_: any command that may be run with riverctl
-*map-pointer* _mode_ _modifiers_ _button_ _action_
- Move or resize views when _button_ and _modifiers_ are held down
- while in the specified _mode_.
+*map-pointer* _mode_ _modifiers_ _button_ _action_|_command_
+ Move or resize views or run _command_ when _button_ and _modifiers_ are held
+ down while in the specified _mode_. The view under the cursor will be
+ focused.
- _mode_: name of the mode for which to create the mapping
- _modifiers_: one or more of the modifiers listed above, separated
@@ -223,6 +224,7 @@ A complete list may be found in _/usr/include/linux/input-event-codes.h_
- _action_: one of the following values:
- move-view
- resize-view
+ - _command_: any command that may be run with riverctl
*map-switch* _mode_ *lid*|*tablet* _state_ _command_
Run _command_ when river receives a certain switch event.
diff --git a/example/init b/example/init
index b95a180..08b7cb1 100755
--- a/example/init
+++ b/example/init
@@ -71,6 +71,9 @@ riverctl map-pointer normal Super BTN_LEFT move-view
# Super + Right Mouse Button to resize views
riverctl map-pointer normal Super BTN_RIGHT resize-view
+# Super + Middle Mouse Button to toggle float
+riverctl map-pointer normal Super BTN_MIDDLE toggle-float
+
for i in $(seq 1 9)
do
tags=$((1 << ($i - 1)))
diff --git a/river/Cursor.zig b/river/Cursor.zig
index b09dbff..e99f8e3 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -528,6 +528,10 @@ fn handlePointerMapping(self: *Self, event: *wlr.Pointer.event.Button, view: *Vi
switch (mapping.action) {
.move => if (!fullscreen) self.enterMode(.move, view),
.resize => if (!fullscreen) self.enterMode(.resize, view),
+ .command => |args| {
+ self.seat.focus(view);
+ self.seat.runCommand(args);
+ },
}
break true;
}
diff --git a/river/PointerMapping.zig b/river/PointerMapping.zig
index 6a796bd..bae2cbd 100644
--- a/river/PointerMapping.zig
+++ b/river/PointerMapping.zig
@@ -14,13 +14,64 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
+const Self = @This();
+
+const std = @import("std");
const wlr = @import("wlroots");
-pub const Action = enum {
+const util = @import("util.zig");
+
+pub const ActionType = enum {
move,
resize,
+ command,
+};
+
+pub const Action = union(ActionType) {
+ move: void,
+ resize: void,
+ command: []const [:0]const u8,
};
event_code: u32,
modifiers: wlr.Keyboard.ModifierMask,
action: Action,
+arena: std.heap.ArenaAllocator,
+
+pub fn init(
+ event_code: u32,
+ modifiers: wlr.Keyboard.ModifierMask,
+ action_type: ActionType,
+ command_args: []const [:0]const u8,
+) !Self {
+ var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(util.gpa);
+ errdefer arena.deinit();
+
+ const action: Action = switch (action_type) {
+ ActionType.move => Action.move,
+ ActionType.resize => Action.resize,
+ ActionType.command => blk: {
+ const allocator: std.mem.Allocator = arena.allocator();
+
+ var owned_args = try std.ArrayListUnmanaged([:0]const u8).initCapacity(allocator, command_args.len);
+
+ for (command_args) |arg| {
+ const owned = try allocator.dupeZ(u8, arg);
+ owned_args.appendAssumeCapacity(owned);
+ }
+
+ break :blk Action{ .command = owned_args.toOwnedSlice(allocator) };
+ },
+ };
+
+ return Self{
+ .event_code = event_code,
+ .modifiers = modifiers,
+ .action = action,
+ .arena = arena,
+ };
+}
+
+pub fn deinit(self: *Self) void {
+ self.arena.deinit();
+}
diff --git a/river/Seat.zig b/river/Seat.zig
index 1a4b7e6..892ba14 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -434,7 +434,7 @@ pub fn handleSwitchMapping(
}
}
-fn runCommand(self: *Self, args: []const [:0]const u8) void {
+pub fn runCommand(self: *Self, args: []const [:0]const u8) void {
var out: ?[]const u8 = null;
defer if (out) |s| util.gpa.free(s);
command.run(self, args, &out) catch |err| {
@@ -442,7 +442,12 @@ fn runCommand(self: *Self, args: []const [:0]const u8) void {
command.Error.Other => out.?,
else => command.errToMsg(err),
};
- std.log.scoped(.command).err("{s}: {s}", .{ args[0], failure_message });
+
+ if (args.len == 0) {
+ std.log.scoped(.command).err("{s}", .{failure_message});
+ } else {
+ std.log.scoped(.command).err("{s}: {s}", .{ args[0], failure_message });
+ }
return;
};
if (out) |s| {
diff --git a/river/command/map.zig b/river/command/map.zig
index 4a33503..f321531 100644
--- a/river/command/map.zig
+++ b/river/command/map.zig
@@ -130,33 +130,31 @@ pub fn mapPointer(
out: *?[]const u8,
) Error!void {
if (args.len < 5) return Error.NotEnoughArguments;
- if (args.len > 5) return Error.TooManyArguments;
const mode_id = try modeNameToId(args[1], out);
const modifiers = try parseModifiers(args[2], out);
const event_code = try parseEventCode(args[3], out);
const action = if (mem.eql(u8, args[4], "move-view"))
- PointerMapping.Action.move
+ PointerMapping.ActionType.move
else if (mem.eql(u8, args[4], "resize-view"))
- PointerMapping.Action.resize
- else {
- out.* = try fmt.allocPrint(
- util.gpa,
- "invalid pointer action {s}, must be move-view or resize-view",
- .{args[4]},
- );
- return Error.Other;
- };
+ PointerMapping.ActionType.resize
+ else
+ PointerMapping.ActionType.command;
- const new = PointerMapping{
- .event_code = event_code,
- .modifiers = modifiers,
- .action = action,
- };
+ if (action != PointerMapping.ActionType.command and args.len > 5) return Error.TooManyArguments;
+
+ var new = try PointerMapping.init(
+ event_code,
+ modifiers,
+ action,
+ args[4..],
+ );
+ errdefer new.deinit();
const mode_pointer_mappings = &server.config.modes.items[mode_id].pointer_mappings;
if (pointerMappingExists(mode_pointer_mappings, modifiers, event_code)) |current| {
+ mode_pointer_mappings.items[current].deinit();
mode_pointer_mappings.items[current] = new;
} else {
try mode_pointer_mappings.append(util.gpa, new);
@@ -428,5 +426,6 @@ pub fn unmapPointer(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Err
const mode_pointer_mappings = &server.config.modes.items[mode_id].pointer_mappings;
const mapping_idx = pointerMappingExists(mode_pointer_mappings, modifiers, event_code) orelse return;
- _ = mode_pointer_mappings.swapRemove(mapping_idx);
+ var mapping = mode_pointer_mappings.swapRemove(mapping_idx);
+ mapping.deinit();
}