render: do basic yes/no damage tracking
This commit is contained in:
parent
3390f223a8
commit
13f01bcb4b
11 changed files with 233 additions and 54 deletions
2
deps/zig-pixman
vendored
2
deps/zig-pixman
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 9acac698e073ff54b09a62fecb144de326f67626
|
||||
Subproject commit 135f22345671e0ae2d1bc4b27cfdee9e97b97dfc
|
|
@ -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);
|
||||
|
@ -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.* = .{
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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.?);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
// 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);
|
||||
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 });
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 = .{
|
||||
|
@ -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);
|
||||
|
|
|
@ -404,6 +404,8 @@ fn commitTransaction(self: *Self) void {
|
|||
}
|
||||
|
||||
if (view_tags_changed) output.sendViewTags();
|
||||
|
||||
output.damage.addWhole();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
103
river/Subsurface.zig
Normal file
103
river/Subsurface.zig
Normal file
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
||||
pub fn init(self: *Self, output: *Output, parent_box: *const Box, wlr_xdg_popup: *wlr.XdgPopup) void {
|
||||
// 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 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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ const util = @import("util.zig");
|
|||
|
||||
const Box = @import("Box.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");
|
||||
|
@ -42,10 +43,11 @@ xdg_surface: *wlr.XdgSurface,
|
|||
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),
|
||||
|
||||
// Listeners that are only active while the view 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),
|
||||
// zig fmt: off
|
||||
request_fullscreen: wl.Listener(*wlr.XdgToplevel.event.SetFullscreen) =
|
||||
wl.Listener(*wlr.XdgToplevel.event.SetFullscreen).init(handleRequestFullscreen),
|
||||
|
@ -65,6 +67,8 @@ pub fn init(self: *Self, view: *View, xdg_surface: *wlr.XdgSurface) void {
|
|||
self.xdg_surface.events.destroy.add(&self.destroy);
|
||||
self.xdg_surface.events.map.add(&self.map);
|
||||
self.xdg_surface.events.unmap.add(&self.unmap);
|
||||
self.xdg_surface.events.new_popup.add(&self.new_popup);
|
||||
self.xdg_surface.surface.events.new_subsurface.add(&self.new_subsurface);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
|
@ -73,6 +77,8 @@ pub fn deinit(self: *Self) void {
|
|||
self.destroy.link.remove();
|
||||
self.map.link.remove();
|
||||
self.unmap.link.remove();
|
||||
self.new_popup.link.remove();
|
||||
self.new_subsurface.link.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,7 +167,6 @@ fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurfa
|
|||
|
||||
// Add listeners that are only active while mapped
|
||||
self.xdg_surface.surface.events.commit.add(&self.commit);
|
||||
self.xdg_surface.events.new_popup.add(&self.new_popup);
|
||||
toplevel.events.request_fullscreen.add(&self.request_fullscreen);
|
||||
toplevel.events.request_move.add(&self.request_move);
|
||||
toplevel.events.request_resize.add(&self.request_resize);
|
||||
|
@ -229,7 +234,6 @@ fn handleUnmap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSur
|
|||
|
||||
// Remove listeners that are only active while mapped
|
||||
self.commit.link.remove();
|
||||
self.new_popup.link.remove();
|
||||
self.request_fullscreen.link.remove();
|
||||
self.request_move.link.remove();
|
||||
self.request_resize.link.remove();
|
||||
|
@ -260,6 +264,7 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) voi
|
|||
view.sendFrameDone();
|
||||
}
|
||||
} else {
|
||||
view.output.damage.addWhole();
|
||||
// TODO: handle unexpected change in dimensions
|
||||
if (!std.meta.eql(view.surface_box, new_box))
|
||||
log.err("view changed size unexpectedly", .{});
|
||||
|
@ -267,16 +272,14 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) voi
|
|||
}
|
||||
}
|
||||
|
||||
/// Called when a new xdg popup is requested by the client
|
||||
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, .{ .view = self.view });
|
||||
}
|
||||
|
||||
// This will free itself on destroy
|
||||
const xdg_popup = util.gpa.create(XdgPopup) catch {
|
||||
wlr_xdg_popup.resource.postNoMemory();
|
||||
return;
|
||||
};
|
||||
xdg_popup.init(self.view.output, &self.view.current.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, .{ .view = self.view });
|
||||
}
|
||||
|
||||
/// Called when the client asks to be fullscreened. We always honor the request
|
||||
|
|
|
@ -37,6 +37,7 @@ request_configure: wl.Listener(*wlr.XwaylandSurface.event.Configure) =
|
|||
destroy: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleDestroy),
|
||||
map: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleMap),
|
||||
unmap: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleUnmap),
|
||||
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
|
||||
|
||||
pub fn init(self: *Self, xwayland_surface: *wlr.XwaylandSurface) void {
|
||||
self.* = .{ .xwayland_surface = xwayland_surface };
|
||||
|
@ -78,6 +79,8 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl
|
|||
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
||||
server.root.xwayland_unmanaged_views.prepend(node);
|
||||
|
||||
xwayland_surface.surface.?.events.commit.add(&self.commit);
|
||||
|
||||
// TODO: handle keyboard focus
|
||||
// if (wlr_xwayland_or_surface_wants_focus(self.xwayland_surface)) { ...
|
||||
}
|
||||
|
@ -89,4 +92,11 @@ fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *
|
|||
// Remove self from the list of unmanged views in the root
|
||||
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
||||
server.root.xwayland_unmanaged_views.remove(node);
|
||||
|
||||
self.commit.link.remove();
|
||||
}
|
||||
|
||||
fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
|
||||
var it = server.root.outputs.first;
|
||||
while (it) |node| : (it = node.next) node.data.damage.addWhole();
|
||||
}
|
||||
|
|
|
@ -232,6 +232,9 @@ fn handleRequestConfigure(
|
|||
/// TODO: check for unexpected change in size and react as needed
|
||||
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 = Box{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
|
|
|
@ -53,7 +53,19 @@ pub fn renderOutput(output: *Output) void {
|
|||
var now: os.timespec = undefined;
|
||||
os.clock_gettime(os.CLOCK_MONOTONIC, &now) catch unreachable;
|
||||
|
||||
output.wlr_output.attachRender(null) catch return;
|
||||
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 {
|
||||
log.err("failed to attach renderer", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
if (!needs_frame) {
|
||||
output.wlr_output.rollback();
|
||||
return;
|
||||
}
|
||||
|
||||
renderer.begin(@intCast(u32, output.wlr_output.width), @intCast(u32, output.wlr_output.height));
|
||||
|
||||
|
|
Loading…
Reference in a new issue