Implement passthrough mode
When active, key presses are passed directly to the focused window. I've mostly used this for testing beansprout, but I'm sure there are other uses.
This commit is contained in:
parent
5f4d80f313
commit
1b37ab7afd
4 changed files with 50 additions and 12 deletions
|
|
@ -291,6 +291,7 @@ Full command reference:
|
|||
| `toggle_output_tags` | tags (u32 bitmask) | Toggle a tag on the focused output |
|
||||
| `toggle_window_tags` | tags (u32 bitmask) | Toggle a tag on the focused window |
|
||||
| `reload_config` | | Reload the config file |
|
||||
| `toggle_passthrough` | | Toggle passthrough mode to disable keybinds |
|
||||
|
||||
### Tag Binds
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,8 @@ fn manage(wm: *WindowManager) void {
|
|||
wm.initialize();
|
||||
}
|
||||
|
||||
wm.context.xkb_bindings.manage();
|
||||
|
||||
// Adopt orphan windows before outputs manage so they're included
|
||||
// in calculateLayout() and window.manage() this cycle.
|
||||
if (wm.orphan_windows.first() != null) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ pub const Command = union(enum) {
|
|||
// Swap window position in stack
|
||||
swap_next,
|
||||
swap_prev,
|
||||
|
||||
// When passthrough is enabled, only keybinds set to toggle_passthrough are active
|
||||
toggle_passthrough,
|
||||
};
|
||||
|
||||
const XkbBinding = struct {
|
||||
|
|
@ -93,6 +96,9 @@ const XkbBinding = struct {
|
|||
|
||||
fn executeCommand(xkb_binding: *XkbBinding) void {
|
||||
const context = xkb_binding.context;
|
||||
|
||||
const first_seat = context.wm.seats.first() orelse null;
|
||||
|
||||
// TODO: Should I log.warn when commands return early?
|
||||
switch (xkb_binding.command) {
|
||||
.spawn => |cmd| {
|
||||
|
|
@ -108,8 +114,7 @@ const XkbBinding = struct {
|
|||
.send_to_next_output => sendWindowToOutput(context, .next),
|
||||
.send_to_prev_output => sendWindowToOutput(context, .prev),
|
||||
.zoom => {
|
||||
const wm = context.wm;
|
||||
const seat = wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
const current_focus = if (seat.pending_manage.window) |pending_focus| blk: {
|
||||
switch (pending_focus) {
|
||||
.clear_focus => return,
|
||||
|
|
@ -150,7 +155,7 @@ const XkbBinding = struct {
|
|||
}
|
||||
},
|
||||
.toggle_float => {
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
const window = seat.focused_window orelse return;
|
||||
// Noop if the window is fullscreened
|
||||
if (window.fullscreen) return;
|
||||
|
|
@ -158,19 +163,19 @@ const XkbBinding = struct {
|
|||
context.wm.river_window_manager_v1.manageDirty();
|
||||
},
|
||||
.change_ratio => |diff| {
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
const output = seat.focused_output orelse return;
|
||||
output.pending_manage.primary_ratio = output.primary_ratio + diff;
|
||||
context.wm.river_window_manager_v1.manageDirty();
|
||||
},
|
||||
.increment_primary_count => {
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
const output = seat.focused_output orelse return;
|
||||
output.pending_manage.primary_count = output.primary_count + 1;
|
||||
context.wm.river_window_manager_v1.manageDirty();
|
||||
},
|
||||
.decrement_primary_count => {
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
const output = seat.focused_output orelse return;
|
||||
output.pending_manage.primary_count = output.primary_count - 1;
|
||||
context.wm.river_window_manager_v1.manageDirty();
|
||||
|
|
@ -192,26 +197,26 @@ const XkbBinding = struct {
|
|||
context.wm.river_window_manager_v1.manageDirty();
|
||||
},
|
||||
.toggle_fullscreen => {
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
const window = seat.focused_window orelse return;
|
||||
window.pending_manage.fullscreen = !window.fullscreen;
|
||||
context.wm.river_window_manager_v1.manageDirty();
|
||||
},
|
||||
.close_window => {
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
if (seat.focused_window) |window| {
|
||||
window.river_window_v1.close();
|
||||
}
|
||||
},
|
||||
.set_output_tags => |tags| {
|
||||
// TODO: Support multiple seats
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
const output = seat.focused_output orelse return;
|
||||
output.pending_manage.tags = tags;
|
||||
context.wm.river_window_manager_v1.manageDirty();
|
||||
},
|
||||
.set_window_tags => |tags| {
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
// TODO: I don't think pending_focus should ever be set at this point?
|
||||
// const window = seat.pending_manage.pending_focus orelse seat.focused;
|
||||
const window = seat.focused_window orelse return;
|
||||
|
|
@ -220,7 +225,7 @@ const XkbBinding = struct {
|
|||
},
|
||||
.toggle_output_tags => |tags| {
|
||||
// TODO: Support multiple seats
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
const output = seat.focused_output orelse return;
|
||||
const old_tags = output.pending_manage.tags orelse output.tags;
|
||||
const new_tags = old_tags ^ tags;
|
||||
|
|
@ -230,7 +235,7 @@ const XkbBinding = struct {
|
|||
}
|
||||
},
|
||||
.toggle_window_tags => |tags| {
|
||||
const seat = context.wm.seats.first() orelse return;
|
||||
const seat = first_seat orelse return;
|
||||
// TODO: I don't think pending_focus should ever be set at this point?
|
||||
// const window = seat.pending_manage.pending_focus orelse seat.focused;
|
||||
const window = seat.focused_window orelse return;
|
||||
|
|
@ -250,6 +255,10 @@ const XkbBinding = struct {
|
|||
.center_float => centerFloatingWindow(context),
|
||||
.swap_next => swapWindow(context, .next),
|
||||
.swap_prev => swapWindow(context, .prev),
|
||||
.toggle_passthrough => {
|
||||
context.xkb_bindings.pending_manage.toggle_passthrough = true;
|
||||
context.wm.river_window_manager_v1.manageDirty();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -406,8 +415,17 @@ context: *Context,
|
|||
|
||||
xkb_bindings_v1: *river.XkbBindingsV1,
|
||||
|
||||
/// When passthrough_active is true, keybinds (except for passthrough_toggle) are disabled.
|
||||
passthrough_active: bool = false,
|
||||
|
||||
bindings: wl.list.Head(XkbBinding, .link),
|
||||
|
||||
pending_manage: PendingManage = .{},
|
||||
|
||||
const PendingManage = struct {
|
||||
toggle_passthrough: bool = false,
|
||||
};
|
||||
|
||||
pub fn create(context: *Context, xkb_bindings_v1: *river.XkbBindingsV1) !*XkbBindings {
|
||||
const xkb_bindings = try utils.gpa.create(XkbBindings);
|
||||
errdefer utils.gpa.destroy(xkb_bindings);
|
||||
|
|
@ -445,6 +463,22 @@ pub fn addBinding(xkb_bindings: *XkbBindings, river_seat_v1: *river.SeatV1, keys
|
|||
xkb_binding_v1.enable();
|
||||
}
|
||||
|
||||
pub fn manage(xkb_bindings: *XkbBindings) void {
|
||||
defer xkb_bindings.pending_manage = .{};
|
||||
|
||||
if (xkb_bindings.pending_manage.toggle_passthrough) {
|
||||
xkb_bindings.passthrough_active = !xkb_bindings.passthrough_active;
|
||||
var it = xkb_bindings.bindings.iterator(.forward);
|
||||
while (it.next()) |binding| {
|
||||
if (xkb_bindings.passthrough_active) {
|
||||
binding.xkb_binding_v1.disable();
|
||||
} else {
|
||||
binding.xkb_binding_v1.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ pub fn load(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) !void {
|
|||
.swap_next,
|
||||
.swap_prev,
|
||||
.center_float,
|
||||
.toggle_passthrough,
|
||||
=> |cmd| {
|
||||
// None of these have arguments, just create the union and give it back
|
||||
break :sw @unionInit(XkbBindings.Command, @tagName(cmd), {});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue