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 | |
14 | namespace KWayland |
15 | { |
16 | namespace Client |
17 | { |
18 | class Q_DECL_HIDDEN PlasmaShell::Private |
19 | { |
20 | public: |
21 | WaylandPointer<org_kde_plasma_shell, org_kde_plasma_shell_destroy> shell; |
22 | EventQueue *queue = nullptr; |
23 | }; |
24 | |
25 | class Q_DECL_HIDDEN PlasmaShellSurface::Private |
26 | { |
27 | public: |
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 | |
39 | private: |
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 | |
48 | QList<PlasmaShellSurface::Private *> PlasmaShellSurface::Private::s_surfaces; |
49 | |
50 | PlasmaShell::PlasmaShell(QObject *parent) |
51 | : QObject(parent) |
52 | , d(new Private) |
53 | { |
54 | } |
55 | |
56 | PlasmaShell::~PlasmaShell() |
57 | { |
58 | release(); |
59 | } |
60 | |
61 | void PlasmaShell::destroy() |
62 | { |
63 | if (!d->shell) { |
64 | return; |
65 | } |
66 | Q_EMIT interfaceAboutToBeDestroyed(); |
67 | d->shell.destroy(); |
68 | } |
69 | |
70 | void PlasmaShell::release() |
71 | { |
72 | if (!d->shell) { |
73 | return; |
74 | } |
75 | Q_EMIT interfaceAboutToBeReleased(); |
76 | d->shell.release(); |
77 | } |
78 | |
79 | void 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 | |
86 | void PlasmaShell::setEventQueue(EventQueue *queue) |
87 | { |
88 | d->queue = queue; |
89 | } |
90 | |
91 | EventQueue *PlasmaShell::eventQueue() |
92 | { |
93 | return d->queue; |
94 | } |
95 | |
96 | PlasmaShellSurface *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 | |
117 | PlasmaShellSurface *PlasmaShell::createSurface(Surface *surface, QObject *parent) |
118 | { |
119 | return createSurface(surface: *surface, parent); |
120 | } |
121 | |
122 | bool PlasmaShell::isValid() const |
123 | { |
124 | return d->shell.isValid(); |
125 | } |
126 | |
127 | PlasmaShell::operator org_kde_plasma_shell *() |
128 | { |
129 | return d->shell; |
130 | } |
131 | |
132 | PlasmaShell::operator org_kde_plasma_shell *() const |
133 | { |
134 | return d->shell; |
135 | } |
136 | |
137 | PlasmaShellSurface::Private::Private(PlasmaShellSurface *q) |
138 | : role(PlasmaShellSurface::Role::Normal) |
139 | , q(q) |
140 | { |
141 | s_surfaces << this; |
142 | } |
143 | |
144 | PlasmaShellSurface::Private::~Private() |
145 | { |
146 | s_surfaces.removeAll(t: this); |
147 | } |
148 | |
149 | PlasmaShellSurface *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 | |
162 | void 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 | |
170 | const org_kde_plasma_surface_listener PlasmaShellSurface::Private::s_listener = {.auto_hidden_panel_hidden: autoHidingPanelHiddenCallback, .auto_hidden_panel_shown: autoHidingPanelShownCallback}; |
171 | |
172 | void 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 | |
179 | void 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 | |
186 | PlasmaShellSurface::PlasmaShellSurface(QObject *parent) |
187 | : QObject(parent) |
188 | , d(new Private(this)) |
189 | { |
190 | } |
191 | |
192 | PlasmaShellSurface::~PlasmaShellSurface() |
193 | { |
194 | release(); |
195 | } |
196 | |
197 | void PlasmaShellSurface::release() |
198 | { |
199 | d->surface.release(); |
200 | } |
201 | |
202 | void PlasmaShellSurface::destroy() |
203 | { |
204 | d->surface.destroy(); |
205 | } |
206 | |
207 | void PlasmaShellSurface::setup(org_kde_plasma_surface *surface) |
208 | { |
209 | d->setup(surface); |
210 | } |
211 | |
212 | PlasmaShellSurface *PlasmaShellSurface::get(Surface *surface) |
213 | { |
214 | if (auto s = PlasmaShellSurface::Private::get(surface)) { |
215 | return s; |
216 | } |
217 | |
218 | return nullptr; |
219 | } |
220 | |
221 | bool PlasmaShellSurface::isValid() const |
222 | { |
223 | return d->surface.isValid(); |
224 | } |
225 | |
226 | PlasmaShellSurface::operator org_kde_plasma_surface *() |
227 | { |
228 | return d->surface; |
229 | } |
230 | |
231 | PlasmaShellSurface::operator org_kde_plasma_surface *() const |
232 | { |
233 | return d->surface; |
234 | } |
235 | |
236 | void 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 | |
242 | void PlasmaShellSurface::openUnderCursor() |
243 | { |
244 | org_kde_plasma_surface_open_under_cursor(org_kde_plasma_surface: d->surface); |
245 | } |
246 | |
247 | void 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 | |
295 | PlasmaShellSurface::Role PlasmaShellSurface::role() const |
296 | { |
297 | return d->role; |
298 | } |
299 | |
300 | void 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 | |
324 | void PlasmaShellSurface::setSkipTaskbar(bool skip) |
325 | { |
326 | org_kde_plasma_surface_set_skip_taskbar(org_kde_plasma_surface: d->surface, skip); |
327 | } |
328 | |
329 | void PlasmaShellSurface::setSkipSwitcher(bool skip) |
330 | { |
331 | org_kde_plasma_surface_set_skip_switcher(org_kde_plasma_surface: d->surface, skip); |
332 | } |
333 | |
334 | void PlasmaShellSurface::requestHideAutoHidingPanel() |
335 | { |
336 | org_kde_plasma_surface_panel_auto_hide_hide(org_kde_plasma_surface: d->surface); |
337 | } |
338 | |
339 | void PlasmaShellSurface::requestShowAutoHidingPanel() |
340 | { |
341 | org_kde_plasma_surface_panel_auto_hide_show(org_kde_plasma_surface: d->surface); |
342 | } |
343 | |
344 | void 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 | |