Merge branch 'output-mgmt-viewport' into 'master'

output-management-v1: add viewport

See merge request wlroots/wlroots!4595
This commit is contained in:
Simon Ser 2026-01-14 20:35:38 +00:00
commit e359ab35b8
3 changed files with 79 additions and 11 deletions

View file

@ -55,7 +55,7 @@ struct wlr_output_head_v1_state {
int32_t width, height;
int32_t refresh;
} custom_mode;
int32_t x, y;
int32_t x, y, width, height;
enum wl_output_transform transform;
float scale;
bool adaptive_sync_enabled;

View file

@ -39,7 +39,7 @@
interface version number is reset.
</description>
<interface name="zwlr_output_manager_v1" version="4">
<interface name="zwlr_output_manager_v1" version="5">
<description summary="output device configuration manager">
This interface is a manager that allows reading and writing the current
output device configuration.
@ -125,7 +125,7 @@
</event>
</interface>
<interface name="zwlr_output_head_v1" version="4">
<interface name="zwlr_output_head_v1" version="5">
<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
@ -140,6 +140,11 @@
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.
The viewport indicates the logical size taken by the output in the global
compositor space. If the viewport aspect ratio doesn't match the current
mode aspect ratio, the compositor should letter-box the output with black
borders.
</description>
<event name="name">
@ -229,7 +234,7 @@
<event name="position">
<description summary="current position">
This events describes the position of the head in the global compositor
This event describes the position of the head in the global compositor
space. It is only sent if the output is enabled.
</description>
<arg name="x" type="int"
@ -250,6 +255,9 @@
<description summary="current scale">
This events describes the scale of the head in the global compositor
space. It is only sent if the output is enabled.
Starting from version 5, this event is deprecated: the viewport event
should be used instead.
</description>
<arg name="scale" type="fixed"/>
</event>
@ -364,9 +372,20 @@
</description>
<arg name="state" type="uint" enum="adaptive_sync_state"/>
</event>
<!-- Version 5 additions -->
<event name="viewport" since="5">
<description summary="head viewport">
This event describes the size of the head in the global compositor
space. It is only sent if the output is enabled.
</description>
<arg name="width" type="int" summary="logical width"/>
<arg name="height" type="int" summary="logical height"/>
</event>
</interface>
<interface name="zwlr_output_mode_v1" version="3">
<interface name="zwlr_output_mode_v1" version="5">
<description summary="output mode">
This object describes an output mode.
@ -421,7 +440,7 @@
</request>
</interface>
<interface name="zwlr_output_configuration_v1" version="4">
<interface name="zwlr_output_configuration_v1" version="5">
<description summary="output configuration">
This object is used by the client to describe a full output configuration.
@ -539,7 +558,7 @@
</request>
</interface>
<interface name="zwlr_output_configuration_head_v1" version="4">
<interface name="zwlr_output_configuration_head_v1" version="5">
<description summary="head configuration">
This object is used by the client to update a single head's configuration.
@ -554,6 +573,7 @@
<entry name="invalid_scale" value="5" summary="scale negative or zero"/>
<entry name="invalid_adaptive_sync_state" value="6" since="4"
summary="invalid enum value used in the set_adaptive_sync request"/>
<entry name="invalid_viewport" value="7" summary="viewport negative or zero"/>
</enum>
<request name="set_mode">
@ -594,6 +614,9 @@
<request name="set_scale">
<description summary="set the scale">
This request sets the head's scale.
Starting from version 5, this request is deprecated: clients should use
set_viewport instead.
</description>
<arg name="scale" type="fixed"/>
</request>
@ -607,5 +630,17 @@
</description>
<arg name="state" type="uint" enum="zwlr_output_head_v1.adaptive_sync_state"/>
</request>
<!-- Version 5 additions -->
<request name="set_viewport" since="5">
<description summary="set the viewport">
This request sets the head's viewport.
This overrides the set_scale request, if any was sent.
</description>
<arg name="width" type="int" summary="logical width"/>
<arg name="height" type="int" summary="logical height"/>
</request>
</interface>
</protocol>

View file

@ -6,7 +6,7 @@
#include <wlr/util/log.h>
#include "wlr-output-management-unstable-v1-protocol.h"
#define OUTPUT_MANAGER_VERSION 4
#define OUTPUT_MANAGER_VERSION 5
enum {
HEAD_STATE_ENABLED = 1 << 0,
@ -15,11 +15,12 @@ enum {
HEAD_STATE_TRANSFORM = 1 << 3,
HEAD_STATE_SCALE = 1 << 4,
HEAD_STATE_ADAPTIVE_SYNC = 1 << 5,
HEAD_STATE_VIEWPORT = 1 << 6,
};
static const uint32_t HEAD_STATE_ALL = HEAD_STATE_ENABLED | HEAD_STATE_MODE |
HEAD_STATE_POSITION | HEAD_STATE_TRANSFORM | HEAD_STATE_SCALE |
HEAD_STATE_ADAPTIVE_SYNC;
HEAD_STATE_ADAPTIVE_SYNC | HEAD_STATE_VIEWPORT;
static const struct zwlr_output_head_v1_interface head_impl;
@ -162,6 +163,8 @@ struct wlr_output_configuration_head_v1 *
config_head->state.scale = output->scale;
config_head->state.adaptive_sync_enabled =
output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
config_head->state.width = output->width * output->scale;
config_head->state.height = output->height * output->scale;
return config_head;
}
@ -307,6 +310,26 @@ static void config_head_handle_set_adaptive_sync(struct wl_client *client,
}
}
static void config_head_handle_set_viewport(struct wl_client *client,
struct wl_resource *config_head_resource,
int32_t width, int32_t height) {
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) {
wl_resource_post_error(config_head_resource,
ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_VIEWPORT,
"invalid viewport");
return;
}
config_head->state.width = width;
config_head->state.height = height;
}
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,
@ -314,6 +337,7 @@ static const struct zwlr_output_configuration_head_v1_interface config_head_impl
.set_transform = config_head_handle_set_transform,
.set_scale = config_head_handle_set_scale,
.set_adaptive_sync = config_head_handle_set_adaptive_sync,
.set_viewport = config_head_handle_set_viewport,
};
static void config_head_handle_resource_destroy(struct wl_resource *resource) {
@ -752,6 +776,7 @@ static struct wl_resource *head_send_mode(struct wlr_output_head_v1 *head,
static void head_send_state(struct wlr_output_head_v1 *head,
struct wl_resource *head_resource, uint32_t state) {
struct wl_client *client = wl_resource_get_client(head_resource);
uint32_t version = wl_resource_get_version(head_resource);
if (state & HEAD_STATE_ENABLED) {
zwlr_output_head_v1_send_enabled(head_resource, head->state.enabled);
@ -805,8 +830,7 @@ static void head_send_state(struct wlr_output_head_v1 *head,
}
if ((state & HEAD_STATE_ADAPTIVE_SYNC) &&
wl_resource_get_version(head_resource) >=
ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_SINCE_VERSION) {
version >= ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_SINCE_VERSION) {
if (head->state.adaptive_sync_enabled) {
zwlr_output_head_v1_send_adaptive_sync(head_resource,
ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED);
@ -815,6 +839,12 @@ static void head_send_state(struct wlr_output_head_v1 *head,
ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED);
}
}
if ((state & HEAD_STATE_VIEWPORT) &&
version >= ZWLR_OUTPUT_HEAD_V1_VIEWPORT_SINCE_VERSION) {
zwlr_output_head_v1_send_viewport(head_resource,
head->state.width, head->state.height);
}
}
static void head_handle_resource_destroy(struct wl_resource *resource) {
@ -911,6 +941,9 @@ static bool manager_update_head(struct wlr_output_manager_v1 *manager,
if (current->adaptive_sync_enabled != next->adaptive_sync_enabled) {
state |= HEAD_STATE_ADAPTIVE_SYNC;
}
if (current->width != next->width || current->height != next->height) {
state |= HEAD_STATE_VIEWPORT;
}
// If a mode was added to wlr_output.modes we need to add the new mode
// to the wlr_output_head