render: do basic yes/no damage tracking
This commit is contained in:
parent
3390f223a8
commit
13f01bcb4b
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 Box = @import("Box.zig");
|
||||||
const Output = @import("Output.zig");
|
const Output = @import("Output.zig");
|
||||||
|
const Subsurface = @import("Subsurface.zig");
|
||||||
const XdgPopup = @import("XdgPopup.zig");
|
const XdgPopup = @import("XdgPopup.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.layer_shell);
|
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),
|
destroy: wl.Listener(*wlr.LayerSurfaceV1) = wl.Listener(*wlr.LayerSurfaceV1).init(handleDestroy),
|
||||||
map: wl.Listener(*wlr.LayerSurfaceV1) = wl.Listener(*wlr.LayerSurfaceV1).init(handleMap),
|
map: wl.Listener(*wlr.LayerSurfaceV1) = wl.Listener(*wlr.LayerSurfaceV1).init(handleMap),
|
||||||
unmap: wl.Listener(*wlr.LayerSurfaceV1) = wl.Listener(*wlr.LayerSurfaceV1).init(handleUnmap),
|
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
|
// Listeners only active while the layer surface is mapped
|
||||||
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
|
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 {
|
pub fn init(self: *Self, output: *Output, wlr_layer_surface: *wlr.LayerSurfaceV1) void {
|
||||||
self.* = .{
|
self.* = .{
|
||||||
@ -62,9 +64,11 @@ pub fn init(self: *Self, output: *Output, wlr_layer_surface: *wlr.LayerSurfaceV1
|
|||||||
list.remove(node);
|
list.remove(node);
|
||||||
|
|
||||||
// Set up listeners that are active for the entire lifetime of the layer surface
|
// Set up listeners that are active for the entire lifetime of the layer surface
|
||||||
self.wlr_layer_surface.events.destroy.add(&self.destroy);
|
wlr_layer_surface.events.destroy.add(&self.destroy);
|
||||||
self.wlr_layer_surface.events.map.add(&self.map);
|
wlr_layer_surface.events.map.add(&self.map);
|
||||||
self.wlr_layer_surface.events.unmap.add(&self.unmap);
|
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 {
|
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.destroy.link.remove();
|
||||||
self.map.link.remove();
|
self.map.link.remove();
|
||||||
self.unmap.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);
|
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
||||||
util.gpa.destroy(node);
|
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
|
// Add listeners that are only active while mapped
|
||||||
wlr_layer_surface.surface.events.commit.add(&self.commit);
|
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.?);
|
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
|
// remove listeners only active while the layer surface is mapped
|
||||||
self.commit.link.remove();
|
self.commit.link.remove();
|
||||||
self.new_popup.link.remove();
|
|
||||||
|
|
||||||
// Remove from the output's list of layer surfaces
|
// Remove from the output's list of layer surfaces
|
||||||
const self_node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
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();
|
self.output.arrangeLayers();
|
||||||
server.root.startTransaction();
|
server.root.startTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.output.damage.addWhole();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void {
|
fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void {
|
||||||
const self = @fieldParentPtr(Self, "new_popup", listener);
|
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();
|
fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), new_wlr_subsurface: *wlr.Subsurface) void {
|
||||||
return;
|
const self = @fieldParentPtr(Self, "new_subsurface", listener);
|
||||||
};
|
Subsurface.create(new_wlr_subsurface, .{ .layer_surface = self });
|
||||||
xdg_popup.init(self.output, &self.box, wlr_xdg_popup);
|
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ const State = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
wlr_output: *wlr.Output,
|
wlr_output: *wlr.Output,
|
||||||
|
damage: *wlr.OutputDamage,
|
||||||
|
|
||||||
/// All layer surfaces on the output, indexed by the layer enum.
|
/// All layer surfaces on the output, indexed by the layer enum.
|
||||||
layers: [4]std.TailQueue(LayerSurface) = [1]std.TailQueue(LayerSurface){.{}} ** 4,
|
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),
|
destroy: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleDestroy),
|
||||||
enable: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleEnable),
|
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),
|
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 {
|
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
|
// 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.* = .{
|
self.* = .{
|
||||||
.wlr_output = wlr_output,
|
.wlr_output = wlr_output,
|
||||||
|
.damage = try wlr.OutputDamage.create(wlr_output),
|
||||||
.usable_box = undefined,
|
.usable_box = undefined,
|
||||||
};
|
};
|
||||||
wlr_output.data = @ptrToInt(self);
|
wlr_output.data = @ptrToInt(self);
|
||||||
|
|
||||||
wlr_output.events.destroy.add(&self.destroy);
|
wlr_output.events.destroy.add(&self.destroy);
|
||||||
wlr_output.events.enable.add(&self.enable);
|
wlr_output.events.enable.add(&self.enable);
|
||||||
wlr_output.events.frame.add(&self.frame);
|
|
||||||
wlr_output.events.mode.add(&self.mode);
|
wlr_output.events.mode.add(&self.mode);
|
||||||
|
|
||||||
|
self.damage.events.frame.add(&self.frame);
|
||||||
|
|
||||||
if (wlr_output.isNoop()) {
|
if (wlr_output.isNoop()) {
|
||||||
// A noop output is always 0 x 0
|
// A noop output is always 0 x 0
|
||||||
self.usable_box = .{
|
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);
|
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,
|
// This function is called every time an output is ready to display a frame,
|
||||||
// generally at the output's refresh rate (e.g. 60Hz).
|
// generally at the output's refresh rate (e.g. 60Hz).
|
||||||
const self = @fieldParentPtr(Self, "frame", listener);
|
const self = @fieldParentPtr(Self, "frame", listener);
|
||||||
|
@ -404,6 +404,8 @@ fn commitTransaction(self: *Self) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (view_tags_changed) output.sendViewTags();
|
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.
|
/// Otherwise, apply the pending state immediately.
|
||||||
pub fn notifyConfiguredOrApplyPending(self: *Self) void {
|
pub fn notifyConfiguredOrApplyPending(self: *Self) void {
|
||||||
self.pending_serial = null;
|
self.pending_serial = null;
|
||||||
if (self.shouldTrackConfigure())
|
if (self.shouldTrackConfigure()) {
|
||||||
server.root.notifyConfigured()
|
server.root.notifyConfigured();
|
||||||
else {
|
} else {
|
||||||
const self_tags_changed = self.pending.tags != self.current.tags;
|
const self_tags_changed = self.pending.tags != self.current.tags;
|
||||||
self.current = self.pending;
|
self.current = self.pending;
|
||||||
self.commitOpacityTransition();
|
self.commitOpacityTransition();
|
||||||
if (self_tags_changed) self.output.sendViewTags();
|
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 util = @import("util.zig");
|
||||||
|
|
||||||
const Box = @import("Box.zig");
|
const Subsurface = @import("Subsurface.zig");
|
||||||
const Output = @import("Output.zig");
|
const Parent = Subsurface.Parent;
|
||||||
|
|
||||||
const log = std.log.scoped(.server);
|
/// The parent at the root of this surface tree
|
||||||
|
parent: Parent,
|
||||||
/// 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
|
|
||||||
wlr_xdg_popup: *wlr.XdgPopup,
|
wlr_xdg_popup: *wlr.XdgPopup,
|
||||||
|
|
||||||
|
// Always active
|
||||||
destroy: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleDestroy),
|
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_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.* = .{
|
self.* = .{
|
||||||
.output = output,
|
.parent = parent,
|
||||||
.parent_box = parent_box,
|
|
||||||
.wlr_xdg_popup = wlr_xdg_popup,
|
.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
|
// The output box relative to the parent of the popup
|
||||||
const output_dimensions = output.getEffectiveResolution();
|
|
||||||
var box = wlr.Box{
|
var box = wlr.Box{
|
||||||
.x = -parent_box.x,
|
.x = -parent_box.x,
|
||||||
.y = -parent_box.y,
|
.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.unconstrainFromBox(&box);
|
||||||
|
|
||||||
wlr_xdg_popup.base.events.destroy.add(&self.destroy);
|
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.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 {
|
fn handleDestroy(listener: *wl.Listener(*wlr.XdgSurface), wlr_xdg_surface: *wlr.XdgSurface) void {
|
||||||
const self = @fieldParentPtr(Self, "destroy", listener);
|
const self = @fieldParentPtr(Self, "destroy", listener);
|
||||||
|
|
||||||
self.destroy.link.remove();
|
self.destroy.link.remove();
|
||||||
|
self.map.link.remove();
|
||||||
|
self.unmap.link.remove();
|
||||||
self.new_popup.link.remove();
|
self.new_popup.link.remove();
|
||||||
|
self.new_subsurface.link.remove();
|
||||||
|
|
||||||
util.gpa.destroy(self);
|
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 {
|
fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void {
|
||||||
const self = @fieldParentPtr(Self, "new_popup", listener);
|
const self = @fieldParentPtr(Self, "new_popup", listener);
|
||||||
|
|
||||||
// This will free itself on destroy
|
Self.create(wlr_xdg_popup, self.parent);
|
||||||
const xdg_popup = util.gpa.create(Self) catch {
|
}
|
||||||
wlr_xdg_popup.resource.postNoMemory();
|
|
||||||
log.crit("out of memory", .{});
|
fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), new_wlr_subsurface: *wlr.Subsurface) void {
|
||||||
return;
|
const self = @fieldParentPtr(Self, "new_subsurface", listener);
|
||||||
};
|
|
||||||
xdg_popup.init(self.output, self.parent_box, wlr_xdg_popup);
|
Subsurface.create(new_wlr_subsurface, self.parent);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ const util = @import("util.zig");
|
|||||||
|
|
||||||
const Box = @import("Box.zig");
|
const Box = @import("Box.zig");
|
||||||
const Seat = @import("Seat.zig");
|
const Seat = @import("Seat.zig");
|
||||||
|
const Subsurface = @import("Subsurface.zig");
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||||
const XdgPopup = @import("XdgPopup.zig");
|
const XdgPopup = @import("XdgPopup.zig");
|
||||||
@ -42,10 +43,11 @@ xdg_surface: *wlr.XdgSurface,
|
|||||||
destroy: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleDestroy),
|
destroy: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleDestroy),
|
||||||
map: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleMap),
|
map: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleMap),
|
||||||
unmap: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleUnmap),
|
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
|
// Listeners that are only active while the view is mapped
|
||||||
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
|
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
|
// zig fmt: off
|
||||||
request_fullscreen: wl.Listener(*wlr.XdgToplevel.event.SetFullscreen) =
|
request_fullscreen: wl.Listener(*wlr.XdgToplevel.event.SetFullscreen) =
|
||||||
wl.Listener(*wlr.XdgToplevel.event.SetFullscreen).init(handleRequestFullscreen),
|
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.destroy.add(&self.destroy);
|
||||||
self.xdg_surface.events.map.add(&self.map);
|
self.xdg_surface.events.map.add(&self.map);
|
||||||
self.xdg_surface.events.unmap.add(&self.unmap);
|
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 {
|
pub fn deinit(self: *Self) void {
|
||||||
@ -73,6 +77,8 @@ pub fn deinit(self: *Self) void {
|
|||||||
self.destroy.link.remove();
|
self.destroy.link.remove();
|
||||||
self.map.link.remove();
|
self.map.link.remove();
|
||||||
self.unmap.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
|
// Add listeners that are only active while mapped
|
||||||
self.xdg_surface.surface.events.commit.add(&self.commit);
|
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_fullscreen.add(&self.request_fullscreen);
|
||||||
toplevel.events.request_move.add(&self.request_move);
|
toplevel.events.request_move.add(&self.request_move);
|
||||||
toplevel.events.request_resize.add(&self.request_resize);
|
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
|
// Remove listeners that are only active while mapped
|
||||||
self.commit.link.remove();
|
self.commit.link.remove();
|
||||||
self.new_popup.link.remove();
|
|
||||||
self.request_fullscreen.link.remove();
|
self.request_fullscreen.link.remove();
|
||||||
self.request_move.link.remove();
|
self.request_move.link.remove();
|
||||||
self.request_resize.link.remove();
|
self.request_resize.link.remove();
|
||||||
@ -260,6 +264,7 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) voi
|
|||||||
view.sendFrameDone();
|
view.sendFrameDone();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
view.output.damage.addWhole();
|
||||||
// TODO: handle unexpected change in dimensions
|
// TODO: handle unexpected change in dimensions
|
||||||
if (!std.meta.eql(view.surface_box, new_box))
|
if (!std.meta.eql(view.surface_box, new_box))
|
||||||
log.err("view changed size unexpectedly", .{});
|
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 {
|
fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void {
|
||||||
const self = @fieldParentPtr(Self, "new_popup", listener);
|
const self = @fieldParentPtr(Self, "new_popup", listener);
|
||||||
|
XdgPopup.create(wlr_xdg_popup, .{ .view = self.view });
|
||||||
|
}
|
||||||
|
|
||||||
// This will free itself on destroy
|
fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), new_wlr_subsurface: *wlr.Subsurface) void {
|
||||||
const xdg_popup = util.gpa.create(XdgPopup) catch {
|
const self = @fieldParentPtr(Self, "new_subsurface", listener);
|
||||||
wlr_xdg_popup.resource.postNoMemory();
|
Subsurface.create(new_wlr_subsurface, .{ .view = self.view });
|
||||||
return;
|
|
||||||
};
|
|
||||||
xdg_popup.init(self.view.output, &self.view.current.box, wlr_xdg_popup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the client asks to be fullscreened. We always honor the request
|
/// 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),
|
destroy: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleDestroy),
|
||||||
map: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleMap),
|
map: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleMap),
|
||||||
unmap: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleUnmap),
|
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 {
|
pub fn init(self: *Self, xwayland_surface: *wlr.XwaylandSurface) void {
|
||||||
self.* = .{ .xwayland_surface = xwayland_surface };
|
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);
|
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
||||||
server.root.xwayland_unmanaged_views.prepend(node);
|
server.root.xwayland_unmanaged_views.prepend(node);
|
||||||
|
|
||||||
|
xwayland_surface.surface.?.events.commit.add(&self.commit);
|
||||||
|
|
||||||
// TODO: handle keyboard focus
|
// TODO: handle keyboard focus
|
||||||
// if (wlr_xwayland_or_surface_wants_focus(self.xwayland_surface)) { ...
|
// 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
|
// Remove self from the list of unmanged views in the root
|
||||||
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
||||||
server.root.xwayland_unmanaged_views.remove(node);
|
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
|
/// TODO: check for unexpected change in size and react as needed
|
||||||
fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
|
fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
|
||||||
const self = @fieldParentPtr(Self, "commit", listener);
|
const self = @fieldParentPtr(Self, "commit", listener);
|
||||||
|
|
||||||
|
self.view.output.damage.addWhole();
|
||||||
|
|
||||||
self.view.surface_box = Box{
|
self.view.surface_box = Box{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
|
@ -53,7 +53,19 @@ pub fn renderOutput(output: *Output) void {
|
|||||||
var now: os.timespec = undefined;
|
var now: os.timespec = undefined;
|
||||||
os.clock_gettime(os.CLOCK_MONOTONIC, &now) catch unreachable;
|
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));
|
renderer.begin(@intCast(u32, output.wlr_output.width), @intCast(u32, output.wlr_output.height));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user