From 51e81910314331f696eb3dd9aefb4bf341feaf42 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 27 Mar 2020 02:05:57 +0100 Subject: [PATCH] Flesh out focus handling and add keybinds --- src/root.zig | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/server.zig | 13 ++----------- src/view.zig | 42 +++++++++++++++++++++++++----------------- 3 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/root.zig b/src/root.zig index e31d2e1..77efc27 100644 --- a/src/root.zig +++ b/src/root.zig @@ -19,13 +19,14 @@ pub const Root = struct { views: std.TailQueue(View), unmapped_views: std.TailQueue(View), + focused_view: ?*View, + // Number of pending configures sent in the current transaction. // A value of 0 means there is no current transaction. pending_count: u32, pub fn init(self: *Self, server: *Server) !void { self.server = server; - self.pending_count = 0; // Create an output layout, which a wlroots utility for working with an // arrangement of screens in a physical layout. @@ -34,8 +35,13 @@ pub const Root = struct { errdefer c.wlr_output_layout_destroy(self.wlr_output_layout); self.outputs = std.TailQueue(Output).init(); + self.views = std.TailQueue(View).init(); self.unmapped_views = std.TailQueue(View).init(); + + self.focused_view = null; + + self.pending_count = 0; } pub fn destroy(self: *Self) void { @@ -55,7 +61,7 @@ pub const Root = struct { self.unmapped_views.append(node); } - /// Finds the top most view under the output layout coordinates lx, ly + /// Finds the topmost view under the output layout coordinates lx, ly /// returns the view if found, and a pointer to the wlr_surface as well as the surface coordinates pub fn viewAt(self: *Self, lx: f64, ly: f64, surface: *?*c.wlr_surface, sx: *f64, sy: *f64) ?*View { var it = self.views.last; @@ -67,6 +73,46 @@ pub const Root = struct { return null; } + /// Focus the next view in the stack, wrapping if needed. Does nothing + /// if there is only one view in the stack. + pub fn focusNextView(self: *Self) void { + if (self.focused_view) |current_focus| { + // If there is a currently focused view, focus the next view in the stack. + const node = @fieldParentPtr(std.TailQueue(View).Node, "data", current_focus); + if (node.next) |next_node| { + const view = &next_node.data; + view.focus(view.wlr_xdg_surface.surface); + return; + } + } + // There is either no currently focused view or the last view in the + // stack is focused and we need to wrap. + if (self.views.first) |first_node| { + const view = &first_node.data; + view.focus(view.wlr_xdg_surface.surface); + } + } + + /// Focus the previous view in the stack, wrapping if needed. Does nothing + /// if there is only one view in the stack. + pub fn focusPrevView(self: *Self) void { + if (self.focused_view) |current_focus| { + // If there is a currently focused view, focus the previous view in the stack. + const node = @fieldParentPtr(std.TailQueue(View).Node, "data", current_focus); + if (node.prev) |prev_node| { + const view = &prev_node.data; + view.focus(view.wlr_xdg_surface.surface); + return; + } + } + // There is either no currently focused view or the first view in the + // stack is focused and we need to wrap. + if (self.views.last) |last_node| { + const view = &last_node.data; + view.focus(view.wlr_xdg_surface.surface); + } + } + pub fn arrange(self: *Self) void { if (self.views.len == 0) { return; diff --git a/src/server.zig b/src/server.zig index 2f027bd..209371d 100644 --- a/src/server.zig +++ b/src/server.zig @@ -109,17 +109,8 @@ pub const Server = struct { // This function assumes the proper modifier is held down. switch (sym) { c.XKB_KEY_Escape => c.wl_display_terminate(self.wl_display), - c.XKB_KEY_F1 => { - // Cycle to the next view - //if (c.wl_list_length(&server.views) > 1) { - // const current_view = @fieldParentPtr(View, "link", server.views.next); - // const next_view = @fieldParentPtr(View, "link", current_view.link.next); - // focus_view(next_view, next_view.xdg_surface.surface); - // // Move the previous view to the end of the list - // c.wl_list_remove(¤t_view.link); - // c.wl_list_insert(server.views.prev, ¤t_view.link); - //} - }, + c.XKB_KEY_j => self.root.focusNextView(), + c.XKB_KEY_k => self.root.focusPrevView(), else => return false, } return true; diff --git a/src/view.zig b/src/view.zig index 6f2c776..42535ff 100644 --- a/src/view.zig +++ b/src/view.zig @@ -106,24 +106,41 @@ pub const View = struct { // Called when the surface is mapped, or ready to display on-screen. const view = @fieldParentPtr(View, "listen_map", listener.?); view.mapped = true; + view.focus(view.wlr_xdg_surface.surface); const node = @fieldParentPtr(std.TailQueue(View).Node, "data", view); view.root.unmapped_views.remove(node); - view.root.views.prepend(node); + view.root.views.append(node); view.root.arrange(); } fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const view = @fieldParentPtr(View, "listen_unmap", listener.?); + const root = view.root; view.mapped = false; - const node = @fieldParentPtr(std.TailQueue(View).Node, "data", view); - view.root.views.remove(node); - view.root.unmapped_views.prepend(node); + if (root.focused_view) |current_focus| { + // If the view being unmapped is focused + if (current_focus == view) { + // If there are more views + if (root.views.len > 1) { + // Focus the next view. + root.focusNextView(); + } else { + // Otherwise clear the focus + root.focused_view = null; + _ = c.wlr_xdg_toplevel_set_activated(view.wlr_xdg_surface, false); + } + } + } - view.root.arrange(); + const node = @fieldParentPtr(std.TailQueue(View).Node, "data", view); + root.views.remove(node); + root.unmapped_views.append(node); + + root.arrange(); } fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { @@ -161,9 +178,12 @@ pub const View = struct { if (prev_surface == surface) { // Don't re-focus an already focused surface. + // TODO: debug message? return; } + root.focused_view = self; + if (prev_surface != null) { // Deactivate the previously focused surface. This lets the client know // it no longer has focus and the client will repaint accordingly, e.g. @@ -172,18 +192,6 @@ pub const View = struct { _ = c.wlr_xdg_toplevel_set_activated(prev_xdg_surface, false); } - //// Find the node - //var it = root.views.first; - //const target = while (it) |node| : (it = node.next) { - // if (&node.data == self) { - // break node; - // } - //} else unreachable; - - //// Move the view to the front - //root.views.remove(target); - //root.views.prepend(target); - // Activate the new surface _ = c.wlr_xdg_toplevel_set_activated(self.wlr_xdg_surface, true);