Add cursor warp option
This commit is contained in:
parent
d66decb7c4
commit
5080f07724
@ -18,12 +18,11 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
/// Validate a glob, returning error.InvalidGlob if it is empty, "**" or has a
|
/// Validate a glob, returning error.InvalidGlob if is "**" or has a '*'
|
||||||
/// '*' at any position other than the first and/or last byte.
|
/// at any position other than the first and/or last byte.
|
||||||
pub fn validate(glob: []const u8) error{InvalidGlob}!void {
|
pub fn validate(glob: []const u8) error{InvalidGlob}!void {
|
||||||
switch (glob.len) {
|
switch (glob.len) {
|
||||||
0 => return error.InvalidGlob,
|
0, 1 => {},
|
||||||
1 => {},
|
|
||||||
2 => if (glob[0] == '*' and glob[1] == '*') return error.InvalidGlob,
|
2 => if (glob[0] == '*' and glob[1] == '*') return error.InvalidGlob,
|
||||||
else => if (mem.indexOfScalar(u8, glob[1 .. glob.len - 1], '*') != null) {
|
else => if (mem.indexOfScalar(u8, glob[1 .. glob.len - 1], '*') != null) {
|
||||||
return error.InvalidGlob;
|
return error.InvalidGlob;
|
||||||
@ -34,6 +33,7 @@ pub fn validate(glob: []const u8) error{InvalidGlob}!void {
|
|||||||
test validate {
|
test validate {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
|
try validate("");
|
||||||
try validate("*");
|
try validate("*");
|
||||||
try validate("a");
|
try validate("a");
|
||||||
try validate("*a");
|
try validate("*a");
|
||||||
@ -48,7 +48,6 @@ test validate {
|
|||||||
try validate("abc*");
|
try validate("abc*");
|
||||||
try validate("*abc*");
|
try validate("*abc*");
|
||||||
|
|
||||||
try testing.expectError(error.InvalidGlob, validate(""));
|
|
||||||
try testing.expectError(error.InvalidGlob, validate("**"));
|
try testing.expectError(error.InvalidGlob, validate("**"));
|
||||||
try testing.expectError(error.InvalidGlob, validate("***"));
|
try testing.expectError(error.InvalidGlob, validate("***"));
|
||||||
try testing.expectError(error.InvalidGlob, validate("a*c"));
|
try testing.expectError(error.InvalidGlob, validate("a*c"));
|
||||||
@ -67,7 +66,9 @@ pub fn match(s: []const u8, glob: []const u8) bool {
|
|||||||
validate(glob) catch unreachable;
|
validate(glob) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glob.len == 1) {
|
if (glob.len == 0) {
|
||||||
|
return s.len == 0;
|
||||||
|
} else if (glob.len == 1) {
|
||||||
return glob[0] == '*' or mem.eql(u8, s, glob);
|
return glob[0] == '*' or mem.eql(u8, s, glob);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +90,9 @@ test match {
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
try testing.expect(match("", "*"));
|
try testing.expect(match("", "*"));
|
||||||
|
try testing.expect(match("", ""));
|
||||||
|
try testing.expect(!match("a", ""));
|
||||||
|
try testing.expect(!match("", "a"));
|
||||||
|
|
||||||
try testing.expect(match("a", "*"));
|
try testing.expect(match("a", "*"));
|
||||||
try testing.expect(match("a", "*a*"));
|
try testing.expect(match("a", "*a*"));
|
||||||
@ -165,8 +169,10 @@ pub fn order(a: []const u8, b: []const u8) std.math.Order {
|
|||||||
return .lt;
|
return .lt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const count_a = @as(u2, @intFromBool(a[0] == '*')) + @intFromBool(a[a.len - 1] == '*');
|
const count_a = if (a.len != 0) @as(u2, @intFromBool(a[0] == '*')) +
|
||||||
const count_b = @as(u2, @intFromBool(b[0] == '*')) + @intFromBool(b[b.len - 1] == '*');
|
@intFromBool(a[a.len - 1] == '*') else 0;
|
||||||
|
const count_b = if (b.len != 0) @as(u2, @intFromBool(b[0] == '*')) +
|
||||||
|
@intFromBool(b[b.len - 1] == '*') else 0;
|
||||||
|
|
||||||
if (count_a == 0 and count_b == 0) {
|
if (count_a == 0 and count_b == 0) {
|
||||||
return .eq;
|
return .eq;
|
||||||
@ -182,6 +188,7 @@ test order {
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const Order = std.math.Order;
|
const Order = std.math.Order;
|
||||||
|
|
||||||
|
try testing.expectEqual(Order.eq, order("", ""));
|
||||||
try testing.expectEqual(Order.eq, order("*", "*"));
|
try testing.expectEqual(Order.eq, order("*", "*"));
|
||||||
try testing.expectEqual(Order.eq, order("*a*", "*b*"));
|
try testing.expectEqual(Order.eq, order("*a*", "*b*"));
|
||||||
try testing.expectEqual(Order.eq, order("a*", "*b"));
|
try testing.expectEqual(Order.eq, order("a*", "*b"));
|
||||||
@ -204,6 +211,7 @@ test order {
|
|||||||
"bababab",
|
"bababab",
|
||||||
"b",
|
"b",
|
||||||
"a",
|
"a",
|
||||||
|
"",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (descending, 0..) |a, i| {
|
for (descending, 0..) |a, i| {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
function __riverctl_completion ()
|
function __riverctl_completion ()
|
||||||
{
|
{
|
||||||
local rule_actions="float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen"
|
local rule_actions="float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen warp no-warp"
|
||||||
if [ "${COMP_CWORD}" -eq 1 ]
|
if [ "${COMP_CWORD}" -eq 1 ]
|
||||||
then
|
then
|
||||||
OPTS=" \
|
OPTS=" \
|
||||||
|
@ -91,10 +91,10 @@ complete -c riverctl -n '__fish_seen_subcommand_from default-attach-mode'
|
|||||||
complete -c riverctl -n '__fish_seen_subcommand_from output-attach-mode' -n '__fish_riverctl_complete_arg 2' -a 'top bottom above below after'
|
complete -c riverctl -n '__fish_seen_subcommand_from output-attach-mode' -n '__fish_riverctl_complete_arg 2' -a 'top bottom above below after'
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from focus-follows-cursor' -n '__fish_riverctl_complete_arg 2' -a 'disabled normal always'
|
complete -c riverctl -n '__fish_seen_subcommand_from focus-follows-cursor' -n '__fish_riverctl_complete_arg 2' -a 'disabled normal always'
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from set-cursor-warp' -n '__fish_riverctl_complete_arg 2' -a 'disabled on-output-change on-focus-change'
|
complete -c riverctl -n '__fish_seen_subcommand_from set-cursor-warp' -n '__fish_riverctl_complete_arg 2' -a 'disabled on-output-change on-focus-change'
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from list-rules' -n '__fish_riverctl_complete_arg 2' -a 'float ssd tags output position dimensions fullscreen'
|
complete -c riverctl -n '__fish_seen_subcommand_from list-rules' -n '__fish_riverctl_complete_arg 2' -a 'float ssd tags output position dimensions fullscreen warp'
|
||||||
|
|
||||||
# Options and subcommands for 'rule-add' and 'rule-del'
|
# Options and subcommands for 'rule-add' and 'rule-del'
|
||||||
set -l rule_actions float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen
|
set -l rule_actions float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen warp no-warp
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o app-id' -o 'app-id' -r
|
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o app-id' -o 'app-id' -r
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o title' -o 'title' -r
|
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o title' -o 'title' -r
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'test (math (count (commandline -opc)) % 2) -eq 0' -a "$rule_actions"
|
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'test (math (count (commandline -opc)) % 2) -eq 0' -a "$rule_actions"
|
||||||
|
@ -207,9 +207,9 @@ _riverctl()
|
|||||||
# In case of a new rule added in river, we just need
|
# In case of a new rule added in river, we just need
|
||||||
# to add it to the third option between '()',
|
# to add it to the third option between '()',
|
||||||
# i.e (float no-float <new-option>)
|
# i.e (float no-float <new-option>)
|
||||||
_arguments '1: :(-app-id -title)' '2: : ' ':: :(float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen)'
|
_arguments '1: :(-app-id -title)' '2: : ' ':: :(float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen warp no-warp)'
|
||||||
;;
|
;;
|
||||||
list-rules) _alternative 'arguments:args:(float ssd tags output position dimensions fullscreen)' ;;
|
list-rules) _alternative 'arguments:args:(float ssd tags output position dimensions fullscreen warp)' ;;
|
||||||
*) return 0 ;;
|
*) return 0 ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
@ -315,12 +315,16 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
view's preference. Applies to new and existing views.
|
view's preference. Applies to new and existing views.
|
||||||
- *no-tearing*: Disable tearing for the view regardless of the view's
|
- *no-tearing*: Disable tearing for the view regardless of the view's
|
||||||
preference. Applies to new and existing views.
|
preference. Applies to new and existing views.
|
||||||
|
- *warp*: Always warp the cursor when switching to this view, regardless of
|
||||||
|
the _set-cursor-warp_ setting. Applies to new and existing views.
|
||||||
|
- *no-warp*: Never warp the cursor when switching to this view, regardless
|
||||||
|
of the _set-cursor-warp_ setting. Applies to new and existing views.
|
||||||
|
|
||||||
Both *float* and *no-float* rules are added to the same list,
|
Both *float* and *no-float* rules are added to the same list,
|
||||||
which means that adding a *no-float* rule with the same arguments
|
which means that adding a *no-float* rule with the same arguments
|
||||||
as a *float* rule will overwrite it. The same holds for *ssd* and
|
as a *float* rule will overwrite it. The same holds for *ssd* and
|
||||||
*csd*, *fullscreen* and *no-fullscreen*, *tearing* and
|
*csd*, *fullscreen* and *no-fullscreen*, *tearing* and
|
||||||
*no-tearing* rules.
|
*no-tearing*, *warp* and *no-warp* rules.
|
||||||
|
|
||||||
If multiple rules in a list match a given view the most specific
|
If multiple rules in a list match a given view the most specific
|
||||||
rule will be applied. For example with the following rules
|
rule will be applied. For example with the following rules
|
||||||
@ -348,7 +352,7 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
*rule-del* [*-app-id* _glob_|*-title* _glob_] _action_
|
*rule-del* [*-app-id* _glob_|*-title* _glob_] _action_
|
||||||
Delete a rule created using *rule-add* with the given arguments.
|
Delete a rule created using *rule-add* with the given arguments.
|
||||||
|
|
||||||
*list-rules* *float*|*ssd*|*tags*|*position*|*dimensions*|*fullscreen*
|
*list-rules* *float*|*ssd*|*tags*|*position*|*dimensions*|*fullscreen*|*warp*
|
||||||
Print the specified rule list. The output is ordered from most specific
|
Print the specified rule list. The output is ordered from most specific
|
||||||
to least specific, the same order in which views are checked against
|
to least specific, the same order in which views are checked against
|
||||||
when searching for a match. Only the first matching rule in the list
|
when searching for a match. Only the first matching rule in the list
|
||||||
|
@ -108,6 +108,7 @@ rules: struct {
|
|||||||
dimensions: RuleList(Dimensions) = .{},
|
dimensions: RuleList(Dimensions) = .{},
|
||||||
fullscreen: RuleList(bool) = .{},
|
fullscreen: RuleList(bool) = .{},
|
||||||
tearing: RuleList(bool) = .{},
|
tearing: RuleList(bool) = .{},
|
||||||
|
warp: RuleList(bool) = .{},
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
/// The selected focus_follows_cursor mode
|
/// The selected focus_follows_cursor mode
|
||||||
@ -192,6 +193,7 @@ pub fn deinit(config: *Config) void {
|
|||||||
config.rules.position.deinit();
|
config.rules.position.deinit();
|
||||||
config.rules.dimensions.deinit();
|
config.rules.dimensions.deinit();
|
||||||
config.rules.fullscreen.deinit();
|
config.rules.fullscreen.deinit();
|
||||||
|
config.rules.warp.deinit();
|
||||||
|
|
||||||
util.gpa.free(config.default_layout_namespace);
|
util.gpa.free(config.default_layout_namespace);
|
||||||
|
|
||||||
|
@ -1178,10 +1178,18 @@ fn warp(cursor: *Cursor) void {
|
|||||||
|
|
||||||
const focused_output = cursor.seat.focused_output orelse return;
|
const focused_output = cursor.seat.focused_output orelse return;
|
||||||
|
|
||||||
|
var mode = server.config.warp_cursor;
|
||||||
|
if (cursor.seat.focused == .view) {
|
||||||
|
const view = cursor.seat.focused.view;
|
||||||
|
if (server.config.rules.warp.match(view)) |w| {
|
||||||
|
mode = if (w) .@"on-focus-change" else .disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Warp pointer to center of the focused view/output (In layout coordinates) if enabled.
|
// Warp pointer to center of the focused view/output (In layout coordinates) if enabled.
|
||||||
var output_layout_box: wlr.Box = undefined;
|
var output_layout_box: wlr.Box = undefined;
|
||||||
server.root.output_layout.getBox(focused_output.wlr_output, &output_layout_box);
|
server.root.output_layout.getBox(focused_output.wlr_output, &output_layout_box);
|
||||||
const target_box = switch (server.config.warp_cursor) {
|
const target_box = switch (mode) {
|
||||||
.disabled => return,
|
.disabled => return,
|
||||||
.@"on-output-change" => output_layout_box,
|
.@"on-output-change" => output_layout_box,
|
||||||
.@"on-focus-change" => switch (cursor.seat.focused) {
|
.@"on-focus-change" => switch (cursor.seat.focused) {
|
||||||
|
@ -42,6 +42,8 @@ const Action = enum {
|
|||||||
@"no-fullscreen",
|
@"no-fullscreen",
|
||||||
tearing,
|
tearing,
|
||||||
@"no-tearing",
|
@"no-tearing",
|
||||||
|
warp,
|
||||||
|
@"no-warp",
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
|
pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
|
||||||
@ -57,7 +59,7 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption;
|
const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption;
|
||||||
|
|
||||||
const positional_arguments_count: u8 = switch (action) {
|
const positional_arguments_count: u8 = switch (action) {
|
||||||
.float, .@"no-float", .ssd, .csd, .fullscreen, .@"no-fullscreen", .tearing, .@"no-tearing" => 1,
|
.float, .@"no-float", .ssd, .csd, .fullscreen, .@"no-fullscreen", .tearing, .@"no-tearing", .warp, .@"no-warp" => 1,
|
||||||
.tags, .output => 2,
|
.tags, .output => 2,
|
||||||
.position, .dimensions => 3,
|
.position, .dimensions => 3,
|
||||||
.@"relative-position" => 4,
|
.@"relative-position" => 4,
|
||||||
@ -162,6 +164,13 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
.value = (action == .fullscreen),
|
.value = (action == .fullscreen),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
.warp, .@"no-warp" => {
|
||||||
|
try server.config.rules.warp.add(.{
|
||||||
|
.app_id_glob = app_id_glob,
|
||||||
|
.title_glob = title_glob,
|
||||||
|
.value = (action == .warp),
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,6 +221,9 @@ pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
_ = server.config.rules.tearing.del(rule);
|
_ = server.config.rules.tearing.del(rule);
|
||||||
apply_tearing_rules();
|
apply_tearing_rules();
|
||||||
},
|
},
|
||||||
|
.warp, .@"no-warp" => {
|
||||||
|
_ = server.config.rules.warp.del(rule);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,6 +262,7 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
dimensions,
|
dimensions,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
tearing,
|
tearing,
|
||||||
|
warp,
|
||||||
}, args[1]) orelse return Error.UnknownOption;
|
}, args[1]) orelse return Error.UnknownOption;
|
||||||
const max_glob_len = switch (rule_list) {
|
const max_glob_len = switch (rule_list) {
|
||||||
inline else => |list| @field(server.config.rules, @tagName(list)).getMaxGlobLen(),
|
inline else => |list| @field(server.config.rules, @tagName(list)).getMaxGlobLen(),
|
||||||
@ -265,13 +278,14 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
try writer.writeAll("action\n");
|
try writer.writeAll("action\n");
|
||||||
|
|
||||||
switch (rule_list) {
|
switch (rule_list) {
|
||||||
inline .float, .ssd, .output, .fullscreen, .tearing => |list| {
|
inline .float, .ssd, .output, .fullscreen, .tearing, .warp => |list| {
|
||||||
const rules = switch (list) {
|
const rules = switch (list) {
|
||||||
.float => server.config.rules.float.rules.items,
|
.float => server.config.rules.float.rules.items,
|
||||||
.ssd => server.config.rules.ssd.rules.items,
|
.ssd => server.config.rules.ssd.rules.items,
|
||||||
.output => server.config.rules.output.rules.items,
|
.output => server.config.rules.output.rules.items,
|
||||||
.fullscreen => server.config.rules.fullscreen.rules.items,
|
.fullscreen => server.config.rules.fullscreen.rules.items,
|
||||||
.tearing => server.config.rules.tearing.rules.items,
|
.tearing => server.config.rules.tearing.rules.items,
|
||||||
|
.warp => server.config.rules.warp.rules.items,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
for (rules) |rule| {
|
for (rules) |rule| {
|
||||||
@ -283,6 +297,7 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
.output => rule.value,
|
.output => rule.value,
|
||||||
.fullscreen => if (rule.value) "fullscreen" else "no-fullscreen",
|
.fullscreen => if (rule.value) "fullscreen" else "no-fullscreen",
|
||||||
.tearing => if (rule.value) "tearing" else "no-tearing",
|
.tearing => if (rule.value) "tearing" else "no-tearing",
|
||||||
|
.warp => if (rule.value) "warp" else "no-warp",
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user