diff --git a/protocol/wlr-output-management-unstable-v1.xml b/protocol/wlr-output-management-unstable-v1.xml
index 07586ca1..35f7ca4e 100644
--- a/protocol/wlr-output-management-unstable-v1.xml
+++ b/protocol/wlr-output-management-unstable-v1.xml
@@ -26,7 +26,7 @@
- This protocol exposes interfaces to get and change output device
+ This protocol exposes interfaces to obtain and modify output device
configuration.
Warning! The protocol described in this file is experimental and
@@ -46,15 +46,23 @@
Output devices that display pixels (e.g. a physical monitor or a virtual
output in a window) are represented as heads. Heads cannot be created nor
- destroyed, but they can be enabled or disabled and their properties can be
- changed. Each head may have one or more available modes.
+ destroyed by the client, but they can be enabled or disabled and their
+ properties can be changed. Each head may have one or more available modes.
- Heads are advertised when the output manager is bound, and whenever they
- appear.
+ Whenever a head appears (e.g. a monitor is plugged in), it will be
+ advertised via the head event. Immediately after the output manager is
+ bound, all current heads are advertised.
- Whenever the number of heads or modes changes, the done event will be
- sent. It carries a serial which can be used in a create_configuration
- request to change heads properties.
+ Whenever a head's properties change, the relevant wlr_output_head events
+ will be sent. Not all head properties will be sent: only properties that
+ have changed need to.
+
+ Whenever a head disappears (e.g. a monitor is unplugged), a
+ wlr_output_head.finished event will be sent.
+
+ After one or more heads appear, change or disappear, the done event will
+ be sent. It carries a serial which can be used in a create_configuration
+ request to update heads properties.
The information obtained from this protocol should only be used for output
configuration purposes. This protocol is not designed to be a generic
@@ -64,7 +72,9 @@
- This event introduces a new head.
+ This event introduces a new head. This happens whenever a new head
+ appears (e.g. a monitor is plugged in) or after the output manager is
+ bound.
@@ -75,7 +85,8 @@
the output manager object and after any subsequent changes. This applies
to child head and mode objects as well. In other words, this event is
sent whenever a head or mode is created or destroyed and whenever one of
- their properties has been changed.
+ their properties has been changed. Not all state is re-sent each time
+ the current configuration changes: only the actual changes are sent.
This allows changes to the output configuration to be seen as atomic,
even if they happen via multiple events.
@@ -116,28 +127,21 @@
- A head is an output device. The difference with wl_output is that heads
- are advertized even if they are turned off. A head object only advertises
- properties and cannot be used directly to change them. In order to update
- some properties, one needs to create a wlr_output_configuration object.
+ 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
+ object only advertises properties and cannot be used directly to change
+ them.
- A head has some read-only properties: mode, name, description and
+ A head has some read-only properties: modes, name, description and
physical_size. These cannot be changed by clients.
- enabled and current_mode are physical properties. Updating them might take
- some time, depending on hardware limitations.
+ Other properties can be updated via a wlr_output_configuration object.
- position, transform and scale are logical properties. They describe how
- the output is mapped in the global compositor space.
+ Properties sent via this interface are applied atomically via the
+ wlr_output_manager.done event. No guarantees are made regarding the order
+ in which properties are sent.
-
-
- If the head supports modes, this event is sent once per supported mode.
-
-
-
-
This event describes the head name.
@@ -168,7 +172,9 @@
The description is a UTF-8 string with no convention defined for its
contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11
- output via :1'.
+ output via :1'. However, do not assume that the name is a reflection of
+ the make, model, serial of the underlying DRM connector or the display
+ name of the underlying X11 connection, etc.
If the compositor implements xdg-output and this head is enabled,
the xdg_output.description must report the same description.
@@ -190,6 +196,14 @@
+
+
+ This event introduces a mode for this head. It is sent once per
+ supported mode.
+
+
+
+
This event describes whether the head is enabled. A disabled head is not
@@ -204,7 +218,7 @@
This event describes the mode currently in use for this head. It is only
- sent if the output is enabled and supports modes.
+ sent if the output is enabled.
@@ -251,6 +265,10 @@
Some heads don't support output modes, in which case modes won't be
advertised.
+
+ Properties sent via this interface are applied atomically via the
+ wlr_output_manager.done event. No guarantees are made regarding the order
+ in which properties are sent.
@@ -266,7 +284,8 @@
- This event describes the mode's fixed vertical refresh rate, if any.
+ This event describes the mode's fixed vertical refresh rate. It is only
+ sent if the mode has a fixed refresh rate.
@@ -322,7 +341,7 @@
- Disable a head. The head's properties are irrelevant in this case.
+ Disable a head.
@@ -363,6 +382,9 @@
tested them.
Upon receiving this event, the client should destroy this object.
+
+ If the current configuration has changed, events to describe the changes
+ will be sent followed by a wlr_output_manager.done event.
@@ -404,12 +426,16 @@
This object is used by the client to update a single head's configuration.
+
+ It is a protocol error to set the same property twice.
-
-
-
+
+
+
+
+
@@ -419,6 +445,19 @@
+
+
+ This request assigns a custom mode to the head. The size is given in
+ physical hardware units of the output device. If set to zero, the
+ refresh rate is unspecified.
+
+ It is a protocol error to set both a mode and a custom mode.
+
+
+
+
+
+
This request sets the head's position in the global compositor space.
diff --git a/rootston/output.c b/rootston/output.c
index 4afbfa7b..15737733 100644
--- a/rootston/output.c
+++ b/rootston/output.c
@@ -451,6 +451,11 @@ void handle_output_manager_apply(struct wl_listener *listener, void *data) {
}
if (config_head->state.mode != NULL) {
ok &= wlr_output_set_mode(wlr_output, config_head->state.mode);
+ } else {
+ ok &= wlr_output_set_custom_mode(wlr_output,
+ config_head->state.custom_mode.width,
+ config_head->state.custom_mode.height,
+ config_head->state.custom_mode.refresh);
}
wlr_output_layout_add(desktop->layout, wlr_output,
config_head->state.x, config_head->state.y);
diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c
index f58273e9..f22fbc45 100644
--- a/types/wlr_output_management_v1.c
+++ b/types/wlr_output_management_v1.c
@@ -149,10 +149,11 @@ static void config_head_handle_set_mode(struct wl_client *client,
}
struct wlr_output_mode *mode = mode_from_resource(mode_resource);
+ struct wlr_output *output = config_head->state.output;
- bool found = false;
+ bool found = (mode == NULL && wl_list_empty(&output->modes));
struct wlr_output_mode *m;
- wl_list_for_each(m, &config_head->state.output->modes, link) {
+ wl_list_for_each(m, &output->modes, link) {
if (mode == m) {
found = true;
break;
@@ -167,6 +168,33 @@ static void config_head_handle_set_mode(struct wl_client *client,
}
config_head->state.mode = mode;
+ if (mode != NULL) {
+ config_head->state.custom_mode.width = 0;
+ config_head->state.custom_mode.height = 0;
+ config_head->state.custom_mode.refresh = 0;
+ }
+}
+
+static void config_head_handle_set_custom_mode(struct wl_client *client,
+ struct wl_resource *config_head_resource, int32_t width, int32_t height,
+ int32_t refresh) {
+ struct wlr_output_configuration_head_v1 *config_head =
+ config_head_from_resource(config_head_resource);
+ if (config_head == NULL) {
+ return;
+ }
+
+ if (width <= 0 || height <= 0 || refresh < 0) {
+ wl_resource_post_error(config_head_resource,
+ ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE,
+ "invalid custom mode");
+ return;
+ }
+
+ config_head->state.mode = NULL;
+ config_head->state.custom_mode.width = width;
+ config_head->state.custom_mode.height = height;
+ config_head->state.custom_mode.refresh = refresh;
}
static void config_head_handle_set_position(struct wl_client *client,
@@ -221,6 +249,7 @@ static void config_head_handle_set_scale(struct wl_client *client,
static const struct zwlr_output_configuration_head_v1_interface config_head_impl = {
.set_mode = config_head_handle_set_mode,
+ .set_custom_mode = config_head_handle_set_custom_mode,
.set_position = config_head_handle_set_position,
.set_transform = config_head_handle_set_transform,
.set_scale = config_head_handle_set_scale,