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 |
29 | inline QRect operator/(const QRect &rectangle, qreal factor) |
30 | { |
31 | return QRect(rectangle.topLeft() / factor, rectangle.size() / factor); |
32 | } |
33 | |
34 | class KWindowSystemStaticContainer |
35 | { |
36 | public: |
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 | |
49 | Q_GLOBAL_STATIC(KWindowSystemStaticContainer, g_kwmInstanceContainer) |
50 | |
51 | KWindowSystemPrivate::~KWindowSystemPrivate() |
52 | { |
53 | } |
54 | |
55 | void KWindowSystemPrivateDummy::activateWindow(QWindow *win, long time) |
56 | { |
57 | Q_UNUSED(win) |
58 | Q_UNUSED(time) |
59 | } |
60 | |
61 | bool KWindowSystemPrivateDummy::showingDesktop() |
62 | { |
63 | return false; |
64 | } |
65 | |
66 | void KWindowSystemPrivateDummy::setShowingDesktop(bool showing) |
67 | { |
68 | Q_UNUSED(showing); |
69 | } |
70 | |
71 | KWindowSystem *KWindowSystem::self() |
72 | { |
73 | return &(g_kwmInstanceContainer()->kwm); |
74 | } |
75 | |
76 | KWindowSystemPrivate *KWindowSystem::d_func() |
77 | { |
78 | return g_kwmInstanceContainer()->d.get(); |
79 | } |
80 | |
81 | void KWindowSystem::activateWindow(QWindow *win, long time) |
82 | { |
83 | Q_D(KWindowSystem); |
84 | d->activateWindow(win, time); |
85 | } |
86 | |
87 | void 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 | |
98 | void 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 | |
117 | bool KWindowSystem::showingDesktop() |
118 | { |
119 | Q_D(KWindowSystem); |
120 | return d->showingDesktop(); |
121 | } |
122 | |
123 | void KWindowSystem::setShowingDesktop(bool showing) |
124 | { |
125 | Q_D(KWindowSystem); |
126 | return d->setShowingDesktop(showing); |
127 | } |
128 | |
129 | static 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 | |
150 | KWindowSystem::Platform KWindowSystem::platform() |
151 | { |
152 | static Platform s_platform = initPlatform(); |
153 | return s_platform; |
154 | } |
155 | |
156 | bool KWindowSystem::isPlatformX11() |
157 | { |
158 | return platform() == Platform::X11; |
159 | } |
160 | |
161 | bool KWindowSystem::isPlatformWayland() |
162 | { |
163 | return platform() == Platform::Wayland; |
164 | } |
165 | |
166 | void 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 | |
190 | void 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 | |