This implements version 3 of wlr-output-management-unstable-v1.
This adds the --adaptive-sync option and prints the output head's
make/model/serial if the server advertises a new enough protocol
version.
---
main.c | 88 ++++++++++++-
.../wlr-output-management-unstable-v1.xml | 120 +++++++++++++++++-
2 files changed, 200 insertions(+), 8 deletions(-)
diff --git a/main.c b/main.c
index 5dc4456..150b09b 100644
--- a/main.c
+++ b/main.c
@@ -29,6 +29,7 @@ struct randr_head {
struct wl_list link;
char *name, *description;
+ char *make, *model, *serial_number;
int32_t phys_width, phys_height; // mm
struct wl_list modes;
@@ -41,6 +42,7 @@ struct randr_head {
int32_t x, y;
enum wl_output_transform transform;
double scale;
+ enum zwlr_output_head_v1_adaptive_sync_state adaptive_sync;
};
struct randr_state {
@@ -67,11 +69,20 @@ static void print_state(struct randr_state *state) {
struct randr_head *head;
wl_list_for_each(head, &state->heads, link) {
printf("%s \"%s\"\n", head->name, head->description);
+
+ if (zwlr_output_manager_v1_get_version(state->output_manager) >= 2) {
+ printf(" Make: %s\n", head->make);
+ printf(" Model: %s\n", head->model);
+ printf(" Serial: %s\n", head->serial_number);
+ }
+
if (head->phys_width > 0 && head->phys_height > 0) {
printf(" Physical size: %dx%d mm\n",
head->phys_width, head->phys_height);
}
+
printf(" Enabled: %s\n", head->enabled ? "yes" : "no");
+
if (!wl_list_empty(&head->modes)) {
printf(" Modes:\n");
struct randr_mode *mode;
@@ -105,6 +116,22 @@ static void print_state(struct randr_state *state) {
printf(" Position: %d,%d\n", head->x, head->y);
printf(" Transform: %s\n", output_transform_map[head->transform]);
printf(" Scale: %f\n", head->scale);
+
+ if (zwlr_output_manager_v1_get_version(state->output_manager) >= 3) {
+ switch (head->adaptive_sync) {
+ case ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_UNSUPPORTED:
+ printf(" Adaptive Sync: unsupported\n");
+ break;
+ case ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED:
+ printf(" Adaptive Sync: disabled\n");
+ break;
+ case ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED:
+ printf(" Adaptive Sync: enabled\n");
+ break;
+ default:
+ abort();
+ }
+ }
}
state->running = false;
@@ -172,6 +199,14 @@ static void apply_state(struct randr_state *state, bool dry_run) {
head->transform);
zwlr_output_configuration_head_v1_set_scale(config_head,
wl_fixed_from_double(head->scale));
+
+ if (zwlr_output_manager_v1_get_version(state->output_manager) >= 3) {
+ if (head->adaptive_sync !=
+ ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_UNSUPPORTED) {
+ zwlr_output_configuration_head_v1_set_adaptive_sync(
+ config_head, head->adaptive_sync);
+ }
+ }
}
if (dry_run) {
@@ -300,6 +335,30 @@ static void head_handle_finished(void *data,
free(head);
}
+static void head_handle_make(void *data,
+ struct zwlr_output_head_v1 *wlr_head, const char *make) {
+ struct randr_head *head = data;
+ head->make = strdup(make);
+}
+
+static void head_handle_model(void *data,
+ struct zwlr_output_head_v1 *wlr_head, const char *model) {
+ struct randr_head *head = data;
+ head->model = strdup(model);
+}
+
+static void head_handle_serial_number(void *data,
+ struct zwlr_output_head_v1 *wlr_head, const char *serial_number) {
+ struct randr_head *head = data;
+ head->serial_number = strdup(serial_number);
+}
+
+static void head_handle_adaptive_sync(void *data,
+ struct zwlr_output_head_v1 *wlr_head, uint32_t state) {
+ struct randr_head *head = data;
+ head->adaptive_sync = state;
+}
+
static const struct zwlr_output_head_v1_listener head_listener = {
.name = head_handle_name,
.description = head_handle_description,
@@ -311,6 +370,10 @@ static const struct zwlr_output_head_v1_listener head_listener = {
.transform = head_handle_transform,
.scale = head_handle_scale,
.finished = head_handle_finished,
+ .make = head_handle_make,
+ .model = head_handle_model,
+ .serial_number = head_handle_serial_number,
+ .adaptive_sync = head_handle_adaptive_sync,
};
static void output_manager_handle_head(void *data,
@@ -350,8 +413,9 @@ static void registry_handle_global(void *data, struct wl_registry *registry,
struct randr_state *state = data;
if (strcmp(interface, zwlr_output_manager_v1_interface.name) == 0) {
+ uint32_t version_to_bind = version <= 3 ? version : 3;
state->output_manager = wl_registry_bind(registry, name,
- &zwlr_output_manager_v1_interface, 1);
+ &zwlr_output_manager_v1_interface, version_to_bind);
zwlr_output_manager_v1_add_listener(state->output_manager,
&output_manager_listener, state);
}
@@ -380,6 +444,7 @@ static const struct option long_options[] = {
{"pos", required_argument, 0, 0},
{"transform", required_argument, 0, 0},
{"scale", required_argument, 0, 0},
+ {"adaptive-sync", required_argument, 0, 0},
{0},
};
@@ -571,6 +636,24 @@ static bool parse_output_arg(struct randr_head *head,
}
head->scale = scale;
+ } else if (strcmp(name, "adaptive-sync") == 0) {
+ if (zwlr_output_head_v1_get_version(head->wlr_head) < 3) {
+ fprintf(stderr, "setting adaptive sync not supported by the compositor\n");
+ return false;
+ }
+ if (head->adaptive_sync ==
+ ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_UNSUPPORTED) {
+ fprintf(stderr, "adaptive sync not supported by %s\n", head->name);
+ return false;
+ }
+ if (strcmp(value, "enabled") == 0) {
+ head->adaptive_sync = ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED;
+ } else if (strcmp(value, "disabed") == 0) {
+ head->adaptive_sync = ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED;
+ } else {
+ fprintf(stderr, "invalid adaptive sync state: %s\n", value);
+ return false;
+ }
} else {
fprintf(stderr, "invalid option: %s\n", name);
return false;
@@ -591,7 +674,8 @@ static const char usage[] =
" --preferred\n"
" --pos <x>,<y>\n"
" --transform normal|90|180|270|flipped|flipped-90|flipped-180|flipped-270\n"
- " --scale <factor>\n";
+ " --scale <factor>\n"
+ " --adaptive-sync enabled|disabled\n";
int main(int argc, char *argv[]) {
struct randr_state state = { .running = true };
diff --git a/protocol/wlr-output-management-unstable-v1.xml b/protocol/wlr-output-management-unstable-v1.xml
index 35f7ca4..5652cd7 100644
--- a/protocol/wlr-output-management-unstable-v1.xml
+++ b/protocol/wlr-output-management-unstable-v1.xml
@@ -39,7 +39,7 @@
interface version number is reset.
</description>
- <interface name="zwlr_output_manager_v1" version="1">
+ <interface name="zwlr_output_manager_v1" version="3">
<description summary="output device configuration manager">
This interface is a manager that allows reading and writing the current
output device configuration.
@@ -115,7 +115,7 @@
</description>
</request>
- <event name="finished">
+ <event name="finished" type="destructor">
<description summary="the compositor has finished with the manager">
This event indicates that the compositor is done sending manager events.
The compositor will destroy the object immediately after sending this
@@ -125,7 +125,7 @@
</event>
</interface>
- <interface name="zwlr_output_head_v1" version="1">
+ <interface name="zwlr_output_head_v1" version="3">
<description summary="output device">
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
@@ -257,9 +257,100 @@
resources associated with it.
</description>
</event>
+
+ <!-- Version 2 additions -->
+ <event name="make" since="2">
+ <description summary="head manufacturer">
+ This event describes the manufacturer of the head.
+
+ This must report the same make as the wl_output interface does in its
+ geometry event.
+
+ Together with the model and serial_number events the purpose is to
+ allow clients to recognize heads from previous sessions and for example
+ load head-specific configurations back.
+
+ It is not guaranteed this event will be ever sent. A reason for that
+ can be that the compositor does not have information about the make of
+ the head or the definition of a make is not sensible in the current
+ setup, for example in a virtual session. Clients can still try to
+ identify the head by available information from other events but should
+ be aware that there is an increased risk of false positives.
+
+ It is not recommended to display the make string in UI to users. For
+ that the string provided by the description event should be preferred.
+ </description>
+ <arg name="make" type="string"/>
+ </event>
+
+ <event name="model" since="2">
+ <description summary="head model">
+ This event describes the model of the head.
+
+ This must report the same model as the wl_output interface does in its
+ geometry event.
+
+ Together with the make and serial_number events the purpose is to
+ allow clients to recognize heads from previous sessions and for example
+ load head-specific configurations back.
+
+ It is not guaranteed this event will be ever sent. A reason for that
+ can be that the compositor does not have information about the model of
+ the head or the definition of a model is not sensible in the current
+ setup, for example in a virtual session. Clients can still try to
+ identify the head by available information from other events but should
+ be aware that there is an increased risk of false positives.
+
+ It is not recommended to display the model string in UI to users. For
+ that the string provided by the description event should be preferred.
+ </description>
+ <arg name="model" type="string"/>
+ </event>
+
+ <event name="serial_number" since="2">
+ <description summary="head serial number">
+ This event describes the serial number of the head.
+
+ Together with the make and model events the purpose is to allow clients
+ to recognize heads from previous sessions and for example load head-
+ specific configurations back.
+
+ It is not guaranteed this event will be ever sent. A reason for that
+ can be that the compositor does not have information about the serial
+ number of the head or the definition of a serial number is not sensible
+ in the current setup. Clients can still try to identify the head by
+ available information from other events but should be aware that there
+ is an increased risk of false positives.
+
+ It is not recommended to display the serial_number string in UI to
+ users. For that the string provided by the description event should be
+ preferred.
+ </description>
+ <arg name="serial_number" type="string"/>
+ </event>
+
+ <!-- Version 3 additions -->
+
+ <enum name="adaptive_sync_state" since="3">
+ <entry name="unsupported" value="0"
+ summary="adaptive sync not supported by the head"/>
+ <entry name="disabled" value="1"
+ summary="adaptive sync supported but currently disabled"/>
+ <entry name="enabled" value="2"
+ summary="adaptive sync supported and currently enabled"/>
+ </enum>
+
+ <event name="adaptive_sync" since="3">
+ <description summary="current adaptive sync state">
+ This event describes whether adaptive sync is supported by the head
+ and whether it is currently enabled or not if so. Adaptive sync is
+ also known as Variable Refresh Rate or VRR.
+ </description>
+ <arg name="state" type="uint" enum="adaptive_sync_state"/>
+ </event>
</interface>
- <interface name="zwlr_output_mode_v1" version="1">
+ <interface name="zwlr_output_mode_v1" version="2">
<description summary="output mode">
This object describes an output mode.
@@ -305,7 +396,7 @@
</event>
</interface>
- <interface name="zwlr_output_configuration_v1" version="1">
+ <interface name="zwlr_output_configuration_v1" version="3">
<description summary="output configuration">
This object is used by the client to describe a full output configuration.
@@ -423,7 +514,7 @@
</request>
</interface>
- <interface name="zwlr_output_configuration_head_v1" version="1">
+ <interface name="zwlr_output_configuration_head_v1" version="3">
<description summary="head configuration">
This object is used by the client to update a single head's configuration.
@@ -436,6 +527,8 @@
<entry name="invalid_custom_mode" value="3" summary="mode is invalid"/>
<entry name="invalid_transform" value="4" summary="transform value outside enum"/>
<entry name="invalid_scale" value="5" summary="scale negative or zero"/>
+ <entry name="invalid_adaptive_sync" value="6"
+ summary="adaptive sync state unsupported by head or outside enum"/>
</enum>
<request name="set_mode">
@@ -479,5 +572,20 @@
</description>
<arg name="scale" type="fixed"/>
</request>
+
+ <!-- Version 3 additions -->
+
+ <request name="set_adaptive_sync" since="3">
+ <description summary="enable/disable adaptive sync">
+ This request enables/disables adaptive sync. Adaptive sync is also
+ known as Variable Refresh Rate or VRR.
+
+ It is a protocol error to make this request if the head does not
+ support adaptive sync (see zwlr_output_head_v1.adaptive_sync) or
+ to set the state to the unsupported enum value.
+ </description>
+ <arg name="state" type="uint"
+ enum="zwlr_output_head_v1.adaptive_sync_state"/>
+ </request>
</interface>
</protocol>
--
2.36.1