Isaac Freund: 1 Support wlr-output-management version 3 2 files changed, 200 insertions(+), 8 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~emersion/public-inbox/patches/33086/mbox | git am -3Learn more about email & git
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
Pushed, thanks!