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 #include "wl_output_p.h"
21
22 #include "display.h"
23
24 #include "wayland/client.h"
25 #include "wayland/display.h"
26
27 #include <functional>
28 #include <wayland-server.h>
29
30 namespace Wrapland::Server
31 {
32
Private(Output * output,Display * display,WlOutput * q)33 WlOutput::Private::Private(Output* output, Display* display, WlOutput* q)
34 : WlOutputGlobal(q, display, &wl_output_interface, &s_interface)
35 , displayHandle(display)
36 , output(output)
37 {
38 create();
39 }
40
41 const struct wl_output_interface WlOutput::Private::s_interface = {resourceDestroyCallback};
42
to_subpixel(Output::Subpixel subpixel)43 int32_t to_subpixel(Output::Subpixel subpixel)
44 {
45 switch (subpixel) {
46 case Output::Subpixel::Unknown:
47 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
48 case Output::Subpixel::None:
49 return WL_OUTPUT_SUBPIXEL_NONE;
50 case Output::Subpixel::HorizontalRGB:
51 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
52 case Output::Subpixel::HorizontalBGR:
53 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
54 case Output::Subpixel::VerticalRGB:
55 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
56 case Output::Subpixel::VerticalBGR:
57 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
58 }
59 abort();
60 }
61
62 std::tuple<int32_t, int32_t, int32_t, int32_t, int32_t, const char*, const char*, int32_t>
geometry_args(OutputState const & state)63 WlOutput::Private::geometry_args(OutputState const& state)
64 {
65 auto const position = state.geometry.topLeft();
66
67 return std::make_tuple(position.x(),
68 position.y(),
69 state.info.physical_size.width(),
70 state.info.physical_size.height(),
71 to_subpixel(state.subpixel),
72 state.info.make.c_str(),
73 state.info.model.c_str(),
74 Output::Private::to_transform(state.transform));
75 }
76
bindInit(WlOutputBind * bind)77 void WlOutput::Private::bindInit(WlOutputBind* bind)
78 {
79 auto const state = output->d_ptr->published;
80
81 send<wl_output_send_geometry>(bind, geometry_args(state));
82
83 for (auto const& mode : output->d_ptr->modes) {
84 if (mode != output->d_ptr->published.mode) {
85 sendMode(bind, mode);
86 }
87 }
88 sendMode(bind, output->d_ptr->published.mode);
89
90 send<wl_output_send_scale, WL_OUTPUT_SCALE_SINCE_VERSION>(bind, state.client_scale);
91 done(bind);
92 bind->client()->flush();
93 }
94
sendMode(WlOutputBind * bind,Output::Mode const & mode)95 void WlOutput::Private::sendMode(WlOutputBind* bind, Output::Mode const& mode)
96 {
97 // Only called on bind. In this case we want to send the currently published mode.
98 auto flags = Output::Private::get_mode_flags(mode, output->d_ptr->published);
99
100 send<wl_output_send_mode>(
101 bind, flags, mode.size.width(), mode.size.height(), mode.refresh_rate);
102 }
103
sendMode(Output::Mode const & mode)104 void WlOutput::Private::sendMode(Output::Mode const& mode)
105 {
106 // Only called on update. In this case we want to send the pending mode.
107 auto flags = Output::Private::get_mode_flags(mode, output->d_ptr->pending);
108
109 send<wl_output_send_mode>(flags, mode.size.width(), mode.size.height(), mode.refresh_rate);
110 }
111
broadcast()112 bool WlOutput::Private::broadcast()
113 {
114 auto const published = output->d_ptr->published;
115 auto const pending = output->d_ptr->pending;
116
117 bool changed = false;
118
119 if (published.geometry.topLeft() != pending.geometry.topLeft()
120 || published.info.physical_size != pending.info.physical_size
121 || published.subpixel != pending.subpixel || published.info.make != pending.info.make
122 || published.info.model != pending.info.model || published.transform != pending.transform) {
123 send<wl_output_send_geometry>(geometry_args(pending));
124 changed = true;
125 }
126
127 if (published.client_scale != pending.client_scale) {
128 send<wl_output_send_scale, WL_OUTPUT_SCALE_SINCE_VERSION>(pending.client_scale);
129 changed = true;
130 }
131
132 if (published.mode != pending.mode) {
133 sendMode(pending.mode);
134 changed = true;
135 }
136
137 return changed;
138 }
139
done()140 void WlOutput::Private::done()
141 {
142 send<wl_output_send_done, WL_OUTPUT_DONE_SINCE_VERSION>();
143 }
144
done(WlOutputBind * bind)145 void WlOutput::Private::done(WlOutputBind* bind)
146 {
147 send<wl_output_send_done, WL_OUTPUT_DONE_SINCE_VERSION>(bind);
148 }
149
WlOutput(Output * output,Display * display)150 WlOutput::WlOutput(Output* output, Display* display)
151 : QObject(nullptr)
152 , d_ptr(new Private(output, display, this))
153 {
154 display->add_wl_output(this);
155 }
156
~WlOutput()157 WlOutput::~WlOutput()
158 {
159 Q_EMIT removed();
160
161 if (d_ptr->displayHandle) {
162 d_ptr->displayHandle->removeOutput(this);
163 }
164 }
165
output() const166 Output* WlOutput::output() const
167 {
168 return d_ptr->output;
169 }
170
171 }
172