1 /********************************************************************
2 Copyright 2020 Faveraux Adrien <ad1rie3@hotmail.fr>
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 "plasma_shell_p.h"
21 
22 #include <wayland-server.h>
23 
24 namespace Wrapland::Server
25 {
26 
27 const struct org_kde_plasma_shell_interface PlasmaShell::Private::s_interface = {
28     cb<createSurfaceCallback>,
29 };
30 
Private(Display * display,PlasmaShell * qptr)31 PlasmaShell::Private::Private(Display* display, PlasmaShell* qptr)
32     : PlasmaShellGlobal(qptr, display, &org_kde_plasma_shell_interface, &s_interface)
33 {
34     create();
35 }
36 
37 PlasmaShell::Private::~Private() = default;
38 
createSurfaceCallback(PlasmaShellBind * bind,uint32_t id,wl_resource * surface)39 void PlasmaShell::Private::createSurfaceCallback(PlasmaShellBind* bind,
40                                                  uint32_t id,
41                                                  wl_resource* surface)
42 {
43     auto priv = bind->global()->handle()->d_ptr.get();
44     priv->createSurface(bind, id, Wayland::Resource<Surface>::handle(surface));
45 }
46 
createSurface(PlasmaShellBind * bind,uint32_t id,Surface * surface)47 void PlasmaShell::Private::createSurface(PlasmaShellBind* bind, uint32_t id, Surface* surface)
48 {
49     auto it = std::find_if(surfaces.constBegin(),
50                            surfaces.constEnd(),
51                            [surface](PlasmaShellSurface* s) { return surface == s->surface(); });
52     if (it != surfaces.constEnd()) {
53         surface->d_ptr->postError(WL_DISPLAY_ERROR_INVALID_OBJECT,
54                                   "PlasmaShellSurface already created");
55         return;
56     }
57 
58     auto shellSurface
59         = new PlasmaShellSurface(bind->client()->handle(), bind->version(), id, surface, handle());
60 
61     surfaces << shellSurface;
62     QObject::connect(shellSurface,
63                      &PlasmaShellSurface::resourceDestroyed,
64                      handle(),
65                      [this, shellSurface] { surfaces.removeAll(shellSurface); });
66     Q_EMIT handle()->surfaceCreated(shellSurface);
67 }
68 
PlasmaShell(Display * display,QObject * parent)69 PlasmaShell::PlasmaShell(Display* display, QObject* parent)
70     : QObject(parent)
71     , d_ptr(new Private(display, this))
72 {
73 }
74 
75 PlasmaShell::~PlasmaShell() = default;
76 
77 /*********************************
78  * ShellSurfaceInterface
79  *********************************/
80 
81 const struct org_kde_plasma_surface_interface PlasmaShellSurface::Private::s_interface = {
82     destroyCallback,
83     setOutputCallback,
84     setPositionCallback,
85     setRoleCallback,
86     setPanelBehaviorCallback,
87     setSkipTaskbarCallback,
88     panelAutoHideHideCallback,
89     panelAutoHideShowCallback,
90     panelTakesFocusCallback,
91     setSkipSwitcherCallback,
92 };
93 
Private(Client * client,uint32_t version,uint32_t id,Surface * surface,PlasmaShell * shell,PlasmaShellSurface * qptr)94 PlasmaShellSurface::Private::Private(Client* client,
95                                      uint32_t version,
96                                      uint32_t id,
97                                      Surface* surface,
98                                      PlasmaShell* shell,
99                                      PlasmaShellSurface* qptr)
100     : Wayland::Resource<PlasmaShellSurface>(client,
101                                             version,
102                                             id,
103                                             &org_kde_plasma_surface_interface,
104                                             &s_interface,
105                                             qptr)
106     , surface(surface)
107     , shell(shell)
108 
109 {
110 }
111 
112 PlasmaShellSurface::Private::~Private() = default;
113 
setOutputCallback(wl_client * wlClient,wl_resource * wlResource,wl_resource * output)114 void PlasmaShellSurface::Private::setOutputCallback([[maybe_unused]] wl_client* wlClient,
115                                                     [[maybe_unused]] wl_resource* wlResource,
116                                                     [[maybe_unused]] wl_resource* output)
117 {
118     // TODO(unknown author): implement
119 }
120 
setPositionCallback(wl_client * wlClient,wl_resource * wlResource,int32_t x,int32_t y)121 void PlasmaShellSurface::Private::setPositionCallback([[maybe_unused]] wl_client* wlClient,
122                                                       wl_resource* wlResource,
123                                                       int32_t x,
124                                                       int32_t y)
125 {
126     auto priv = handle(wlResource)->d_ptr;
127     priv->setPosition(QPoint(x, y));
128 }
129 
setPosition(const QPoint & globalPos)130 void PlasmaShellSurface::Private::setPosition(const QPoint& globalPos)
131 {
132     if (m_globalPos == globalPos && m_positionSet) {
133         return;
134     }
135     m_positionSet = true;
136     m_globalPos = globalPos;
137     Q_EMIT handle()->positionChanged();
138 }
139 
setRoleCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t role)140 void PlasmaShellSurface::Private::setRoleCallback([[maybe_unused]] wl_client* wlClient,
141                                                   wl_resource* wlResource,
142                                                   uint32_t role)
143 {
144     auto priv = handle(wlResource)->d_ptr;
145     priv->setRole(role);
146 }
147 
setRole(uint32_t role)148 void PlasmaShellSurface::Private::setRole(uint32_t role)
149 {
150     Role r = Role::Normal;
151     switch (role) {
152     case ORG_KDE_PLASMA_SURFACE_ROLE_DESKTOP:
153         r = Role::Desktop;
154         break;
155     case ORG_KDE_PLASMA_SURFACE_ROLE_PANEL:
156         r = Role::Panel;
157         break;
158     case ORG_KDE_PLASMA_SURFACE_ROLE_ONSCREENDISPLAY:
159         r = Role::OnScreenDisplay;
160         break;
161     case ORG_KDE_PLASMA_SURFACE_ROLE_NOTIFICATION:
162         r = Role::Notification;
163         break;
164     case ORG_KDE_PLASMA_SURFACE_ROLE_TOOLTIP:
165         r = Role::ToolTip;
166         break;
167     case ORG_KDE_PLASMA_SURFACE_ROLE_CRITICALNOTIFICATION:
168         r = Role::CriticalNotification;
169         break;
170     case ORG_KDE_PLASMA_SURFACE_ROLE_NORMAL:
171     default:
172         r = Role::Normal;
173         break;
174     }
175     if (r == m_role) {
176         return;
177     }
178     m_role = r;
179     Q_EMIT handle()->roleChanged();
180 }
181 
setPanelBehaviorCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t flag)182 void PlasmaShellSurface::Private::setPanelBehaviorCallback([[maybe_unused]] wl_client* wlClient,
183                                                            wl_resource* wlResource,
184                                                            uint32_t flag)
185 {
186     auto priv = handle(wlResource)->d_ptr;
187     priv->setPanelBehavior(org_kde_plasma_surface_panel_behavior(flag));
188 }
189 
setSkipTaskbarCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t skip)190 void PlasmaShellSurface::Private::setSkipTaskbarCallback([[maybe_unused]] wl_client* wlClient,
191                                                          wl_resource* wlResource,
192                                                          uint32_t skip)
193 {
194     auto priv = handle(wlResource)->d_ptr;
195     priv->m_skipTaskbar = static_cast<bool>(skip);
196     Q_EMIT priv->handle()->skipTaskbarChanged();
197 }
198 
setSkipSwitcherCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t skip)199 void PlasmaShellSurface::Private::setSkipSwitcherCallback([[maybe_unused]] wl_client* wlClient,
200                                                           wl_resource* wlResource,
201                                                           uint32_t skip)
202 {
203     auto priv = handle(wlResource)->d_ptr;
204     priv->m_skipSwitcher = static_cast<bool>(skip);
205     Q_EMIT priv->handle()->skipSwitcherChanged();
206 }
207 
panelAutoHideHideCallback(wl_client * wlClient,wl_resource * wlResource)208 void PlasmaShellSurface::Private::panelAutoHideHideCallback([[maybe_unused]] wl_client* wlClient,
209                                                             wl_resource* wlResource)
210 {
211     auto priv = handle(wlResource)->d_ptr;
212     if (priv->m_role != Role::Panel
213         || (priv->m_panelBehavior != PanelBehavior::AutoHide
214             && priv->m_panelBehavior != PanelBehavior::WindowsCanCover)) {
215         priv->postError(ORG_KDE_PLASMA_SURFACE_ERROR_PANEL_NOT_AUTO_HIDE, "Not an auto hide panel");
216         return;
217     }
218     Q_EMIT priv->handle()->panelAutoHideHideRequested();
219 }
220 
panelAutoHideShowCallback(wl_client * wlClient,wl_resource * wlResource)221 void PlasmaShellSurface::Private::panelAutoHideShowCallback([[maybe_unused]] wl_client* wlClient,
222                                                             wl_resource* wlResource)
223 {
224     auto priv = handle(wlResource)->d_ptr;
225     if (priv->m_role != Role::Panel || priv->m_panelBehavior != PanelBehavior::AutoHide) {
226         priv->postError(ORG_KDE_PLASMA_SURFACE_ERROR_PANEL_NOT_AUTO_HIDE, "Not an auto hide panel");
227         return;
228     }
229     Q_EMIT priv->handle()->panelAutoHideShowRequested();
230 }
231 
panelTakesFocusCallback(wl_client * wlClient,wl_resource * wlResource,uint32_t takesFocus)232 void PlasmaShellSurface::Private::panelTakesFocusCallback([[maybe_unused]] wl_client* wlClient,
233                                                           wl_resource* wlResource,
234                                                           uint32_t takesFocus)
235 {
236     auto priv = handle(wlResource)->d_ptr;
237     if (priv->panelTakesFocus == takesFocus) {
238         return;
239     }
240     priv->panelTakesFocus = takesFocus;
241     Q_EMIT priv->handle()->panelTakesFocusChanged();
242 }
243 
setPanelBehavior(org_kde_plasma_surface_panel_behavior behavior)244 void PlasmaShellSurface::Private::setPanelBehavior(org_kde_plasma_surface_panel_behavior behavior)
245 {
246     PanelBehavior newBehavior = PanelBehavior::AlwaysVisible;
247     switch (behavior) {
248     case ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_AUTO_HIDE:
249         newBehavior = PanelBehavior::AutoHide;
250         break;
251     case ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_WINDOWS_CAN_COVER:
252         newBehavior = PanelBehavior::WindowsCanCover;
253         break;
254     case ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_WINDOWS_GO_BELOW:
255         newBehavior = PanelBehavior::WindowsGoBelow;
256         break;
257     case ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_ALWAYS_VISIBLE:
258     default:
259         break;
260     }
261     if (m_panelBehavior == newBehavior) {
262         return;
263     }
264     m_panelBehavior = newBehavior;
265     Q_EMIT handle()->panelBehaviorChanged();
266 }
267 
PlasmaShellSurface(Client * client,uint32_t version,uint32_t id,Surface * surface,PlasmaShell * shell)268 PlasmaShellSurface::PlasmaShellSurface(Client* client,
269                                        uint32_t version,
270                                        uint32_t id,
271                                        Surface* surface,
272                                        PlasmaShell* shell)
273     : QObject(nullptr)
274     , d_ptr(new Private(client, version, id, surface, shell, this))
275 
276 {
277     auto unsetSurface = [this] { d_ptr->surface = nullptr; };
278     connect(surface, &Surface::resourceDestroyed, this, unsetSurface);
279 }
280 
surface() const281 Surface* PlasmaShellSurface::surface() const
282 {
283     return d_ptr->surface;
284 }
285 
shell() const286 PlasmaShell* PlasmaShellSurface::shell() const
287 {
288     return d_ptr->shell;
289 }
290 
resource() const291 wl_resource* PlasmaShellSurface::resource() const
292 {
293     return d_ptr->resource();
294 }
295 
client() const296 Client* PlasmaShellSurface::client() const
297 {
298     return d_ptr->client()->handle();
299 }
300 
position() const301 QPoint PlasmaShellSurface::position() const
302 {
303     return d_ptr->m_globalPos;
304 }
305 
role() const306 PlasmaShellSurface::Role PlasmaShellSurface::role() const
307 {
308     return d_ptr->m_role;
309 }
310 
isPositionSet() const311 bool PlasmaShellSurface::isPositionSet() const
312 {
313     return d_ptr->m_positionSet;
314 }
315 
panelBehavior() const316 PlasmaShellSurface::PanelBehavior PlasmaShellSurface::panelBehavior() const
317 {
318     return d_ptr->m_panelBehavior;
319 }
320 
skipTaskbar() const321 bool PlasmaShellSurface::skipTaskbar() const
322 {
323     return d_ptr->m_skipTaskbar;
324 }
325 
skipSwitcher() const326 bool PlasmaShellSurface::skipSwitcher() const
327 {
328     return d_ptr->m_skipSwitcher;
329 }
330 
hideAutoHidingPanel()331 void PlasmaShellSurface::hideAutoHidingPanel()
332 {
333     d_ptr->send<org_kde_plasma_surface_send_auto_hidden_panel_hidden>();
334 }
335 
showAutoHidingPanel()336 void PlasmaShellSurface::showAutoHidingPanel()
337 {
338     d_ptr->send<org_kde_plasma_surface_send_auto_hidden_panel_shown>();
339 }
340 
panelTakesFocus() const341 bool PlasmaShellSurface::panelTakesFocus() const
342 {
343     return d_ptr->panelTakesFocus;
344 }
345 
get(wl_resource * native)346 PlasmaShellSurface* PlasmaShellSurface::get(wl_resource* native)
347 {
348     if (native == nullptr) {
349         return nullptr;
350     }
351     return Private::handle(native);
352 }
353 
354 }
355