Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
rwm: use global names for wl_output/wl_seat references
This simplifies the code and prevents possible races. Clients need to
keep track of wl_output/wl_seat names anyways to handle global_remove
properly.
protocol/river-window-management-v1.xml | 24 +++++++++++-----------
river/Output.zig | 35 ++++++---------------------------
river/Seat.zig | 9 +--------
3 files changed, 19 insertions(+), 49 deletions(-)
diff --git a/protocol/river-window-management-v1.xml b/protocol/river-window-management-v1.xml
index 9f2e34d..80eb7b3 100644
--- a/protocol/river-window-management-v1.xml
+++ b/protocol/river-window-management-v1.xml
@@ -1129,16 +1129,16 @@
<event name="wl_output">
<description summary="corresponding wl_output">
- The wl_output object corresponding to the river_output_v1.
+ The wl_output object corresponding to the river_output_v1. The argument
+ is the global name of the wl_output advertised with wl_registry.global.
+
+ It is guaranteed that the corresponding wl_output is advertised before
+ this event is sent.
This event is sent exactly once. The wl_output associated with a
river_output_v1 cannot change. It is guaranteed that there is a 1-to-1
mapping between wl_output and river_output_v1 objects.
- Note that this event will only be sent after the client binds the
- wl_output global. It is guaranteed that the corresponding wl_output is
- advertised before the river_window_manager_v1.output event is sent.
-
The global_remove event for the corresponding wl_output may be sent
before the river_output_v1.remove event. This is due to the fact that
river_output_v1 state changes are synced to the river window management
@@ -1148,7 +1148,7 @@
wl_output interface such as the name/description. It also may need the
wl_output object to start screencopy for example.
</description>
- <arg name="wl_output" type="object" interface="wl_output"/>
+ <arg name="name" type="uint" summary="name of the wl_output global"/>
</event>
<event name="position">
@@ -1231,16 +1231,16 @@
<event name="wl_seat">
<description summary="corresponding wl_seat">
- The wl_seat object corresponding to the river_seat_v1.
+ The wl_seat object corresponding to the river_seat_v1. The argument is
+ the global name of the wl_seat advertised with wl_registry.global.
+
+ It is guaranteed that the corresponding wl_seat is advertised before
+ this event is sent.
This event is sent exactly once. The wl_seat associated with a
river_seat_v1 cannot change. It is guaranteed that there is a 1-to-1
mapping between wl_seat and river_seat_v1 objects.
- Note that this event will only be sent after the client binds the
- wl_seat global. It is guaranteed that the corresponding wl_seat is
- advertised before the river_window_manager_v1.seat event is sent.
-
The global_remove event for the corresponding wl_seat may be sent before
the river_seat_v1.remove event. This is due to the fact that
river_seat_v1 state changes are synced to the river window management
@@ -1250,7 +1250,7 @@
state changes based on normal input events received by its shell
surfaces for example.
</description>
- <arg name="wl_seat" type="object" interface="wl_seat"/>
+ <arg name="name" type="uint" summary="name of the wl_seat global"/>
</event>
<request name="focus_window">
diff --git a/river/Output.zig b/river/Output.zig
index aea90d2..18be1e5 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -132,7 +132,6 @@ wlr_output: ?*wlr.Output,
scene_output: ?*wlr.SceneOutput,
object: ?*river.OutputV1 = null,
-sent_wl_output: bool = false,
/// Tracks the currently presented frame on the output as it pertains to ext-session-lock.
/// The output is initially considered blanked:
@@ -168,7 +167,6 @@ link_sent: wl.list.Link,
current: State,
destroy: wl.Listener(*wlr.Output) = .init(handleDestroy),
-bind: wl.Listener(*wlr.Output.event.Bind) = .init(handleBind),
request_state: wl.Listener(*wlr.Output.event.RequestState) = .init(handleRequestState),
frame: wl.Listener(*wlr.Output) = .init(handleFrame),
present: wl.Listener(*wlr.Output.event.Present) = .init(handlePresent),
@@ -208,7 +206,6 @@ pub fn create(wlr_output: *wlr.Output) !void {
output.link_sent.init();
wlr_output.events.destroy.add(&output.destroy);
- wlr_output.events.bind.add(&output.bind);
wlr_output.events.request_state.add(&output.request_state);
wlr_output.events.frame.add(&output.frame);
wlr_output.events.present.add(&output.present);
@@ -229,7 +226,6 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) v
output.link.remove();
output.destroy.link.remove();
- output.bind.link.remove();
output.request_state.link.remove();
output.frame.link.remove();
output.present.link.remove();
@@ -243,23 +239,11 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) v
server.wm.dirtyWindowing();
}
-fn handleBind(listener: *wl.Listener(*wlr.Output.event.Bind), event: *wlr.Output.event.Bind) void {
- const output: *Output = @fieldParentPtr("bind", listener);
- // Guard against a client binding the same wl_output global more than once.
- if (output.sent_wl_output) {
- return;
- }
- if (output.object) |output_v1| {
- if (output_v1.getClient() == event.resource.getClient()) {
- output_v1.sendWlOutput(event.resource);
- output.sent_wl_output = true;
- }
- }
-}
-
pub fn manageStart(output: *Output) void {
switch (output.scheduled.state) {
.enabled, .disabled_soft => {
+ const wlr_output = output.wlr_output.?;
+
if (server.wm.object) |wm_v1| {
const new = output.object == null;
const output_v1 = output.object orelse blk: {
@@ -280,17 +264,10 @@ pub fn manageStart(output: *Output) void {
const sent = &output.sent;
if (new) {
- const client = output_v1.getClient();
- var it = output.wlr_output.?.resources.iterator(.forward);
- while (it.next()) |wl_output| {
- if (client == wl_output.getClient()) {
- output_v1.sendWlOutput(wl_output);
- output.sent_wl_output = true;
- break;
- }
- } else {
- output.sent_wl_output = false;
- }
+ // Ensure that the wl_output global has been created,
+ // this is a noop if it already has been.
+ wlr_output.createGlobal(server.wl_server);
+ output_v1.sendWlOutput(wlr_output.global.?.getName(output_v1.getClient()));
}
if (new or pending.width() != sent.width() or pending.height() != sent.height()) {
diff --git a/river/Seat.zig b/river/Seat.zig
index 0f95fdf..5814da2 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -315,14 +315,7 @@ pub fn manageStart(seat: *Seat) void {
errdefer comptime unreachable;
if (new) {
- // TODO(wlroots): send on bind if wl_seat global not yet bound:
- // https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5099
- const client = seat_v1.getClient();
- if (seat.wlr_seat.clientForWlClient(client)) |seat_client| {
- if (seat_client.resources.first()) |wl_seat| {
- seat_v1.sendWlSeat(wl_seat);
- }
- }
+ seat_v1.sendWlSeat(seat.wlr_seat.global.getName(seat_v1.getClient()));
}
if (new) {