Libplasma

plasmashellwaylandintegration.cpp
1/*
2 SPDX-FileCopyrightText: 2023 David Edmundson <davidedmundson@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "plasmashellwaylandintegration.h"
8
9#include <QGuiApplication>
10#include <QPlatformSurfaceEvent>
11#include <QWaylandClientExtensionTemplate>
12#include <QWindow>
13
14#include <qpa/qplatformwindow_p.h>
15
16#include <KWindowSystem>
17
18class PlasmaShellManager : public QWaylandClientExtensionTemplate<PlasmaShellManager>, public QtWayland::org_kde_plasma_shell
19{
20public:
21 PlasmaShellManager()
22 : QWaylandClientExtensionTemplate<PlasmaShellManager>(8)
23 {
24 initialize();
25 }
26};
27
28class PlasmaShellSurface : public QtWayland::org_kde_plasma_surface
29{
30public:
31 PlasmaShellSurface(struct ::org_kde_plasma_surface *impl)
32 : QtWayland::org_kde_plasma_surface(impl)
33 {
34 }
35 ~PlasmaShellSurface()
36 {
37 destroy();
38 }
39};
40
41class WaylandIntegrationSingleton
42{
43public:
44 WaylandIntegrationSingleton();
45 std::unique_ptr<PlasmaShellManager> shellManager;
47};
48
49WaylandIntegrationSingleton::WaylandIntegrationSingleton()
50{
52 shellManager = std::make_unique<PlasmaShellManager>();
53 }
54}
55
56Q_GLOBAL_STATIC(WaylandIntegrationSingleton, s_waylandIntegration)
57
58class PlasmaShellWaylandIntegrationPrivate
59{
60public:
61 PlasmaShellWaylandIntegrationPrivate(PlasmaShellWaylandIntegration *integration, QWindow *window);
62
63 void platformSurfaceCreated(QWindow *window);
64 void surfaceCreated();
65 void surfaceDestroyed();
66
68 QWindow *m_window = nullptr;
69 std::optional<QPoint> m_position;
70 QtWayland::org_kde_plasma_surface::panel_behavior m_panelBehavior = QtWayland::org_kde_plasma_surface::panel_behavior_always_visible;
71 QtWayland::org_kde_plasma_surface::role m_role = QtWayland::org_kde_plasma_surface::role_normal;
72 bool m_takesFocus = false;
73 std::unique_ptr<PlasmaShellSurface> m_shellSurface;
74};
75
76PlasmaShellWaylandIntegrationPrivate::PlasmaShellWaylandIntegrationPrivate(PlasmaShellWaylandIntegration *integration, QWindow *window)
77 : q(integration)
78 , m_window(window)
79{
80}
81
82void PlasmaShellWaylandIntegrationPrivate::platformSurfaceCreated(QWindow *window)
83{
84 auto waylandWindow = window->nativeInterface<QNativeInterface::Private::QWaylandWindow>();
85 if (!waylandWindow) { // It may be null, e.g. when called within KWin
86 return;
87 }
88 QObject::connect(waylandWindow, SIGNAL(surfaceCreated()), q, SLOT(surfaceCreated()));
89 QObject::connect(waylandWindow, SIGNAL(surfaceDestroyed()), q, SLOT(surfaceDestroyed()));
90 if (waylandWindow->surface()) {
91 surfaceCreated();
92 }
93}
94
95void PlasmaShellWaylandIntegrationPrivate::surfaceCreated()
96{
97 struct wl_surface *surface = nullptr;
98 if (!s_waylandIntegration->shellManager || !s_waylandIntegration->shellManager->isActive()) {
99 return;
100 }
101
102 if (auto waylandWindow = m_window->nativeInterface<QNativeInterface::Private::QWaylandWindow>()) {
103 surface = waylandWindow->surface();
104 }
105
106 if (!surface) {
107 return;
108 }
109
110 m_shellSurface = std::make_unique<PlasmaShellSurface>(s_waylandIntegration->shellManager->get_surface(surface));
111 if (m_shellSurface) {
112 if (m_position) {
113 m_shellSurface->set_position(m_position->x(), m_position->y());
114 }
115 m_shellSurface->set_panel_takes_focus(m_takesFocus);
116 m_shellSurface->set_role(m_role);
117 m_shellSurface->set_skip_switcher(true);
118 m_shellSurface->set_skip_taskbar(true);
119 }
120}
121
122void PlasmaShellWaylandIntegrationPrivate::surfaceDestroyed()
123{
124 m_shellSurface.reset();
125}
126
128{
129 PlasmaShellWaylandIntegration *&it = s_waylandIntegration->windows[window];
130 if (!it) {
131 it = new PlasmaShellWaylandIntegration(window);
132 }
133 return it;
134}
135
136PlasmaShellWaylandIntegration::~PlasmaShellWaylandIntegration()
137{
138 s_waylandIntegration->windows.remove(d->m_window);
139}
140
141PlasmaShellWaylandIntegration::PlasmaShellWaylandIntegration(QWindow *window)
142 : QObject(window)
143 , d(new PlasmaShellWaylandIntegrationPrivate(this, window))
144{
146 return;
147 }
148 d->m_window->installEventFilter(this);
149 d->platformSurfaceCreated(window);
150}
151
152bool PlasmaShellWaylandIntegration::eventFilter(QObject *watched, QEvent *event)
153{
154 auto window = qobject_cast<QWindow *>(watched);
155 if (!window) {
156 return false;
157 }
158 if (event->type() == QEvent::PlatformSurface) {
159 auto surfaceEvent = static_cast<QPlatformSurfaceEvent *>(event);
160 if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) {
161 d->platformSurfaceCreated(window);
162 }
163 }
164 return false;
165}
166
167void PlasmaShellWaylandIntegration::setPosition(const QPoint &position)
168{
169 if (position == d->m_position) {
170 return;
171 }
172
173 d->m_position = position;
174 if (d->m_shellSurface) {
175 d->m_shellSurface->set_position(d->m_position->x(), d->m_position->y());
176 }
177}
178
179void PlasmaShellWaylandIntegration::setPanelBehavior(QtWayland::org_kde_plasma_surface::panel_behavior panelBehavior)
180{
181 if (panelBehavior == d->m_panelBehavior) {
182 return;
183 }
184 d->m_panelBehavior = panelBehavior;
185 if (d->m_shellSurface) {
186 d->m_shellSurface->set_panel_behavior(panelBehavior);
187 }
188}
189
190void PlasmaShellWaylandIntegration::setRole(QtWayland::org_kde_plasma_surface::role role)
191{
192 if (role == d->m_role) {
193 return;
194 }
195 d->m_role = role;
196 if (d->m_shellSurface) {
197 d->m_shellSurface->set_role(role);
198 }
199}
200
201void PlasmaShellWaylandIntegration::setTakesFocus(bool takesFocus)
202{
203 if (takesFocus == d->m_takesFocus) {
204 return;
205 }
206 d->m_takesFocus = takesFocus;
207 if (d->m_shellSurface) {
208 d->m_shellSurface->set_panel_takes_focus(takesFocus);
209 }
210}
211
212#include "moc_plasmashellwaylandintegration.cpp"
static bool isPlatformWayland()
The PlasmaWaylandShellIntegration class exposes Plasma specific specific wayland extensions for.
static PlasmaShellWaylandIntegration * get(QWindow *window)
Returns the relevant PlasmaWaylandShellIntegration instance for this window creating one if needed.
KCRASH_EXPORT void initialize()
QWidget * window(QObject *job)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
T qobject_cast(QObject *object)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:34:35 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.