Allow floating views to appear at the mouse
This commit is contained in:
		| @ -1,6 +1,6 @@ | ||||
| function __riverctl_completion () | ||||
| { | ||||
| 	local rule_actions="float no-float ssd csd tags output position dimensions fullscreen no-fullscreen" | ||||
| 	local rule_actions="float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen" | ||||
| 	if [ "${COMP_CWORD}" -eq 1 ] | ||||
| 	then | ||||
| 		OPTS=" \ | ||||
|  | ||||
| @ -89,7 +89,7 @@ complete -c riverctl -n '__fish_seen_subcommand_from set-cursor-warp' | ||||
| complete -c riverctl -n '__fish_seen_subcommand_from list-rules'                  -n '__fish_riverctl_complete_arg 2' -a 'float ssd tags output position dimensions fullscreen' | ||||
|  | ||||
| # Options and subcommands for 'rule-add' and 'rule-del' | ||||
| set -l rule_actions float no-float ssd csd tags output position dimensions fullscreen no-fullscreen | ||||
| set -l rule_actions float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen | ||||
| 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 'test (math (count (commandline -opc)) % 2) -eq 0' -a "$rule_actions" | ||||
|  | ||||
| @ -202,7 +202,7 @@ _riverctl() | ||||
|                     # In case of a new rule added in river, we just need | ||||
|                     # to add it to the third option between '()', | ||||
|                     # i.e (float no-float <new-option>) | ||||
|                     _arguments '1: :(-app-id -title)' '2: : ' ':: :(float no-float ssd csd tags output 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)' | ||||
|                 ;; | ||||
|                 list-rules) _alternative 'arguments:args:(float ssd tags output position dimensions fullscreen)' ;; | ||||
|                 *) return 0 ;; | ||||
|  | ||||
| @ -298,9 +298,13 @@ matches everything while _\*\*_ and the empty string are invalid. | ||||
| 	  with make: _HP Inc._, model: _HP 22w_, and serial: _CNC93720WF_, the | ||||
| 	  identifier would be: _HP Inc. HP 22w CNC93720WF_. If the make, model, or | ||||
| 	  serial is unknown, the word "Unknown" is used instead. | ||||
| 	- *position*: Set the initial position of the view, clamping to the | ||||
| 	  bounds of the output. Requires x and y coordinates of the view as | ||||
| 	  arguments, both of which must be non-negative. Applies only to new views. | ||||
| 	- *position*: Set the initial position of the view, clamping to the bounds | ||||
| 	  of the output. Requires x and y coordinates of the view as arguments, both | ||||
| 	  of which must be non-negative. Applies only to new views. | ||||
|     - *relative-position*: Set the position of the view relative to | ||||
|       something. Requires the anchor and the x and y coordinates of the | ||||
| 	  view. The coordinates are either positive or negative numbers that are | ||||
| 	  relative to the anchor. Applies only to new views. | ||||
| 	- *dimensions*: Set the initial dimensions of the view, clamping to the | ||||
| 	  constraints of the view. Requires width and height of the view as | ||||
| 	  arguments, both of which must be non-negative. Applies only to new views. | ||||
|  | ||||
| @ -58,9 +58,15 @@ pub const HideCursorWhenTypingMode = enum { | ||||
|     enabled, | ||||
| }; | ||||
|  | ||||
| pub const Anchor = enum { | ||||
|     absolute, | ||||
|     mouse, | ||||
| }; | ||||
|  | ||||
| pub const Position = struct { | ||||
|     x: u31, | ||||
|     y: u31, | ||||
|     anchor: Anchor, | ||||
|     x: i31, | ||||
|     y: i31, | ||||
| }; | ||||
|  | ||||
| pub const Dimensions = struct { | ||||
|  | ||||
| @ -681,8 +681,18 @@ pub fn map(view: *View) !void { | ||||
|         server.input_manager.defaultSeat().focused_output; | ||||
|  | ||||
|     if (server.config.rules.position.match(view)) |position| { | ||||
|         view.pending.box.x = position.x; | ||||
|         view.pending.box.y = position.y; | ||||
|         var base_x: i31 = 0; | ||||
|         var base_y: i31 = 0; | ||||
|         switch (position.anchor) { | ||||
|             .absolute => {}, | ||||
|             .mouse => { | ||||
|                 const cursor = server.input_manager.defaultSeat().wlr_seat.pointer_state; | ||||
|                 base_x = @intCast(@as(i31, @intFromFloat(cursor.sx))); | ||||
|                 base_y = @intCast(@as(i31, @intFromFloat(cursor.sy))); | ||||
|             }, | ||||
|         } | ||||
|         view.pending.box.x = base_x + position.x; | ||||
|         view.pending.box.y = base_y + position.y; | ||||
|     } else if (output) |o| { | ||||
|         // Center the initial pending box on the output | ||||
|         view.pending.box.x = @divTrunc(@max(0, o.usable_box.width - view.pending.box.width), 2); | ||||
|  | ||||
| @ -26,6 +26,7 @@ const util = @import("../util.zig"); | ||||
| const Error = @import("../command.zig").Error; | ||||
| const Seat = @import("../Seat.zig"); | ||||
| const View = @import("../View.zig"); | ||||
| const Anchor = @import("../Config.zig").Anchor; | ||||
| const RuleGlobs = @import("../rule_list.zig").RuleGlobs; | ||||
|  | ||||
| const Action = enum { | ||||
| @ -36,6 +37,7 @@ const Action = enum { | ||||
|     tags, | ||||
|     output, | ||||
|     position, | ||||
|     @"relative-position", | ||||
|     dimensions, | ||||
|     fullscreen, | ||||
|     @"no-fullscreen", | ||||
| @ -59,6 +61,7 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void | ||||
|         .float, .@"no-float", .ssd, .csd, .fullscreen, .@"no-fullscreen", .tearing, .@"no-tearing" => 1, | ||||
|         .tags, .output => 2, | ||||
|         .position, .dimensions => 3, | ||||
|         .@"relative-position" => 4, | ||||
|     }; | ||||
|     if (result.args.len > positional_arguments_count) return Error.TooManyArguments; | ||||
|     if (result.args.len < positional_arguments_count) return Error.NotEnoughArguments; | ||||
| @ -112,14 +115,32 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void | ||||
|             }); | ||||
|         }, | ||||
|         .position => { | ||||
|             const x = try fmt.parseInt(u31, result.args[1], 10); | ||||
|             const y = try fmt.parseInt(u31, result.args[2], 10); | ||||
|             const x = try fmt.parseInt(i31, result.args[1], 10); | ||||
|             const y = try fmt.parseInt(i31, result.args[2], 10); | ||||
|             if (x < 0 or y < 0) return Error.OutOfBounds; | ||||
|             try server.config.rules.position.add(.{ | ||||
|                 .app_id_glob = app_id_glob, | ||||
|                 .title_glob = title_glob, | ||||
|                 .value = .{ | ||||
|                     .x = x, | ||||
|                     .y = y, | ||||
|                     .anchor = .absolute, | ||||
|                     .x = @intCast(x), | ||||
|                     .y = @intCast(y), | ||||
|                 }, | ||||
|             }); | ||||
|         }, | ||||
|         .@"relative-position" => { | ||||
|             const anchor = std.meta.stringToEnum(Anchor, result.args[1]) orelse return Error.UnknownOption; | ||||
|             // force the use of the normal position command for absolute positions | ||||
|             if (anchor == .absolute) return Error.UnknownOption; | ||||
|             const x_off = try fmt.parseInt(i31, result.args[2], 10); | ||||
|             const y_off = try fmt.parseInt(i31, result.args[3], 10); | ||||
|             try server.config.rules.position.add(.{ | ||||
|                 .app_id_glob = app_id_glob, | ||||
|                 .title_glob = title_glob, | ||||
|                 .value = .{ | ||||
|                     .anchor = anchor, | ||||
|                     .x = x_off, | ||||
|                     .y = y_off, | ||||
|                 }, | ||||
|             }); | ||||
|         }, | ||||
| @ -179,7 +200,7 @@ pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void | ||||
|                 util.gpa.free(output_rule); | ||||
|             } | ||||
|         }, | ||||
|         .position => { | ||||
|         .position, .@"relative-position" => { | ||||
|             _ = server.config.rules.position.del(rule); | ||||
|         }, | ||||
|         .dimensions => { | ||||
| @ -278,7 +299,7 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error! | ||||
|             for (server.config.rules.position.rules.items) |rule| { | ||||
|                 try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer); | ||||
|                 try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer); | ||||
|                 try writer.print("{d},{d}\n", .{ rule.value.x, rule.value.y }); | ||||
|                 try writer.print("{s},{d},{d}", .{ @tagName(rule.value.anchor), rule.value.x, rule.value.y }); | ||||
|             } | ||||
|         }, | ||||
|         .dimensions => { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user