Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

render: do basic yes/no damage tracking #296

Merged
merged 1 commit into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deps/zig-pixman
Submodule zig-pixman updated 1 files
+2 −2 pixman.zig
29 changes: 17 additions & 12 deletions river/LayerSurface.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const util = @import("util.zig");

const Box = @import("Box.zig");
const Output = @import("Output.zig");
const Subsurface = @import("Subsurface.zig");
const XdgPopup = @import("XdgPopup.zig");

const log = std.log.scoped(.layer_shell);
Expand All @@ -40,10 +41,11 @@ state: wlr.LayerSurfaceV1.State,
destroy: wl.Listener(*wlr.LayerSurfaceV1) = wl.Listener(*wlr.LayerSurfaceV1).init(handleDestroy),
map: wl.Listener(*wlr.LayerSurfaceV1) = wl.Listener(*wlr.LayerSurfaceV1).init(handleMap),
unmap: wl.Listener(*wlr.LayerSurfaceV1) = wl.Listener(*wlr.LayerSurfaceV1).init(handleUnmap),
new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup),
new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleNewSubsurface),

// Listeners only active while the layer surface is mapped
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup),

pub fn init(self: *Self, output: *Output, wlr_layer_surface: *wlr.LayerSurfaceV1) void {
self.* = .{
Expand All @@ -62,9 +64,11 @@ pub fn init(self: *Self, output: *Output, wlr_layer_surface: *wlr.LayerSurfaceV1
list.remove(node);

// Set up listeners that are active for the entire lifetime of the layer surface
self.wlr_layer_surface.events.destroy.add(&self.destroy);
self.wlr_layer_surface.events.map.add(&self.map);
self.wlr_layer_surface.events.unmap.add(&self.unmap);
wlr_layer_surface.events.destroy.add(&self.destroy);
wlr_layer_surface.events.map.add(&self.map);
wlr_layer_surface.events.unmap.add(&self.unmap);
wlr_layer_surface.events.new_popup.add(&self.new_popup);
wlr_layer_surface.surface.events.new_subsurface.add(&self.new_subsurface);
}

fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
Expand All @@ -76,6 +80,8 @@ fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface:
self.destroy.link.remove();
self.map.link.remove();
self.unmap.link.remove();
self.new_popup.link.remove();
self.new_subsurface.link.remove();

const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
util.gpa.destroy(node);
Expand All @@ -88,7 +94,6 @@ fn handleMap(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wl

// Add listeners that are only active while mapped
wlr_layer_surface.surface.events.commit.add(&self.commit);
wlr_layer_surface.events.new_popup.add(&self.new_popup);

wlr_layer_surface.surface.sendEnter(wlr_layer_surface.output.?);

Expand All @@ -103,7 +108,6 @@ fn handleUnmap(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *

// remove listeners only active while the layer surface is mapped
self.commit.link.remove();
self.new_popup.link.remove();

// Remove from the output's list of layer surfaces
const self_node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
Expand Down Expand Up @@ -154,15 +158,16 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), wlr_surface: *wlr.Surface)
self.output.arrangeLayers();
server.root.startTransaction();
}

self.output.damage.addWhole();
}

fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void {
const self = @fieldParentPtr(Self, "new_popup", listener);
XdgPopup.create(wlr_xdg_popup, .{ .layer_surface = self });
}

// This will free itself on destroy
const xdg_popup = util.gpa.create(XdgPopup) catch {
wlr_xdg_popup.resource.postNoMemory();
return;
};
xdg_popup.init(self.output, &self.box, wlr_xdg_popup);
fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), new_wlr_subsurface: *wlr.Subsurface) void {
const self = @fieldParentPtr(Self, "new_subsurface", listener);
Subsurface.create(new_wlr_subsurface, .{ .layer_surface = self });
}
9 changes: 6 additions & 3 deletions river/Output.zig
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const State = struct {
};

wlr_output: *wlr.Output,
damage: *wlr.OutputDamage,

/// All layer surfaces on the output, indexed by the layer enum.
layers: [4]std.TailQueue(LayerSurface) = [1]std.TailQueue(LayerSurface){.{}} ** 4,
Expand Down Expand Up @@ -93,8 +94,8 @@ status_trackers: std.SinglyLinkedList(OutputStatus) = .{},

destroy: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleDestroy),
enable: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleEnable),
frame: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleFrame),
mode: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleMode),
frame: wl.Listener(*wlr.OutputDamage) = wl.Listener(*wlr.OutputDamage).init(handleFrame),

pub fn init(self: *Self, wlr_output: *wlr.Output) !void {
// Some backends don't have modes. DRM+KMS does, and we need to set a mode
Expand All @@ -110,15 +111,17 @@ pub fn init(self: *Self, wlr_output: *wlr.Output) !void {

self.* = .{
.wlr_output = wlr_output,
.damage = try wlr.OutputDamage.create(wlr_output),
.usable_box = undefined,
};
wlr_output.data = @ptrToInt(self);

wlr_output.events.destroy.add(&self.destroy);
wlr_output.events.enable.add(&self.enable);
wlr_output.events.frame.add(&self.frame);
wlr_output.events.mode.add(&self.mode);

self.damage.events.frame.add(&self.frame);

if (wlr_output.isNoop()) {
// A noop output is always 0 x 0
self.usable_box = .{
Expand Down Expand Up @@ -453,7 +456,7 @@ fn handleEnable(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) vo
if (wlr_output.enabled) server.root.addOutput(self);
}

fn handleFrame(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void {
fn handleFrame(listener: *wl.Listener(*wlr.OutputDamage), wlr_output: *wlr.OutputDamage) void {
// This function is called every time an output is ready to display a frame,
// generally at the output's refresh rate (e.g. 60Hz).
const self = @fieldParentPtr(Self, "frame", listener);
Expand Down
2 changes: 2 additions & 0 deletions river/Root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ fn commitTransaction(self: *Self) void {
}

if (view_tags_changed) output.sendViewTags();

output.damage.addWhole();
}
}

Expand Down
103 changes: 103 additions & 0 deletions river/Subsurface.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// This file is part of river, a dynamic tiling wayland compositor.
//
// Copyright 2021 The River Developers
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

const Subsurface = @This();

const std = @import("std");
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;

const util = @import("util.zig");

const LayerSurface = @import("LayerSurface.zig");
const View = @import("View.zig");

pub const Parent = union(enum) {
view: *View,
layer_surface: *LayerSurface,

pub fn damageWholeOutput(parent: Parent) void {
switch (parent) {
.view => |view| view.output.damage.addWhole(),
.layer_surface => |layer_surface| layer_surface.output.damage.addWhole(),
}
}
};

/// The parent at the root of this surface tree
parent: Parent,
wlr_subsurface: *wlr.Subsurface,

// Always active
destroy: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleDestroy),
map: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleMap),
unmap: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleUnmap),
new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleNewSubsurface),

// Only active while mapped
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),

pub fn create(wlr_subsurface: *wlr.Subsurface, parent: Parent) void {
const subsurface = util.gpa.create(Subsurface) catch {
std.log.crit("out of memory", .{});
wlr_subsurface.resource.getClient().postNoMemory();
return;
};
subsurface.* = .{ .wlr_subsurface = wlr_subsurface, .parent = parent };

wlr_subsurface.events.destroy.add(&subsurface.destroy);
wlr_subsurface.events.map.add(&subsurface.map);
wlr_subsurface.events.unmap.add(&subsurface.unmap);
wlr_subsurface.surface.events.new_subsurface.add(&subsurface.new_subsurface);
}

fn handleDestroy(listener: *wl.Listener(*wlr.Subsurface), wlr_subsurface: *wlr.Subsurface) void {
const subsurface = @fieldParentPtr(Subsurface, "destroy", listener);

subsurface.destroy.link.remove();
subsurface.map.link.remove();
subsurface.unmap.link.remove();
subsurface.new_subsurface.link.remove();

util.gpa.destroy(subsurface);
}

fn handleMap(listener: *wl.Listener(*wlr.Subsurface), wlr_subsurface: *wlr.Subsurface) void {
const subsurface = @fieldParentPtr(Subsurface, "map", listener);

wlr_subsurface.surface.events.commit.add(&subsurface.commit);
subsurface.parent.damageWholeOutput();
}

fn handleUnmap(listener: *wl.Listener(*wlr.Subsurface), wlr_subsurface: *wlr.Subsurface) void {
const subsurface = @fieldParentPtr(Subsurface, "unmap", listener);

subsurface.commit.link.remove();
subsurface.parent.damageWholeOutput();
}

fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
const subsurface = @fieldParentPtr(Subsurface, "commit", listener);

subsurface.parent.damageWholeOutput();
}

fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), new_wlr_subsurface: *wlr.Subsurface) void {
const subsurface = @fieldParentPtr(Subsurface, "new_subsurface", listener);

Subsurface.create(new_wlr_subsurface, subsurface.parent);
}
7 changes: 4 additions & 3 deletions river/View.zig
Original file line number Diff line number Diff line change
Expand Up @@ -278,13 +278,14 @@ pub fn saveBuffers(self: *Self) void {
/// Otherwise, apply the pending state immediately.
pub fn notifyConfiguredOrApplyPending(self: *Self) void {
self.pending_serial = null;
if (self.shouldTrackConfigure())
server.root.notifyConfigured()
else {
if (self.shouldTrackConfigure()) {
server.root.notifyConfigured();
} else {
const self_tags_changed = self.pending.tags != self.current.tags;
self.current = self.pending;
self.commitOpacityTransition();
if (self_tags_changed) self.output.sendViewTags();
self.output.damage.addWhole();
}
}

Expand Down
83 changes: 60 additions & 23 deletions river/XdgPopup.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,44 @@ const wl = @import("wayland").server.wl;

const util = @import("util.zig");

const Box = @import("Box.zig");
const Output = @import("Output.zig");
const Subsurface = @import("Subsurface.zig");
const Parent = Subsurface.Parent;

const log = std.log.scoped(.server);

/// The output this popup is displayed on.
output: *Output,

/// Box of the parent of this popup tree. Needed to unconstrain child popups.
parent_box: *const Box,

/// The corresponding wlroots object
/// The parent at the root of this surface tree
parent: Parent,
wlr_xdg_popup: *wlr.XdgPopup,

// Always active
destroy: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleDestroy),
map: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleMap),
unmap: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleUnmap),
new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup),
new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleNewSubsurface),

// Only active while mapped
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),

pub fn init(self: *Self, output: *Output, parent_box: *const Box, wlr_xdg_popup: *wlr.XdgPopup) void {
pub fn create(wlr_xdg_popup: *wlr.XdgPopup, parent: Parent) void {
const self = util.gpa.create(Self) catch {
std.log.crit("out of memory", .{});
wlr_xdg_popup.resource.postNoMemory();
return;
};
self.* = .{
.output = output,
.parent_box = parent_box,
.parent = parent,
.wlr_xdg_popup = wlr_xdg_popup,
};

const parent_box = switch (parent) {
.view => |view| &view.pending.box,
.layer_surface => |layer_surface| &layer_surface.box,
};
const output_dimensions = switch (parent) {
.view => |view| view.output.getEffectiveResolution(),
.layer_surface => |layer_surface| layer_surface.output.getEffectiveResolution(),
};

// The output box relative to the parent of the popup
const output_dimensions = output.getEffectiveResolution();
var box = wlr.Box{
.x = -parent_box.x,
.y = -parent_box.y,
Expand All @@ -58,27 +70,52 @@ pub fn init(self: *Self, output: *Output, parent_box: *const Box, wlr_xdg_popup:
wlr_xdg_popup.unconstrainFromBox(&box);

wlr_xdg_popup.base.events.destroy.add(&self.destroy);
wlr_xdg_popup.base.events.map.add(&self.map);
wlr_xdg_popup.base.events.unmap.add(&self.unmap);
wlr_xdg_popup.base.events.new_popup.add(&self.new_popup);
wlr_xdg_popup.base.surface.events.new_subsurface.add(&self.new_subsurface);
}

fn handleDestroy(listener: *wl.Listener(*wlr.XdgSurface), wlr_xdg_surface: *wlr.XdgSurface) void {
const self = @fieldParentPtr(Self, "destroy", listener);

self.destroy.link.remove();
self.map.link.remove();
self.unmap.link.remove();
self.new_popup.link.remove();
self.new_subsurface.link.remove();

util.gpa.destroy(self);
}

/// Called when a new xdg popup is requested by the client
fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurface) void {
const self = @fieldParentPtr(Self, "map", listener);

self.wlr_xdg_popup.base.surface.events.commit.add(&self.commit);
self.parent.damageWholeOutput();
}

fn handleUnmap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurface) void {
const self = @fieldParentPtr(Self, "unmap", listener);

self.commit.link.remove();
self.parent.damageWholeOutput();
}

fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
const self = @fieldParentPtr(Self, "commit", listener);

self.parent.damageWholeOutput();
}

fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void {
const self = @fieldParentPtr(Self, "new_popup", listener);

// This will free itself on destroy
const xdg_popup = util.gpa.create(Self) catch {
wlr_xdg_popup.resource.postNoMemory();
log.crit("out of memory", .{});
return;
};
xdg_popup.init(self.output, self.parent_box, wlr_xdg_popup);
Self.create(wlr_xdg_popup, self.parent);
}

fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), new_wlr_subsurface: *wlr.Subsurface) void {
const self = @fieldParentPtr(Self, "new_subsurface", listener);

Subsurface.create(new_wlr_subsurface, self.parent);
}
Loading