Add support for wlr-output-management-unstable-v1
This commit is contained in:
		
							parent
							
								
									b6d0de177a
								
							
						
					
					
						commit
						3a233b3fcc
					
				|  | @ -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', | ||||||
|  |  | ||||||
|  | @ -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', | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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', | ||||||
|  |  | ||||||
|  | @ -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 New Issue