build: update to wlroots 0.17
This commit is contained in:
parent
50ccd4c5b3
commit
7ee6c79b6b
@ -27,13 +27,13 @@ sources:
|
||||
tasks:
|
||||
- install_deps: |
|
||||
cd wayland
|
||||
git checkout 1.21.0
|
||||
git checkout 1.22.0
|
||||
meson setup build -Ddocumentation=false -Dtests=false --prefix /usr
|
||||
sudo ninja -C build install
|
||||
cd ..
|
||||
|
||||
cd wlroots
|
||||
git checkout 0.16.0
|
||||
git checkout 0.17.0
|
||||
meson setup build --auto-features=enabled -Drenderers=gles2 -Dexamples=false \
|
||||
-Dwerror=false -Db_ndebug=false -Dxcb-errors=disabled --prefix /usr
|
||||
sudo ninja -C build/ install
|
||||
|
@ -25,13 +25,13 @@ sources:
|
||||
tasks:
|
||||
- install_deps: |
|
||||
cd wayland
|
||||
git checkout 1.21.0
|
||||
git checkout 1.22.0
|
||||
meson setup build -Ddocumentation=false -Dtests=false --prefix /usr
|
||||
sudo ninja -C build install
|
||||
cd ..
|
||||
|
||||
cd wlroots
|
||||
git checkout 0.16.0
|
||||
git checkout 0.17.0
|
||||
meson setup build --auto-features=enabled -Drenderers=gles2 -Dexamples=false \
|
||||
-Dwerror=false -Db_ndebug=false --prefix /usr
|
||||
sudo ninja -C build/ install
|
||||
|
@ -19,6 +19,7 @@ packages:
|
||||
- x11/xcb-util-wm
|
||||
- x11-servers/xwayland
|
||||
- sysutils/seatd
|
||||
- sysutils/libdisplay-info
|
||||
- gmake
|
||||
- scdoc
|
||||
- wget
|
||||
@ -29,13 +30,13 @@ sources:
|
||||
tasks:
|
||||
- install_deps: |
|
||||
cd wayland
|
||||
git checkout 1.21.0
|
||||
git checkout 1.22.0
|
||||
meson setup build -Ddocumentation=false -Dtests=false --prefix /usr
|
||||
sudo ninja -C build install
|
||||
cd ..
|
||||
|
||||
cd wlroots
|
||||
git checkout 0.16.0
|
||||
git checkout 0.17.0
|
||||
meson setup build --auto-features=enabled -Drenderers=gles2 -Dexamples=false \
|
||||
-Dwerror=false -Db_ndebug=false --prefix /usr
|
||||
sudo ninja -C build/ install
|
||||
|
@ -38,7 +38,7 @@ distribution.
|
||||
- [zig](https://ziglang.org/download/) 0.11
|
||||
- wayland
|
||||
- wayland-protocols
|
||||
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.16
|
||||
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.17
|
||||
- xkbcommon
|
||||
- libevdev
|
||||
- pixman
|
||||
|
2
deps/zig-wlroots
vendored
2
deps/zig-wlroots
vendored
@ -1 +1 @@
|
||||
Subproject commit 0f07b2c666125d06529dfc688da4e71bff9a04f9
|
||||
Subproject commit a4e100599b9f742215fa09afce8c56cffea2e796
|
@ -98,37 +98,6 @@ const Mode = union(enum) {
|
||||
},
|
||||
};
|
||||
|
||||
const Image = enum {
|
||||
/// The current image of the cursor is unknown, perhaps because it was set by a client.
|
||||
unknown,
|
||||
left_ptr,
|
||||
move,
|
||||
@"n-resize",
|
||||
@"s-resize",
|
||||
@"w-resize",
|
||||
@"e-resize",
|
||||
@"nw-resize",
|
||||
@"ne-resize",
|
||||
@"sw-resize",
|
||||
@"se-resize",
|
||||
|
||||
fn resize(edges: wlr.Edges) Image {
|
||||
assert(!(edges.top and edges.bottom));
|
||||
assert(!(edges.left and edges.right));
|
||||
|
||||
if (edges.top and edges.left) return .@"nw-resize";
|
||||
if (edges.top and edges.right) return .@"ne-resize";
|
||||
if (edges.bottom and edges.left) return .@"sw-resize";
|
||||
if (edges.bottom and edges.right) return .@"se-resize";
|
||||
if (edges.top) return .@"n-resize";
|
||||
if (edges.bottom) return .@"s-resize";
|
||||
if (edges.left) return .@"w-resize";
|
||||
if (edges.right) return .@"e-resize";
|
||||
|
||||
return .@"se-resize";
|
||||
}
|
||||
};
|
||||
|
||||
const default_size = 24;
|
||||
|
||||
const LayoutPoint = struct {
|
||||
@ -150,9 +119,12 @@ inflight_mode: Mode = .passthrough,
|
||||
seat: *Seat,
|
||||
wlr_cursor: *wlr.Cursor,
|
||||
pointer_gestures: *wlr.PointerGesturesV1,
|
||||
xcursor_manager: *wlr.XcursorManager,
|
||||
|
||||
image: Image = .unknown,
|
||||
/// Xcursor manager for the currently configured Xcursor theme.
|
||||
xcursor_manager: *wlr.XcursorManager,
|
||||
/// Name of the current Xcursor shape, or null if a client has configured a
|
||||
/// surface to be used as the cursor shape instead.
|
||||
xcursor_name: ?[*:0]const u8 = null,
|
||||
|
||||
/// Number of distinct buttons currently pressed
|
||||
pressed_count: u32 = 0,
|
||||
@ -301,26 +273,15 @@ pub fn setTheme(self: *Self, theme: ?[*:0]const u8, _size: ?u32) !void {
|
||||
@intCast(image.hotspot_y),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (self.image != .unknown) {
|
||||
self.xcursor_manager.setCursorImage(@tagName(self.image), self.wlr_cursor);
|
||||
}
|
||||
if (self.xcursor_name) |name| {
|
||||
self.wlr_cursor.setXcursor(self.xcursor_manager, name);
|
||||
}
|
||||
}
|
||||
|
||||
/// It seems that setCursorImage is actually fairly expensive to call repeatedly
|
||||
/// as it does no checks to see if the the given image is already set. Therefore,
|
||||
/// do that check here.
|
||||
fn setImage(self: *Self, image: Image) void {
|
||||
assert(image != .unknown);
|
||||
|
||||
if (image == self.image) return;
|
||||
self.image = image;
|
||||
self.xcursor_manager.setCursorImage(@tagName(image), self.wlr_cursor);
|
||||
}
|
||||
|
||||
fn clearFocus(self: *Self) void {
|
||||
self.setImage(.left_ptr);
|
||||
self.wlr_cursor.setXcursor(self.xcursor_manager, "left_ptr");
|
||||
self.seat.wlr_seat.pointerNotifyClearFocus();
|
||||
}
|
||||
|
||||
@ -685,15 +646,15 @@ fn handleRequestSetCursor(
|
||||
// cursor moves between outputs.
|
||||
log.debug("focused client set cursor", .{});
|
||||
self.wlr_cursor.setSurface(event.surface, event.hotspot_x, event.hotspot_y);
|
||||
self.image = .unknown;
|
||||
self.xcursor_name = null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hide(self: *Self) void {
|
||||
if (self.pressed_count > 0) return;
|
||||
self.hidden = true;
|
||||
self.wlr_cursor.setImage(null, 0, 0, 0, 0, 0, 0);
|
||||
self.image = .unknown;
|
||||
self.wlr_cursor.unsetImage();
|
||||
self.xcursor_name = null;
|
||||
self.seat.wlr_seat.pointerNotifyClearFocus();
|
||||
self.hide_cursor_timer.timerUpdate(0) catch {
|
||||
log.err("failed to update cursor hide timeout", .{});
|
||||
@ -725,7 +686,7 @@ pub fn startMove(cursor: *Self, view: *View) void {
|
||||
.offset_x = @as(i32, @intFromFloat(cursor.wlr_cursor.x)) - view.current.box.x,
|
||||
.offset_y = @as(i32, @intFromFloat(cursor.wlr_cursor.y)) - view.current.box.y,
|
||||
} };
|
||||
cursor.enterMode(new_mode, view, .move);
|
||||
cursor.enterMode(new_mode, view, "move");
|
||||
}
|
||||
|
||||
pub fn startResize(cursor: *Self, view: *View, proposed_edges: ?wlr.Edges) void {
|
||||
@ -758,7 +719,7 @@ pub fn startResize(cursor: *Self, view: *View, proposed_edges: ?wlr.Edges) void
|
||||
.initial_width = @intCast(box.width),
|
||||
.initial_height = @intCast(box.height),
|
||||
} };
|
||||
cursor.enterMode(new_mode, view, Image.resize(edges));
|
||||
cursor.enterMode(new_mode, view, wlr.Xcursor.getResizeName(edges));
|
||||
}
|
||||
|
||||
fn computeEdges(cursor: *const Self, view: *const View) wlr.Edges {
|
||||
@ -798,7 +759,7 @@ fn computeEdges(cursor: *const Self, view: *const View) wlr.Edges {
|
||||
}
|
||||
}
|
||||
|
||||
fn enterMode(cursor: *Self, mode: Mode, view: *View, image: Image) void {
|
||||
fn enterMode(cursor: *Self, mode: Mode, view: *View, xcursor_name: [*:0]const u8) void {
|
||||
assert(cursor.mode == .passthrough or cursor.mode == .down);
|
||||
assert(mode == .move or mode == .resize);
|
||||
|
||||
@ -814,7 +775,7 @@ fn enterMode(cursor: *Self, mode: Mode, view: *View, image: Image) void {
|
||||
}
|
||||
|
||||
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
||||
cursor.setImage(image);
|
||||
cursor.wlr_cursor.setXcursor(cursor.xcursor_manager, xcursor_name);
|
||||
|
||||
server.root.applyPending();
|
||||
}
|
||||
|
@ -27,43 +27,33 @@ const Cursor = @import("Cursor.zig");
|
||||
const SceneNodeData = @import("SceneNodeData.zig");
|
||||
|
||||
wlr_drag_icon: *wlr.Drag.Icon,
|
||||
|
||||
tree: *wlr.SceneTree,
|
||||
surface: *wlr.SceneTree,
|
||||
scene_drag_icon: *wlr.SceneTree,
|
||||
|
||||
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),
|
||||
|
||||
pub fn create(wlr_drag_icon: *wlr.Drag.Icon, cursor: *Cursor) error{OutOfMemory}!void {
|
||||
const tree = try server.root.drag_icons.createSceneTree();
|
||||
errdefer tree.node.destroy();
|
||||
const scene_drag_icon = try server.root.drag_icons.createSceneDragIcon(wlr_drag_icon);
|
||||
errdefer scene_drag_icon.node.destroy();
|
||||
|
||||
const drag_icon = try util.gpa.create(DragIcon);
|
||||
errdefer util.gpa.destroy(drag_icon);
|
||||
|
||||
drag_icon.* = .{
|
||||
.wlr_drag_icon = wlr_drag_icon,
|
||||
.tree = tree,
|
||||
.surface = try tree.createSceneSubsurfaceTree(wlr_drag_icon.surface),
|
||||
.scene_drag_icon = scene_drag_icon,
|
||||
};
|
||||
tree.node.data = @intFromPtr(drag_icon);
|
||||
scene_drag_icon.node.data = @intFromPtr(drag_icon);
|
||||
|
||||
drag_icon.updatePosition(cursor);
|
||||
tree.node.setEnabled(wlr_drag_icon.mapped);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
pub fn updatePosition(drag_icon: *DragIcon, cursor: *Cursor) void {
|
||||
switch (drag_icon.wlr_drag_icon.drag.grab_type) {
|
||||
.keyboard => unreachable,
|
||||
.keyboard_pointer => {
|
||||
drag_icon.tree.node.setPosition(
|
||||
drag_icon.scene_drag_icon.node.setPosition(
|
||||
@intFromFloat(cursor.wlr_cursor.x),
|
||||
@intFromFloat(cursor.wlr_cursor.y),
|
||||
);
|
||||
@ -71,7 +61,7 @@ pub fn updatePosition(drag_icon: *DragIcon, cursor: *Cursor) void {
|
||||
.keyboard_touch => {
|
||||
const touch_id = drag_icon.wlr_drag_icon.drag.touch_id;
|
||||
if (cursor.touch_points.get(touch_id)) |point| {
|
||||
drag_icon.tree.node.setPosition(
|
||||
drag_icon.scene_drag_icon.node.setPosition(
|
||||
@intFromFloat(point.lx),
|
||||
@intFromFloat(point.ly),
|
||||
);
|
||||
@ -83,33 +73,7 @@ pub fn updatePosition(drag_icon: *DragIcon, cursor: *Cursor) void {
|
||||
fn handleDestroy(listener: *wl.Listener(*wlr.Drag.Icon), _: *wlr.Drag.Icon) void {
|
||||
const drag_icon = @fieldParentPtr(DragIcon, "destroy", listener);
|
||||
|
||||
drag_icon.tree.node.destroy();
|
||||
|
||||
drag_icon.destroy.link.remove();
|
||||
drag_icon.map.link.remove();
|
||||
drag_icon.unmap.link.remove();
|
||||
drag_icon.commit.link.remove();
|
||||
|
||||
util.gpa.destroy(drag_icon);
|
||||
}
|
||||
|
||||
fn handleMap(listener: *wl.Listener(*wlr.Drag.Icon), _: *wlr.Drag.Icon) void {
|
||||
const drag_icon = @fieldParentPtr(DragIcon, "map", listener);
|
||||
|
||||
drag_icon.tree.node.setEnabled(true);
|
||||
}
|
||||
|
||||
fn handleUnmap(listener: *wl.Listener(*wlr.Drag.Icon), _: *wlr.Drag.Icon) void {
|
||||
const drag_icon = @fieldParentPtr(DragIcon, "unmap", listener);
|
||||
|
||||
drag_icon.tree.node.setEnabled(false);
|
||||
}
|
||||
|
||||
fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
|
||||
const drag_icon = @fieldParentPtr(DragIcon, "commit", listener);
|
||||
|
||||
drag_icon.surface.node.setPosition(
|
||||
drag_icon.surface.node.x + surface.current.dx,
|
||||
drag_icon.surface.node.y + surface.current.dy,
|
||||
);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ pub fn idleInhibitCheckActive(self: *Self) void {
|
||||
}
|
||||
},
|
||||
.layer_surface => |layer_surface| {
|
||||
if (layer_surface.wlr_layer_surface.mapped) {
|
||||
if (layer_surface.wlr_layer_surface.surface.mapped) {
|
||||
inhibited = true;
|
||||
break;
|
||||
}
|
||||
|
@ -147,13 +147,11 @@ fn handleBuiltinMapping(keysym: xkb.Keysym) bool {
|
||||
switch (@intFromEnum(keysym)) {
|
||||
xkb.Keysym.XF86Switch_VT_1...xkb.Keysym.XF86Switch_VT_12 => {
|
||||
log.debug("switch VT keysym received", .{});
|
||||
if (server.backend.isMulti()) {
|
||||
if (server.backend.getSession()) |session| {
|
||||
const vt = @intFromEnum(keysym) - xkb.Keysym.XF86Switch_VT_1 + 1;
|
||||
const log_server = std.log.scoped(.server);
|
||||
log_server.info("switching to VT {}", .{vt});
|
||||
session.changeVt(vt) catch log_server.err("changing VT failed", .{});
|
||||
}
|
||||
if (server.session) |session| {
|
||||
const vt = @intFromEnum(keysym) - xkb.Keysym.XF86Switch_VT_1 + 1;
|
||||
const log_server = std.log.scoped(.server);
|
||||
log_server.info("switching to VT {}", .{vt});
|
||||
session.changeVt(vt) catch log_server.err("changing VT failed", .{});
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
@ -37,8 +37,8 @@ scene_layer_surface: *wlr.SceneLayerSurfaceV1,
|
||||
popup_tree: *wlr.SceneTree,
|
||||
|
||||
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),
|
||||
map: wl.Listener(void) = wl.Listener(void).init(handleMap),
|
||||
unmap: wl.Listener(void) = wl.Listener(void).init(handleUnmap),
|
||||
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
|
||||
new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup),
|
||||
|
||||
@ -63,8 +63,8 @@ pub fn create(wlr_layer_surface: *wlr.LayerSurfaceV1) error{OutOfMemory}!void {
|
||||
wlr_layer_surface.surface.data = @intFromPtr(&layer_surface.scene_layer_surface.tree.node);
|
||||
|
||||
wlr_layer_surface.events.destroy.add(&layer_surface.destroy);
|
||||
wlr_layer_surface.events.map.add(&layer_surface.map);
|
||||
wlr_layer_surface.events.unmap.add(&layer_surface.unmap);
|
||||
wlr_layer_surface.surface.events.map.add(&layer_surface.map);
|
||||
wlr_layer_surface.surface.events.unmap.add(&layer_surface.unmap);
|
||||
wlr_layer_surface.surface.events.commit.add(&layer_surface.commit);
|
||||
wlr_layer_surface.events.new_popup.add(&layer_surface.new_popup);
|
||||
|
||||
@ -96,20 +96,20 @@ fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), _: *wlr.LayerSurfa
|
||||
util.gpa.destroy(layer_surface);
|
||||
}
|
||||
|
||||
fn handleMap(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
|
||||
fn handleMap(listener: *wl.Listener(void)) void {
|
||||
const layer_surface = @fieldParentPtr(LayerSurface, "map", listener);
|
||||
|
||||
log.debug("layer surface '{s}' mapped", .{wlr_layer_surface.namespace});
|
||||
log.debug("layer surface '{s}' mapped", .{layer_surface.wlr_layer_surface.namespace});
|
||||
|
||||
layer_surface.output.arrangeLayers();
|
||||
handleKeyboardInteractiveExclusive(layer_surface.output);
|
||||
server.root.applyPending();
|
||||
}
|
||||
|
||||
fn handleUnmap(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
|
||||
fn handleUnmap(listener: *wl.Listener(void)) void {
|
||||
const layer_surface = @fieldParentPtr(LayerSurface, "unmap", listener);
|
||||
|
||||
log.debug("layer surface '{s}' unmapped", .{wlr_layer_surface.namespace});
|
||||
log.debug("layer surface '{s}' unmapped", .{layer_surface.wlr_layer_surface.namespace});
|
||||
|
||||
layer_surface.output.arrangeLayers();
|
||||
handleKeyboardInteractiveExclusive(layer_surface.output);
|
||||
@ -128,10 +128,9 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||
layer_surface.scene_layer_surface.tree.node.reparent(tree);
|
||||
}
|
||||
|
||||
// If a surface is committed while it is not mapped, we must send a configure.
|
||||
// TODO: this mapped check is not correct as it will be true in the commit
|
||||
// that triggers the unmap as well.
|
||||
if (!wlr_layer_surface.mapped or @as(u32, @bitCast(wlr_layer_surface.current.committed)) != 0) {
|
||||
if (wlr_layer_surface.initial_commit or
|
||||
@as(u32, @bitCast(wlr_layer_surface.current.committed)) != 0)
|
||||
{
|
||||
layer_surface.output.arrangeLayers();
|
||||
handleKeyboardInteractiveExclusive(layer_surface.output);
|
||||
server.root.applyPending();
|
||||
@ -153,7 +152,7 @@ fn handleKeyboardInteractiveExclusive(output: *Output) void {
|
||||
if (@as(?*SceneNodeData, @ptrFromInt(node.data))) |node_data| {
|
||||
const layer_surface = node_data.data.layer_surface;
|
||||
const wlr_layer_surface = layer_surface.wlr_layer_surface;
|
||||
if (wlr_layer_surface.mapped and
|
||||
if (wlr_layer_surface.surface.mapped and
|
||||
wlr_layer_surface.current.keyboard_interactive == .exclusive)
|
||||
{
|
||||
break :outer layer_surface;
|
||||
@ -179,7 +178,7 @@ fn handleKeyboardInteractiveExclusive(output: *Output) void {
|
||||
const current_focus = seat.focused.layer.wlr_layer_surface;
|
||||
// If the seat is currently focusing an unmapped layer surface or one
|
||||
// without keyboard interactivity, stop focusing that layer surface.
|
||||
if (!current_focus.mapped or current_focus.current.keyboard_interactive == .none) {
|
||||
if (!current_focus.surface.mapped or current_focus.current.keyboard_interactive == .none) {
|
||||
seat.setFocusRaw(.{ .none = {} });
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ const server = &@import("main.zig").server;
|
||||
const util = @import("util.zig");
|
||||
|
||||
const LockSurface = @import("LockSurface.zig");
|
||||
const Output = @import("Output.zig");
|
||||
|
||||
const log = std.log.scoped(.session_lock);
|
||||
|
||||
@ -190,12 +191,6 @@ pub fn maybeLock(manager: *LockManager) void {
|
||||
fn handleUnlock(listener: *wl.Listener(void)) void {
|
||||
const manager = @fieldParentPtr(LockManager, "unlock", listener);
|
||||
|
||||
// TODO(wlroots): this will soon be handled by the wlroots session lock implementation
|
||||
if (manager.state != .locked) {
|
||||
manager.lock.?.resource.postError(.invalid_unlock, "the locked event was never sent");
|
||||
return;
|
||||
}
|
||||
|
||||
manager.state = .unlocked;
|
||||
|
||||
log.info("session unlocked", .{});
|
||||
@ -263,3 +258,15 @@ fn handleSurface(
|
||||
wlr_lock_surface.resource.postNoMemory();
|
||||
};
|
||||
}
|
||||
|
||||
pub fn updateLockSurfaceSize(manager: *LockManager, output: *Output) void {
|
||||
const lock = manager.lock orelse return;
|
||||
|
||||
var it = lock.surfaces.iterator(.forward);
|
||||
while (it.next()) |wlr_lock_surface| {
|
||||
const lock_surface: *LockSurface = @ptrFromInt(wlr_lock_surface.data);
|
||||
if (output == lock_surface.getOutput()) {
|
||||
lock_surface.configure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ lock: *wlr.SessionLockV1,
|
||||
|
||||
idle_update_focus: ?*wl.EventSource = null,
|
||||
|
||||
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),
|
||||
|
||||
@ -55,11 +54,10 @@ pub fn create(wlr_lock_surface: *wlr.SessionLockSurfaceV1, lock: *wlr.SessionLoc
|
||||
|
||||
wlr_lock_surface.surface.data = @intFromPtr(&tree.node);
|
||||
|
||||
wlr_lock_surface.output.events.mode.add(&lock_surface.output_mode);
|
||||
wlr_lock_surface.events.map.add(&lock_surface.map);
|
||||
wlr_lock_surface.surface.events.map.add(&lock_surface.map);
|
||||
wlr_lock_surface.events.destroy.add(&lock_surface.surface_destroy);
|
||||
|
||||
handleOutputMode(&lock_surface.output_mode, wlr_lock_surface.output);
|
||||
lock_surface.configure();
|
||||
}
|
||||
|
||||
pub fn destroy(lock_surface: *LockSurface) void {
|
||||
@ -84,20 +82,17 @@ pub fn destroy(lock_surface: *LockSurface) void {
|
||||
event_source.remove();
|
||||
}
|
||||
|
||||
lock_surface.output_mode.link.remove();
|
||||
lock_surface.map.link.remove();
|
||||
lock_surface.surface_destroy.link.remove();
|
||||
|
||||
util.gpa.destroy(lock_surface);
|
||||
}
|
||||
|
||||
fn getOutput(lock_surface: *LockSurface) *Output {
|
||||
pub fn getOutput(lock_surface: *LockSurface) *Output {
|
||||
return @ptrFromInt(lock_surface.wlr_lock_surface.output.data);
|
||||
}
|
||||
|
||||
fn handleOutputMode(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
||||
const lock_surface = @fieldParentPtr(LockSurface, "output_mode", listener);
|
||||
|
||||
pub fn configure(lock_surface: *LockSurface) void {
|
||||
var output_width: i32 = undefined;
|
||||
var output_height: i32 = undefined;
|
||||
lock_surface.getOutput().wlr_output.effectiveResolution(&output_width, &output_height);
|
||||
|
110
river/Output.zig
110
river/Output.zig
@ -184,8 +184,7 @@ layout: ?*Layout = null,
|
||||
status: 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),
|
||||
request_state: wl.Listener(*wlr.Output.event.RequestState) = wl.Listener(*wlr.Output.event.RequestState).init(handleRequestState),
|
||||
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),
|
||||
|
||||
@ -195,23 +194,19 @@ pub fn create(wlr_output: *wlr.Output) !void {
|
||||
|
||||
if (!wlr_output.initRender(server.allocator, server.renderer)) return error.InitRenderFailed;
|
||||
|
||||
var state = wlr.Output.State.init();
|
||||
defer state.finish();
|
||||
|
||||
state.setEnabled(true);
|
||||
|
||||
if (wlr_output.preferredMode()) |preferred_mode| {
|
||||
wlr_output.setMode(preferred_mode);
|
||||
wlr_output.enable(true);
|
||||
wlr_output.commit() catch {
|
||||
var it = wlr_output.modes.iterator(.forward);
|
||||
while (it.next()) |mode| {
|
||||
if (mode == preferred_mode) continue;
|
||||
wlr_output.setMode(mode);
|
||||
wlr_output.commit() catch continue;
|
||||
// This mode works, use it
|
||||
break;
|
||||
}
|
||||
// If no mode works, then we will just leave the output disabled.
|
||||
// Perhaps the user will want to set a custom mode using wlr-output-management.
|
||||
};
|
||||
state.setMode(preferred_mode);
|
||||
}
|
||||
|
||||
// Ignore failure here and create the Output anyways.
|
||||
// It will stay disabled unless the user configures a custom mode which may work.
|
||||
_ = wlr_output.commitState(&state);
|
||||
|
||||
var width: c_int = undefined;
|
||||
var height: c_int = undefined;
|
||||
wlr_output.effectiveResolution(&width, &height);
|
||||
@ -270,8 +265,7 @@ pub fn create(wlr_output: *wlr.Output) !void {
|
||||
output.layers.fullscreen.node.setEnabled(false);
|
||||
|
||||
wlr_output.events.destroy.add(&output.destroy);
|
||||
wlr_output.events.enable.add(&output.enable);
|
||||
wlr_output.events.mode.add(&output.mode);
|
||||
wlr_output.events.request_state.add(&output.request_state);
|
||||
wlr_output.events.frame.add(&output.frame);
|
||||
wlr_output.events.present.add(&output.present);
|
||||
|
||||
@ -289,7 +283,7 @@ pub fn create(wlr_output: *wlr.Output) !void {
|
||||
output.active_link.init();
|
||||
server.root.all_outputs.append(output);
|
||||
|
||||
handleEnable(&output.enable, wlr_output);
|
||||
output.handleEnable();
|
||||
}
|
||||
|
||||
pub fn layerSurfaceTree(self: Self, layer: zwlr.LayerShellV1.Layer) *wlr.SceneTree {
|
||||
@ -370,9 +364,8 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
||||
output.all_link.remove();
|
||||
|
||||
output.destroy.link.remove();
|
||||
output.enable.link.remove();
|
||||
output.request_state.link.remove();
|
||||
output.frame.link.remove();
|
||||
output.mode.link.remove();
|
||||
output.present.link.remove();
|
||||
|
||||
output.tree.node.destroy();
|
||||
@ -386,42 +379,53 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
||||
server.root.applyPending();
|
||||
}
|
||||
|
||||
fn handleEnable(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void {
|
||||
const self = @fieldParentPtr(Self, "enable", listener);
|
||||
fn handleRequestState(listener: *wl.Listener(*wlr.Output.event.RequestState), event: *wlr.Output.event.RequestState) void {
|
||||
const output = @fieldParentPtr(Self, "request_state", listener);
|
||||
|
||||
// We can't assert the current state of normal_content/locked_content
|
||||
// here as this output may be newly created.
|
||||
if (wlr_output.enabled) {
|
||||
switch (server.lock_manager.state) {
|
||||
.unlocked => {
|
||||
assert(self.lock_render_state == .blanked);
|
||||
self.normal_content.node.setEnabled(true);
|
||||
self.locked_content.node.setEnabled(false);
|
||||
},
|
||||
.waiting_for_lock_surfaces, .waiting_for_blank, .locked => {
|
||||
assert(self.lock_render_state == .blanked);
|
||||
self.normal_content.node.setEnabled(false);
|
||||
self.locked_content.node.setEnabled(true);
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// Disabling and re-enabling an output always blanks it.
|
||||
self.lock_render_state = .blanked;
|
||||
self.normal_content.node.setEnabled(false);
|
||||
self.locked_content.node.setEnabled(true);
|
||||
// TODO double buffer output state changes for frame perfection and cleaner code.
|
||||
// Schedule a frame and commit in the frame handler.
|
||||
if (!output.wlr_output.commitState(event.state)) {
|
||||
log.err("failed to commit requested state", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the output to root.active_outputs and the output layout if it has not
|
||||
// already been added.
|
||||
if (wlr_output.enabled) server.root.activateOutput(self);
|
||||
if (event.state.committed.enabled) {
|
||||
output.handleEnable();
|
||||
}
|
||||
|
||||
if (event.state.committed.mode) {
|
||||
output.updateBackgroundRect();
|
||||
output.arrangeLayers();
|
||||
server.lock_manager.updateLockSurfaceSize(output);
|
||||
server.root.applyPending();
|
||||
}
|
||||
}
|
||||
|
||||
fn handleMode(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
||||
const output = @fieldParentPtr(Self, "mode", listener);
|
||||
|
||||
output.updateBackgroundRect();
|
||||
output.arrangeLayers();
|
||||
server.root.applyPending();
|
||||
fn handleEnable(output: *Self) void {
|
||||
// We can't assert the current state of normal_content/locked_content
|
||||
// here as this output may be newly created.
|
||||
if (output.wlr_output.enabled) {
|
||||
switch (server.lock_manager.state) {
|
||||
.unlocked => {
|
||||
assert(output.lock_render_state == .blanked);
|
||||
output.normal_content.node.setEnabled(true);
|
||||
output.locked_content.node.setEnabled(false);
|
||||
},
|
||||
.waiting_for_lock_surfaces, .waiting_for_blank, .locked => {
|
||||
assert(output.lock_render_state == .blanked);
|
||||
output.normal_content.node.setEnabled(false);
|
||||
output.locked_content.node.setEnabled(true);
|
||||
},
|
||||
}
|
||||
// Add the output to root.active_outputs and the output layout if it has not
|
||||
// already been added.
|
||||
server.root.activateOutput(output);
|
||||
} else {
|
||||
// Disabling and re-enabling an output always blanks it.
|
||||
output.lock_render_state = .blanked;
|
||||
output.normal_content.node.setEnabled(false);
|
||||
output.locked_content.node.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateBackgroundRect(output: *Self) void {
|
||||
@ -439,7 +443,7 @@ fn handleFrame(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
||||
const output = @fieldParentPtr(Self, "frame", listener);
|
||||
const scene_output = server.root.scene.getSceneOutput(output.wlr_output).?;
|
||||
|
||||
if (scene_output.commit()) {
|
||||
if (scene_output.commit(null)) {
|
||||
if (server.lock_manager.state == .locked or
|
||||
(server.lock_manager.state == .waiting_for_lock_surfaces and output.locked_content.node.enabled) or
|
||||
server.lock_manager.state == .waiting_for_blank)
|
||||
|
@ -90,6 +90,7 @@ views: wl.list.Head(View, .link),
|
||||
new_output: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleNewOutput),
|
||||
|
||||
output_layout: *wlr.OutputLayout,
|
||||
scene_output_layout: *wlr.SceneOutputLayout,
|
||||
layout_change: wl.Listener(*wlr.OutputLayout) = wl.Listener(*wlr.OutputLayout).init(handleLayoutChange),
|
||||
|
||||
output_manager: *wlr.OutputManagerV1,
|
||||
@ -133,7 +134,7 @@ pub fn init(self: *Self) !void {
|
||||
const outputs = try interactive_content.createSceneTree();
|
||||
const xwayland_override_redirect = if (build_options.xwayland) try interactive_content.createSceneTree();
|
||||
|
||||
try scene.attachOutputLayout(output_layout);
|
||||
const scene_output_layout = try scene.attachOutputLayout(output_layout);
|
||||
|
||||
_ = try wlr.XdgOutputManagerV1.create(server.wl_server, output_layout);
|
||||
|
||||
@ -175,6 +176,7 @@ pub fn init(self: *Self) !void {
|
||||
},
|
||||
.views = undefined,
|
||||
.output_layout = output_layout,
|
||||
.scene_output_layout = scene_output_layout,
|
||||
.all_outputs = undefined,
|
||||
.active_outputs = undefined,
|
||||
.output_manager = try wlr.OutputManagerV1.create(server.wl_server),
|
||||
@ -226,7 +228,7 @@ pub fn at(self: Self, lx: f64, ly: f64) ?AtResult {
|
||||
const surface: ?*wlr.Surface = blk: {
|
||||
if (node.type == .buffer) {
|
||||
const scene_buffer = wlr.SceneBuffer.fromNode(node);
|
||||
if (wlr.SceneSurface.fromBuffer(scene_buffer)) |scene_surface| {
|
||||
if (wlr.SceneSurface.tryFromBuffer(scene_buffer)) |scene_surface| {
|
||||
break :blk scene_surface.surface;
|
||||
}
|
||||
}
|
||||
@ -354,9 +356,20 @@ pub fn activateOutput(root: *Self, output: *Output) void {
|
||||
// This arranges outputs from left-to-right in the order they appear. The
|
||||
// wlr-output-management protocol may be used to modify this arrangement.
|
||||
// This also creates a wl_output global which is advertised to clients.
|
||||
root.output_layout.addAuto(output.wlr_output);
|
||||
const layout_output = root.output_layout.addAuto(output.wlr_output) catch {
|
||||
// This would currently be very awkward to handle well and this output
|
||||
// handling code needs to be heavily refactored soon anyways for double
|
||||
// buffered state application as part of the transaction system.
|
||||
// In any case, wlroots 0.16 would have crashed here, the error is only
|
||||
// possible to handle after updating to 0.17.
|
||||
@panic("TODO handle allocation failure here");
|
||||
};
|
||||
const scene_output = root.scene.createSceneOutput(output.wlr_output) catch {
|
||||
// See above
|
||||
@panic("TODO handle allocation failure here");
|
||||
};
|
||||
root.scene_output_layout.addOutput(layout_output, scene_output);
|
||||
|
||||
const layout_output = root.output_layout.get(output.wlr_output).?;
|
||||
output.tree.node.setEnabled(true);
|
||||
output.tree.node.setPosition(layout_output.x, layout_output.y);
|
||||
|
||||
@ -767,7 +780,8 @@ fn processOutputConfig(
|
||||
if (wlr_output.commitState(&proposed_state)) {
|
||||
if (head.state.enabled) {
|
||||
// Just updates the output's position if it is already in the layout
|
||||
self.output_layout.add(output.wlr_output, head.state.x, head.state.y);
|
||||
// This can't fail if the output is already in the layout, which we know to be the case here.
|
||||
_ = self.output_layout.add(output.wlr_output, head.state.x, head.state.y) catch unreachable;
|
||||
output.tree.node.setEnabled(true);
|
||||
output.tree.node.setPosition(head.state.x, head.state.y);
|
||||
// Even though we call this in the output's handler for the mode event
|
||||
|
@ -51,9 +51,9 @@ pub fn attach(node: *wlr.SceneNode, data: Data) error{OutOfMemory}!void {
|
||||
}
|
||||
|
||||
pub fn fromNode(node: *wlr.SceneNode) ?*SceneNodeData {
|
||||
var it: ?*wlr.SceneNode = node;
|
||||
while (it) |n| : (it = n.parent) {
|
||||
if (@as(?*SceneNodeData, @ptrFromInt(n.data))) |scene_node_data| {
|
||||
var it: ?*wlr.SceneTree = node.parent;
|
||||
while (it) |tree| : (it = tree.node.parent) {
|
||||
if (@as(?*SceneNodeData, @ptrFromInt(tree.node.data))) |scene_node_data| {
|
||||
return scene_node_data;
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ pub fn focus(self: *Self, _target: ?*View) void {
|
||||
// While a layer surface is exclusively focused, views may not receive focus
|
||||
if (self.focused == .layer) {
|
||||
const wlr_layer_surface = self.focused.layer.wlr_layer_surface;
|
||||
assert(wlr_layer_surface.mapped);
|
||||
assert(wlr_layer_surface.surface.mapped);
|
||||
if (wlr_layer_surface.current.keyboard_interactive == .exclusive and
|
||||
(wlr_layer_surface.current.layer == .top or wlr_layer_surface.current.layer == .overlay))
|
||||
{
|
||||
|
@ -48,6 +48,7 @@ sigint_source: *wl.EventSource,
|
||||
sigterm_source: *wl.EventSource,
|
||||
|
||||
backend: *wlr.Backend,
|
||||
session: ?*wlr.Session,
|
||||
|
||||
renderer: *wlr.Renderer,
|
||||
allocator: *wlr.Allocator,
|
||||
@ -89,7 +90,7 @@ pub fn init(self: *Self) !void {
|
||||
errdefer self.sigterm_source.remove();
|
||||
|
||||
// This frees itself when the wl.Server is destroyed
|
||||
self.backend = try wlr.Backend.autocreate(self.wl_server);
|
||||
self.backend = try wlr.Backend.autocreate(self.wl_server, &self.session);
|
||||
|
||||
self.renderer = try wlr.Renderer.autocreate(self.backend);
|
||||
errdefer self.renderer.destroy();
|
||||
@ -98,7 +99,7 @@ pub fn init(self: *Self) !void {
|
||||
self.allocator = try wlr.Allocator.autocreate(self.backend, self.renderer);
|
||||
errdefer self.allocator.destroy();
|
||||
|
||||
const compositor = try wlr.Compositor.create(self.wl_server, self.renderer);
|
||||
const compositor = try wlr.Compositor.create(self.wl_server, 6, self.renderer);
|
||||
_ = try wlr.Subcompositor.create(self.wl_server);
|
||||
|
||||
self.xdg_shell = try wlr.XdgShell.create(self.wl_server, 5);
|
||||
@ -109,7 +110,7 @@ pub fn init(self: *Self) !void {
|
||||
self.new_toplevel_decoration.setNotify(handleNewToplevelDecoration);
|
||||
self.xdg_decoration_manager.events.new_toplevel_decoration.add(&self.new_toplevel_decoration);
|
||||
|
||||
self.layer_shell = try wlr.LayerShellV1.create(self.wl_server);
|
||||
self.layer_shell = try wlr.LayerShellV1.create(self.wl_server, 4);
|
||||
self.new_layer_surface.setNotify(handleNewLayerSurface);
|
||||
self.layer_shell.events.new_surface.add(&self.new_layer_surface);
|
||||
|
||||
@ -203,7 +204,7 @@ fn handleNewXdgSurface(_: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSu
|
||||
|
||||
log.debug("new xdg_toplevel", .{});
|
||||
|
||||
XdgToplevel.create(xdg_surface.role_data.toplevel) catch {
|
||||
XdgToplevel.create(xdg_surface.role_data.toplevel.?) catch {
|
||||
log.err("out of memory", .{});
|
||||
xdg_surface.resource.postNoMemory();
|
||||
return;
|
||||
@ -214,17 +215,6 @@ fn handleNewToplevelDecoration(
|
||||
_: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
||||
wlr_decoration: *wlr.XdgToplevelDecorationV1,
|
||||
) void {
|
||||
const xdg_toplevel: *XdgToplevel = @ptrFromInt(wlr_decoration.surface.data);
|
||||
|
||||
// TODO(wlroots): The next wlroots version will handle this for us
|
||||
if (xdg_toplevel.decoration != null) {
|
||||
wlr_decoration.resource.postError(
|
||||
.already_constructed,
|
||||
"xdg_toplevel already has a decoration object",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
XdgDecoration.init(wlr_decoration);
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ request_mode: wl.Listener(*wlr.XdgToplevelDecorationV1) =
|
||||
wl.Listener(*wlr.XdgToplevelDecorationV1).init(handleRequestMode),
|
||||
|
||||
pub fn init(wlr_decoration: *wlr.XdgToplevelDecorationV1) void {
|
||||
const xdg_toplevel: *XdgToplevel = @ptrFromInt(wlr_decoration.surface.data);
|
||||
const xdg_toplevel: *XdgToplevel = @ptrFromInt(wlr_decoration.toplevel.base.data);
|
||||
|
||||
xdg_toplevel.decoration = .{ .wlr_decoration = wlr_decoration };
|
||||
const decoration = &xdg_toplevel.decoration.?;
|
||||
@ -52,21 +52,15 @@ pub fn init(wlr_decoration: *wlr.XdgToplevelDecorationV1) void {
|
||||
xdg_toplevel.view.pending.ssd = ssd;
|
||||
}
|
||||
|
||||
// TODO(wlroots): remove this function when updating to 0.17.0
|
||||
// https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4051
|
||||
pub fn deinit(decoration: *XdgDecoration) void {
|
||||
decoration.destroy.link.remove();
|
||||
decoration.request_mode.link.remove();
|
||||
}
|
||||
|
||||
fn handleDestroy(
|
||||
listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
||||
_: *wlr.XdgToplevelDecorationV1,
|
||||
) void {
|
||||
const decoration = @fieldParentPtr(XdgDecoration, "destroy", listener);
|
||||
const xdg_toplevel: *XdgToplevel = @ptrFromInt(decoration.wlr_decoration.surface.data);
|
||||
const xdg_toplevel: *XdgToplevel = @ptrFromInt(decoration.wlr_decoration.toplevel.base.data);
|
||||
|
||||
decoration.deinit();
|
||||
decoration.destroy.link.remove();
|
||||
decoration.request_mode.link.remove();
|
||||
|
||||
assert(xdg_toplevel.decoration != null);
|
||||
xdg_toplevel.decoration = null;
|
||||
@ -78,7 +72,7 @@ fn handleRequestMode(
|
||||
) void {
|
||||
const decoration = @fieldParentPtr(XdgDecoration, "request_mode", listener);
|
||||
|
||||
const xdg_toplevel: *XdgToplevel = @ptrFromInt(decoration.wlr_decoration.surface.data);
|
||||
const xdg_toplevel: *XdgToplevel = @ptrFromInt(decoration.wlr_decoration.toplevel.base.data);
|
||||
const view = xdg_toplevel.view;
|
||||
|
||||
const ssd = server.config.rules.ssd.match(xdg_toplevel.view) orelse
|
||||
|
@ -90,8 +90,8 @@ pub fn create(xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
|
||||
|
||||
// Add listeners that are active over the toplevel's entire lifetime
|
||||
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.surface.events.map.add(&self.map);
|
||||
xdg_toplevel.base.surface.events.unmap.add(&self.unmap);
|
||||
xdg_toplevel.base.events.new_popup.add(&self.new_popup);
|
||||
|
||||
_ = xdg_toplevel.setWmCapabilities(.{ .fullscreen = true });
|
||||
@ -183,16 +183,7 @@ pub fn destroyPopups(self: Self) void {
|
||||
fn handleDestroy(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "destroy", listener);
|
||||
|
||||
// TODO(wlroots): Replace this with an assertion when updating to wlroots 0.17.0
|
||||
// https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4051
|
||||
if (self.decoration) |*decoration| {
|
||||
decoration.wlr_decoration.resource.postError(
|
||||
.orphaned,
|
||||
"xdg_toplevel destroyed before xdg_toplevel_decoration",
|
||||
);
|
||||
decoration.deinit();
|
||||
self.decoration = null;
|
||||
}
|
||||
assert(self.decoration == null);
|
||||
|
||||
// Remove listeners that are active for the entire lifetime of the view
|
||||
self.destroy.link.remove();
|
||||
@ -392,18 +383,6 @@ fn handleRequestResize(listener: *wl.Listener(*wlr.XdgToplevel.event.Resize), ev
|
||||
const seat: *Seat = @ptrFromInt(event.seat.seat.data);
|
||||
const view = self.view;
|
||||
|
||||
{
|
||||
// TODO(wlroots) remove this after updating to the next wlroots version
|
||||
// https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4041
|
||||
if ((event.edges.top and event.edges.bottom) or (event.edges.left and event.edges.right)) {
|
||||
self.xdg_toplevel.resource.postError(
|
||||
.invalid_resize_edge,
|
||||
"provided value is not a valid variant of the resize_edge enum",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (view.current.output == null or view.pending.output == null) return;
|
||||
if (view.current.tags & view.current.output.?.current.tags == 0) return;
|
||||
if (view.pending.fullscreen) return;
|
||||
|
@ -34,14 +34,21 @@ const log = std.log.scoped(.xwayland);
|
||||
xwayland_surface: *wlr.XwaylandSurface,
|
||||
surface_tree: ?*wlr.SceneTree = null,
|
||||
|
||||
// Active over entire lifetime
|
||||
request_configure: wl.Listener(*wlr.XwaylandSurface.event.Configure) =
|
||||
wl.Listener(*wlr.XwaylandSurface.event.Configure).init(handleRequestConfigure),
|
||||
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),
|
||||
set_geometry: wl.Listener(void) = wl.Listener(void).init(handleSetGeometry),
|
||||
set_override_redirect: wl.Listener(*wlr.XwaylandSurface) =
|
||||
wl.Listener(*wlr.XwaylandSurface).init(handleSetOverrideRedirect),
|
||||
associate: wl.Listener(void) = wl.Listener(void).init(handleAssociate),
|
||||
dissociate: wl.Listener(void) = wl.Listener(void).init(handleDissociate),
|
||||
|
||||
// Active while the xwayland_surface is associated with a wlr_surface
|
||||
map: wl.Listener(void) = wl.Listener(void).init(handleMap),
|
||||
unmap: wl.Listener(void) = wl.Listener(void).init(handleUnmap),
|
||||
|
||||
// Active while mapped
|
||||
set_geometry: wl.Listener(void) = wl.Listener(void).init(handleSetGeometry),
|
||||
|
||||
pub fn create(xwayland_surface: *wlr.XwaylandSurface) error{OutOfMemory}!void {
|
||||
const self = try util.gpa.create(Self);
|
||||
@ -51,12 +58,16 @@ pub fn create(xwayland_surface: *wlr.XwaylandSurface) error{OutOfMemory}!void {
|
||||
|
||||
xwayland_surface.events.request_configure.add(&self.request_configure);
|
||||
xwayland_surface.events.destroy.add(&self.destroy);
|
||||
xwayland_surface.events.map.add(&self.map);
|
||||
xwayland_surface.events.unmap.add(&self.unmap);
|
||||
xwayland_surface.events.set_override_redirect.add(&self.set_override_redirect);
|
||||
|
||||
if (xwayland_surface.mapped) {
|
||||
handleMap(&self.map, xwayland_surface);
|
||||
xwayland_surface.events.associate.add(&self.associate);
|
||||
xwayland_surface.events.dissociate.add(&self.dissociate);
|
||||
|
||||
if (xwayland_surface.surface) |surface| {
|
||||
handleAssociate(&self.associate);
|
||||
if (surface.mapped) {
|
||||
handleMap(&self.map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,14 +83,28 @@ fn handleDestroy(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandS
|
||||
|
||||
self.request_configure.link.remove();
|
||||
self.destroy.link.remove();
|
||||
self.map.link.remove();
|
||||
self.unmap.link.remove();
|
||||
self.associate.link.remove();
|
||||
self.dissociate.link.remove();
|
||||
self.set_override_redirect.link.remove();
|
||||
|
||||
util.gpa.destroy(self);
|
||||
}
|
||||
|
||||
pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSurface) void {
|
||||
fn handleAssociate(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "associate", listener);
|
||||
|
||||
self.xwayland_surface.surface.?.events.map.add(&self.map);
|
||||
self.xwayland_surface.surface.?.events.unmap.add(&self.unmap);
|
||||
}
|
||||
|
||||
fn handleDissociate(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "dissociate", listener);
|
||||
|
||||
self.map.link.remove();
|
||||
self.unmap.link.remove();
|
||||
}
|
||||
|
||||
pub fn handleMap(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "map", listener);
|
||||
|
||||
self.mapImpl() catch {
|
||||
@ -124,7 +149,7 @@ pub fn focusIfDesired(self: *Self) void {
|
||||
}
|
||||
}
|
||||
|
||||
fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSurface) void {
|
||||
fn handleUnmap(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "unmap", listener);
|
||||
|
||||
self.set_geometry.link.remove();
|
||||
@ -165,7 +190,12 @@ fn handleSetOverrideRedirect(
|
||||
|
||||
assert(!xwayland_surface.override_redirect);
|
||||
|
||||
if (xwayland_surface.mapped) handleUnmap(&self.unmap, xwayland_surface);
|
||||
if (xwayland_surface.surface) |surface| {
|
||||
if (surface.mapped) {
|
||||
handleUnmap(&self.unmap);
|
||||
}
|
||||
handleDissociate(&self.dissociate);
|
||||
}
|
||||
handleDestroy(&self.destroy, xwayland_surface);
|
||||
|
||||
XwaylandView.create(xwayland_surface) catch {
|
||||
|
@ -39,16 +39,20 @@ xwayland_surface: *wlr.XwaylandSurface,
|
||||
/// Created on map and destroyed on unmap
|
||||
surface_tree: ?*wlr.SceneTree = null,
|
||||
|
||||
// Listeners that are always active over the view's lifetime
|
||||
// Active over entire lifetime
|
||||
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),
|
||||
request_configure: wl.Listener(*wlr.XwaylandSurface.event.Configure) =
|
||||
wl.Listener(*wlr.XwaylandSurface.event.Configure).init(handleRequestConfigure),
|
||||
set_override_redirect: wl.Listener(*wlr.XwaylandSurface) =
|
||||
wl.Listener(*wlr.XwaylandSurface).init(handleSetOverrideRedirect),
|
||||
associate: wl.Listener(void) = wl.Listener(void).init(handleAssociate),
|
||||
dissociate: wl.Listener(void) = wl.Listener(void).init(handleDissociate),
|
||||
|
||||
// Listeners that are only active while the view is mapped
|
||||
// Active while the xwayland_surface is associated with a wlr_surface
|
||||
map: wl.Listener(void) = wl.Listener(void).init(handleMap),
|
||||
unmap: wl.Listener(void) = wl.Listener(void).init(handleUnmap),
|
||||
|
||||
// Active while mapped
|
||||
set_title: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleSetTitle),
|
||||
set_class: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleSetClass),
|
||||
set_decorations: wl.Listener(*wlr.XwaylandSurface) =
|
||||
@ -70,13 +74,16 @@ pub fn create(xwayland_surface: *wlr.XwaylandSurface) error{OutOfMemory}!void {
|
||||
|
||||
// Add listeners that are active over the view's entire lifetime
|
||||
xwayland_surface.events.destroy.add(&self.destroy);
|
||||
xwayland_surface.events.map.add(&self.map);
|
||||
xwayland_surface.events.unmap.add(&self.unmap);
|
||||
xwayland_surface.events.associate.add(&self.associate);
|
||||
xwayland_surface.events.dissociate.add(&self.dissociate);
|
||||
xwayland_surface.events.request_configure.add(&self.request_configure);
|
||||
xwayland_surface.events.set_override_redirect.add(&self.set_override_redirect);
|
||||
|
||||
if (xwayland_surface.mapped) {
|
||||
handleMap(&self.map, xwayland_surface);
|
||||
if (xwayland_surface.surface) |surface| {
|
||||
handleAssociate(&self.associate);
|
||||
if (surface.mapped) {
|
||||
handleMap(&self.map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,8 +157,8 @@ fn handleDestroy(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandS
|
||||
|
||||
// Remove listeners that are active for the entire lifetime of the view
|
||||
self.destroy.link.remove();
|
||||
self.map.link.remove();
|
||||
self.unmap.link.remove();
|
||||
self.associate.link.remove();
|
||||
self.dissociate.link.remove();
|
||||
self.request_configure.link.remove();
|
||||
self.set_override_redirect.link.remove();
|
||||
|
||||
@ -160,10 +167,24 @@ fn handleDestroy(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandS
|
||||
view.destroy();
|
||||
}
|
||||
|
||||
pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wlr.XwaylandSurface) void {
|
||||
fn handleAssociate(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "associate", listener);
|
||||
|
||||
self.xwayland_surface.surface.?.events.map.add(&self.map);
|
||||
self.xwayland_surface.surface.?.events.unmap.add(&self.unmap);
|
||||
}
|
||||
|
||||
fn handleDissociate(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "dissociate", listener);
|
||||
self.map.link.remove();
|
||||
self.unmap.link.remove();
|
||||
}
|
||||
|
||||
pub fn handleMap(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "map", listener);
|
||||
const view = self.view;
|
||||
|
||||
const xwayland_surface = self.xwayland_surface;
|
||||
const surface = xwayland_surface.surface.?;
|
||||
surface.data = @intFromPtr(&view.tree.node);
|
||||
|
||||
@ -213,7 +234,7 @@ pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface:
|
||||
};
|
||||
}
|
||||
|
||||
fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSurface) void {
|
||||
fn handleUnmap(listener: *wl.Listener(void)) void {
|
||||
const self = @fieldParentPtr(Self, "unmap", listener);
|
||||
|
||||
self.xwayland_surface.surface.?.data = 0;
|
||||
@ -239,7 +260,9 @@ fn handleRequestConfigure(
|
||||
const self = @fieldParentPtr(Self, "request_configure", listener);
|
||||
|
||||
// If unmapped, let the client do whatever it wants
|
||||
if (!self.xwayland_surface.mapped) {
|
||||
if (self.xwayland_surface.surface == null or
|
||||
!self.xwayland_surface.surface.?.mapped)
|
||||
{
|
||||
self.xwayland_surface.configure(event.x, event.y, event.width, event.height);
|
||||
return;
|
||||
}
|
||||
@ -262,7 +285,12 @@ fn handleSetOverrideRedirect(
|
||||
|
||||
assert(xwayland_surface.override_redirect);
|
||||
|
||||
if (xwayland_surface.mapped) handleUnmap(&self.unmap, xwayland_surface);
|
||||
if (xwayland_surface.surface) |surface| {
|
||||
if (surface.mapped) {
|
||||
handleUnmap(&self.unmap);
|
||||
}
|
||||
handleDissociate(&self.dissociate);
|
||||
}
|
||||
handleDestroy(&self.destroy, xwayland_surface);
|
||||
|
||||
XwaylandOverrideRedirect.create(xwayland_surface) catch {
|
||||
|
Loading…
Reference in New Issue
Block a user