1 /*
2     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
3     SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
4 
5     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7 #include "plasmashell_interface.h"
8 #include "display.h"
9 #include "surface_interface.h"
10 #include "utils.h"
11 
12 #include <qwayland-server-plasma-shell.h>
13 
14 namespace KWaylandServer
15 {
16 static const quint32 s_version = 6;
17 static QList<PlasmaShellSurfaceInterface *> s_shellSurfaces;
18 
19 class PlasmaShellInterfacePrivate : public QtWaylandServer::org_kde_plasma_shell
20 {
21 public:
22     PlasmaShellInterfacePrivate(PlasmaShellInterface *q, Display *display);
23 
24 private:
25     void org_kde_plasma_shell_get_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface) override;
26     PlasmaShellInterface *q;
27 };
28 
PlasmaShellInterfacePrivate(PlasmaShellInterface * _q,Display * display)29 PlasmaShellInterfacePrivate::PlasmaShellInterfacePrivate(PlasmaShellInterface *_q, Display *display)
30     : QtWaylandServer::org_kde_plasma_shell(*display, s_version)
31     , q(_q)
32 {
33 }
34 
35 class PlasmaShellSurfaceInterfacePrivate : public QtWaylandServer::org_kde_plasma_surface
36 {
37 public:
38     PlasmaShellSurfaceInterfacePrivate(PlasmaShellSurfaceInterface *q, SurfaceInterface *surface, wl_resource *resource);
39 
40     QPointer<SurfaceInterface> surface;
41     PlasmaShellSurfaceInterface *q;
42     QPoint m_globalPos;
43     PlasmaShellSurfaceInterface::Role m_role = PlasmaShellSurfaceInterface::Role::Normal;
44     PlasmaShellSurfaceInterface::PanelBehavior m_panelBehavior = PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible;
45     bool m_positionSet = false;
46     bool m_skipTaskbar = false;
47     bool m_skipSwitcher = false;
48     bool m_panelTakesFocus = false;
49 
50 private:
51     void org_kde_plasma_surface_destroy_resource(Resource *resource) override;
52     void org_kde_plasma_surface_destroy(Resource *resource) override;
53     void org_kde_plasma_surface_set_output(Resource *resource, struct ::wl_resource *output) override;
54     void org_kde_plasma_surface_set_position(Resource *resource, int32_t x, int32_t y) override;
55     void org_kde_plasma_surface_set_role(Resource *resource, uint32_t role) override;
56     void org_kde_plasma_surface_set_panel_behavior(Resource *resource, uint32_t flag) override;
57     void org_kde_plasma_surface_set_skip_taskbar(Resource *resource, uint32_t skip) override;
58     void org_kde_plasma_surface_panel_auto_hide_hide(Resource *resource) override;
59     void org_kde_plasma_surface_panel_auto_hide_show(Resource *resource) override;
60     void org_kde_plasma_surface_set_panel_takes_focus(Resource *resource, uint32_t takes_focus) override;
61     void org_kde_plasma_surface_set_skip_switcher(Resource *resource, uint32_t skip) override;
62 };
63 
PlasmaShellInterface(Display * display,QObject * parent)64 PlasmaShellInterface::PlasmaShellInterface(Display *display, QObject *parent)
65     : QObject(parent)
66     , d(new PlasmaShellInterfacePrivate(this, display))
67 {
68 }
69 
70 PlasmaShellInterface::~PlasmaShellInterface() = default;
71 
org_kde_plasma_shell_get_surface(QtWaylandServer::org_kde_plasma_shell::Resource * resource,uint32_t id,struct::wl_resource * surface)72 void PlasmaShellInterfacePrivate::org_kde_plasma_shell_get_surface(QtWaylandServer::org_kde_plasma_shell::Resource *resource,
73                                                                    uint32_t id,
74                                                                    struct ::wl_resource *surface)
75 {
76     SurfaceInterface *s = SurfaceInterface::get(surface);
77     if (!s) {
78         wl_resource_post_error(resource->handle, 0, "Invalid  surface");
79         return;
80     }
81 
82     if (PlasmaShellSurfaceInterface::get(s)) {
83         wl_resource_post_error(resource->handle, 0, "org_kde_plasma_shell_surface already exists");
84         return;
85     }
86 
87     wl_resource *shell_resource = wl_resource_create(resource->client(), &org_kde_plasma_surface_interface, resource->version(), id);
88 
89     auto shellSurface = new PlasmaShellSurfaceInterface(s, shell_resource);
90     s_shellSurfaces.append(shellSurface);
91 
92     QObject::connect(shellSurface, &QObject::destroyed, [shellSurface]() {
93         s_shellSurfaces.removeOne(shellSurface);
94     });
95 
96     Q_EMIT q->surfaceCreated(shellSurface);
97 }
98 
99 /*********************************
100  * ShellSurfaceInterface
101  *********************************/
PlasmaShellSurfaceInterfacePrivate(PlasmaShellSurfaceInterface * _q,SurfaceInterface * surface,wl_resource * resource)102 PlasmaShellSurfaceInterfacePrivate::PlasmaShellSurfaceInterfacePrivate(PlasmaShellSurfaceInterface *_q, SurfaceInterface *surface, wl_resource *resource)
103     : QtWaylandServer::org_kde_plasma_surface(resource)
104     , surface(surface)
105     , q(_q)
106 {
107 }
108 
PlasmaShellSurfaceInterface(SurfaceInterface * surface,wl_resource * resource)109 PlasmaShellSurfaceInterface::PlasmaShellSurfaceInterface(SurfaceInterface *surface, wl_resource *resource)
110     : d(new PlasmaShellSurfaceInterfacePrivate(this, surface, resource))
111 {
112 }
113 
114 PlasmaShellSurfaceInterface::~PlasmaShellSurfaceInterface() = default;
115 
surface() const116 SurfaceInterface *PlasmaShellSurfaceInterface::surface() const
117 {
118     return d->surface;
119 }
120 
org_kde_plasma_surface_destroy(Resource * resource)121 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_destroy(Resource *resource)
122 {
123     wl_resource_destroy(resource->handle);
124 }
125 
org_kde_plasma_surface_destroy_resource(Resource * resource)126 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_destroy_resource(Resource *resource)
127 {
128     Q_UNUSED(resource)
129     delete q;
130 }
131 
org_kde_plasma_surface_set_output(Resource * resource,struct::wl_resource * output)132 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_output(Resource *resource, struct ::wl_resource *output)
133 {
134     Q_UNUSED(resource)
135     Q_UNUSED(output)
136     // TODO: implement
137 }
138 
org_kde_plasma_surface_set_position(Resource * resource,int32_t x,int32_t y)139 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_position(Resource *resource, int32_t x, int32_t y)
140 {
141     Q_UNUSED(resource);
142     QPoint globalPos(x, y);
143     if (m_globalPos == globalPos && m_positionSet) {
144         return;
145     }
146     m_positionSet = true;
147     m_globalPos = globalPos;
148     Q_EMIT q->positionChanged();
149 }
150 
org_kde_plasma_surface_set_role(Resource * resource,uint32_t role)151 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_role(Resource *resource, uint32_t role)
152 {
153     Q_UNUSED(resource)
154 
155     PlasmaShellSurfaceInterface::Role r = PlasmaShellSurfaceInterface::Role::Normal;
156     switch (role) {
157     case role_desktop:
158         r = PlasmaShellSurfaceInterface::Role::Desktop;
159         break;
160     case role_panel:
161         r = PlasmaShellSurfaceInterface::Role::Panel;
162         break;
163     case role_onscreendisplay:
164         r = PlasmaShellSurfaceInterface::Role::OnScreenDisplay;
165         break;
166     case role_notification:
167         r = PlasmaShellSurfaceInterface::Role::Notification;
168         break;
169     case role_tooltip:
170         r = PlasmaShellSurfaceInterface::Role::ToolTip;
171         break;
172     case role_criticalnotification:
173         r = PlasmaShellSurfaceInterface::Role::CriticalNotification;
174         break;
175     case role_normal:
176     default:
177         r = PlasmaShellSurfaceInterface::Role::Normal;
178         break;
179     }
180     if (r == m_role) {
181         return;
182     }
183     m_role = r;
184     Q_EMIT q->roleChanged();
185 }
186 
org_kde_plasma_surface_set_panel_behavior(Resource * resource,uint32_t flag)187 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_panel_behavior(Resource *resource, uint32_t flag)
188 {
189     Q_UNUSED(resource)
190 
191     PlasmaShellSurfaceInterface::PanelBehavior newBehavior = PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible;
192     switch (flag) {
193     case panel_behavior_auto_hide:
194         newBehavior = PlasmaShellSurfaceInterface::PanelBehavior::AutoHide;
195         break;
196     case panel_behavior_windows_can_cover:
197         newBehavior = PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover;
198         break;
199     case panel_behavior_windows_go_below:
200         newBehavior = PlasmaShellSurfaceInterface::PanelBehavior::WindowsGoBelow;
201         break;
202     case panel_behavior_always_visible:
203     default:
204         break;
205     }
206     if (m_panelBehavior == newBehavior) {
207         return;
208     }
209     m_panelBehavior = newBehavior;
210     Q_EMIT q->panelBehaviorChanged();
211 }
212 
org_kde_plasma_surface_set_skip_taskbar(Resource * resource,uint32_t skip)213 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_skip_taskbar(Resource *resource, uint32_t skip)
214 {
215     Q_UNUSED(resource)
216 
217     m_skipTaskbar = (bool)skip;
218     Q_EMIT q->skipTaskbarChanged();
219 }
220 
org_kde_plasma_surface_set_skip_switcher(Resource * resource,uint32_t skip)221 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_skip_switcher(Resource *resource, uint32_t skip)
222 {
223     Q_UNUSED(resource)
224 
225     m_skipSwitcher = (bool)skip;
226     Q_EMIT q->skipSwitcherChanged();
227 }
228 
org_kde_plasma_surface_panel_auto_hide_hide(Resource * resource)229 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_panel_auto_hide_hide(Resource *resource)
230 {
231     if (m_role != PlasmaShellSurfaceInterface::Role::Panel
232         || (m_panelBehavior != PlasmaShellSurfaceInterface::PanelBehavior::AutoHide
233             && m_panelBehavior != PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover)) {
234         wl_resource_post_error(resource->handle, error_panel_not_auto_hide, "Not an auto hide panel");
235         return;
236     }
237     Q_EMIT q->panelAutoHideHideRequested();
238 }
239 
org_kde_plasma_surface_panel_auto_hide_show(Resource * resource)240 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_panel_auto_hide_show(Resource *resource)
241 {
242     if (m_role != PlasmaShellSurfaceInterface::Role::Panel || m_panelBehavior != PlasmaShellSurfaceInterface::PanelBehavior::AutoHide) {
243         wl_resource_post_error(resource->handle, error_panel_not_auto_hide, "Not an auto hide panel");
244         return;
245     }
246     Q_EMIT q->panelAutoHideShowRequested();
247 }
248 
org_kde_plasma_surface_set_panel_takes_focus(Resource * resource,uint32_t takesFocus)249 void PlasmaShellSurfaceInterfacePrivate::org_kde_plasma_surface_set_panel_takes_focus(Resource *resource, uint32_t takesFocus)
250 {
251     Q_UNUSED(resource)
252 
253     if (m_panelTakesFocus == takesFocus) {
254         return;
255     }
256     m_panelTakesFocus = takesFocus;
257     Q_EMIT q->panelTakesFocusChanged();
258 }
259 
position() const260 QPoint PlasmaShellSurfaceInterface::position() const
261 {
262     return d->m_globalPos;
263 }
264 
role() const265 PlasmaShellSurfaceInterface::Role PlasmaShellSurfaceInterface::role() const
266 {
267     return d->m_role;
268 }
269 
isPositionSet() const270 bool PlasmaShellSurfaceInterface::isPositionSet() const
271 {
272     return d->m_positionSet;
273 }
274 
panelBehavior() const275 PlasmaShellSurfaceInterface::PanelBehavior PlasmaShellSurfaceInterface::panelBehavior() const
276 {
277     return d->m_panelBehavior;
278 }
279 
skipTaskbar() const280 bool PlasmaShellSurfaceInterface::skipTaskbar() const
281 {
282     return d->m_skipTaskbar;
283 }
284 
skipSwitcher() const285 bool PlasmaShellSurfaceInterface::skipSwitcher() const
286 {
287     return d->m_skipSwitcher;
288 }
289 
hideAutoHidingPanel()290 void PlasmaShellSurfaceInterface::hideAutoHidingPanel()
291 {
292     d->send_auto_hidden_panel_hidden();
293 }
294 
showAutoHidingPanel()295 void PlasmaShellSurfaceInterface::showAutoHidingPanel()
296 {
297     d->send_auto_hidden_panel_shown();
298 }
299 
panelTakesFocus() const300 bool PlasmaShellSurfaceInterface::panelTakesFocus() const
301 {
302     return d->m_panelTakesFocus;
303 }
304 
get(wl_resource * native)305 PlasmaShellSurfaceInterface *PlasmaShellSurfaceInterface::get(wl_resource *native)
306 {
307     if (auto surfacePrivate = resource_cast<PlasmaShellSurfaceInterfacePrivate *>(native)) {
308         return surfacePrivate->q;
309     }
310     return nullptr;
311 }
312 
get(SurfaceInterface * surface)313 PlasmaShellSurfaceInterface *PlasmaShellSurfaceInterface::get(SurfaceInterface *surface)
314 {
315     for (PlasmaShellSurfaceInterface *shellSurface : qAsConst(s_shellSurfaces)) {
316         if (shellSurface->surface() == surface) {
317             return shellSurface;
318         }
319     }
320     return nullptr;
321 }
322 
323 }
324