xdg-shell: improve child handling
- wait until map to send tiled state - only set toplevels with no parent to tiled (toplevels with a parent are generally popup-like things such as a file chooser or yes/no prompt) - track dimesions and offset of the surface and take offset into account for rendering.
This commit is contained in:
parent
c2d32a44c3
commit
e1a1459177
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user