wlr-output-management: Implement version 3 release requests

Head/mode resources older than version 3 and lacking a release request
are intentionally leaked as this is the only way to fix the race.

Implements: https://gitlab.freedesktop.org/wlroots/wlr-protocols/-/merge_requests/114
This commit is contained in:
Isaac Freund 2022-06-30 14:01:46 +02:00 committed by Simon Ser
parent d3cb6b73a2
commit 4c1afb126b
2 changed files with 63 additions and 21 deletions

View File

@ -39,7 +39,7 @@
interface version number is reset. interface version number is reset.
</description> </description>
<interface name="zwlr_output_manager_v1" version="2"> <interface name="zwlr_output_manager_v1" version="3">
<description summary="output device configuration manager"> <description summary="output device configuration manager">
This interface is a manager that allows reading and writing the current This interface is a manager that allows reading and writing the current
output device configuration. output device configuration.
@ -115,7 +115,7 @@
</description> </description>
</request> </request>
<event name="finished"> <event name="finished" type="destructor">
<description summary="the compositor has finished with the manager"> <description summary="the compositor has finished with the manager">
This event indicates that the compositor is done sending manager events. This event indicates that the compositor is done sending manager events.
The compositor will destroy the object immediately after sending this The compositor will destroy the object immediately after sending this
@ -125,7 +125,7 @@
</event> </event>
</interface> </interface>
<interface name="zwlr_output_head_v1" version="2"> <interface name="zwlr_output_head_v1" version="3">
<description summary="output device"> <description summary="output device">
A head is an output device. The difference between a wl_output object and A head is an output device. The difference between a wl_output object and
a head is that heads are advertised even if they are turned off. A head a head is that heads are advertised even if they are turned off. A head
@ -251,14 +251,15 @@
</event> </event>
<event name="finished"> <event name="finished">
<description summary="the head has been destroyed"> <description summary="the head has disappeared">
The compositor will destroy the object immediately after sending this This event indicates that the head is no longer available. The head
event, so it will become invalid and the client should release any object becomes inert. Clients should send a destroy request and release
resources associated with it. any resources associated with it.
</description> </description>
</event> </event>
<!-- Version 2 additions --> <!-- Version 2 additions -->
<event name="make" since="2"> <event name="make" since="2">
<description summary="head manufacturer"> <description summary="head manufacturer">
This event describes the manufacturer of the head. This event describes the manufacturer of the head.
@ -328,9 +329,18 @@
</description> </description>
<arg name="serial_number" type="string"/> <arg name="serial_number" type="string"/>
</event> </event>
<!-- Version 3 additions -->
<request name="release" type="destructor" since="3">
<description summary="destroy the head object">
This request indicates that the client will no longer use this head
object.
</description>
</request>
</interface> </interface>
<interface name="zwlr_output_mode_v1" version="2"> <interface name="zwlr_output_mode_v1" version="3">
<description summary="output mode"> <description summary="output mode">
This object describes an output mode. This object describes an output mode.
@ -368,15 +378,24 @@
</event> </event>
<event name="finished"> <event name="finished">
<description summary="the mode has been destroyed"> <description summary="the mode has disappeared">
The compositor will destroy the object immediately after sending this This event indicates that the mode is no longer available. The mode
event, so it will become invalid and the client should release any object becomes inert. Clients should send a destroy request and release
resources associated with it. any resources associated with it.
</description> </description>
</event> </event>
<!-- Version 3 additions -->
<request name="release" type="destructor" since="3">
<description summary="destroy the mode object">
This request indicates that the client will no longer use this mode
object.
</description>
</request>
</interface> </interface>
<interface name="zwlr_output_configuration_v1" version="2"> <interface name="zwlr_output_configuration_v1" version="3">
<description summary="output configuration"> <description summary="output configuration">
This object is used by the client to describe a full output configuration. This object is used by the client to describe a full output configuration.
@ -494,7 +513,7 @@
</request> </request>
</interface> </interface>
<interface name="zwlr_output_configuration_head_v1" version="2"> <interface name="zwlr_output_configuration_head_v1" version="3">
<description summary="head configuration"> <description summary="head configuration">
This object is used by the client to update a single head's configuration. This object is used by the client to update a single head's configuration.

View File

@ -5,7 +5,7 @@
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "wlr-output-management-unstable-v1-protocol.h" #include "wlr-output-management-unstable-v1-protocol.h"
#define OUTPUT_MANAGER_VERSION 2 #define OUTPUT_MANAGER_VERSION 3
enum { enum {
HEAD_STATE_ENABLED = 1 << 0, HEAD_STATE_ENABLED = 1 << 0,
@ -27,6 +27,7 @@ static struct wlr_output_head_v1 *head_from_resource(
return wl_resource_get_user_data(resource); return wl_resource_get_user_data(resource);
} }
// Can return NULL if the mode is inert
static struct wlr_output_mode *mode_from_resource( static struct wlr_output_mode *mode_from_resource(
struct wl_resource *resource) { struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, assert(wl_resource_instance_of(resource,
@ -41,11 +42,15 @@ static void head_destroy(struct wlr_output_head_v1 *head) {
struct wl_resource *resource, *tmp; struct wl_resource *resource, *tmp;
wl_resource_for_each_safe(resource, tmp, &head->mode_resources) { wl_resource_for_each_safe(resource, tmp, &head->mode_resources) {
zwlr_output_mode_v1_send_finished(resource); zwlr_output_mode_v1_send_finished(resource);
wl_resource_destroy(resource); wl_list_remove(wl_resource_get_link(resource));
wl_list_init(wl_resource_get_link(resource));
wl_resource_set_user_data(resource, NULL);
} }
wl_resource_for_each_safe(resource, tmp, &head->resources) { wl_resource_for_each_safe(resource, tmp, &head->resources) {
zwlr_output_head_v1_send_finished(resource); zwlr_output_head_v1_send_finished(resource);
wl_resource_destroy(resource); wl_list_remove(wl_resource_get_link(resource));
wl_list_init(wl_resource_get_link(resource));
wl_resource_set_user_data(resource, NULL);
} }
wl_list_remove(&head->link); wl_list_remove(&head->link);
wl_list_remove(&head->output_destroy.link); wl_list_remove(&head->output_destroy.link);
@ -648,10 +653,19 @@ static void send_mode_state(struct wl_resource *mode_resource,
} }
} }
static void mode_handle_resource_destroy(struct wl_resource *resource) { static void output_mode_handle_resource_destroy(struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource)); wl_list_remove(wl_resource_get_link(resource));
} }
static void output_mode_handle_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct zwlr_output_mode_v1_interface output_mode_impl = {
.release = output_mode_handle_release,
};
static struct wl_resource *head_send_mode(struct wlr_output_head_v1 *head, static struct wl_resource *head_send_mode(struct wlr_output_head_v1 *head,
struct wl_resource *head_resource, struct wlr_output_mode *mode) { struct wl_resource *head_resource, struct wlr_output_mode *mode) {
struct wl_client *client = wl_resource_get_client(head_resource); struct wl_client *client = wl_resource_get_client(head_resource);
@ -662,8 +676,8 @@ static struct wl_resource *head_send_mode(struct wlr_output_head_v1 *head,
wl_resource_post_no_memory(head_resource); wl_resource_post_no_memory(head_resource);
return NULL; return NULL;
} }
wl_resource_set_implementation(mode_resource, NULL, mode, wl_resource_set_implementation(mode_resource, &output_mode_impl, mode,
mode_handle_resource_destroy); output_mode_handle_resource_destroy);
wl_list_insert(&head->mode_resources, wl_resource_get_link(mode_resource)); wl_list_insert(&head->mode_resources, wl_resource_get_link(mode_resource));
zwlr_output_head_v1_send_mode(head_resource, mode_resource); zwlr_output_head_v1_send_mode(head_resource, mode_resource);
@ -739,6 +753,15 @@ static void head_handle_resource_destroy(struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource)); wl_list_remove(wl_resource_get_link(resource));
} }
static void head_handle_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct zwlr_output_head_v1_interface head_impl = {
.release = head_handle_release,
};
static void manager_send_head(struct wlr_output_manager_v1 *manager, static void manager_send_head(struct wlr_output_manager_v1 *manager,
struct wlr_output_head_v1 *head, struct wl_resource *manager_resource) { struct wlr_output_head_v1 *head, struct wl_resource *manager_resource) {
struct wlr_output *output = head->state.output; struct wlr_output *output = head->state.output;
@ -751,7 +774,7 @@ static void manager_send_head(struct wlr_output_manager_v1 *manager,
wl_resource_post_no_memory(manager_resource); wl_resource_post_no_memory(manager_resource);
return; return;
} }
wl_resource_set_implementation(head_resource, NULL, head, wl_resource_set_implementation(head_resource, &head_impl, head,
head_handle_resource_destroy); head_handle_resource_destroy);
wl_list_insert(&head->resources, wl_resource_get_link(head_resource)); wl_list_insert(&head->resources, wl_resource_get_link(head_resource));