render: remove damage tracking

This will be handled by wlr_scene shortly.
This commit is contained in:
Isaac Freund 2023-01-27 19:51:56 +01:00
parent b7ac5becfb
commit 168756cbe8
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
14 changed files with 7 additions and 503 deletions

View File

@ -24,7 +24,6 @@ const server = &@import("main.zig").server;
const util = @import("util.zig");
const Seat = @import("Seat.zig");
const Subsurface = @import("Subsurface.zig");
seat: *Seat,
wlr_drag_icon: *wlr.Drag.Icon,
@ -35,63 +34,29 @@ sy: i32 = 0,
// Always active
destroy: wl.Listener(*wlr.Drag.Icon) = wl.Listener(*wlr.Drag.Icon).init(handleDestroy),
map: wl.Listener(*wlr.Drag.Icon) = wl.Listener(*wlr.Drag.Icon).init(handleMap),
unmap: wl.Listener(*wlr.Drag.Icon) = wl.Listener(*wlr.Drag.Icon).init(handleUnmap),
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleNewSubsurface),
pub fn init(drag_icon: *DragIcon, seat: *Seat, wlr_drag_icon: *wlr.Drag.Icon) void {
drag_icon.* = .{ .seat = seat, .wlr_drag_icon = wlr_drag_icon };
wlr_drag_icon.events.destroy.add(&drag_icon.destroy);
wlr_drag_icon.events.map.add(&drag_icon.map);
wlr_drag_icon.events.unmap.add(&drag_icon.unmap);
wlr_drag_icon.surface.events.commit.add(&drag_icon.commit);
wlr_drag_icon.surface.events.new_subsurface.add(&drag_icon.new_subsurface);
if (wlr_drag_icon.mapped) handleMap(&drag_icon.map, wlr_drag_icon);
Subsurface.handleExisting(wlr_drag_icon.surface, .{ .drag_icon = drag_icon });
}
fn handleDestroy(listener: *wl.Listener(*wlr.Drag.Icon), wlr_drag_icon: *wlr.Drag.Icon) void {
fn handleDestroy(listener: *wl.Listener(*wlr.Drag.Icon), _: *wlr.Drag.Icon) void {
const drag_icon = @fieldParentPtr(DragIcon, "destroy", listener);
drag_icon.seat.drag_icon = null;
drag_icon.destroy.link.remove();
drag_icon.map.link.remove();
drag_icon.unmap.link.remove();
drag_icon.commit.link.remove();
drag_icon.new_subsurface.link.remove();
Subsurface.destroySubsurfaces(wlr_drag_icon.surface);
util.gpa.destroy(drag_icon);
}
fn handleMap(_: *wl.Listener(*wlr.Drag.Icon), _: *wlr.Drag.Icon) void {
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
}
fn handleUnmap(_: *wl.Listener(*wlr.Drag.Icon), _: *wlr.Drag.Icon) void {
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
}
fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
const drag_icon = @fieldParentPtr(DragIcon, "commit", listener);
drag_icon.sx += surface.current.dx;
drag_icon.sy += surface.current.dy;
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
}
fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), wlr_subsurface: *wlr.Subsurface) void {
const drag_icon = @fieldParentPtr(DragIcon, "new_subsurface", listener);
Subsurface.create(wlr_subsurface, .{ .drag_icon = drag_icon });
}

View File

@ -26,8 +26,6 @@ const server = &@import("main.zig").server;
const util = @import("util.zig");
const Output = @import("Output.zig");
const Subsurface = @import("Subsurface.zig");
const XdgPopup = @import("XdgPopup.zig");
const log = std.log.scoped(.layer_shell);
@ -40,8 +38,6 @@ layer: zwlr.LayerShellV1.Layer,
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),
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
pub fn init(self: *Self, output: *Output, wlr_layer_surface: *wlr.LayerSurfaceV1) void {
@ -56,19 +52,15 @@ pub fn init(self: *Self, output: *Output, wlr_layer_surface: *wlr.LayerSurfaceV1
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.commit.add(&self.commit);
wlr_layer_surface.surface.events.new_subsurface.add(&self.new_subsurface);
// wlroots only informs us of the new surface after the first commit,
// so our listener does not get called for this first commit. However,
// we do want our listener called in order to send the initial configure.
handleCommit(&self.commit, wlr_layer_surface.surface);
Subsurface.handleExisting(wlr_layer_surface.surface, .{ .layer_surface = self });
}
fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), _: *wlr.LayerSurfaceV1) void {
const self = @fieldParentPtr(Self, "destroy", listener);
log.debug("layer surface '{s}' destroyed", .{self.wlr_layer_surface.namespace});
@ -77,15 +69,7 @@ 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.commit.link.remove();
self.new_subsurface.link.remove();
Subsurface.destroySubsurfaces(self.wlr_layer_surface.surface);
var it = wlr_layer_surface.popups.iterator(.forward);
while (it.next()) |wlr_xdg_popup| {
if (@intToPtr(?*XdgPopup, wlr_xdg_popup.base.data)) |xdg_popup| xdg_popup.destroy();
}
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
util.gpa.destroy(node);
@ -163,16 +147,4 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
self.output.arrangeLayers(.mapped);
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 });
}
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 });
}

View File

@ -130,16 +130,6 @@ fn handleLockSurfacesTimeout(manager: *LockManager) c_int {
assert(manager.state == .waiting_for_lock_surfaces);
manager.state = .waiting_for_blank;
{
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) {
const output = &node.data;
if (output.lock_render_state == .unlocked) {
output.damage.?.addWhole();
}
}
}
// This call is necessary in the case that all outputs in the layout are disabled.
manager.maybeLock();

View File

@ -25,7 +25,6 @@ const util = @import("util.zig");
const Output = @import("Output.zig");
const Seat = @import("Seat.zig");
const Subsurface = @import("Subsurface.zig");
wlr_lock_surface: *wlr.SessionLockSurfaceV1,
lock: *wlr.SessionLockV1,
@ -33,8 +32,6 @@ lock: *wlr.SessionLockV1,
output_mode: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleOutputMode),
map: wl.Listener(void) = wl.Listener(void).init(handleMap),
surface_destroy: wl.Listener(void) = wl.Listener(void).init(handleDestroy),
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleSubsurface),
pub fn create(wlr_lock_surface: *wlr.SessionLockSurfaceV1, lock: *wlr.SessionLockV1) void {
const lock_surface = util.gpa.create(LockSurface) catch {
@ -51,17 +48,12 @@ pub fn create(wlr_lock_surface: *wlr.SessionLockSurfaceV1, lock: *wlr.SessionLoc
wlr_lock_surface.output.events.mode.add(&lock_surface.output_mode);
wlr_lock_surface.events.map.add(&lock_surface.map);
wlr_lock_surface.events.destroy.add(&lock_surface.surface_destroy);
wlr_lock_surface.surface.events.commit.add(&lock_surface.commit);
wlr_lock_surface.surface.events.new_subsurface.add(&lock_surface.new_subsurface);
handleOutputMode(&lock_surface.output_mode, wlr_lock_surface.output);
Subsurface.handleExisting(wlr_lock_surface.surface, .{ .lock_surface = lock_surface });
}
pub fn destroy(lock_surface: *LockSurface) void {
lock_surface.output().lock_surface = null;
if (lock_surface.output().damage) |damage| damage.addWhole();
{
var surface_it = lock_surface.lock.surfaces.iterator(.forward);
@ -83,10 +75,6 @@ pub fn destroy(lock_surface: *LockSurface) void {
lock_surface.output_mode.link.remove();
lock_surface.map.link.remove();
lock_surface.surface_destroy.link.remove();
lock_surface.commit.link.remove();
lock_surface.new_subsurface.link.remove();
Subsurface.destroySubsurfaces(lock_surface.wlr_lock_surface.surface);
util.gpa.destroy(lock_surface);
}
@ -126,14 +114,3 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
lock_surface.destroy();
}
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
const lock_surface = @fieldParentPtr(LockSurface, "commit", listener);
lock_surface.output().damage.?.addWhole();
}
fn handleSubsurface(listener: *wl.Listener(*wlr.Subsurface), subsurface: *wlr.Subsurface) void {
const lock_surface = @fieldParentPtr(LockSurface, "new_subsurface", listener);
Subsurface.create(subsurface, .{ .lock_surface = lock_surface });
}

View File

@ -55,7 +55,6 @@ 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,
@ -115,9 +114,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),
mode: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleMode),
frame: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleFrame),
present: wl.Listener(*wlr.Output.event.Present) = wl.Listener(*wlr.Output.event.Present).init(handlePresent),
frame: wl.Listener(*wlr.OutputDamage) = wl.Listener(*wlr.OutputDamage).init(handleFrame),
damage_destroy: wl.Listener(*wlr.OutputDamage) = wl.Listener(*wlr.OutputDamage).init(handleDamageDestroy),
pub fn init(self: *Self, wlr_output: *wlr.Output) !void {
if (!wlr_output.initRender(server.allocator, server.renderer)) return;
@ -146,7 +144,6 @@ 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);
@ -154,11 +151,9 @@ pub fn init(self: *Self, wlr_output: *wlr.Output) !void {
wlr_output.events.destroy.add(&self.destroy);
wlr_output.events.enable.add(&self.enable);
wlr_output.events.mode.add(&self.mode);
wlr_output.events.frame.add(&self.frame);
wlr_output.events.present.add(&self.present);
self.damage.?.events.frame.add(&self.frame);
self.damage.?.events.destroy.add(&self.damage_destroy);
// Ensure that a cursor image at the output's scale factor is loaded
// for each seat.
var it = server.input_manager.seats.first;
@ -458,17 +453,6 @@ fn arrangeLayer(
}
}
fn handleDamageDestroy(listener: *wl.Listener(*wlr.OutputDamage), _: *wlr.OutputDamage) void {
const self = @fieldParentPtr(Self, "damage_destroy", listener);
// The wlr.OutputDamage is only destroyed by wlroots when the output is
// destroyed and is never destroyed manually by river.
self.frame.link.remove();
// Ensure that it is safe to call remove() again in handleDestroy()
self.frame.link = .{ .prev = &self.frame.link, .next = &self.frame.link };
self.damage = null;
}
fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
const self = @fieldParentPtr(Self, "destroy", listener);
@ -527,9 +511,7 @@ fn handleEnable(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) vo
}
}
fn handleFrame(listener: *wl.Listener(*wlr.OutputDamage), _: *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).
fn handleFrame(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
const self = @fieldParentPtr(Self, "frame", listener);
render.renderOutput(self);
}
@ -552,7 +534,6 @@ fn handlePresent(
.pending_blank, .pending_lock_surface => {
if (!event.presented) {
self.lock_render_state = .unlocked;
self.damage.?.addWhole();
return;
}

View File

@ -91,8 +91,6 @@ pub fn init(self: *Self) !void {
.transaction_timer = transaction_timer,
.noop_output = .{
.wlr_output = noop_wlr_output,
// TODO: find a good way to not create a wlr.OutputDamage for the noop output
.damage = try wlr.OutputDamage.create(noop_wlr_output),
.usable_box = .{ .x = 0, .y = 0, .width = 0, .height = 0 },
},
};
@ -390,8 +388,6 @@ fn commitTransaction(self: *Self) void {
if (view_tags_changed) output.sendViewTags();
if (urgent_tags_dirty) output.sendUrgentTags();
output.damage.?.addWhole();
}
server.input_manager.updateCursorState();
server.idle_inhibitor_manager.idleInhibitCheckActive();

View File

@ -1,160 +0,0 @@
// 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, version 3.
//
// 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 assert = std.debug.assert;
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
const server = &@import("main.zig").server;
const util = @import("util.zig");
const DragIcon = @import("DragIcon.zig");
const LayerSurface = @import("LayerSurface.zig");
const LockSurface = @import("LockSurface.zig");
const XdgToplevel = @import("XdgToplevel.zig");
pub const Parent = union(enum) {
xdg_toplevel: *XdgToplevel,
layer_surface: *LayerSurface,
lock_surface: *LockSurface,
drag_icon: *DragIcon,
pub fn damageWholeOutput(parent: Parent) void {
switch (parent) {
.xdg_toplevel => |xdg_toplevel| xdg_toplevel.view.output.damage.?.addWhole(),
.layer_surface => |layer_surface| layer_surface.output.damage.?.addWhole(),
.lock_surface => |lock_surface| lock_surface.output().damage.?.addWhole(),
.drag_icon => |_| {
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
},
}
}
};
/// The parent at the root of this surface tree
parent: Parent,
wlr_subsurface: *wlr.Subsurface,
// Always active
subsurface_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.err("out of memory", .{});
wlr_subsurface.resource.getClient().postNoMemory();
return;
};
subsurface.* = .{ .wlr_subsurface = wlr_subsurface, .parent = parent };
assert(wlr_subsurface.data == 0);
wlr_subsurface.data = @ptrToInt(subsurface);
wlr_subsurface.events.destroy.add(&subsurface.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);
if (wlr_subsurface.mapped) wlr_subsurface.surface.events.commit.add(&subsurface.commit);
Subsurface.handleExisting(wlr_subsurface.surface, parent);
}
/// Create Subsurface structs to track subsurfaces already present on the
/// given surface when river becomes aware of the surface as we won't
/// recieve a new_subsurface event for them.
pub fn handleExisting(surface: *wlr.Surface, parent: Parent) void {
var below_it = surface.current.subsurfaces_below.iterator(.forward);
while (below_it.next()) |parent_state| {
const subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state);
Subsurface.create(subsurface, parent);
}
var above_it = surface.current.subsurfaces_above.iterator(.forward);
while (above_it.next()) |parent_state| {
const subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state);
Subsurface.create(subsurface, parent);
}
}
/// Destroy this Subsurface and all of its children
pub fn destroy(subsurface: *Subsurface) void {
subsurface.subsurface_destroy.link.remove();
subsurface.map.link.remove();
subsurface.unmap.link.remove();
subsurface.new_subsurface.link.remove();
if (subsurface.wlr_subsurface.mapped) subsurface.commit.link.remove();
Subsurface.destroySubsurfaces(subsurface.wlr_subsurface.surface);
subsurface.wlr_subsurface.data = 0;
util.gpa.destroy(subsurface);
}
pub fn destroySubsurfaces(surface: *wlr.Surface) void {
var below_it = surface.current.subsurfaces_below.iterator(.forward);
while (below_it.next()) |parent_state| {
const wlr_subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state);
if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy();
}
var above_it = surface.current.subsurfaces_above.iterator(.forward);
while (above_it.next()) |parent_state| {
const wlr_subsurface = @fieldParentPtr(wlr.Subsurface, "current", parent_state);
if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy();
}
}
fn handleDestroy(listener: *wl.Listener(*wlr.Subsurface), _: *wlr.Subsurface) void {
const subsurface = @fieldParentPtr(Subsurface, "subsurface_destroy", listener);
subsurface.destroy();
}
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) void {
const subsurface = @fieldParentPtr(Subsurface, "unmap", listener);
subsurface.commit.link.remove();
subsurface.parent.damageWholeOutput();
}
fn handleCommit(listener: *wl.Listener(*wlr.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);
}

View File

@ -462,13 +462,6 @@ pub fn fromWlrSurface(surface: *wlr.Surface) ?*Self {
const xwayland_surface = wlr.XwaylandSurface.fromWlrSurface(surface) orelse return null;
return @intToPtr(?*Self, xwayland_surface.data);
}
if (surface.isSubsurface()) {
if (wlr.Subsurface.fromWlrSurface(surface)) |ss| {
if (ss.parent) |s| {
return fromWlrSurface(s);
}
}
}
return null;
}

View File

@ -1,149 +0,0 @@
// This file is part of river, a dynamic tiling wayland compositor.
//
// Copyright 2020 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, version 3.
//
// 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 XdgPopup = @This();
const std = @import("std");
const assert = std.debug.assert;
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
const util = @import("util.zig");
const Subsurface = @import("Subsurface.zig");
const Parent = Subsurface.Parent;
/// The parent at the root of this surface tree
parent: Parent,
wlr_xdg_popup: *wlr.XdgPopup,
// Always active
surface_destroy: wl.Listener(void) = wl.Listener(void).init(handleDestroy),
map: wl.Listener(void) = wl.Listener(void).init(handleMap),
unmap: wl.Listener(void) = wl.Listener(void).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 create(wlr_xdg_popup: *wlr.XdgPopup, parent: Parent) void {
const xdg_popup = util.gpa.create(XdgPopup) catch {
std.log.err("out of memory", .{});
wlr_xdg_popup.resource.postNoMemory();
return;
};
xdg_popup.* = .{
.parent = parent,
.wlr_xdg_popup = wlr_xdg_popup,
};
assert(wlr_xdg_popup.base.data == 0);
wlr_xdg_popup.base.data = @ptrToInt(xdg_popup);
switch (parent) {
.xdg_toplevel => |xdg_toplevel| {
// The output box relative to the parent of the xdg_popup
var box = wlr.Box{
.x = xdg_toplevel.view.surface_box.x - xdg_toplevel.view.pending.box.x,
.y = xdg_toplevel.view.surface_box.y - xdg_toplevel.view.pending.box.y,
.width = undefined,
.height = undefined,
};
xdg_toplevel.view.output.wlr_output.effectiveResolution(&box.width, &box.height);
wlr_xdg_popup.unconstrainFromBox(&box);
},
.layer_surface => |layer_surface| {
// The output box relative to the parent of the xdg_popup
var box = wlr.Box{
.x = -layer_surface.box.x,
.y = -layer_surface.box.y,
.width = undefined,
.height = undefined,
};
layer_surface.output.wlr_output.effectiveResolution(&box.width, &box.height);
wlr_xdg_popup.unconstrainFromBox(&box);
},
.drag_icon, .lock_surface => unreachable,
}
wlr_xdg_popup.base.events.destroy.add(&xdg_popup.surface_destroy);
wlr_xdg_popup.base.events.map.add(&xdg_popup.map);
wlr_xdg_popup.base.events.unmap.add(&xdg_popup.unmap);
wlr_xdg_popup.base.events.new_popup.add(&xdg_popup.new_popup);
wlr_xdg_popup.base.surface.events.new_subsurface.add(&xdg_popup.new_subsurface);
Subsurface.handleExisting(wlr_xdg_popup.base.surface, parent);
}
pub fn destroy(xdg_popup: *XdgPopup) void {
xdg_popup.surface_destroy.link.remove();
xdg_popup.map.link.remove();
xdg_popup.unmap.link.remove();
xdg_popup.new_popup.link.remove();
xdg_popup.new_subsurface.link.remove();
if (xdg_popup.wlr_xdg_popup.base.mapped) xdg_popup.commit.link.remove();
Subsurface.destroySubsurfaces(xdg_popup.wlr_xdg_popup.base.surface);
XdgPopup.destroyPopups(xdg_popup.wlr_xdg_popup.base);
xdg_popup.wlr_xdg_popup.base.data = 0;
util.gpa.destroy(xdg_popup);
}
pub fn destroyPopups(wlr_xdg_surface: *wlr.XdgSurface) void {
var it = wlr_xdg_surface.popups.iterator(.forward);
while (it.next()) |wlr_xdg_popup| {
if (@intToPtr(?*XdgPopup, wlr_xdg_popup.base.data)) |xdg_popup| xdg_popup.destroy();
}
}
fn handleDestroy(listener: *wl.Listener(void)) void {
const xdg_popup = @fieldParentPtr(XdgPopup, "surface_destroy", listener);
xdg_popup.destroy();
}
fn handleMap(listener: *wl.Listener(void)) void {
const xdg_popup = @fieldParentPtr(XdgPopup, "map", listener);
xdg_popup.wlr_xdg_popup.base.surface.events.commit.add(&xdg_popup.commit);
xdg_popup.parent.damageWholeOutput();
}
fn handleUnmap(listener: *wl.Listener(void)) void {
const xdg_popup = @fieldParentPtr(XdgPopup, "unmap", listener);
xdg_popup.commit.link.remove();
xdg_popup.parent.damageWholeOutput();
}
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
const xdg_popup = @fieldParentPtr(XdgPopup, "commit", listener);
xdg_popup.parent.damageWholeOutput();
}
fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void {
const xdg_popup = @fieldParentPtr(XdgPopup, "new_popup", listener);
XdgPopup.create(wlr_xdg_popup, xdg_popup.parent);
}
fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), new_wlr_subsurface: *wlr.Subsurface) void {
const xdg_popup = @fieldParentPtr(XdgPopup, "new_subsurface", listener);
Subsurface.create(new_wlr_subsurface, xdg_popup.parent);
}

View File

@ -26,10 +26,8 @@ const util = @import("util.zig");
const Output = @import("Output.zig");
const Seat = @import("Seat.zig");
const Subsurface = @import("Subsurface.zig");
const View = @import("View.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
const XdgPopup = @import("XdgPopup.zig");
const log = std.log.scoped(.xdg_shell);
@ -46,8 +44,6 @@ acked_pending_serial: bool = false,
destroy: wl.Listener(void) = wl.Listener(void).init(handleDestroy),
map: wl.Listener(void) = wl.Listener(void).init(handleMap),
unmap: wl.Listener(void) = wl.Listener(void).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 that are only active while the view is mapped
ack_configure: wl.Listener(*wlr.XdgSurface.Configure) =
@ -78,10 +74,6 @@ pub fn create(output: *Output, xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory
xdg_toplevel.base.events.destroy.add(&self.destroy);
xdg_toplevel.base.events.map.add(&self.map);
xdg_toplevel.base.events.unmap.add(&self.unmap);
xdg_toplevel.base.events.new_popup.add(&self.new_popup);
xdg_toplevel.base.surface.events.new_subsurface.add(&self.new_subsurface);
Subsurface.handleExisting(xdg_toplevel.base.surface, .{ .xdg_toplevel = self });
}
/// Returns true if a configure must be sent to ensure that the pending
@ -164,11 +156,6 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
self.destroy.link.remove();
self.map.link.remove();
self.unmap.link.remove();
self.new_popup.link.remove();
self.new_subsurface.link.remove();
Subsurface.destroySubsurfaces(self.xdg_toplevel.base.surface);
XdgPopup.destroyPopups(self.xdg_toplevel.base);
self.view.destroy();
}
@ -296,7 +283,6 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
// before some change occured that caused shouldTrackConfigure() to return false.
view.dropSavedBuffers();
view.output.damage.?.addWhole();
server.input_manager.updateCursorState();
}
} else {
@ -307,7 +293,6 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
view.sendFrameDone();
}
} else {
view.output.damage.?.addWhole();
const size_changed = !std.meta.eql(view.surface_box, new_box);
view.surface_box = new_box;
// If the client has decided to resize itself and the view is floating,
@ -320,16 +305,6 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
}
}
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, .{ .xdg_toplevel = self });
}
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, .{ .xdg_toplevel = self });
}
/// Called when the client asks to be fullscreened. We always honor the request
/// for now, perhaps it should be denied in some cases in the future.
fn handleRequestFullscreen(listener: *wl.Listener(void)) void {

View File

@ -43,9 +43,6 @@ unmap: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).ini
set_override_redirect: wl.Listener(*wlr.XwaylandSurface) =
wl.Listener(*wlr.XwaylandSurface).init(handleSetOverrideRedirect),
// Listeners that are only active while mapped
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
/// The override redirect surface will add itself to the list in Root when it is mapped.
pub fn create(xwayland_surface: *wlr.XwaylandSurface) error{OutOfMemory}!*Self {
const node = try util.gpa.create(std.TailQueue(Self).Node);
@ -89,14 +86,12 @@ fn handleDestroy(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandS
}
/// Called when the xwayland surface is mapped, or ready to display on-screen.
pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wlr.XwaylandSurface) void {
pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSurface) void {
const self = @fieldParentPtr(Self, "map", listener);
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
server.root.xwayland_override_redirect_views.prepend(node);
xwayland_surface.surface.?.events.commit.add(&self.commit);
self.focusIfDesired();
}
@ -129,8 +124,6 @@ fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSur
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
server.root.xwayland_override_redirect_views.remove(node);
self.commit.link.remove();
// If the unmapped surface is currently focused, pass keyboard focus
// to the most appropriate surface.
var seat_it = server.input_manager.seats.first;
@ -151,11 +144,6 @@ fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSur
server.root.startTransaction();
}
fn handleCommit(_: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
}
fn handleSetOverrideRedirect(
listener: *wl.Listener(*wlr.XwaylandSurface),
xwayland_surface: *wlr.XwaylandSurface,

View File

@ -29,7 +29,6 @@ const util = @import("util.zig");
const Output = @import("Output.zig");
const View = @import("View.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
const XdgPopup = @import("XdgPopup.zig");
const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
const log = std.log.scoped(.xwayland);
@ -297,8 +296,6 @@ fn handleSetOverrideRedirect(
fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
const self = @fieldParentPtr(Self, "commit", listener);
self.view.output.damage.?.addWhole();
self.view.surface_box = .{
.x = 0,
.y = 0,

View File

@ -46,9 +46,6 @@ pub fn backgroundColor(
if (args.len > 2) return Error.TooManyArguments;
server.config.background_color = try parseRgba(args[1]);
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
}
pub fn borderColorFocused(
@ -60,9 +57,6 @@ pub fn borderColorFocused(
if (args.len > 2) return Error.TooManyArguments;
server.config.border_color_focused = try parseRgba(args[1]);
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
}
pub fn borderColorUnfocused(
@ -74,9 +68,6 @@ pub fn borderColorUnfocused(
if (args.len > 2) return Error.TooManyArguments;
server.config.border_color_unfocused = try parseRgba(args[1]);
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
}
pub fn borderColorUrgent(
@ -88,9 +79,6 @@ pub fn borderColorUrgent(
if (args.len > 2) return Error.TooManyArguments;
server.config.border_color_urgent = try parseRgba(args[1]);
var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.?.addWhole();
}
pub fn setCursorWarp(

View File

@ -47,20 +47,11 @@ pub fn renderOutput(output: *Output) void {
var now: os.timespec = undefined;
os.clock_gettime(os.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
var needs_frame: bool = undefined;
var damage_region: pixman.Region32 = undefined;
damage_region.init();
defer damage_region.deinit();
output.damage.?.attachRender(&needs_frame, &damage_region) catch {
output.wlr_output.attachRender(null) catch {
log.err("failed to attach renderer", .{});
return;
};
if (!needs_frame) {
output.wlr_output.rollback();
return;
}
server.renderer.begin(@intCast(u32, output.wlr_output.width), @intCast(u32, output.wlr_output.height));
// In order to avoid flashing a blank black screen as the session is locked