1/*
2 SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#include "plasmashell.h"
7#include "event_queue.h"
8#include "output.h"
9#include "surface.h"
10#include "wayland_pointer_p.h"
11// Wayland
12#include <wayland-plasma-shell-client-protocol.h>
13
14namespace KWayland
15{
16namespace Client
17{
18class Q_DECL_HIDDEN PlasmaShell::Private
19{
20public:
21 WaylandPointer<org_kde_plasma_shell, org_kde_plasma_shell_destroy> shell;
22 EventQueue *queue = nullptr;
23};
24
25class Q_DECL_HIDDEN PlasmaShellSurface::Private
26{
27public:
28 Private(PlasmaShellSurface *q);
29 ~Private();
30 void setup(org_kde_plasma_surface *surface);
31
32 WaylandPointer<org_kde_plasma_surface, org_kde_plasma_surface_destroy> surface;
33 QSize size;
34 QPointer<Surface> parentSurface;
35 PlasmaShellSurface::Role role;
36
37 static PlasmaShellSurface *get(Surface *surface);
38
39private:
40 static void autoHidingPanelHiddenCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface);
41 static void autoHidingPanelShownCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface);
42
43 PlasmaShellSurface *q;
44 static QList<Private *> s_surfaces;
45 static const org_kde_plasma_surface_listener s_listener;
46};
47
48QList<PlasmaShellSurface::Private *> PlasmaShellSurface::Private::s_surfaces;
49
50PlasmaShell::PlasmaShell(QObject *parent)
51 : QObject(parent)
52 , d(new Private)
53{
54}
55
56PlasmaShell::~PlasmaShell()
57{
58 release();
59}
60
61void PlasmaShell::destroy()
62{
63 if (!d->shell) {
64 return;
65 }
66 Q_EMIT interfaceAboutToBeDestroyed();
67 d->shell.destroy();
68}
69
70void PlasmaShell::release()
71{
72 if (!d->shell) {
73 return;
74 }
75 Q_EMIT interfaceAboutToBeReleased();
76 d->shell.release();
77}
78
79void PlasmaShell::setup(org_kde_plasma_shell *shell)
80{
81 Q_ASSERT(!d->shell);
82 Q_ASSERT(shell);
83 d->shell.setup(pointer: shell);
84}
85
86void PlasmaShell::setEventQueue(EventQueue *queue)
87{
88 d->queue = queue;
89}
90
91EventQueue *PlasmaShell::eventQueue()
92{
93 return d->queue;
94}
95
96PlasmaShellSurface *PlasmaShell::createSurface(wl_surface *surface, QObject *parent)
97{
98 Q_ASSERT(isValid());
99 auto kwS = Surface::get(native: surface);
100 if (kwS) {
101 if (auto s = PlasmaShellSurface::Private::get(surface: kwS)) {
102 return s;
103 }
104 }
105 PlasmaShellSurface *s = new PlasmaShellSurface(parent);
106 connect(sender: this, signal: &PlasmaShell::interfaceAboutToBeReleased, context: s, slot: &PlasmaShellSurface::release);
107 connect(sender: this, signal: &PlasmaShell::interfaceAboutToBeDestroyed, context: s, slot: &PlasmaShellSurface::destroy);
108 auto w = org_kde_plasma_shell_get_surface(org_kde_plasma_shell: d->shell, surface);
109 if (d->queue) {
110 d->queue->addProxy(proxy: w);
111 }
112 s->setup(w);
113 s->d->parentSurface = QPointer<Surface>(kwS);
114 return s;
115}
116
117PlasmaShellSurface *PlasmaShell::createSurface(Surface *surface, QObject *parent)
118{
119 return createSurface(surface: *surface, parent);
120}
121
122bool PlasmaShell::isValid() const
123{
124 return d->shell.isValid();
125}
126
127PlasmaShell::operator org_kde_plasma_shell *()
128{
129 return d->shell;
130}
131
132PlasmaShell::operator org_kde_plasma_shell *() const
133{
134 return d->shell;
135}
136
137PlasmaShellSurface::Private::Private(PlasmaShellSurface *q)
138 : role(PlasmaShellSurface::Role::Normal)
139 , q(q)
140{
141 s_surfaces << this;
142}
143
144PlasmaShellSurface::Private::~Private()
145{
146 s_surfaces.removeAll(t: this);
147}
148
149PlasmaShellSurface *PlasmaShellSurface::Private::get(Surface *surface)
150{
151 if (!surface) {
152 return nullptr;
153 }
154 for (auto it = s_surfaces.constBegin(); it != s_surfaces.constEnd(); ++it) {
155 if ((*it)->parentSurface == surface) {
156 return (*it)->q;
157 }
158 }
159 return nullptr;
160}
161
162void PlasmaShellSurface::Private::setup(org_kde_plasma_surface *s)
163{
164 Q_ASSERT(s);
165 Q_ASSERT(!surface);
166 surface.setup(pointer: s);
167 org_kde_plasma_surface_add_listener(org_kde_plasma_surface: surface, listener: &s_listener, data: this);
168}
169
170const org_kde_plasma_surface_listener PlasmaShellSurface::Private::s_listener = {.auto_hidden_panel_hidden: autoHidingPanelHiddenCallback, .auto_hidden_panel_shown: autoHidingPanelShownCallback};
171
172void PlasmaShellSurface::Private::autoHidingPanelHiddenCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface)
173{
174 auto p = reinterpret_cast<PlasmaShellSurface::Private *>(data);
175 Q_ASSERT(p->surface == org_kde_plasma_surface);
176 Q_EMIT p->q->autoHidePanelHidden();
177}
178
179void PlasmaShellSurface::Private::autoHidingPanelShownCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface)
180{
181 auto p = reinterpret_cast<PlasmaShellSurface::Private *>(data);
182 Q_ASSERT(p->surface == org_kde_plasma_surface);
183 Q_EMIT p->q->autoHidePanelShown();
184}
185
186PlasmaShellSurface::PlasmaShellSurface(QObject *parent)
187 : QObject(parent)
188 , d(new Private(this))
189{
190}
191
192PlasmaShellSurface::~PlasmaShellSurface()
193{
194 release();
195}
196
197void PlasmaShellSurface::release()
198{
199 d->surface.release();
200}
201
202void PlasmaShellSurface::destroy()
203{
204 d->surface.destroy();
205}
206
207void PlasmaShellSurface::setup(org_kde_plasma_surface *surface)
208{
209 d->setup(surface);
210}
211
212PlasmaShellSurface *PlasmaShellSurface::get(Surface *surface)
213{
214 if (auto s = PlasmaShellSurface::Private::get(surface)) {
215 return s;
216 }
217
218 return nullptr;
219}
220
221bool PlasmaShellSurface::isValid() const
222{
223 return d->surface.isValid();
224}
225
226PlasmaShellSurface::operator org_kde_plasma_surface *()
227{
228 return d->surface;
229}
230
231PlasmaShellSurface::operator org_kde_plasma_surface *() const
232{
233 return d->surface;
234}
235
236void PlasmaShellSurface::setPosition(const QPoint &point)
237{
238 Q_ASSERT(isValid());
239 org_kde_plasma_surface_set_position(org_kde_plasma_surface: d->surface, x: point.x(), y: point.y());
240}
241
242void PlasmaShellSurface::openUnderCursor()
243{
244 org_kde_plasma_surface_open_under_cursor(org_kde_plasma_surface: d->surface);
245}
246
247void PlasmaShellSurface::setRole(PlasmaShellSurface::Role role)
248{
249 Q_ASSERT(isValid());
250 uint32_t wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_NORMAL;
251 switch (role) {
252 case Role::Normal:
253 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_NORMAL;
254 break;
255 case Role::Desktop:
256 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_DESKTOP;
257 break;
258 case Role::Panel:
259 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_PANEL;
260 break;
261 case Role::OnScreenDisplay:
262 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_ONSCREENDISPLAY;
263 break;
264 case Role::Notification:
265 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_NOTIFICATION;
266 break;
267 case Role::ToolTip:
268 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_TOOLTIP;
269 break;
270 case Role::CriticalNotification:
271 if (wl_proxy_get_version(proxy: d->surface) < ORG_KDE_PLASMA_SURFACE_ROLE_CRITICALNOTIFICATION_SINCE_VERSION) {
272 // Fall back to generic notification type if not supported
273 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_NOTIFICATION;
274 } else {
275 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_CRITICALNOTIFICATION;
276 }
277 break;
278 case Role::AppletPopup:
279 if (wl_proxy_get_version(proxy: d->surface) < ORG_KDE_PLASMA_SURFACE_ROLE_APPLETPOPUP_SINCE_VERSION) {
280 // dock is what applet popups were before
281 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_PANEL;
282 setPanelBehavior(PanelBehavior::WindowsGoBelow);
283 } else {
284 wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_APPLETPOPUP;
285 }
286 break;
287 default:
288 Q_UNREACHABLE();
289 break;
290 }
291 org_kde_plasma_surface_set_role(org_kde_plasma_surface: d->surface, role: wlRole);
292 d->role = role;
293}
294
295PlasmaShellSurface::Role PlasmaShellSurface::role() const
296{
297 return d->role;
298}
299
300void PlasmaShellSurface::setPanelBehavior(PlasmaShellSurface::PanelBehavior behavior)
301{
302 Q_ASSERT(isValid());
303 uint32_t wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_ALWAYS_VISIBLE;
304 switch (behavior) {
305 case PanelBehavior::AlwaysVisible:
306 wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_ALWAYS_VISIBLE;
307 break;
308 case PanelBehavior::AutoHide:
309 wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_AUTO_HIDE;
310 break;
311 case PanelBehavior::WindowsCanCover:
312 wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_WINDOWS_CAN_COVER;
313 break;
314 case PanelBehavior::WindowsGoBelow:
315 wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_WINDOWS_GO_BELOW;
316 break;
317 default:
318 Q_UNREACHABLE();
319 break;
320 }
321 org_kde_plasma_surface_set_panel_behavior(org_kde_plasma_surface: d->surface, flag: wlRole);
322}
323
324void PlasmaShellSurface::setSkipTaskbar(bool skip)
325{
326 org_kde_plasma_surface_set_skip_taskbar(org_kde_plasma_surface: d->surface, skip);
327}
328
329void PlasmaShellSurface::setSkipSwitcher(bool skip)
330{
331 org_kde_plasma_surface_set_skip_switcher(org_kde_plasma_surface: d->surface, skip);
332}
333
334void PlasmaShellSurface::requestHideAutoHidingPanel()
335{
336 org_kde_plasma_surface_panel_auto_hide_hide(org_kde_plasma_surface: d->surface);
337}
338
339void PlasmaShellSurface::requestShowAutoHidingPanel()
340{
341 org_kde_plasma_surface_panel_auto_hide_show(org_kde_plasma_surface: d->surface);
342}
343
344void PlasmaShellSurface::setPanelTakesFocus(bool takesFocus)
345{
346 org_kde_plasma_surface_set_panel_takes_focus(org_kde_plasma_surface: d->surface, takes_focus: takesFocus);
347}
348
349}
350}
351
352#include "moc_plasmashell.cpp"
353

source code of kwayland/src/client/plasmashell.cpp