1/*
2 SPDX-FileCopyrightText: 2014 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 "kwindowsystem.h"
7#include "kwindowsystem_debug.h"
8#include "kwindowsystem_dummy_p.h"
9#include "pluginwrapper_p.h"
10
11#include <config-kwindowsystem.h>
12
13#if KWINDOWSYSTEM_HAVE_X11
14#include "kstartupinfo.h"
15#endif
16
17#include <QGuiApplication>
18#include <QMetaMethod>
19#include <QPixmap>
20#include <QPluginLoader>
21#include <QTimer>
22#include <QWindow>
23#if KWINDOWSYSTEM_HAVE_X11
24#include <private/qtx11extras_p.h>
25#endif
26
27// QPoint and QSize all have handy / operators which are useful for scaling, positions and sizes for high DPI support
28// QRect does not, so we create one for internal purposes within this class
29inline QRect operator/(const QRect &rectangle, qreal factor)
30{
31 return QRect(rectangle.topLeft() / factor, rectangle.size() / factor);
32}
33
34class KWindowSystemStaticContainer
35{
36public:
37 KWindowSystemStaticContainer()
38 {
39 d.reset(p: KWindowSystemPluginWrapper::self().createWindowSystem());
40
41 if (QCoreApplication::instance()) {
42 kwm.moveToThread(thread: QCoreApplication::instance()->thread());
43 }
44 }
45 KWindowSystem kwm;
46 std::unique_ptr<KWindowSystemPrivate> d;
47};
48
49Q_GLOBAL_STATIC(KWindowSystemStaticContainer, g_kwmInstanceContainer)
50
51KWindowSystemPrivate::~KWindowSystemPrivate()
52{
53}
54
55void KWindowSystemPrivateDummy::activateWindow(QWindow *win, long time)
56{
57 Q_UNUSED(win)
58 Q_UNUSED(time)
59}
60
61bool KWindowSystemPrivateDummy::showingDesktop()
62{
63 return false;
64}
65
66void KWindowSystemPrivateDummy::setShowingDesktop(bool showing)
67{
68 Q_UNUSED(showing);
69}
70
71KWindowSystem *KWindowSystem::self()
72{
73 return &(g_kwmInstanceContainer()->kwm);
74}
75
76KWindowSystemPrivate *KWindowSystem::d_func()
77{
78 return g_kwmInstanceContainer()->d.get();
79}
80
81void KWindowSystem::activateWindow(QWindow *win, long time)
82{
83 Q_D(KWindowSystem);
84 d->activateWindow(win, time);
85}
86
87void KWindowSystem::setMainWindow(QWindow *subWindow, WId mainWindowId)
88{
89 QWindow *mainWindow = QWindow::fromWinId(id: mainWindowId);
90 if (mainWindow) { // foreign windows not supported on all platforms
91 subWindow->setTransientParent(mainWindow);
92
93 // mainWindow is not the child of any object, so make sure it gets deleted at some point
94 connect(sender: subWindow, signal: &QObject::destroyed, context: mainWindow, slot: &QObject::deleteLater);
95 }
96}
97
98void KWindowSystem::setMainWindow(QWindow *subWindow, const QString &mainWindowId)
99{
100 Q_D(KWindowSystem);
101 if (isPlatformWayland()) {
102 if (auto dv2 = dynamic_cast<KWindowSystemPrivateV2 *>(d)) {
103 dv2->setMainWindow(window: subWindow, handle: mainWindowId);
104 }
105 } else {
106 bool ok = false;
107 // base 0 means "C style" parsing with 0x for base 16, 0b for base 2, etc.
108 WId wid = mainWindowId.toULongLong(ok: &ok, base: 0);
109 if (ok) {
110 setMainWindow(subWindow, mainWindowId: wid);
111 } else {
112 qCWarning(LOG_KWINDOWSYSTEM) << "Failed to convert" << mainWindowId << "to WId";
113 }
114 }
115}
116
117bool KWindowSystem::showingDesktop()
118{
119 Q_D(KWindowSystem);
120 return d->showingDesktop();
121}
122
123void KWindowSystem::setShowingDesktop(bool showing)
124{
125 Q_D(KWindowSystem);
126 return d->setShowingDesktop(showing);
127}
128
129static inline KWindowSystem::Platform initPlatform()
130{
131 auto platformName = QGuiApplication::platformName();
132 if (platformName == QLatin1String("flatpak")) {
133 // here we cannot know what is the actual windowing system, let's try it's env variable
134 const auto flatpakPlatform = QString::fromLocal8Bit(ba: qgetenv(varName: "QT_QPA_FLATPAK_PLATFORM"));
135 if (!flatpakPlatform.isEmpty()) {
136 platformName = flatpakPlatform;
137 }
138 }
139#if KWINDOWSYSTEM_HAVE_X11
140 if (platformName == QLatin1String("xcb")) {
141 return KWindowSystem::Platform::X11;
142 }
143#endif
144 if (platformName.startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive)) {
145 return KWindowSystem::Platform::Wayland;
146 }
147 return KWindowSystem::Platform::Unknown;
148}
149
150KWindowSystem::Platform KWindowSystem::platform()
151{
152 static Platform s_platform = initPlatform();
153 return s_platform;
154}
155
156bool KWindowSystem::isPlatformX11()
157{
158 return platform() == Platform::X11;
159}
160
161bool KWindowSystem::isPlatformWayland()
162{
163 return platform() == Platform::Wayland;
164}
165
166void KWindowSystem::updateStartupId(QWindow *window)
167{
168 // clang-format off
169 // TODO: move to a new KWindowSystemPrivate interface
170#if KWINDOWSYSTEM_HAVE_X11
171 if (isPlatformX11()) {
172 const QByteArray startupId = QX11Info::nextStartupId();
173 if (!startupId.isEmpty()) {
174 KStartupInfo::setNewStartupId(window, startup_id: startupId);
175 }
176 } else
177#else
178 Q_UNUSED(window);
179#endif
180 if (isPlatformWayland()) {
181 const QString token = qEnvironmentVariable(varName: "XDG_ACTIVATION_TOKEN");
182 if (!token.isEmpty()) {
183 setCurrentXdgActivationToken(token);
184 qunsetenv(varName: "XDG_ACTIVATION_TOKEN");
185 }
186 }
187 // clang-format on
188}
189
190void KWindowSystem::setCurrentXdgActivationToken(const QString &token)
191{
192 Q_D(KWindowSystem);
193 auto dv2 = dynamic_cast<KWindowSystemPrivateV2 *>(d);
194 if (!dv2) {
195 return;
196 }
197 dv2->setCurrentToken(token);
198}
199
200#include "moc_kwindowsystem.cpp"
201

source code of kwindowsystem/src/kwindowsystem.cpp