Refactor keybindings to be runtime defined.

This commit is contained in:
Isaac Freund 2020-04-07 21:48:56 +02:00
parent 15f97314a9
commit fa65333789
No known key found for this signature in database
GPG key ID: 86DED400DDFD7A11
8 changed files with 116 additions and 68 deletions

View file

@ -4,23 +4,33 @@ const c = @import("c.zig");
const Server = @import("server.zig").Server;
const ViewStack = @import("view_stack.zig").ViewStack;
pub const Arg = union {
int: i32,
uint: u32,
float: f64,
none: void,
};
pub const Command = fn (server: *Server, arg: Arg) void;
/// Exit the compositor, terminating the wayland session.
pub fn exitCompositor(server: *Server) void {
pub fn exitCompositor(server: *Server, arg: Arg) void {
c.wl_display_terminate(server.wl_display);
}
/// Shift focus to the next visible view, wrapping if needed.
pub fn focusNextView(server: *Server) void {
pub fn focusNextView(server: *Server, arg: Arg) void {
server.root.focusNextView();
}
/// Shift focus to the previous visible view, wrapping if needed.
pub fn focusPrevView(server: *Server) void {
pub fn focusPrevView(server: *Server, arg: Arg) void {
server.root.focusPrevView();
}
/// Modify the number of master views
pub fn modifyMasterCount(server: *Server, delta: i32) void {
pub fn modifyMasterCount(server: *Server, arg: Arg) void {
const delta = arg.int;
server.root.master_count = @intCast(u32, std.math.max(
0,
@intCast(i32, server.root.master_count) + delta,
@ -29,7 +39,8 @@ pub fn modifyMasterCount(server: *Server, delta: i32) void {
}
/// Modify the percent of the width of the screen that the master views occupy.
pub fn modifyMasterFactor(server: *Server, delta: f64) void {
pub fn modifyMasterFactor(server: *Server, arg: Arg) void {
const delta = arg.float;
const new_master_factor = std.math.min(
std.math.max(server.root.master_factor + delta, 0.05),
0.95,
@ -42,7 +53,7 @@ pub fn modifyMasterFactor(server: *Server, delta: f64) void {
/// Bump the focused view to the top of the stack.
/// TODO: if the top of the stack is focused, bump the next visible view.
pub fn zoom(server: *Server) void {
pub fn zoom(server: *Server, arg: Arg) void {
if (server.root.focused_view) |current_focus| {
const node = @fieldParentPtr(ViewStack.Node, "view", current_focus);
if (node != server.root.views.first) {
@ -54,13 +65,15 @@ pub fn zoom(server: *Server) void {
}
/// Switch focus to the passed tags.
pub fn focusTags(server: *Server, tags: u32) void {
pub fn focusTags(server: *Server, arg: Arg) void {
const tags = arg.uint;
server.root.pending_focused_tags = tags;
server.root.arrange();
}
/// Set the tags of the focused view.
pub fn setFocusedViewTags(server: *Server, tags: u32) void {
pub fn setFocusedViewTags(server: *Server, arg: Arg) void {
const tags = arg.uint;
if (server.root.focused_view) |view| {
if (view.current_tags != tags) {
view.pending_tags = tags;
@ -71,7 +84,7 @@ pub fn setFocusedViewTags(server: *Server, tags: u32) void {
/// Spawn a program.
/// TODO: make this take a program as a paramter and spawn that
pub fn spawn(server: *Server) void {
pub fn spawn(server: *Server, arg: Arg) void {
const argv = [_][]const u8{ "/bin/sh", "-c", "alacritty" };
const child = std.ChildProcess.init(&argv, std.heap.c_allocator) catch unreachable;
std.ChildProcess.spawn(child) catch unreachable;

62
src/config.zig Normal file
View file

@ -0,0 +1,62 @@
const std = @import("std");
const c = @import("c.zig");
const command = @import("command.zig");
const Server = @import("server.zig");
pub const Config = struct {
const Self = @This();
/// Width of borders in pixels
border_width: u32 = 2,
/// Amount of view padding in pixels
view_padding: u32 = 10,
const Keybind = struct {
keysym: c.xkb_keysym_t,
modifiers: u32,
command: command.Command,
arg: command.Arg,
};
/// All user-defined keybindings
keybinds: std.ArrayList(Keybind),
pub fn init(self: *Self, allocator: *std.mem.Allocator) !void {
self.border_width = 2;
self.view_padding = 10;
self.keybinds = std.ArrayList(Keybind).init(allocator);
const mod = c.WLR_MODIFIER_LOGO;
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_e, .modifiers = mod, .command = command.exitCompositor, .arg = .{ .none = {} } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_j, .modifiers = mod, .command = command.focusNextView, .arg = .{ .none = {} } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_k, .modifiers = mod, .command = command.focusPrevView, .arg = .{ .none = {} } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_h, .modifiers = mod, .command = command.modifyMasterFactor, .arg = .{ .float = 0.05 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_l, .modifiers = mod, .command = command.modifyMasterFactor, .arg = .{ .float = -0.05 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_Return, .modifiers = mod, .command = command.zoom, .arg = .{ .none = {} } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_1, .modifiers = mod, .command = command.focusTags, .arg = .{ .uint = 1 << 0 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_2, .modifiers = mod, .command = command.focusTags, .arg = .{ .uint = 1 << 1 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_3, .modifiers = mod, .command = command.focusTags, .arg = .{ .uint = 1 << 2 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_4, .modifiers = mod, .command = command.focusTags, .arg = .{ .uint = 1 << 3 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_5, .modifiers = mod, .command = command.focusTags, .arg = .{ .uint = 1 << 4 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_6, .modifiers = mod, .command = command.focusTags, .arg = .{ .uint = 1 << 5 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_h, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.modifyMasterCount, .arg = .{ .int = 1 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_l, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.modifyMasterCount, .arg = .{ .int = -1 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_Return, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.spawn, .arg = .{ .none = {} } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_1, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.setFocusedViewTags, .arg = .{ .uint = 1 << 0 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_2, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.setFocusedViewTags, .arg = .{ .uint = 1 << 1 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_3, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.setFocusedViewTags, .arg = .{ .uint = 1 << 2 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_4, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.setFocusedViewTags, .arg = .{ .uint = 1 << 3 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_5, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.setFocusedViewTags, .arg = .{ .uint = 1 << 4 } });
try self.keybinds.append(Keybind{ .keysym = c.XKB_KEY_6, .modifiers = mod | c.WLR_MODIFIER_SHIFT, .command = command.setFocusedViewTags, .arg = .{ .uint = 1 << 5 } });
}
};

View file

@ -112,7 +112,7 @@ pub const Keyboard = struct {
if (keyboard.handleBuiltinKeybind(translated_keysyms.?[i])) {
handled = true;
break;
} else if (keyboard.seat.server.handleKeybinding(translated_keysyms.?[i], modifiers)) {
} else if (keyboard.seat.handleKeybinding(translated_keysyms.?[i], modifiers)) {
handled = true;
break;
}
@ -123,7 +123,7 @@ pub const Keyboard = struct {
if (keyboard.handleBuiltinKeybind(raw_keysyms.?[i])) {
handled = true;
break;
} else if (keyboard.seat.server.handleKeybinding(raw_keysyms.?[i], modifiers)) {
} else if (keyboard.seat.handleKeybinding(raw_keysyms.?[i], modifiers)) {
handled = true;
break;
}

View file

@ -129,8 +129,8 @@ pub const Output = struct {
// If we have a stashed buffer, we are in the middle of a transaction
// and need to render that buffer until the transaction is complete.
if (view.stashed_buffer) |buffer| {
const border_width = view.root.border_width;
const view_padding = view.root.view_padding;
const border_width = view.root.server.config.border_width;
const view_padding = view.root.server.config.view_padding;
var box = c.wlr_box{
.x = view.current_box.x + @intCast(i32, border_width + view_padding),
.y = view.current_box.y + @intCast(i32, border_width + view_padding),
@ -194,11 +194,13 @@ pub const Output = struct {
return;
}
const border_width = view.root.server.config.border_width;
const view_padding = view.root.server.config.view_padding;
var box = c.wlr_box{
.x = @floatToInt(c_int, rdata.ox) + view.current_box.x + sx +
@intCast(c_int, view.root.border_width + view.root.view_padding),
@intCast(c_int, border_width + view_padding),
.y = @floatToInt(c_int, rdata.oy) + view.current_box.y + sy +
@intCast(c_int, view.root.border_width + view.root.view_padding),
@intCast(c_int, border_width + view_padding),
.width = surface.current.width,
.height = surface.current.height,
};
@ -229,8 +231,8 @@ pub const Output = struct {
[_]f32{ 0.57647059, 0.63137255, 0.63137255, 1.0 } // Solarized base1
else
[_]f32{ 0.34509804, 0.43137255, 0.45882353, 1.0 }; // Solarized base01
const border_width = self.root.border_width;
const view_padding = self.root.view_padding;
const border_width = self.root.server.config.border_width;
const view_padding = self.root.server.config.view_padding;
// left border
border.x = @floatToInt(c_int, ox) + view.current_box.x + @intCast(c_int, view_padding);

View file

@ -34,12 +34,6 @@ pub const Root = struct {
/// Percentage of the total screen that the master section takes up.
master_factor: f64,
/// Width of borders in pixels
border_width: u32,
/// Amount of view padding in pixels
view_padding: u32,
/// Number of pending configures sent in the current transaction.
/// A value of 0 means there is no current transaction.
pending_configures: u32,
@ -69,10 +63,6 @@ pub const Root = struct {
self.master_factor = 0.6;
self.border_width = 4;
self.view_padding = 10;
self.pending_configures = 0;
self.transaction_timer = null;

View file

@ -41,6 +41,19 @@ pub const Seat = struct {
self.cursor.destroy();
}
/// Handle any user-defined keybinding for the passed keysym and modifiers
/// Returns true if the key was handled
pub fn handleKeybinding(self: Self, keysym: c.xkb_keysym_t, modifiers: u32) bool {
for (self.server.config.keybinds.items) |keybind| {
if (modifiers == keybind.modifiers and keysym == keybind.keysym) {
// Execute the bound command
keybind.command(self.server, keybind.arg);
return true;
}
}
return false;
}
fn addKeyboard(self: *Self, device: *c.wlr_input_device) !void {
c.wlr_seat_set_keyboard(self.wlr_seat, device);

View file

@ -2,6 +2,7 @@ const std = @import("std");
const c = @import("c.zig");
const command = @import("command.zig");
const Config = @import("config.zig").Config;
const DecorationManager = @import("decoration_manager.zig").DecorationManager;
const Output = @import("output.zig").Output;
const Root = @import("root.zig").Root;
@ -25,6 +26,8 @@ pub const Server = struct {
root: Root,
seat: Seat,
config: Config,
listen_new_output: c.wl_listener,
listen_new_xdg_surface: c.wl_listener,
@ -73,6 +76,8 @@ pub const Server = struct {
try self.seat.init(self);
try self.config.init(self.allocator);
// Register our listeners for new outputs and xdg_surfaces.
self.listen_new_output.notify = handleNewOutput;
c.wl_signal_add(&self.wlr_backend.events.new_output, &self.listen_new_output);
@ -112,45 +117,6 @@ pub const Server = struct {
c.wl_display_run(self.wl_display);
}
/// Handle all compositor keybindings
/// Note: this is a hacky initial implementation for testing and will be rewritten eventually
pub fn handleKeybinding(self: *Self, sym: c.xkb_keysym_t, modifiers: u32) bool {
if (modifiers & @intCast(u32, c.WLR_MODIFIER_LOGO) == 0) {
return false;
}
if (modifiers & @intCast(u32, c.WLR_MODIFIER_SHIFT) != 0) {
switch (sym) {
c.XKB_KEY_H => command.modifyMasterCount(self, 1),
c.XKB_KEY_L => command.modifyMasterCount(self, -1),
c.XKB_KEY_Return => command.spawn(self),
c.XKB_KEY_1 => command.setFocusedViewTags(self, 1 << 0),
c.XKB_KEY_2 => command.setFocusedViewTags(self, 1 << 1),
c.XKB_KEY_3 => command.setFocusedViewTags(self, 1 << 2),
c.XKB_KEY_4 => command.setFocusedViewTags(self, 1 << 3),
c.XKB_KEY_5 => command.setFocusedViewTags(self, 1 << 4),
c.XKB_KEY_6 => command.setFocusedViewTags(self, 1 << 5),
else => return false,
}
} else {
switch (sym) {
c.XKB_KEY_e => command.exitCompositor(self),
c.XKB_KEY_j => command.focusNextView(self),
c.XKB_KEY_k => command.focusPrevView(self),
c.XKB_KEY_h => command.modifyMasterFactor(self, 0.05),
c.XKB_KEY_l => command.modifyMasterFactor(self, -0.05),
c.XKB_KEY_Return => command.zoom(self),
c.XKB_KEY_1 => command.focusTags(self, 1 << 0),
c.XKB_KEY_2 => command.focusTags(self, 1 << 1),
c.XKB_KEY_3 => command.focusTags(self, 1 << 2),
c.XKB_KEY_4 => command.focusTags(self, 1 << 3),
c.XKB_KEY_5 => command.focusTags(self, 1 << 4),
c.XKB_KEY_6 => command.focusTags(self, 1 << 5),
else => return false,
}
}
return true;
}
fn handleNewOutput(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
const server = @fieldParentPtr(Server, "listen_new_output", listener.?);
const wlr_output = @ptrCast(*c.wlr_output, @alignCast(@alignOf(*c.wlr_output), data));

View file

@ -91,10 +91,12 @@ pub const View = struct {
pub fn configurePending(self: *Self) void {
if (self.pending_box) |pending_box| {
const border_width = self.root.server.config.border_width;
const view_padding = self.root.server.config.view_padding;
self.pending_serial = c.wlr_xdg_toplevel_set_size(
self.wlr_xdg_surface,
pending_box.width - self.root.border_width * 2 - self.root.view_padding * 2,
pending_box.height - self.root.border_width * 2 - self.root.view_padding * 2,
pending_box.width - border_width * 2 - view_padding * 2,
pending_box.height - border_width * 2 - view_padding * 2,
);
} else {
// TODO: log warning