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 "xdg_decoration.h"
21
22 #include "display.h"
23 #include "xdg_shell_p.h"
24
25 #include "wayland/global.h"
26 #include "wayland/resource.h"
27
28 #include "wayland-xdg-decoration-server-protocol.h"
29
30 #include <map>
31
32 namespace Wrapland::Server
33 {
34
35 constexpr uint32_t XdgDecorationManagerVersion = 1;
36 using XdgDecorationManagerGlobal
37 = Wayland::Global<XdgDecorationManager, XdgDecorationManagerVersion>;
38 using XdgDecorationManagerBind = Wayland::Bind<XdgDecorationManagerGlobal>;
39
40 class XdgDecorationManager::Private : public XdgDecorationManagerGlobal
41 {
42 public:
43 Private(XdgDecorationManager* q, Display* display, XdgShell* shell);
44
45 std::map<XdgShellToplevel*, XdgDecoration*> m_decorations;
46
47 private:
48 static void getToplevelDecorationCallback(XdgDecorationManagerBind* bind,
49 uint32_t id,
50 wl_resource* wlToplevel);
51
52 XdgShell* m_shell;
53
54 static const struct zxdg_decoration_manager_v1_interface s_interface;
55 };
56
Private(XdgDecorationManager * q,Display * display,XdgShell * shell)57 XdgDecorationManager::Private::Private(XdgDecorationManager* q, Display* display, XdgShell* shell)
58 : Wayland::Global<XdgDecorationManager>(q,
59 display,
60 &zxdg_decoration_manager_v1_interface,
61 &s_interface)
62 , m_shell{shell}
63 {
64 }
65
66 const struct zxdg_decoration_manager_v1_interface XdgDecorationManager::Private::s_interface = {
67 resourceDestroyCallback,
68 cb<getToplevelDecorationCallback>,
69 };
70
getToplevelDecorationCallback(XdgDecorationManagerBind * bind,uint32_t id,wl_resource * wlToplevel)71 void XdgDecorationManager::Private::getToplevelDecorationCallback(XdgDecorationManagerBind* bind,
72 uint32_t id,
73 wl_resource* wlToplevel)
74 {
75 auto priv = bind->global()->handle()->d_ptr.get();
76
77 auto toplevel = priv->m_shell->d_ptr->getToplevel(wlToplevel);
78 if (!toplevel) {
79 bind->post_error(ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED, "No xdg-toplevel found.");
80 return;
81 }
82 if (priv->m_decorations.count(toplevel) > 0) {
83 bind->post_error(ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED,
84 "xdg decoration already created for this xdg-toplevel.");
85 return;
86 }
87
88 auto deco = new XdgDecoration(bind->client()->handle(), bind->version(), id, toplevel);
89 // TODO(romangg): check resource
90
91 priv->m_decorations[toplevel] = deco;
92 QObject::connect(deco, &XdgDecoration::resourceDestroyed, priv->handle(), [toplevel, priv]() {
93 priv->m_decorations.erase(toplevel);
94 });
95 Q_EMIT priv->handle()->decorationCreated(deco);
96 }
97
XdgDecorationManager(Display * display,XdgShell * shell,QObject * parent)98 XdgDecorationManager::XdgDecorationManager(Display* display, XdgShell* shell, QObject* parent)
99 : QObject(parent)
100 , d_ptr(new Private(this, display, shell))
101 {
102 d_ptr->create();
103 }
104
105 XdgDecorationManager::~XdgDecorationManager() = default;
106
107 class XdgDecoration::Private : public Wayland::Resource<XdgDecoration>
108 {
109 public:
110 Private(Client* client,
111 uint32_t version,
112 uint32_t id,
113 XdgShellToplevel* toplevel,
114 XdgDecoration* q);
115
116 XdgDecoration::Mode m_requestedMode = XdgDecoration::Mode::Undefined;
117 XdgShellToplevel* toplevel;
118
119 private:
120 static void setModeCallback(wl_client* wlClient, wl_resource* wlResource, uint32_t wlMode);
121 static void unsetModeCallback(wl_client* wlClient, wl_resource* wlResource);
122
123 static const struct zxdg_toplevel_decoration_v1_interface s_interface;
124 };
125
Private(Client * client,uint32_t version,uint32_t id,XdgShellToplevel * toplevel,XdgDecoration * q)126 XdgDecoration::Private::Private(Client* client,
127 uint32_t version,
128 uint32_t id,
129 XdgShellToplevel* toplevel,
130 XdgDecoration* q)
131 : Wayland::Resource<XdgDecoration>(client,
132 version,
133 id,
134 &zxdg_toplevel_decoration_v1_interface,
135 &s_interface,
136 q)
137 , toplevel{toplevel}
138 {
139 }
140
141 const struct zxdg_toplevel_decoration_v1_interface XdgDecoration::Private::s_interface = {
142 destroyCallback,
143 setModeCallback,
144 unsetModeCallback,
145 };
146
setModeCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t wlMode)147 void XdgDecoration::Private::setModeCallback([[maybe_unused]] wl_client* wlClient,
148 wl_resource* wlResource,
149 uint32_t wlMode)
150 {
151 auto priv = handle(wlResource)->d_ptr;
152
153 Mode mode = Mode::Undefined;
154 switch (wlMode) {
155 case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
156 mode = Mode::ClientSide;
157 break;
158 case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
159 mode = Mode::ServerSide;
160 break;
161 default:
162 break;
163 }
164
165 priv->m_requestedMode = mode;
166 Q_EMIT priv->handle()->modeRequested();
167 }
168
unsetModeCallback(wl_client * wlClient,wl_resource * wlResource)169 void XdgDecoration::Private::unsetModeCallback([[maybe_unused]] wl_client* wlClient,
170 wl_resource* wlResource)
171 {
172 auto priv = handle(wlResource)->d_ptr;
173
174 priv->m_requestedMode = Mode::Undefined;
175 Q_EMIT priv->handle()->modeRequested();
176 }
177
XdgDecoration(Client * client,uint32_t version,uint32_t id,XdgShellToplevel * toplevel)178 XdgDecoration::XdgDecoration(Client* client,
179 uint32_t version,
180 uint32_t id,
181 XdgShellToplevel* toplevel)
182 : QObject(nullptr)
183 , d_ptr(new Private(client, version, id, toplevel, this))
184 {
185 }
186
configure(XdgDecoration::Mode mode)187 void XdgDecoration::configure(XdgDecoration::Mode mode)
188 {
189 switch (mode) {
190 case Mode::ClientSide:
191 d_ptr->send<zxdg_toplevel_decoration_v1_send_configure>(
192 ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
193 break;
194 case Mode::ServerSide:
195 d_ptr->send<zxdg_toplevel_decoration_v1_send_configure>(
196 ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
197 break;
198 default:
199 break;
200 }
201 }
202
requestedMode() const203 XdgDecoration::Mode XdgDecoration::requestedMode() const
204 {
205 return d_ptr->m_requestedMode;
206 }
207
toplevel() const208 XdgShellToplevel* XdgDecoration::toplevel() const
209 {
210 return d_ptr->toplevel;
211 }
212
213 }
214