Flesh out focus handling and add keybinds
This commit is contained in:
parent
647545d9fb
commit
51e8191031
3 changed files with 75 additions and 30 deletions
50
src/root.zig
50
src/root.zig
|
@ -19,13 +19,14 @@ pub const Root = struct {
|
||||||
views: std.TailQueue(View),
|
views: std.TailQueue(View),
|
||||||
unmapped_views: std.TailQueue(View),
|
unmapped_views: std.TailQueue(View),
|
||||||
|
|
||||||
|
focused_view: ?*View,
|
||||||
|
|
||||||
// Number of pending configures sent in the current transaction.
|
// Number of pending configures sent in the current transaction.
|
||||||
// A value of 0 means there is no current transaction.
|
// A value of 0 means there is no current transaction.
|
||||||
pending_count: u32,
|
pending_count: u32,
|
||||||
|
|
||||||
pub fn init(self: *Self, server: *Server) !void {
|
pub fn init(self: *Self, server: *Server) !void {
|
||||||
self.server = server;
|
self.server = server;
|
||||||
self.pending_count = 0;
|
|
||||||
|
|
||||||
// Create an output layout, which a wlroots utility for working with an
|
// Create an output layout, which a wlroots utility for working with an
|
||||||
// arrangement of screens in a physical layout.
|
// 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);
|
errdefer c.wlr_output_layout_destroy(self.wlr_output_layout);
|
||||||
|
|
||||||
self.outputs = std.TailQueue(Output).init();
|
self.outputs = std.TailQueue(Output).init();
|
||||||
|
|
||||||
self.views = std.TailQueue(View).init();
|
self.views = std.TailQueue(View).init();
|
||||||
self.unmapped_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 {
|
pub fn destroy(self: *Self) void {
|
||||||
|
@ -55,7 +61,7 @@ pub const Root = struct {
|
||||||
self.unmapped_views.append(node);
|
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
|
/// 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 {
|
pub fn viewAt(self: *Self, lx: f64, ly: f64, surface: *?*c.wlr_surface, sx: *f64, sy: *f64) ?*View {
|
||||||
var it = self.views.last;
|
var it = self.views.last;
|
||||||
|
@ -67,6 +73,46 @@ pub const Root = struct {
|
||||||
return null;
|
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 {
|
pub fn arrange(self: *Self) void {
|
||||||
if (self.views.len == 0) {
|
if (self.views.len == 0) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -109,17 +109,8 @@ pub const Server = struct {
|
||||||
// This function assumes the proper modifier is held down.
|
// This function assumes the proper modifier is held down.
|
||||||
switch (sym) {
|
switch (sym) {
|
||||||
c.XKB_KEY_Escape => c.wl_display_terminate(self.wl_display),
|
c.XKB_KEY_Escape => c.wl_display_terminate(self.wl_display),
|
||||||
c.XKB_KEY_F1 => {
|
c.XKB_KEY_j => self.root.focusNextView(),
|
||||||
// Cycle to the next view
|
c.XKB_KEY_k => self.root.focusPrevView(),
|
||||||
//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);
|
|
||||||
//}
|
|
||||||
},
|
|
||||||
else => return false,
|
else => return false,
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
42
src/view.zig
42
src/view.zig
|
@ -106,24 +106,41 @@ pub const View = struct {
|
||||||
// Called when the surface is mapped, or ready to display on-screen.
|
// Called when the surface is mapped, or ready to display on-screen.
|
||||||
const view = @fieldParentPtr(View, "listen_map", listener.?);
|
const view = @fieldParentPtr(View, "listen_map", listener.?);
|
||||||
view.mapped = true;
|
view.mapped = true;
|
||||||
|
|
||||||
view.focus(view.wlr_xdg_surface.surface);
|
view.focus(view.wlr_xdg_surface.surface);
|
||||||
|
|
||||||
const node = @fieldParentPtr(std.TailQueue(View).Node, "data", view);
|
const node = @fieldParentPtr(std.TailQueue(View).Node, "data", view);
|
||||||
view.root.unmapped_views.remove(node);
|
view.root.unmapped_views.remove(node);
|
||||||
view.root.views.prepend(node);
|
view.root.views.append(node);
|
||||||
|
|
||||||
view.root.arrange();
|
view.root.arrange();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
|
fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
|
||||||
const view = @fieldParentPtr(View, "listen_unmap", listener.?);
|
const view = @fieldParentPtr(View, "listen_unmap", listener.?);
|
||||||
|
const root = view.root;
|
||||||
view.mapped = false;
|
view.mapped = false;
|
||||||
|
|
||||||
const node = @fieldParentPtr(std.TailQueue(View).Node, "data", view);
|
if (root.focused_view) |current_focus| {
|
||||||
view.root.views.remove(node);
|
// If the view being unmapped is focused
|
||||||
view.root.unmapped_views.prepend(node);
|
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 {
|
fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
|
||||||
|
@ -161,9 +178,12 @@ pub const View = struct {
|
||||||
|
|
||||||
if (prev_surface == surface) {
|
if (prev_surface == surface) {
|
||||||
// Don't re-focus an already focused surface.
|
// Don't re-focus an already focused surface.
|
||||||
|
// TODO: debug message?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
root.focused_view = self;
|
||||||
|
|
||||||
if (prev_surface != null) {
|
if (prev_surface != null) {
|
||||||
// Deactivate the previously focused surface. This lets the client know
|
// Deactivate the previously focused surface. This lets the client know
|
||||||
// it no longer has focus and the client will repaint accordingly, e.g.
|
// 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);
|
_ = 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
|
// Activate the new surface
|
||||||
_ = c.wlr_xdg_toplevel_set_activated(self.wlr_xdg_surface, true);
|
_ = c.wlr_xdg_toplevel_set_activated(self.wlr_xdg_surface, true);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue