aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--river/Output.zig8
-rw-r--r--river/OutputStatus.zig2
-rw-r--r--river/Root.zig21
-rw-r--r--river/Seat.zig2
-rw-r--r--river/View.zig88
-rw-r--r--river/XdgToplevel.zig32
-rw-r--r--river/XwaylandView.zig11
-rw-r--r--river/command/tags.zig12
-rw-r--r--river/command/toggle_float.zig16
-rw-r--r--river/command/zoom.zig2
-rw-r--r--river/render.zig28
-rw-r--r--river/view_stack.zig7
12 files changed, 105 insertions, 124 deletions
diff --git a/river/Output.zig b/river/Output.zig
index f1f4419..7dc10cf 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -181,7 +181,7 @@ fn layoutFull(self: *Self, visible_count: u32, output_tags: u32) void {
var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
while (it.next()) |node| {
const view = &node.view;
- if (view.mode == .layout) view.pending_box = full_box;
+ if (view.pending.mode == .layout) view.pending.box = full_box;
}
}
@@ -286,8 +286,8 @@ fn layoutExternal(self: *Self, visible_count: u32, output_tags: u32) !void {
var view_it = ViewStack(View).pendingIterator(self.views.first, output_tags);
while (view_it.next()) |node| {
const view = &node.view;
- if (view.mode == .layout) {
- view.pending_box = view_boxen.items[i];
+ if (view.pending.mode == .layout) {
+ view.pending.box = view_boxen.items[i];
i += 1;
}
}
@@ -310,7 +310,7 @@ pub fn arrangeViews(self: *Self) void {
var count: u32 = 0;
var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
while (it.next()) |node| {
- if (node.view.mode == .layout) count += 1;
+ if (node.view.pending.mode == .layout) count += 1;
}
break :blk count;
};
diff --git a/river/OutputStatus.zig b/river/OutputStatus.zig
index 980dbe8..be0568f 100644
--- a/river/OutputStatus.zig
+++ b/river/OutputStatus.zig
@@ -62,7 +62,7 @@ pub fn sendViewTags(self: Self) void {
var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
while (it.next()) |node|
- view_tags.append(node.view.current_tags) catch {
+ view_tags.append(node.view.current.tags) catch {
c.wl_resource_post_no_memory(self.wl_resource);
log.crit(.river_status, "out of memory", .{});
return;
diff --git a/river/Root.zig b/river/Root.zig
index 7bcb83e..81478c8 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -175,7 +175,7 @@ fn startTransaction(self: *Self) void {
fn handleTimeout(data: ?*c_void) callconv(.C) c_int {
const self = util.voidCast(Self, data.?);
- log.err(.transaction, "time out occurred, some imperfect frames may be shown", .{});
+ log.err(.transaction, "timeout occurred, some imperfect frames may be shown", .{});
self.commitTransaction();
@@ -225,19 +225,10 @@ fn commitTransaction(self: *Self) void {
var view_it = ViewStack(View).iterator(output.views.first, std.math.maxInt(u32));
while (view_it.next()) |view_node| {
const view = &view_node.view;
- // Ensure that all pending state is cleared
+ // Apply pending state
view.pending_serial = null;
- if (view.pending_box) |state| {
- view.current_box = state;
- view.pending_box = null;
- }
-
- // Apply possible pending tags
- if (view.pending_tags) |tags| {
- view.current_tags = tags;
- view.pending_tags = null;
- view_tags_changed = true;
- }
+ if (view.pending.tags != view.current.tags) view_tags_changed = true;
+ view.current = view.pending;
view.dropSavedBuffers();
}
@@ -247,7 +238,5 @@ fn commitTransaction(self: *Self) void {
// Iterate over all seats and update focus
var it = self.server.input_manager.seats.first;
- while (it) |seat_node| : (it = seat_node.next) {
- seat_node.data.focus(null);
- }
+ while (it) |seat_node| : (it = seat_node.next) seat_node.data.focus(null);
}
diff --git a/river/Seat.zig b/river/Seat.zig
index cdc08ed..f67fbae 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -125,7 +125,7 @@ pub fn focus(self: *Self, _view: ?*View) void {
// If view is null or not currently visible
if (if (view) |v|
v.output != self.focused_output or
- v.current_tags & self.focused_output.current_focused_tags == 0
+ v.current.tags & self.focused_output.current_focused_tags == 0
else
true) {
// Set view to the first currently visible view on in the focus stack if any
diff --git a/river/View.zig b/river/View.zig
index a50957e..ffa7e4e 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -41,6 +41,18 @@ const Mode = enum {
float,
};
+const State = struct {
+ /// The output-relative coordinates and dimensions of the view. The
+ /// surface itself may have other dimensions which are stored in the
+ /// surface_box member.
+ box: Box,
+
+ /// The tags of the view, as a bitmask
+ tags: u32,
+
+ mode: Mode,
+};
+
const SavedBuffer = struct {
wlr_buffer: *c.wlr_buffer,
box: Box,
@@ -56,19 +68,15 @@ output: *Output,
/// This is non-null exactly when the view is mapped
wlr_surface: ?*c.wlr_surface,
-/// The current mode of the view
-mode: Mode,
-
/// True if the view is currently focused by at least one seat
focused: bool,
-/// The current output-relative coordinates and dimensions of the view. The
-/// surface itself may have other dimensions which are stored in the
-/// surface_box member.
-current_box: Box,
+/// The double-buffered state of the view
+current: State,
+pending: State,
-/// Pending dimensions of the view during a transaction
-pending_box: ?Box,
+/// The serial sent with the currently pending configure event
+pending_serial: ?u32,
/// The currently commited geometry of the surface. The x/y may be negative if
/// for example the client has decided to draw CSD shadows a la GTK.
@@ -85,29 +93,24 @@ saved_buffers: std.ArrayList(SavedBuffer),
natural_width: u32,
natural_height: u32,
-current_tags: u32,
-pending_tags: ?u32,
-
-pending_serial: ?u32,
-
pub fn init(self: *Self, output: *Output, tags: u32, surface: var) void {
self.output = output;
self.wlr_surface = null;
- self.mode = .layout;
self.focused = false;
- self.current_box = Box{
- .x = 0,
- .y = 0,
- .height = 0,
- .width = 0,
+ self.current = .{
+ .box = .{
+ .x = 0,
+ .y = 0,
+ .height = 0,
+ .width = 0,
+ },
+ .tags = tags,
+ .mode = .layout,
};
- self.pending_box = null;
-
- self.current_tags = tags;
- self.pending_tags = null;
+ self.pending = self.current;
self.pending_serial = null;
@@ -135,13 +138,9 @@ pub fn needsConfigure(self: Self) bool {
}
pub fn configure(self: Self) void {
- if (self.pending_box) |pending_box| {
- switch (self.impl) {
- .xdg_toplevel => |xdg_toplevel| xdg_toplevel.configure(pending_box),
- .xwayland_view => |xwayland_view| xwayland_view.configure(pending_box),
- }
- } else {
- log.err(.transaction, "configure called on a View with no pending box", .{});
+ switch (self.impl) {
+ .xdg_toplevel => |xdg_toplevel| xdg_toplevel.configure(self.pending.box),
+ .xwayland_view => |xwayland_view| xwayland_view.configure(self.pending.box),
}
}
@@ -190,7 +189,8 @@ fn saveBuffersIterator(
}
}
-/// Set the focued bool and the active state of the view if it is a toplevel
+/// Set the focused bool and the active state of the view if it is a toplevel
+/// TODO: This is insufficient for multi-seat, probably need a focus counter.
pub fn setFocused(self: *Self, focused: bool) void {
self.focused = focused;
switch (self.impl) {
@@ -199,30 +199,6 @@ pub fn setFocused(self: *Self, focused: bool) void {
}
}
-/// Set the mode of the view to the given mode
-pub fn setMode(self: *Self, mode: Mode) void {
- switch (self.mode) {
- .layout => switch (mode) {
- .layout => {},
- .float => {
- self.mode = .float;
- self.pending_box = Box{
- .x = std.math.max(0, @divTrunc(@intCast(i32, self.output.usable_box.width) -
- @intCast(i32, self.natural_width), 2)),
- .y = std.math.max(0, @divTrunc(@intCast(i32, self.output.usable_box.height) -
- @intCast(i32, self.natural_height), 2)),
- .width = self.natural_width,
- .height = self.natural_height,
- };
- },
- },
- .float => switch (mode) {
- .float => {},
- .layout => self.mode = .layout,
- },
- }
-}
-
/// Move a view from one output to another, sending the required enter/leave
/// events.
pub fn sendToOutput(self: *Self, destination_output: *Output) void {
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index dbbcb9d..b08e8bd 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -62,8 +62,6 @@ pub fn init(self: *Self, view: *View, wlr_xdg_surface: *c.wlr_xdg_surface) void
/// Returns true if a configure must be sent to ensure the dimensions of the
/// pending_box are applied.
pub fn needsConfigure(self: Self) bool {
- const pending_box = self.view.pending_box orelse return false;
-
const wlr_xdg_toplevel: *c.wlr_xdg_toplevel = @field(
self.wlr_xdg_surface,
c.wlr_xdg_surface_union,
@@ -73,8 +71,8 @@ pub fn needsConfigure(self: Self) bool {
// sync with the current dimensions or be the dimensions sent with the
// most recent configure. In both cases server_pending has the values we
// want to check against.
- return pending_box.width != wlr_xdg_toplevel.server_pending.width or
- pending_box.height != wlr_xdg_toplevel.server_pending.height;
+ return self.view.pending.box.width != wlr_xdg_toplevel.server_pending.width or
+ self.view.pending.box.height != wlr_xdg_toplevel.server_pending.height;
}
/// Send a configure event, applying the width/height of the pending box.
@@ -109,8 +107,8 @@ pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surfa
const view = self.view;
return c.wlr_xdg_surface_surface_at(
self.wlr_xdg_surface,
- ox - @intToFloat(f64, view.current_box.x - view.surface_box.x),
- oy - @intToFloat(f64, view.current_box.y - view.surface_box.y),
+ ox - @intToFloat(f64, view.current.box.x - view.surface_box.x),
+ oy - @intToFloat(f64, view.current.box.y - view.surface_box.y),
sx,
sy,
);
@@ -171,7 +169,15 @@ fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
for (root.server.config.float_filter.items) |filter_app_id| {
// Make views with app_ids listed in the float filter float
if (std.mem.eql(u8, std.mem.span(app_id), std.mem.span(filter_app_id))) {
- view.setMode(.float);
+ view.pending.mode = .float;
+ view.pending.box = .{
+ .x = std.math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.width) -
+ @intCast(i32, view.natural_width), 2)),
+ .y = std.math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.height) -
+ @intCast(i32, view.natural_height), 2)),
+ .width = view.natural_width,
+ .height = view.natural_height,
+ };
break;
}
} else if ((wlr_xdg_toplevel.parent != null) or
@@ -179,7 +185,15 @@ fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
(state.min_width == state.max_width or state.min_height == state.max_height)))
{
// If the toplevel has a parent or is of fixed size make it float
- view.setMode(.float);
+ view.pending.mode = .float;
+ view.pending.box = .{
+ .x = std.math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.width) -
+ @intCast(i32, view.natural_width), 2)),
+ .y = std.math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.height) -
+ @intCast(i32, view.natural_height), 2)),
+ .width = view.natural_width,
+ .height = view.natural_height,
+ };
}
// If the toplevel has no parent, inform it that it is tiled. This
@@ -246,5 +260,5 @@ fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
// This will free itself on destroy
var xdg_popup = util.gpa.create(XdgPopup) catch unreachable;
- xdg_popup.init(self.view.output, &self.view.current_box, wlr_xdg_popup);
+ xdg_popup.init(self.view.output, &self.view.current.box, wlr_xdg_popup);
}
diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig
index 6ac5840..1cd0143 100644
--- a/river/XwaylandView.zig
+++ b/river/XwaylandView.zig
@@ -57,11 +57,8 @@ pub fn init(self: *Self, view: *View, wlr_xwayland_surface: *c.wlr_xwayland_surf
}
pub fn needsConfigure(self: Self) bool {
- const view = self.view;
- if (view.pending_box) |pending_box|
- return view.current_box.width != pending_box.width or
- view.current_box.height != pending_box.height;
- return false;
+ return self.view.current.box.width != self.view.pending.box.width or
+ self.view.current.box.height != self.view.pending.box.height;
}
/// Tell the client to take a new size
@@ -105,8 +102,8 @@ pub fn forEachSurface(
pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surface {
return c.wlr_surface_surface_at(
self.wlr_xwayland_surface.surface,
- ox - @intToFloat(f64, self.view.current_box.x),
- oy - @intToFloat(f64, self.view.current_box.y),
+ ox - @intToFloat(f64, self.view.current.box.x),
+ oy - @intToFloat(f64, self.view.current.box.y),
sx,
sy,
);
diff --git a/river/command/tags.zig b/river/command/tags.zig
index 48aaa28..5c14aaa 100644
--- a/river/command/tags.zig
+++ b/river/command/tags.zig
@@ -43,10 +43,8 @@ pub fn setViewTags(
) Error!void {
const tags = try parseTags(allocator, args, out);
if (seat.focused_view) |view| {
- if (view.current_tags != tags) {
- view.pending_tags = tags;
- seat.input_manager.server.root.arrange();
- }
+ view.pending.tags = tags;
+ view.output.root.arrange();
}
}
@@ -75,10 +73,10 @@ pub fn toggleViewTags(
) Error!void {
const tags = try parseTags(allocator, args, out);
if (seat.focused_view) |view| {
- const new_tags = view.current_tags ^ tags;
+ const new_tags = view.current.tags ^ tags;
if (new_tags != 0) {
- view.pending_tags = new_tags;
- seat.input_manager.server.root.arrange();
+ view.pending.tags = new_tags;
+ view.output.root.arrange();
}
}
}
diff --git a/river/command/toggle_float.zig b/river/command/toggle_float.zig
index 4ade683..b918043 100644
--- a/river/command/toggle_float.zig
+++ b/river/command/toggle_float.zig
@@ -30,9 +30,19 @@ pub fn toggleFloat(
) Error!void {
if (args.len > 1) return Error.TooManyArguments;
if (seat.focused_view) |view| {
- switch (view.mode) {
- .layout => view.setMode(.float),
- .float => view.setMode(.layout),
+ switch (view.current.mode) {
+ .layout => {
+ view.pending.mode = .float;
+ view.pending.box = .{
+ .x = std.math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.width) -
+ @intCast(i32, view.natural_width), 2)),
+ .y = std.math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.height) -
+ @intCast(i32, view.natural_height), 2)),
+ .width = view.natural_width,
+ .height = view.natural_height,
+ };
+ },
+ .float => view.pending.mode = .layout,
}
view.output.root.arrange();
}
diff --git a/river/command/zoom.zig b/river/command/zoom.zig
index e21e038..783570f 100644
--- a/river/command/zoom.zig
+++ b/river/command/zoom.zig
@@ -37,7 +37,7 @@ pub fn zoom(
const focused_node = @fieldParentPtr(ViewStack(View).Node, "view", current_focus);
// Only zoom views that are part of the layout
- if (current_focus.mode != .layout) return;
+ if (current_focus.current.mode != .layout) return;
var it = ViewStack(View).iterator(output.views.first, output.current_focused_tags);
const zoom_node = if (focused_node == it.next())
diff --git a/river/render.zig b/river/render.zig
index 4a2256e..6847ffe 100644
--- a/river/render.zig
+++ b/river/render.zig
@@ -68,7 +68,7 @@ pub fn renderOutput(output: *Output) void {
// This check prevents a race condition when a frame is requested
// between mapping of a view and the first configure being handled.
- if (view.current_box.width == 0 or view.current_box.height == 0) continue;
+ if (view.current.box.width == 0 or view.current.box.height == 0) continue;
// Focused views are rendered on top of normal views, skip them for now
if (view.focused) continue;
@@ -84,7 +84,7 @@ pub fn renderOutput(output: *Output) void {
// This check prevents a race condition when a frame is requested
// between mapping of a view and the first configure being handled.
- if (view.current_box.width == 0 or view.current_box.height == 0) continue;
+ if (view.current.box.width == 0 or view.current.box.height == 0) continue;
// Skip unfocused views since we already rendered them
if (!view.focused) continue;
@@ -144,8 +144,8 @@ fn renderView(output: Output, view: *View, now: *c.timespec) void {
output,
saved_buffer.wlr_buffer.texture,
.{
- .x = saved_buffer.box.x + view.current_box.x - view.saved_surface_box.x,
- .y = saved_buffer.box.y + view.current_box.y - view.saved_surface_box.y,
+ .x = saved_buffer.box.x + view.current.box.x - view.saved_surface_box.x,
+ .y = saved_buffer.box.y + view.current.box.y - view.saved_surface_box.y,
.width = @intCast(c_int, saved_buffer.box.width),
.height = @intCast(c_int, saved_buffer.box.height),
},
@@ -156,8 +156,8 @@ fn renderView(output: Output, view: *View, now: *c.timespec) void {
// a transaction and may simply render each toplevel surface.
var rdata = SurfaceRenderData{
.output = &output,
- .output_x = view.current_box.x - view.surface_box.x,
- .output_y = view.current_box.y - view.surface_box.y,
+ .output_x = view.current.box.x - view.surface_box.x,
+ .output_y = view.current.box.y - view.surface_box.y,
.when = now,
};
@@ -248,29 +248,29 @@ fn renderBorders(output: Output, view: *View, now: *c.timespec) void {
const border_width = output.root.server.config.border_width;
// left and right, covering the corners as well
- border.y = view.current_box.y - @intCast(i32, border_width);
+ border.y = view.current.box.y - @intCast(i32, border_width);
border.width = border_width;
- border.height = view.current_box.height + border_width * 2;
+ border.height = view.current.box.height + border_width * 2;
// left
- border.x = view.current_box.x - @intCast(i32, border_width);
+ border.x = view.current.box.x - @intCast(i32, border_width);
renderRect(output, border, color);
// right
- border.x = view.current_box.x + @intCast(i32, view.current_box.width);
+ border.x = view.current.box.x + @intCast(i32, view.current.box.width);
renderRect(output, border, color);
// top and bottom
- border.x = view.current_box.x;
- border.width = view.current_box.width;
+ border.x = view.current.box.x;
+ border.width = view.current.box.width;
border.height = border_width;
// top
- border.y = view.current_box.y - @intCast(i32, border_width);
+ border.y = view.current.box.y - @intCast(i32, border_width);
renderRect(output, border, color);
// bottom border
- border.y = view.current_box.y + @intCast(i32, view.current_box.height);
+ border.y = view.current.box.y + @intCast(i32, view.current.box.height);
renderRect(output, border, color);
}
diff --git a/river/view_stack.zig b/river/view_stack.zig
index 36be14b..2082591 100644
--- a/river/view_stack.zig
+++ b/river/view_stack.zig
@@ -93,12 +93,9 @@ pub fn ViewStack(comptime T: type) type {
pub fn next(self: *Iterator) ?*Node {
while (self.it) |node| : (self.it = if (self.reverse) node.prev else node.next) {
if (if (self.pending)
- if (node.view.pending_tags) |pending_tags|
- self.tags & pending_tags != 0
- else
- self.tags & node.view.current_tags != 0
+ self.tags & node.view.pending.tags != 0
else
- self.tags & node.view.current_tags != 0) {
+ self.tags & node.view.current.tags != 0) {
self.it = if (self.reverse) node.prev else node.next;
return node;
}