mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-29 16:05:59 +01:00
Add support for wlr-output-management-unstable-v1
This commit is contained in:
parent
b6d0de177a
commit
3a233b3fcc
6 changed files with 928 additions and 0 deletions
|
@ -23,6 +23,7 @@ install_headers(
|
||||||
'wlr_matrix.h',
|
'wlr_matrix.h',
|
||||||
'wlr_output_damage.h',
|
'wlr_output_damage.h',
|
||||||
'wlr_output_layout.h',
|
'wlr_output_layout.h',
|
||||||
|
'wlr_output_management_v1.h',
|
||||||
'wlr_output.h',
|
'wlr_output.h',
|
||||||
'wlr_pointer_constraints_v1.h',
|
'wlr_pointer_constraints_v1.h',
|
||||||
'wlr_pointer_gestures_v1.h',
|
'wlr_pointer_gestures_v1.h',
|
||||||
|
|
66
include/wlr/types/wlr_output_management_v1.h
Normal file
66
include/wlr/types/wlr_output_management_v1.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||||
|
* future consistency of this API.
|
||||||
|
*/
|
||||||
|
#ifndef WLR_USE_UNSTABLE
|
||||||
|
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WLR_TYPES_WLR_OUTPUT_MANAGEMENT_V1_H
|
||||||
|
#define WLR_TYPES_WLR_OUTPUT_MANAGEMENT_V1_H
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#include <wlr/types/wlr_output.h>
|
||||||
|
|
||||||
|
struct wlr_output_configuration_v1;
|
||||||
|
|
||||||
|
struct wlr_output_manager_v1 {
|
||||||
|
struct wl_display *display;
|
||||||
|
struct wl_global *global;
|
||||||
|
struct wl_list resources;
|
||||||
|
|
||||||
|
struct wlr_output_configuration_v1 *current;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct wl_listener display_destroy;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: split this into multiple structs (state + output_head + output_configuration_head)
|
||||||
|
struct wlr_output_configuration_head_v1 {
|
||||||
|
struct wlr_output_configuration_v1 *config;
|
||||||
|
struct wlr_output *output;
|
||||||
|
struct wl_list link;
|
||||||
|
|
||||||
|
// for current config only
|
||||||
|
struct wl_list resources;
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
|
struct wl_listener output_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_output_configuration_v1 {
|
||||||
|
struct wl_list heads;
|
||||||
|
uint32_t serial;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_output_manager_v1 *wlr_output_manager_v1_create(
|
||||||
|
struct wl_display *display);
|
||||||
|
void wlr_output_manager_v1_set_configuration(
|
||||||
|
struct wlr_output_manager_v1 *manager,
|
||||||
|
struct wlr_output_configuration_v1 *config);
|
||||||
|
|
||||||
|
struct wlr_output_configuration_v1 *wlr_output_configuration_v1_create(void);
|
||||||
|
void wlr_output_configuration_v1_destroy(
|
||||||
|
struct wlr_output_configuration_v1 *config);
|
||||||
|
|
||||||
|
struct wlr_output_configuration_head_v1 *
|
||||||
|
wlr_output_configuration_head_v1_create(
|
||||||
|
struct wlr_output_configuration_v1 *config, struct wlr_output *output);
|
||||||
|
|
||||||
|
#endif
|
|
@ -38,6 +38,7 @@ protocols = [
|
||||||
'wlr-gamma-control-unstable-v1.xml',
|
'wlr-gamma-control-unstable-v1.xml',
|
||||||
'wlr-input-inhibitor-unstable-v1.xml',
|
'wlr-input-inhibitor-unstable-v1.xml',
|
||||||
'wlr-layer-shell-unstable-v1.xml',
|
'wlr-layer-shell-unstable-v1.xml',
|
||||||
|
'wlr-output-management-unstable-v1.xml',
|
||||||
'wlr-screencopy-unstable-v1.xml',
|
'wlr-screencopy-unstable-v1.xml',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
444
protocol/wlr-output-management-unstable-v1.xml
Normal file
444
protocol/wlr-output-management-unstable-v1.xml
Normal file
|
@ -0,0 +1,444 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wlr_output_management_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2019 Purism SPC
|
||||||
|
|
||||||
|
Permission to use, copy, modify, distribute, and sell this
|
||||||
|
software and its documentation for any purpose is hereby granted
|
||||||
|
without fee, provided that the above copyright notice appear in
|
||||||
|
all copies and that both that copyright notice and this permission
|
||||||
|
notice appear in supporting documentation, and that the name of
|
||||||
|
the copyright holders not be used in advertising or publicity
|
||||||
|
pertaining to distribution of the software without specific,
|
||||||
|
written prior permission. The copyright holders make no
|
||||||
|
representations about the suitability of this software for any
|
||||||
|
purpose. It is provided "as is" without express or implied
|
||||||
|
warranty.
|
||||||
|
|
||||||
|
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||||
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||||
|
THIS SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<description summary="protocol to configure output devices">
|
||||||
|
This protocol exposes interfaces to get and change output device
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is experimental and
|
||||||
|
backward incompatible changes may be made. Backward compatible changes
|
||||||
|
may be added together with the corresponding interface version bump.
|
||||||
|
Backward incompatible changes are done by bumping the version number in
|
||||||
|
the protocol and interface names and resetting the interface version.
|
||||||
|
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||||
|
version number in the protocol and interface names are removed and the
|
||||||
|
interface version number is reset.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_manager_v1" version="1">
|
||||||
|
<description summary="output device configuration manager">
|
||||||
|
This interface is a manager that allows reading and writing the current
|
||||||
|
output device configuration.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Heads are advertised when the output manager is bound, and whenever they
|
||||||
|
appear.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
The information obtained from this protocol should only be used for output
|
||||||
|
configuration purposes. This protocol is not designed to be a generic
|
||||||
|
output property advertisement protocol for regular clients. Instead,
|
||||||
|
protocols such as xdg-output should be used.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="head">
|
||||||
|
<description summary="introduce a new head">
|
||||||
|
This event introduces a new head.
|
||||||
|
</description>
|
||||||
|
<arg name="head" type="new_id" interface="zwlr_output_head_v1"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="done">
|
||||||
|
<description summary="sent all information about current configuration">
|
||||||
|
This event is sent after all information has been sent after binding to
|
||||||
|
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.
|
||||||
|
|
||||||
|
This allows changes to the output configuration to be seen as atomic,
|
||||||
|
even if they happen via multiple events.
|
||||||
|
|
||||||
|
A serial is sent to be used in a future create_configuration request.
|
||||||
|
</description>
|
||||||
|
<arg name="serial" type="uint" summary="current configuration serial"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="create_configuration">
|
||||||
|
<description summary="create a new output configuration object">
|
||||||
|
Create a new output configuration object. This allows to update head
|
||||||
|
properties.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwlr_output_configuration_v1"/>
|
||||||
|
<arg name="serial" type="uint"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="stop">
|
||||||
|
<description summary="stop sending events">
|
||||||
|
Indicates the client no longer wishes to receive events for output
|
||||||
|
configuration changes. However the compositor may emit further events,
|
||||||
|
until the finished event is emitted.
|
||||||
|
|
||||||
|
The client must not send any more requests after this one.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="finished">
|
||||||
|
<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
|
||||||
|
event, so it will become invalid and the client should release any
|
||||||
|
resources associated with it.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_head_v1" version="1">
|
||||||
|
<description summary="output device">
|
||||||
|
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 has some read-only properties: mode, 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.
|
||||||
|
|
||||||
|
position, transform and scale are logical properties. They describe how
|
||||||
|
the output is mapped in the global compositor space.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="mode">
|
||||||
|
<description summary="advertise a supported mode">
|
||||||
|
If the head supports modes, this event is sent once per supported mode.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="new_id" interface="zwlr_output_mode_v1"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="name">
|
||||||
|
<description summary="head name">
|
||||||
|
This event describes the head name.
|
||||||
|
|
||||||
|
The naming convention is compositor defined, but limited to alphanumeric
|
||||||
|
characters and dashes (-). Each name is unique among all wlr_output_head
|
||||||
|
objects, but if a wlr_output_head object is destroyed the same name may
|
||||||
|
be reused later. The names will also remain consistent across sessions
|
||||||
|
with the same hardware and software configuration.
|
||||||
|
|
||||||
|
Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do
|
||||||
|
not assume that the name is a reflection of an underlying DRM
|
||||||
|
connector, X11 connection, etc.
|
||||||
|
|
||||||
|
If the compositor implements the xdg-output protocol and this head is
|
||||||
|
enabled, the xdg_output.name event must report the same name.
|
||||||
|
|
||||||
|
The name event is sent after a wlr_output_head object is created. This
|
||||||
|
event is only sent once per object, and the name does not change over
|
||||||
|
the lifetime of the wlr_output_head object.
|
||||||
|
</description>
|
||||||
|
<arg name="name" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="description">
|
||||||
|
<description summary="head description">
|
||||||
|
This event describes a human-readable description of the head.
|
||||||
|
|
||||||
|
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'.
|
||||||
|
|
||||||
|
If the compositor implements xdg-output and this head is enabled,
|
||||||
|
the xdg_output.description must report the same description.
|
||||||
|
|
||||||
|
The description event is sent after a wlr_output_head object is created.
|
||||||
|
This event is only sent once per object, and the description does not
|
||||||
|
change over the lifetime of the wlr_output_head object.
|
||||||
|
</description>
|
||||||
|
<arg name="description" type="string"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="physical_size">
|
||||||
|
<description summary="head physical size">
|
||||||
|
This event describes the physical size of the head. This event is only
|
||||||
|
sent if the head has a physical size (e.g. is not a projector or a
|
||||||
|
virtual device).
|
||||||
|
</description>
|
||||||
|
<arg name="width" type="int" summary="width in millimeters of the output"/>
|
||||||
|
<arg name="height" type="int" summary="height in millimeters of the output"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="enabled">
|
||||||
|
<description summary="head is enabled or disabled">
|
||||||
|
This event describes whether the head is enabled. A disabled head is not
|
||||||
|
mapped to a region of the global compositor space.
|
||||||
|
|
||||||
|
When a head is disabled, some properties (current_mode, position,
|
||||||
|
transform and scale) are irrelevant.
|
||||||
|
</description>
|
||||||
|
<arg name="enabled" type="int" summary="zero if disabled, non-zero if enabled"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="current_mode">
|
||||||
|
<description summary="current mode">
|
||||||
|
This event describes the mode currently in use for this head. It is only
|
||||||
|
sent if the output is enabled and supports modes.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="object" interface="zwlr_output_mode_v1"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="position">
|
||||||
|
<description summary="current position">
|
||||||
|
This events 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"
|
||||||
|
summary="x position within the global compositor space"/>
|
||||||
|
<arg name="y" type="int"
|
||||||
|
summary="y position within the global compositor space"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="transform">
|
||||||
|
<description summary="current transformation">
|
||||||
|
This event describes the transformation currently applied to the head.
|
||||||
|
It is only sent if the output is enabled.
|
||||||
|
</description>
|
||||||
|
<arg name="transform" type="int" enum="wl_output.transform"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="scale">
|
||||||
|
<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.
|
||||||
|
</description>
|
||||||
|
<arg name="scale" type="fixed"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="finished">
|
||||||
|
<description summary="the head has been destroyed">
|
||||||
|
The compositor will destroy the object immediately after sending this
|
||||||
|
event, so it will become invalid and the client should release any
|
||||||
|
resources associated with it.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_mode_v1" version="1">
|
||||||
|
<description summary="output mode">
|
||||||
|
This object describes an output mode.
|
||||||
|
|
||||||
|
Some heads don't support output modes, in which case modes won't be
|
||||||
|
advertised.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="size">
|
||||||
|
<description summary="mode size">
|
||||||
|
This event describes the mode size. The size is given in physical
|
||||||
|
hardware units of the output device. This is not necessarily the same as
|
||||||
|
the output size in the global compositor space. For instance, the output
|
||||||
|
may be scaled or transformed.
|
||||||
|
</description>
|
||||||
|
<arg name="width" type="int" summary="width of the mode in hardware units"/>
|
||||||
|
<arg name="height" type="int" summary="height of the mode in hardware units"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="refresh">
|
||||||
|
<description summary="mode refresh rate">
|
||||||
|
This event describes the mode's fixed vertical refresh rate, if any.
|
||||||
|
</description>
|
||||||
|
<arg name="refresh" type="int" summary="vertical refresh rate in mHz"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="preferred">
|
||||||
|
<description summary="mode is preferred">
|
||||||
|
This event advertises this mode as preferred.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="finished">
|
||||||
|
<description summary="the mode has been destroyed">
|
||||||
|
The compositor will destroy the object immediately after sending this
|
||||||
|
event, so it will become invalid and the client should release any
|
||||||
|
resources associated with it.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_configuration_v1" version="1">
|
||||||
|
<description summary="output configuration">
|
||||||
|
This object is used by the client to describe a full output configuration.
|
||||||
|
|
||||||
|
First, the client needs to setup the output configuration. Each head can
|
||||||
|
be either enabled (and configured) or disabled. It is a protocol error to
|
||||||
|
send two enable_head or disable_head requests with the same head. It is a
|
||||||
|
protocol error to omit a head in a configuration.
|
||||||
|
|
||||||
|
Then, the client can apply or test the configuration. The compositor will
|
||||||
|
then reply with a succeeded, failed or cancelled event. Finally the client
|
||||||
|
should destroy the configuration object.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_configured_head" value="1"
|
||||||
|
summary="head has been configured twice"/>
|
||||||
|
<entry name="unconfigured_head" value="2"
|
||||||
|
summary="head has not been configured"/>
|
||||||
|
<entry name="already_used" value="3"
|
||||||
|
summary="request sent after configuration has been applied or tested"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="enable_head">
|
||||||
|
<description summary="enable and configure a head">
|
||||||
|
Enable a head. This request creates a head configuration object that can
|
||||||
|
be used to change the head's properties.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwlr_output_configuration_head_v1"
|
||||||
|
summary="a new object to configure the head"/>
|
||||||
|
<arg name="head" type="object" interface="zwlr_output_head_v1"
|
||||||
|
summary="the head to be enabled"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="disable_head">
|
||||||
|
<description summary="disable a head">
|
||||||
|
Disable a head. The head's properties are irrelevant in this case.
|
||||||
|
</description>
|
||||||
|
<arg name="head" type="object" interface="zwlr_output_head_v1"
|
||||||
|
summary="the head to be disabled"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="apply">
|
||||||
|
<description summary="apply the configuration">
|
||||||
|
Apply the new output configuration.
|
||||||
|
|
||||||
|
In case the configuration is successfully applied, there is no guarantee
|
||||||
|
that the new output state matches completely the requested
|
||||||
|
configuration. For instance, a compositor might round the scale if it
|
||||||
|
doesn't support fractional scaling.
|
||||||
|
|
||||||
|
After this request has been sent, the compositor must respond with an
|
||||||
|
succeeded, failed or cancelled event. Sending a request that isn't the
|
||||||
|
destructor is a protocol error.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="test">
|
||||||
|
<description summary="test the configuration">
|
||||||
|
Test the new output configuration. The configuration won't be applied,
|
||||||
|
but will only be validated.
|
||||||
|
|
||||||
|
Even if the compositor succeeds to test a configuration, applying it may
|
||||||
|
fail.
|
||||||
|
|
||||||
|
After this request has been sent, the compositor must respond with an
|
||||||
|
succeeded, failed or cancelled event. Sending a request that isn't the
|
||||||
|
destructor is a protocol error.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="succeeded">
|
||||||
|
<description summary="configuration changes succeeded">
|
||||||
|
Sent after the compositor has successfully applied the changes or
|
||||||
|
tested them.
|
||||||
|
|
||||||
|
Upon receiving this event, the client should destroy this object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="failed">
|
||||||
|
<description summary="configuration changes failed">
|
||||||
|
Sent if the compositor rejects the changes or failed to apply them. The
|
||||||
|
compositor should revert any changes made by the apply request that
|
||||||
|
triggered this event.
|
||||||
|
|
||||||
|
Upon receiving this event, the client should destroy this object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="cancelled">
|
||||||
|
<description summary="configuration has been cancelled">
|
||||||
|
Sent if the compositor cancels the configuration because the state of an
|
||||||
|
output changed and the client has outdated information (e.g. after an
|
||||||
|
output has been hotplugged).
|
||||||
|
|
||||||
|
The client can create a new configuration with a newer serial and try
|
||||||
|
again.
|
||||||
|
|
||||||
|
Upon receiving this event, the client should destroy this object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the output configuration">
|
||||||
|
Using this request a client can tell the compositor that it is not going
|
||||||
|
to use the configuration object anymore. Any changes to the outputs
|
||||||
|
that have not been applied will be discarded.
|
||||||
|
|
||||||
|
This request also destroys wlr_output_configuration_head objects created
|
||||||
|
via this object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_configuration_head_v1" version="1">
|
||||||
|
<description summary="head configuration">
|
||||||
|
This object is used by the client to update a single head's configuration.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="invalid_mode" value="1" summary="mode doesn't belong to head"/>
|
||||||
|
<entry name="invalid_transform" value="2" summary="transform value outside enum"/>
|
||||||
|
<entry name="invalid_scale" value="3" summary="scale negative or zero"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="set_mode">
|
||||||
|
<description summary="set the mode">
|
||||||
|
This request sets the head's mode.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="object" interface="zwlr_output_mode_v1"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_position">
|
||||||
|
<description summary="set the position">
|
||||||
|
This request sets the head's position in the global compositor space.
|
||||||
|
</description>
|
||||||
|
<arg name="x" type="int" summary="x position in the global compositor space"/>
|
||||||
|
<arg name="y" type="int" summary="y position in the global compositor space"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_transform">
|
||||||
|
<description summary="set the transform">
|
||||||
|
This request sets the head's transform.
|
||||||
|
</description>
|
||||||
|
<arg name="transform" type="int" enum="wl_output.transform"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_scale">
|
||||||
|
<description summary="set the scale">
|
||||||
|
This request sets the head's scale.
|
||||||
|
</description>
|
||||||
|
<arg name="scale" type="fixed"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
|
@ -46,6 +46,7 @@ lib_wlr_types = static_library(
|
||||||
'wlr_matrix.c',
|
'wlr_matrix.c',
|
||||||
'wlr_output_damage.c',
|
'wlr_output_damage.c',
|
||||||
'wlr_output_layout.c',
|
'wlr_output_layout.c',
|
||||||
|
'wlr_output_management_v1.c',
|
||||||
'wlr_output.c',
|
'wlr_output.c',
|
||||||
'wlr_pointer_constraints_v1.c',
|
'wlr_pointer_constraints_v1.c',
|
||||||
'wlr_pointer_gestures_v1.c',
|
'wlr_pointer_gestures_v1.c',
|
||||||
|
|
415
types/wlr_output_management_v1.c
Normal file
415
types/wlr_output_management_v1.c
Normal file
|
@ -0,0 +1,415 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_output_management_v1.h>
|
||||||
|
#include "util/signal.h"
|
||||||
|
#include "wlr-output-management-unstable-v1-protocol.h"
|
||||||
|
|
||||||
|
#define OUTPUT_MANAGER_VERSION 1
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HEAD_STATE_ENABLED = 1 << 0,
|
||||||
|
// TODO: other properties
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t HEAD_STATE_ALL = HEAD_STATE_ENABLED;
|
||||||
|
|
||||||
|
|
||||||
|
// Can return NULL if the head is inert
|
||||||
|
static struct wlr_output_configuration_head_v1 *
|
||||||
|
config_head_from_head_resource(struct wl_resource *resource) {
|
||||||
|
assert(wl_resource_instance_of(resource,
|
||||||
|
&zwlr_output_head_v1_interface, NULL));
|
||||||
|
return wl_resource_get_user_data(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_head_destroy(struct wlr_output_configuration_head_v1 *head) {
|
||||||
|
if (head == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct wl_resource *resource, *tmp;
|
||||||
|
wl_resource_for_each_safe(resource, tmp, &head->resources) {
|
||||||
|
zwlr_output_head_v1_send_finished(resource);
|
||||||
|
wl_resource_set_user_data(resource, NULL); // make the resource inert
|
||||||
|
wl_list_remove(wl_resource_get_link(resource));
|
||||||
|
wl_list_init(wl_resource_get_link(resource));
|
||||||
|
}
|
||||||
|
wl_list_remove(&head->link);
|
||||||
|
wl_list_remove(&head->output_destroy.link);
|
||||||
|
free(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_head_handle_output_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct wlr_output_configuration_head_v1 *head =
|
||||||
|
wl_container_of(listener, head, output_destroy);
|
||||||
|
config_head_destroy(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_output_configuration_head_v1 *
|
||||||
|
wlr_output_configuration_head_v1_create(
|
||||||
|
struct wlr_output_configuration_v1 *config, struct wlr_output *output) {
|
||||||
|
struct wlr_output_configuration_head_v1 *head = calloc(1, sizeof(*head));
|
||||||
|
if (head == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
head->config = config;
|
||||||
|
head->output = output;
|
||||||
|
wl_list_init(&head->resources);
|
||||||
|
wl_list_insert(&config->heads, &head->link);
|
||||||
|
head->output_destroy.notify = config_head_handle_output_destroy;
|
||||||
|
wl_signal_add(&output->events.destroy, &head->output_destroy);
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct zwlr_output_configuration_head_v1_interface config_head_impl;
|
||||||
|
|
||||||
|
static struct wlr_output_configuration_head_v1 *config_head_from_resource(
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
assert(wl_resource_instance_of(resource,
|
||||||
|
&zwlr_output_head_v1_interface, &config_head_impl));
|
||||||
|
return wl_resource_get_user_data(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwlr_output_configuration_head_v1_interface config_head_impl = {
|
||||||
|
0 // TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
static void config_head_handle_resource_destroy(struct wl_resource *resource) {
|
||||||
|
struct wlr_output_configuration_head_v1 *head =
|
||||||
|
config_head_from_resource(resource);
|
||||||
|
config_head_destroy(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct zwlr_output_configuration_v1_interface config_impl;
|
||||||
|
|
||||||
|
static struct wlr_output_configuration_v1 *config_from_resource(
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
assert(wl_resource_instance_of(resource,
|
||||||
|
&zwlr_output_configuration_v1_interface, &config_impl));
|
||||||
|
return wl_resource_get_user_data(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_output_configuration_head_v1 *config_create_head(
|
||||||
|
struct wlr_output_configuration_v1 *config, struct wlr_output *output) {
|
||||||
|
struct wlr_output_configuration_head_v1 *head;
|
||||||
|
wl_list_for_each(head, &config->heads, link) {
|
||||||
|
if (head->output == output) {
|
||||||
|
return NULL; // TODO: post already_configured_head error instead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wlr_output_configuration_head_v1_create(config, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_handle_enable_head(struct wl_client *client,
|
||||||
|
struct wl_resource *config_resource, uint32_t id,
|
||||||
|
struct wl_resource *head_resource) {
|
||||||
|
struct wlr_output_configuration_v1 *config =
|
||||||
|
config_from_resource(config_resource);
|
||||||
|
// Can be NULL if the head no longer exists
|
||||||
|
struct wlr_output_configuration_head_v1 *existing_head =
|
||||||
|
config_head_from_head_resource(head_resource);
|
||||||
|
|
||||||
|
struct wlr_output_configuration_head_v1 *config_head = NULL;
|
||||||
|
if (existing_head != NULL) {
|
||||||
|
config_head = config_create_head(config, existing_head->output);
|
||||||
|
if (config_head == NULL) {
|
||||||
|
wl_resource_post_no_memory(config_resource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t version = wl_resource_get_version(config_resource);
|
||||||
|
struct wl_resource *resource = wl_resource_create(client,
|
||||||
|
&zwlr_output_configuration_head_v1_interface, version, id);
|
||||||
|
if (resource == NULL) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(resource, &config_head_impl,
|
||||||
|
config_head, config_head_handle_resource_destroy);
|
||||||
|
|
||||||
|
config_head->enabled = true;
|
||||||
|
|
||||||
|
// TODO: when the output is destroyed, make this resource inert
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_handle_disable_head(struct wl_client *client,
|
||||||
|
struct wl_resource *config_resource,
|
||||||
|
struct wl_resource *head_resource) {
|
||||||
|
struct wlr_output_configuration_v1 *config =
|
||||||
|
config_from_resource(config_resource);
|
||||||
|
struct wlr_output_configuration_head_v1 *existing_head =
|
||||||
|
config_head_from_head_resource(head_resource);
|
||||||
|
if (existing_head == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_output_configuration_head_v1 *config_head =
|
||||||
|
config_create_head(config, existing_head->output);
|
||||||
|
if (config_head == NULL) {
|
||||||
|
wl_resource_post_no_memory(config_resource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_head->enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_handle_apply(struct wl_client *client,
|
||||||
|
struct wl_resource *config_resource) {
|
||||||
|
//struct wlr_output_configuration_v1 *config =
|
||||||
|
// config_from_resource(config_resource);
|
||||||
|
// TODO: post already_used if needed
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_handle_destroy(struct wl_client *client,
|
||||||
|
struct wl_resource *config_resource) {
|
||||||
|
wl_resource_destroy(config_resource);
|
||||||
|
// TODO: destroy head configurations
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwlr_output_configuration_v1_interface config_impl = {
|
||||||
|
.enable_head = config_handle_enable_head,
|
||||||
|
.disable_head = config_handle_disable_head,
|
||||||
|
.apply = config_handle_apply,
|
||||||
|
// TODO: test
|
||||||
|
.destroy = config_handle_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_output_configuration_v1 *wlr_output_configuration_v1_create(void) {
|
||||||
|
struct wlr_output_configuration_v1 *config = calloc(1, sizeof(*config));
|
||||||
|
if (config == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
wl_list_init(&config->heads);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_output_configuration_v1_destroy(
|
||||||
|
struct wlr_output_configuration_v1 *config) {
|
||||||
|
if (config == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct wlr_output_configuration_head_v1 *head, *tmp;
|
||||||
|
wl_list_for_each_safe(head, tmp, &config->heads, link) {
|
||||||
|
config_head_destroy(head);
|
||||||
|
}
|
||||||
|
free(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void config_handle_resource_destroy(struct wl_resource *resource) {
|
||||||
|
struct wlr_output_configuration_v1 *config = config_from_resource(resource);
|
||||||
|
wlr_output_configuration_v1_destroy(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void manager_handle_create_configuration(struct wl_client *client,
|
||||||
|
struct wl_resource *manager_resource, uint32_t id, uint32_t serial) {
|
||||||
|
struct wlr_output_configuration_v1 *config =
|
||||||
|
wlr_output_configuration_v1_create();
|
||||||
|
config->serial = serial;
|
||||||
|
|
||||||
|
uint32_t version = wl_resource_get_version(manager_resource);
|
||||||
|
struct wl_resource *resource = wl_resource_create(client,
|
||||||
|
&zwlr_output_configuration_v1_interface, version, id);
|
||||||
|
if (resource == NULL) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(resource, &config_impl,
|
||||||
|
config, config_handle_resource_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_handle_stop(struct wl_client *client,
|
||||||
|
struct wl_resource *manager_resource) {
|
||||||
|
zwlr_output_manager_v1_send_finished(manager_resource);
|
||||||
|
wl_resource_destroy(manager_resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zwlr_output_manager_v1_interface manager_impl = {
|
||||||
|
.create_configuration = manager_handle_create_configuration,
|
||||||
|
.stop = manager_handle_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void manager_handle_resource_destroy(struct wl_resource *resource) {
|
||||||
|
wl_list_remove(wl_resource_get_link(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_bind(struct wl_client *client, void *data, uint32_t version,
|
||||||
|
uint32_t id) {
|
||||||
|
struct wlr_output_manager_v1 *manager = data;
|
||||||
|
|
||||||
|
struct wl_resource *resource = wl_resource_create(client,
|
||||||
|
&zwlr_output_manager_v1_interface, version, id);
|
||||||
|
if (resource == NULL) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(resource, &manager_impl, manager,
|
||||||
|
manager_handle_resource_destroy);
|
||||||
|
|
||||||
|
wl_list_insert(&manager->resources, wl_resource_get_link(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_handle_display_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct wlr_output_manager_v1 *manager =
|
||||||
|
wl_container_of(listener, manager, display_destroy);
|
||||||
|
wlr_signal_emit_safe(&manager->events.destroy, manager);
|
||||||
|
wl_list_remove(&manager->display_destroy.link);
|
||||||
|
wlr_output_configuration_v1_destroy(manager->current);
|
||||||
|
wl_global_destroy(manager->global);
|
||||||
|
free(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_output_manager_v1 *wlr_output_manager_v1_create(
|
||||||
|
struct wl_display *display) {
|
||||||
|
struct wlr_output_manager_v1 *manager = calloc(1, sizeof(*manager));
|
||||||
|
if (manager == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
manager->display = display;
|
||||||
|
|
||||||
|
wl_signal_init(&manager->events.destroy);
|
||||||
|
|
||||||
|
manager->global = wl_global_create(display,
|
||||||
|
&zwlr_output_manager_v1_interface, OUTPUT_MANAGER_VERSION,
|
||||||
|
manager, manager_bind);
|
||||||
|
if (manager->global == NULL) {
|
||||||
|
free(manager);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->display_destroy.notify = manager_handle_display_destroy;
|
||||||
|
wl_display_add_destroy_listener(display, &manager->display_destroy);
|
||||||
|
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_output_configuration_head_v1 *configuration_get_head(
|
||||||
|
struct wlr_output_configuration_v1 *config, struct wlr_output *output) {
|
||||||
|
struct wlr_output_configuration_head_v1 *head;
|
||||||
|
wl_list_for_each(head, &config->heads, link) {
|
||||||
|
if (head->output == output) {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void head_send_state(struct wlr_output_configuration_head_v1 *head,
|
||||||
|
struct wl_resource *resource, uint32_t state) {
|
||||||
|
if (state & HEAD_STATE_ENABLED) {
|
||||||
|
zwlr_output_head_v1_send_enabled(resource, head->enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!head->enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: send other properties
|
||||||
|
}
|
||||||
|
|
||||||
|
static void head_handle_resource_destroy(struct wl_resource *resource) {
|
||||||
|
wl_list_remove(wl_resource_get_link(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_send_head(struct wlr_output_manager_v1 *manager,
|
||||||
|
struct wlr_output_configuration_head_v1 *head,
|
||||||
|
struct wl_resource *manager_resource) {
|
||||||
|
struct wlr_output *output = head->output;
|
||||||
|
|
||||||
|
struct wl_client *client = wl_resource_get_client(manager_resource);
|
||||||
|
uint32_t version = wl_resource_get_version(manager_resource);
|
||||||
|
struct wl_resource *resource = wl_resource_create(client,
|
||||||
|
&zwlr_output_head_v1_interface, version, 0);
|
||||||
|
if (resource == NULL) {
|
||||||
|
wl_resource_post_no_memory(manager_resource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(resource, NULL, head,
|
||||||
|
head_handle_resource_destroy);
|
||||||
|
wl_list_insert(&head->resources, wl_resource_get_link(resource));
|
||||||
|
|
||||||
|
zwlr_output_manager_v1_send_head(manager_resource, resource);
|
||||||
|
|
||||||
|
// TODO: send modes
|
||||||
|
|
||||||
|
zwlr_output_head_v1_send_name(resource, output->name);
|
||||||
|
|
||||||
|
char description[128];
|
||||||
|
snprintf(description, sizeof(description), "%s %s %s (%s)",
|
||||||
|
output->make, output->model, output->serial, output->name);
|
||||||
|
zwlr_output_head_v1_send_description(resource, description);
|
||||||
|
|
||||||
|
if (output->phys_width > 0 && output->phys_height > 0) {
|
||||||
|
zwlr_output_head_v1_send_physical_size(resource,
|
||||||
|
output->phys_width, output->phys_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
head_send_state(head, resource, HEAD_STATE_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void manager_update_head(struct wlr_output_manager_v1 *manager,
|
||||||
|
struct wlr_output_configuration_head_v1 *head,
|
||||||
|
struct wlr_output_configuration_head_v1 *next) {
|
||||||
|
uint32_t state = 0;
|
||||||
|
if (head->enabled != next->enabled) {
|
||||||
|
state |= HEAD_STATE_ENABLED;
|
||||||
|
head->enabled = next->enabled;
|
||||||
|
}
|
||||||
|
// TODO: update other properties
|
||||||
|
|
||||||
|
struct wl_resource *resource;
|
||||||
|
wl_resource_for_each(resource, &head->resources) {
|
||||||
|
head_send_state(head, resource, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_output_manager_v1_set_configuration(
|
||||||
|
struct wlr_output_manager_v1 *manager,
|
||||||
|
struct wlr_output_configuration_v1 *config) {
|
||||||
|
if (manager->current != NULL) {
|
||||||
|
// Either update or destroy existing heads
|
||||||
|
struct wlr_output_configuration_head_v1 *existing_head, *tmp;
|
||||||
|
wl_list_for_each_safe(existing_head, tmp,
|
||||||
|
&manager->current->heads, link) {
|
||||||
|
struct wlr_output_configuration_head_v1 *updated_head =
|
||||||
|
configuration_get_head(config, existing_head->output);
|
||||||
|
if (updated_head != NULL) {
|
||||||
|
manager_update_head(manager, existing_head, updated_head);
|
||||||
|
config_head_destroy(updated_head);
|
||||||
|
} else {
|
||||||
|
config_head_destroy(existing_head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heads remaining in `config` are new heads
|
||||||
|
} else {
|
||||||
|
manager->current = wlr_output_configuration_v1_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move new heads to current config
|
||||||
|
struct wlr_output_configuration_head_v1 *head, *tmp;
|
||||||
|
wl_list_for_each_safe(head, tmp, &config->heads, link) {
|
||||||
|
head->config = manager->current;
|
||||||
|
wl_list_remove(&head->link);
|
||||||
|
wl_list_insert(&manager->current->heads, &head->link);
|
||||||
|
|
||||||
|
struct wl_resource *manager_resource;
|
||||||
|
wl_resource_for_each(manager_resource, &manager->resources) {
|
||||||
|
manager_send_head(manager, head, manager_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->current->serial = wl_display_next_serial(manager->display);
|
||||||
|
struct wl_resource *manager_resource;
|
||||||
|
wl_resource_for_each(manager_resource, &manager->resources) {
|
||||||
|
zwlr_output_manager_v1_send_done(manager_resource,
|
||||||
|
manager->current->serial);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue