1 /********************************************************************
2 Copyright © 2020 Roman Gilg <subdiff@gmail.com>
3 
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11 
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library.  If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #pragma once
21 
22 #include "wlr_output_manager_v1.h"
23 
24 #include <Wrapland/Client/wraplandclient_export.h>
25 
26 #include <QObject>
27 #include <QPoint>
28 
29 struct zkwinft_output_management_v1;
30 struct zwlr_output_configuration_v1;
31 
32 namespace Wrapland
33 {
34 namespace Client
35 {
36 
37 class EventQueue;
38 
39 /** @class WlrOutputConfigurationV1
40  *
41  * WlrOutputConfigurationV1 provides access to changing WlrOutputHeadV1s. The interface is async
42  * and atomic. An WlrOutputConfigurationV1 is created through
43  * WlrOutputManagerV1::createConfiguration().
44  *
45  * The overall mechanism is to get a new WlrOutputConfigurationV1 from the WlrOutputManagerV1 global
46  * and apply changes through the WlrOutputConfigurationV1::set* calls. When all changes are set, the
47  * client calls apply, which asks the server to look at the changes and apply them. The server will
48  * then signal back whether the changes have been applied successfully (@c applied()) or were
49  * rejected or failed to apply (@c failed()).
50  *
51  * The current settings for heads can be gotten from @c Registry::WlrOutputHeadV1s(), these
52  * are used in the set* calls to identify the output the setting applies to.
53  *
54  * These Wrapland classes will not apply changes to the heads, this is the compositor's
55  * task. As such, the configuration set through this interface can be seen as a hint what the
56  * compositor should set up, but whether or not the compositor does it (based on hardware or
57  * rendering policies, for example), is up to the compositor. The mode setting is passed on to
58  * the DRM subsystem through the compositor. The compositor also saves this configuration and reads
59  * it on startup, this interface is not involved in that process.
60  *
61  * @c apply() should only be called after changes to all heads have been made, not after
62  * each change. This allows to test the new configuration as a whole, and is a lot faster since
63  * hardware changes can be tested in their new combination, they done in parallel.and rolled back
64  * as a whole.
65  *
66  * \verbatim
67     // We're just picking the first of our heads
68     Wrapland::Client::WlrOutputHeadV1 *output = m_clientOutputs.first();
69 
70     // Create a new configuration object
71     auto config = m_outputManagement.createConfiguration();
72 
73     // handle applied and failed signals
74     connect(config, &WlrOutputConfigurationV1::applied, []() {
75         qDebug() << "Configuration applied!";
76     });
77     connect(config, &WlrOutputConfigurationV1::failed, []() {
78         qDebug() << "Configuration failed!";
79     });
80 
81     // Change settings
82     config->setMode(output, m_clientOutputs.first()->modes().last().id);
83     config->setTransform(output, WlrOutputHeadV1::Transform::Normal);
84     config->setPosition(output, QPoint(0, 1920));
85     config->setScale(output, 2);
86 
87     // Now ask the compositor to apply the changes
88     config->apply();
89     // You may wait for the applied() or failed() signal here
90    \endverbatim
91 
92  * @see WlrOutputHeadV1
93  * @see WlrOutputManagerV1
94  * @see WlrOutputManagerV1::createConfiguration()
95  * @since 0.519.0
96  */
97 class WRAPLANDCLIENT_EXPORT WlrOutputConfigurationV1 : public QObject
98 {
99     Q_OBJECT
100 public:
101     ~WlrOutputConfigurationV1() override;
102 
103     /**
104      * Setup this WlrOutputConfigurationV1 to manage the @p outputconfiguration.
105      * When using WlrOutputManagerV1::createOutputConfiguration there is no need to call this
106      * method.
107      * @param outputconfiguration the outputconfiguration object to set up.
108      */
109     void setup(zwlr_output_configuration_v1* outputconfiguration);
110     /**
111      * @returns @c true if managing a zwlr_output_configuration_v1.
112      */
113     bool isValid() const;
114     /**
115      * Releases the zwlr_output_configuration_v1 interface.
116      * After the interface has been released the WlrOutputConfigurationV1 instance is no
117      * longer valid and can be setup with another zwlr_output_configuration_v1 interface.
118      */
119     void release();
120 
121     /**
122      * Sets the @p queue to use for creating a WlrOutputConfigurationV1.
123      */
124     void setEventQueue(EventQueue* queue);
125     /**
126      * @returns The event queue to use for creating a WlrOutputConfigurationV1
127      */
128     EventQueue* eventQueue();
129 
130     /**
131      * Enable or disable an output. Enabled means it's used by the
132      * compositor for rendering, Disabled means, that no wl_output
133      * is connected to this, and the head is sitting there unused
134      * by this compositor.
135      * The changes done in this call will be recorded in the
136      * head and only applied after apply() has been called.
137      *
138      * @param head the head this change applies to.
139      * @param enable new Enablement state of this head.
140      */
141     void setEnabled(WlrOutputHeadV1* head, bool enable);
142 
143     /**
144      * Set the mode of this output.
145      *
146      * @param head the head this change applies to.
147      * @param mode the mode to set as current.
148      */
149     void setMode(WlrOutputHeadV1* head, WlrOutputModeV1* mode);
150 
151     /**
152      * Set a custom mode for this output.
153      *
154      * @param head the head this change applies to.
155      * @param size the custom mode size of the head.
156      * @param refresh the custom refresh rate of the head.
157      */
158     void setCustomMode(WlrOutputHeadV1* head, const QSize& size, int refresh);
159 
160     /**
161      * Set transformation for this output, for example rotated or flipped.
162      * The changes done in this call will be recorded in the
163      * head and only applied after apply() has been called.
164      *
165      * @param head the head this change applies to.
166      * @param scale the scaling factor for this head.
167      */
168     void setTransform(WlrOutputHeadV1* head, WlrOutputHeadV1::Transform transform);
169 
170     /**
171      * Sets the position of this output in the global space.
172      *
173      * @param head the head this change applies to.
174      * @param geo the head geometry relative to other outputs,
175      *
176      */
177     void setPosition(WlrOutputHeadV1* head, const QPoint& pos);
178 
179     /**
180      * Sets the position of this output in the global space.
181      *
182      * @param head the head this change applies to.
183      * @param geo the head geometry relative to other outputs,
184      *
185      */
186     void setScale(WlrOutputHeadV1* head, double scale);
187 
188     /**
189      * Check if current configuration is valid. Either succeeded() or failed() will be emitted
190      * later on as a result of this call.
191      */
192     void test();
193 
194     /**
195      * Ask the compositor to apply the changes.
196      * This results in the compositor looking at all heads and if they have
197      * pending changes from the set* calls, these changes will be tested with the
198      * hardware and applied if possible. The compositor will react to these changes
199      * with the applied() or failed() signals. Note that mode setting may take a
200      * while, so the interval between calling apply() and receiving the applied()
201      * signal may be considerable, depending on the hardware.
202      *
203      * @see applied()
204      * @see failed()
205      */
206     void apply();
207 
208     operator zwlr_output_configuration_v1*();
209     operator zwlr_output_configuration_v1*() const;
210 
211 Q_SIGNALS:
212     /**
213      * The server has applied all settings successfully. In case test() was called before that
214      * nothing else happens. Otherwise pending changes in the heads have been cleared, changed
215      * signals from the head have been emitted.
216      */
217     void succeeded();
218     /**
219      * The server has failed to apply the settings or rejected them. Pending changes
220      * in the * heads have been cleared. No changes have been applied to the
221      * heads.
222      */
223     void failed();
224 
225     /**
226      * Sent if the current configuration is outdated. A new configuration object should be created
227      * via the output manager global and this configura.
228      */
229     void cancelled();
230 
231 private:
232     explicit WlrOutputConfigurationV1(QObject* parent = nullptr);
233     friend class WlrOutputManagerV1;
234 
235     class Private;
236     std::unique_ptr<Private> d;
237 };
238 
239 }
240 }
241 
242 Q_DECLARE_METATYPE(Wrapland::Client::WlrOutputConfigurationV1*)
243