aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--river/Box.zig9
-rw-r--r--river/View.zig21
-rw-r--r--river/XdgToplevel.zig38
-rw-r--r--river/XwaylandView.zig16
-rw-r--r--river/render.zig8
5 files changed, 71 insertions, 21 deletions
diff --git a/river/Box.zig b/river/Box.zig
index 0ba3e63..58210a0 100644
--- a/river/Box.zig
+++ b/river/Box.zig
@@ -24,6 +24,15 @@ y: i32,
width: u32,
height: u32,
+pub fn fromWlrBox(wlr_box: c.wlr_box) Self {
+ return Self{
+ .x = @intCast(i32, wlr_box.x),
+ .y = @intCast(i32, wlr_box.y),
+ .width = @intCast(u32, wlr_box.width),
+ .height = @intCast(u32, wlr_box.height),
+ };
+}
+
pub fn toWlrBox(self: Self) c.wlr_box {
return c.wlr_box{
.x = @intCast(c_int, self.x),
diff --git a/river/View.zig b/river/View.zig
index 171d829..4f8f0bb 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -59,10 +59,25 @@ floating: bool,
/// 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 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,
+
+/// Pending dimensions of the view during a transaction
pending_box: ?Box,
+/// 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.
+surface_box: Box,
+
+/// The geometry the view's surface had when the transaction started and
+/// buffers were saved.
+saved_surface_box: Box,
+
+/// These are what we render while a transaction is in progress
+saved_buffers: std.ArrayList(SavedBuffer),
+
/// The dimensions the view would have taken if we didn't force it to tile
natural_width: u32,
natural_height: u32,
@@ -72,9 +87,6 @@ pending_tags: ?u32,
pending_serial: ?u32,
-/// These are what we render while a transaction is in progress
-saved_buffers: std.ArrayList(SavedBuffer),
-
pub fn init(
self: *Self,
output: *Output,
@@ -151,6 +163,7 @@ pub fn saveBuffers(self: *Self) void {
self.saved_buffers.items.len = 0;
}
+ self.saved_surface_box = self.surface_box;
self.forEachSurface(saveBuffersIterator, &self.saved_buffers);
}
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 5d43b92..c76312a 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -47,11 +47,6 @@ pub fn init(self: *Self, view: *View, wlr_xdg_surface: *c.wlr_xdg_surface) void
self.wlr_xdg_surface = wlr_xdg_surface;
wlr_xdg_surface.data = self;
- // Inform the xdg toplevel that it is tiled.
- // For example this prevents firefox from drawing shadows around itself
- _ = c.wlr_xdg_toplevel_set_tiled(self.wlr_xdg_surface, c.WLR_EDGE_LEFT |
- c.WLR_EDGE_RIGHT | c.WLR_EDGE_TOP | c.WLR_EDGE_BOTTOM);
-
// Add listeners that are active over the view's entire lifetime
self.listen_destroy.notify = handleDestroy;
c.wl_signal_add(&self.wlr_xdg_surface.events.destroy, &self.listen_destroy);
@@ -110,10 +105,11 @@ pub fn forEachSurface(
/// Return the surface at output coordinates ox, oy and set sx, sy to the
/// corresponding surface-relative coordinates, if there is a surface.
pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surface {
+ const view = self.view;
return c.wlr_xdg_surface_surface_at(
self.wlr_xdg_surface,
- ox - @intToFloat(f64, self.view.current_box.x),
- oy - @intToFloat(f64, self.view.current_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,
);
@@ -186,6 +182,14 @@ fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
view.setFloating(true);
}
+ // If the toplevel has no parent, inform it that it is tiled. This
+ // prevents firefox, for example, from drawing shadows around itself.
+ if (wlr_xdg_toplevel.parent == null)
+ _ = c.wlr_xdg_toplevel_set_tiled(
+ self.wlr_xdg_surface,
+ c.WLR_EDGE_LEFT | c.WLR_EDGE_RIGHT | c.WLR_EDGE_TOP | c.WLR_EDGE_BOTTOM,
+ );
+
view.map();
}
@@ -202,22 +206,36 @@ fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
}
/// Called when the surface is comitted
-/// TODO: check for unexpected change in size and react as needed
fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
const self = @fieldParentPtr(Self, "listen_commit", listener.?);
const view = self.view;
+ var wlr_box: c.wlr_box = undefined;
+ c.wlr_xdg_surface_get_geometry(self.wlr_xdg_surface, &wlr_box);
+ const new_box = Box.fromWlrBox(wlr_box);
+
+ // If we have sent a configure changing the size
if (view.pending_serial) |s| {
+ // Update the stored dimensions of the surface
+ view.surface_box = new_box;
+
if (s == self.wlr_xdg_surface.configure_serial) {
+ // If this commit is in response to our configure, notify the
+ // transaction code.
view.output.root.notifyConfigured();
view.pending_serial = null;
} else {
- // If the view has not yet acked our configure, we need to send a
- // frame done event so that they commit another buffer. These
+ // If the client has not yet acked our configure, we need to send a
+ // frame done event so that it commits another buffer. These
// buffers won't be rendered since we are still rendering our
// stashed buffer from when the transaction started.
view.sendFrameDone();
}
+ } else {
+ // TODO: handle unexpected change in dimensions
+ if (!std.meta.eql(view.surface_box, new_box))
+ Log.Error.log("View changed size unexpectedly", .{});
+ view.surface_box = new_box;
}
}
diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig
index f978e50..171aba2 100644
--- a/river/XwaylandView.zig
+++ b/river/XwaylandView.zig
@@ -57,10 +57,12 @@ pub fn init(self: *Self, view: *View, wlr_xwayland_surface: *c.wlr_xwayland_surf
c.wl_signal_add(&self.wlr_xwayland_surface.events.unmap, &self.listen_unmap);
}
-/// Don't really care about efficiency with xwayland, we don't wait for them
-/// to ack anyways since they don't use serials.
pub fn needsConfigure(self: Self) bool {
- return true;
+ 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;
}
/// Tell the client to take a new size
@@ -162,6 +164,14 @@ fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
const self = @fieldParentPtr(Self, "listen_commit", listener.?);
const view = self.view;
+
+ view.surface_box = Box{
+ .x = 0,
+ .y = 0,
+ .width = @intCast(u32, self.wlr_xwayland_surface.surface.*.current.width),
+ .height = @intCast(u32, self.wlr_xwayland_surface.surface.*.current.height),
+ };
+
// See comment in XwaylandView.configure()
if (view.pending_serial != null) {
view.output.root.notifyConfigured();
diff --git a/river/render.zig b/river/render.zig
index 6414630..14e8ae0 100644
--- a/river/render.zig
+++ b/river/render.zig
@@ -143,8 +143,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,
- .y = saved_buffer.box.y + view.current_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),
},
@@ -155,8 +155,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,
- .output_y = view.current_box.y,
+ .output_x = view.current_box.x - view.surface_box.x,
+ .output_y = view.current_box.y - view.surface_box.y,
.when = now,
};