~emersion/public-inbox

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH wlr-randr v2] Support wlr-output-management version 3

Details
Message ID
<20220617205937.30441-1-mail@isaacfreund.com>
DKIM signature
missing
Download raw message
Patch: +200 -8
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
Details
Message ID
<T_zAYhYo7YY7zR0F-7XHGJ_pULv8QdTlywWAeP_8fex0rHJMxDKHa4hLeoBzio9MJU-8XJJbRyhUGiRRuztajew0PyH302NV4nkPjEkvHXk=@emersion.fr>
In-Reply-To
<20220617205937.30441-1-mail@isaacfreund.com> (view parent)
DKIM signature
missing
Download raw message
Pushed, thanks!
Reply to thread Export thread (mbox)