File indexing completed on 2024-05-12 17:00:19

0001 /*
0002     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "windowsystem.h"
0007 #include "logging.h"
0008 #include "waylandintegration.h"
0009 #include "waylandxdgactivationv1_p.h"
0010 
0011 #include <KWindowSystem>
0012 
0013 #include <KWayland/Client/connection_thread.h>
0014 #include <KWayland/Client/plasmashell.h>
0015 #include <KWayland/Client/plasmawindowmanagement.h>
0016 #include <KWayland/Client/registry.h>
0017 #include <KWayland/Client/seat.h>
0018 #include <KWayland/Client/surface.h>
0019 
0020 #include <QGuiApplication>
0021 #include <QPixmap>
0022 #include <QPoint>
0023 #include <QString>
0024 #include <QWindow>
0025 #include <private/qwaylanddisplay_p.h>
0026 #include <private/qwaylandinputdevice_p.h>
0027 #include <private/qwaylandwindow_p.h>
0028 #include <qpa/qplatformnativeinterface.h>
0029 
0030 using namespace KWayland::Client;
0031 
0032 WindowSystem::WindowSystem()
0033     : QObject()
0034     , KWindowSystemPrivateV2()
0035     , m_lastToken(qEnvironmentVariable("XDG_ACTIVATION_TOKEN"))
0036 {
0037 }
0038 
0039 void WindowSystem::activateWindow(WId win, long int time)
0040 {
0041     Q_UNUSED(time);
0042     Surface *s = Surface::fromQtWinId(win);
0043     if (!s) {
0044         return;
0045     }
0046     WaylandXdgActivationV1 *activation = WaylandIntegration::self()->activation();
0047     if (!activation) {
0048         return;
0049     }
0050     activation->activate(m_lastToken, *s);
0051 }
0052 
0053 void WindowSystem::forceActiveWindow(WId win, long int time)
0054 {
0055     activateWindow(win, time);
0056 }
0057 
0058 void WindowSystem::requestToken(QWindow *window, uint32_t serial, const QString &app_id)
0059 {
0060     wl_surface *wlSurface = [](QWindow *window) -> wl_surface * {
0061         if (!window) {
0062             return nullptr;
0063         }
0064 
0065         QPlatformNativeInterface *native = qGuiApp->platformNativeInterface();
0066         if (!native) {
0067             return nullptr;
0068         }
0069         window->create();
0070         return reinterpret_cast<wl_surface *>(native->nativeResourceForWindow(QByteArrayLiteral("surface"), window));
0071     }(window);
0072 
0073     WaylandXdgActivationV1 *activation = WaylandIntegration::self()->activation();
0074     if (!activation) {
0075         // Ensure that xdgActivationTokenArrived is always emitted asynchronously
0076         QTimer::singleShot(0, [serial] {
0077             Q_EMIT KWindowSystem::self()->xdgActivationTokenArrived(serial, {});
0078         });
0079         return;
0080     }
0081 
0082     auto waylandWindow = window ? dynamic_cast<QtWaylandClient::QWaylandWindow *>(window->handle()) : nullptr;
0083     auto seat = waylandWindow ? waylandWindow->display()->defaultInputDevice()->wl_seat() : nullptr;
0084     auto tokenReq = activation->requestXdgActivationToken(seat, wlSurface, serial, app_id);
0085     connect(tokenReq, &WaylandXdgActivationTokenV1::failed, KWindowSystem::self(), [serial, app_id]() {
0086         Q_EMIT KWindowSystem::self()->xdgActivationTokenArrived(serial, {});
0087     });
0088     connect(tokenReq, &WaylandXdgActivationTokenV1::done, KWindowSystem::self(), [serial](const QString &token) {
0089         Q_EMIT KWindowSystem::self()->xdgActivationTokenArrived(serial, token);
0090     });
0091 }
0092 
0093 void WindowSystem::setCurrentToken(const QString &token)
0094 {
0095     m_lastToken = token;
0096 }
0097 
0098 quint32 WindowSystem::lastInputSerial(QWindow *window)
0099 {
0100     auto waylandWindow = window ? dynamic_cast<QtWaylandClient::QWaylandWindow *>(window->handle()) : nullptr;
0101     if (!waylandWindow) {
0102         // Should never get here
0103         return 0;
0104     }
0105     return waylandWindow->display()->lastInputSerial();
0106 }
0107 
0108 WId WindowSystem::activeWindow()
0109 {
0110     qCDebug(KWAYLAND_KWS) << "This plugin does not support querying the active window";
0111     return 0;
0112 }
0113 
0114 bool WindowSystem::allowedActionsSupported()
0115 {
0116     return false;
0117 }
0118 
0119 void WindowSystem::allowExternalProcessWindowActivation(int pid)
0120 {
0121     Q_UNUSED(pid)
0122 }
0123 
0124 bool WindowSystem::compositingActive()
0125 {
0126     // wayland is always composited
0127     return true;
0128 }
0129 
0130 void WindowSystem::connectNotify(const QMetaMethod &signal)
0131 {
0132     Q_UNUSED(signal)
0133 }
0134 
0135 QPoint WindowSystem::constrainViewportRelativePosition(const QPoint &pos)
0136 {
0137     Q_UNUSED(pos)
0138     qCDebug(KWAYLAND_KWS) << "This plugin does not support viewport positions";
0139     return QPoint();
0140 }
0141 
0142 int WindowSystem::currentDesktop()
0143 {
0144     qCDebug(KWAYLAND_KWS) << "This plugin does not support virtual desktops";
0145     return 0;
0146 }
0147 
0148 #if KWINDOWSYSTEM_BUILD_DEPRECATED_SINCE(5, 101)
0149 void WindowSystem::demandAttention(WId win, bool set)
0150 {
0151     Q_UNUSED(win)
0152     Q_UNUSED(set)
0153     qCDebug(KWAYLAND_KWS) << "This plugin does not support demanding attention";
0154 }
0155 #endif
0156 
0157 QString WindowSystem::desktopName(int desktop)
0158 {
0159     Q_UNUSED(desktop)
0160     qCDebug(KWAYLAND_KWS) << "This plugin does not support virtual desktops";
0161     return QString();
0162 }
0163 
0164 QPoint WindowSystem::desktopToViewport(int desktop, bool absolute)
0165 {
0166     Q_UNUSED(desktop)
0167     Q_UNUSED(absolute)
0168     qCDebug(KWAYLAND_KWS) << "This plugin does not support viewport positions";
0169     return QPoint();
0170 }
0171 
0172 #if KWINDOWSYSTEM_BUILD_DEPRECATED_SINCE(5, 0)
0173 WId WindowSystem::groupLeader(WId window)
0174 {
0175     Q_UNUSED(window)
0176     qCDebug(KWAYLAND_KWS) << "This plugin does not support group leader";
0177     return 0;
0178 }
0179 #endif
0180 
0181 bool WindowSystem::icccmCompliantMappingState()
0182 {
0183     return false;
0184 }
0185 
0186 QPixmap WindowSystem::icon(WId win, int width, int height, bool scale, int flags)
0187 {
0188     Q_UNUSED(win)
0189     Q_UNUSED(width)
0190     Q_UNUSED(height)
0191     Q_UNUSED(scale)
0192     Q_UNUSED(flags)
0193     qCDebug(KWAYLAND_KWS) << "This plugin does not support getting window icons";
0194     return QPixmap();
0195 }
0196 
0197 void WindowSystem::lowerWindow(WId win)
0198 {
0199     Q_UNUSED(win)
0200     qCDebug(KWAYLAND_KWS) << "This plugin does not support lower window";
0201 }
0202 
0203 bool WindowSystem::mapViewport()
0204 {
0205     qCDebug(KWAYLAND_KWS) << "This plugin does not support viewport positions";
0206     return false;
0207 }
0208 
0209 void WindowSystem::minimizeWindow(WId win)
0210 {
0211     Q_UNUSED(win)
0212     qCDebug(KWAYLAND_KWS) << "This plugin does not support minimizing windows";
0213 }
0214 
0215 void WindowSystem::unminimizeWindow(WId win)
0216 {
0217     Q_UNUSED(win)
0218     qCDebug(KWAYLAND_KWS) << "This plugin does not support unminimizing windows";
0219 }
0220 
0221 int WindowSystem::numberOfDesktops()
0222 {
0223     qCDebug(KWAYLAND_KWS) << "This plugin does not support virtual desktops";
0224     return 1;
0225 }
0226 
0227 void WindowSystem::raiseWindow(WId win)
0228 {
0229     Q_UNUSED(win)
0230     qCDebug(KWAYLAND_KWS) << "This plugin does not support raising windows";
0231 }
0232 
0233 QString WindowSystem::readNameProperty(WId window, long unsigned int atom)
0234 {
0235     Q_UNUSED(window)
0236     Q_UNUSED(atom)
0237     qCDebug(KWAYLAND_KWS) << "This plugin does not support reading X11 properties";
0238     return QString();
0239 }
0240 
0241 void WindowSystem::setBlockingCompositing(WId window, bool active)
0242 {
0243     Q_UNUSED(window)
0244     Q_UNUSED(active)
0245     qCDebug(KWAYLAND_KWS) << "This plugin does not support blocking compositing";
0246 }
0247 
0248 void WindowSystem::setCurrentDesktop(int desktop)
0249 {
0250     Q_UNUSED(desktop)
0251     qCDebug(KWAYLAND_KWS) << "This plugin does not support virtual desktops";
0252 }
0253 
0254 void WindowSystem::setDesktopName(int desktop, const QString &name)
0255 {
0256     Q_UNUSED(desktop)
0257     Q_UNUSED(name)
0258     qCDebug(KWAYLAND_KWS) << "This plugin does not support virtual desktops";
0259 }
0260 
0261 void WindowSystem::setExtendedStrut(WId win,
0262                                     int left_width,
0263                                     int left_start,
0264                                     int left_end,
0265                                     int right_width,
0266                                     int right_start,
0267                                     int right_end,
0268                                     int top_width,
0269                                     int top_start,
0270                                     int top_end,
0271                                     int bottom_width,
0272                                     int bottom_start,
0273                                     int bottom_end)
0274 {
0275     Q_UNUSED(win)
0276     Q_UNUSED(left_width)
0277     Q_UNUSED(left_start)
0278     Q_UNUSED(left_end)
0279     Q_UNUSED(right_width)
0280     Q_UNUSED(right_start)
0281     Q_UNUSED(right_end)
0282     Q_UNUSED(top_width)
0283     Q_UNUSED(top_start)
0284     Q_UNUSED(top_end)
0285     Q_UNUSED(bottom_width)
0286     Q_UNUSED(bottom_start)
0287     Q_UNUSED(bottom_end)
0288     qCDebug(KWAYLAND_KWS) << "This plugin does not support window struts";
0289 }
0290 
0291 void WindowSystem::setStrut(WId win, int left, int right, int top, int bottom)
0292 {
0293     Q_UNUSED(win)
0294     Q_UNUSED(left)
0295     Q_UNUSED(right)
0296     Q_UNUSED(top)
0297     Q_UNUSED(bottom)
0298     qCDebug(KWAYLAND_KWS) << "This plugin does not support window struts";
0299 }
0300 
0301 #if KWINDOWSYSTEM_BUILD_DEPRECATED_SINCE(5, 101)
0302 void WindowSystem::setIcons(WId win, const QPixmap &icon, const QPixmap &miniIcon)
0303 {
0304     Q_UNUSED(win)
0305     Q_UNUSED(icon)
0306     Q_UNUSED(miniIcon)
0307     qCDebug(KWAYLAND_KWS) << "This plugin does not support setting window icons";
0308 }
0309 #endif
0310 
0311 void WindowSystem::setOnActivities(WId win, const QStringList &activities)
0312 {
0313     Q_UNUSED(win)
0314     Q_UNUSED(activities)
0315     qCDebug(KWAYLAND_KWS) << "This plugin does not support activities";
0316 }
0317 
0318 void WindowSystem::setOnAllDesktops(WId win, bool b)
0319 {
0320     Q_UNUSED(win)
0321     Q_UNUSED(b)
0322     qCDebug(KWAYLAND_KWS) << "This plugin does not support setting window on all desktops";
0323 }
0324 
0325 void WindowSystem::setOnDesktop(WId win, int desktop)
0326 {
0327     Q_UNUSED(win)
0328     Q_UNUSED(desktop)
0329     qCDebug(KWAYLAND_KWS) << "This plugin does not support setting window on a specific desktop";
0330 }
0331 
0332 void WindowSystem::setShowingDesktop(bool showing)
0333 {
0334     if (!WaylandIntegration::self()->plasmaWindowManagement()) {
0335         return;
0336     }
0337     WaylandIntegration::self()->plasmaWindowManagement()->setShowingDesktop(showing);
0338 }
0339 
0340 void WindowSystem::clearState(WId win, NET::States state)
0341 {
0342     Surface *s = Surface::fromQtWinId(win);
0343     if (!s) {
0344         return;
0345     }
0346 
0347     KWayland::Client::PlasmaShellSurface *plasmaShellSurface = nullptr;
0348 
0349     if (state & NET::SkipTaskbar || state & NET::SkipSwitcher) {
0350         if (!WaylandIntegration::self()->waylandPlasmaShell()) {
0351             return;
0352         }
0353         plasmaShellSurface = PlasmaShellSurface::get(s);
0354         if (!plasmaShellSurface) {
0355             plasmaShellSurface = WaylandIntegration::self()->waylandPlasmaShell()->createSurface(s, this);
0356         }
0357         if (!plasmaShellSurface) {
0358             return;
0359         }
0360     }
0361 
0362     if (state & NET::SkipTaskbar) {
0363         plasmaShellSurface->setSkipTaskbar(false);
0364     }
0365 
0366     if (state & NET::SkipSwitcher) {
0367         plasmaShellSurface->setSkipSwitcher(false);
0368     }
0369 
0370     if (state & NET::Max) {
0371         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Max window state";
0372     }
0373     if (state & NET::FullScreen) {
0374         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing FullScreen window state";
0375     }
0376     if (state & NET::Modal) {
0377         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Modal window state";
0378     }
0379     if (state & NET::Sticky) {
0380         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Sticky window state";
0381     }
0382     if (state & NET::Shaded) {
0383         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Shaded window state";
0384     }
0385     if (state & NET::KeepAbove) {
0386         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing KeepAbove window state";
0387     }
0388     if (state & NET::KeepAbove) {
0389         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing StaysOnTop window state";
0390     }
0391     if (state & NET::SkipPager) {
0392         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing SkipPager window state";
0393     }
0394     if (state & NET::Hidden) {
0395         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Hidden window state";
0396     }
0397     if (state & NET::KeepBelow) {
0398         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing KeepBelow window state";
0399     }
0400     if (state & NET::DemandsAttention) {
0401         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing DemandsAttention window state";
0402     }
0403 }
0404 
0405 void WindowSystem::setState(WId win, NET::States state)
0406 {
0407     Surface *s = Surface::fromQtWinId(win);
0408     if (!s) {
0409         return;
0410     }
0411 
0412     KWayland::Client::PlasmaShellSurface *plasmaShellSurface = nullptr;
0413 
0414     if (state & NET::SkipTaskbar || state & NET::SkipSwitcher) {
0415         if (!WaylandIntegration::self()->waylandPlasmaShell()) {
0416             return;
0417         }
0418         plasmaShellSurface = PlasmaShellSurface::get(s);
0419         if (!plasmaShellSurface) {
0420             plasmaShellSurface = WaylandIntegration::self()->waylandPlasmaShell()->createSurface(s, this);
0421         }
0422         if (!plasmaShellSurface) {
0423             return;
0424         }
0425     }
0426 
0427     if (state & NET::SkipTaskbar) {
0428         plasmaShellSurface->setSkipTaskbar(true);
0429     }
0430 
0431     if (state & NET::SkipSwitcher) {
0432         plasmaShellSurface->setSkipSwitcher(true);
0433     }
0434 
0435     if (state & NET::Max) {
0436         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Max window state";
0437     }
0438     if (state & NET::FullScreen) {
0439         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing FullScreen window state";
0440     }
0441     if (state & NET::Modal) {
0442         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Modal window state";
0443     }
0444     if (state & NET::Sticky) {
0445         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Sticky window state";
0446     }
0447     if (state & NET::Shaded) {
0448         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Shaded window state";
0449     }
0450     if (state & NET::KeepAbove) {
0451         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing KeepAbove window state";
0452     }
0453     if (state & NET::KeepAbove) {
0454         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing StaysOnTop window state";
0455     }
0456     if (state & NET::SkipPager) {
0457         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing SkipPager window state";
0458     }
0459     if (state & NET::Hidden) {
0460         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing Hidden window state";
0461     }
0462     if (state & NET::KeepBelow) {
0463         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing KeepBelow window state";
0464     }
0465     if (state & NET::DemandsAttention) {
0466         qCDebug(KWAYLAND_KWS) << "This plugin does not support changing DemandsAttention window state";
0467     }
0468 }
0469 
0470 void WindowSystem::setType(WId win, NET::WindowType windowType)
0471 {
0472     if (!WaylandIntegration::self()->waylandPlasmaShell()) {
0473         return;
0474     }
0475     KWayland::Client::PlasmaShellSurface::Role role;
0476 
0477     switch (windowType) {
0478     case NET::Normal:
0479         role = KWayland::Client::PlasmaShellSurface::Role::Normal;
0480         break;
0481     case NET::Desktop:
0482         role = KWayland::Client::PlasmaShellSurface::Role::Desktop;
0483         break;
0484     case NET::Dock:
0485         role = KWayland::Client::PlasmaShellSurface::Role::Panel;
0486         break;
0487     case NET::OnScreenDisplay:
0488         role = KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay;
0489         break;
0490     case NET::Notification:
0491         role = KWayland::Client::PlasmaShellSurface::Role::Notification;
0492         break;
0493     case NET::Tooltip:
0494     case NET::PopupMenu:
0495         role = KWayland::Client::PlasmaShellSurface::Role::ToolTip;
0496         break;
0497     case NET::CriticalNotification:
0498         role = KWayland::Client::PlasmaShellSurface::Role::CriticalNotification;
0499         break;
0500     default:
0501         return;
0502     }
0503     Surface *s = Surface::fromQtWinId(win);
0504     if (!s) {
0505         return;
0506     }
0507     KWayland::Client::PlasmaShellSurface *shellSurface = WaylandIntegration::self()->waylandPlasmaShell()->createSurface(s, this);
0508 
0509     shellSurface->setRole(role);
0510 }
0511 
0512 void WindowSystem::setUserTime(WId win, long int time)
0513 {
0514     Q_UNUSED(win)
0515     Q_UNUSED(time)
0516     qCDebug(KWAYLAND_KWS) << "This plugin does not support setting user type";
0517 }
0518 
0519 bool WindowSystem::showingDesktop()
0520 {
0521     if (!WaylandIntegration::self()->plasmaWindowManagement()) {
0522         return false;
0523     }
0524     return WaylandIntegration::self()->plasmaWindowManagement()->isShowingDesktop();
0525 }
0526 
0527 QList<WId> WindowSystem::stackingOrder()
0528 {
0529     qCDebug(KWAYLAND_KWS) << "This plugin does not support getting windows";
0530     return QList<WId>();
0531 }
0532 
0533 #if KWINDOWSYSTEM_BUILD_DEPRECATED_SINCE(5, 0)
0534 WId WindowSystem::transientFor(WId window)
0535 {
0536     Q_UNUSED(window)
0537     qCDebug(KWAYLAND_KWS) << "This plugin does not support transient for windows";
0538     return 0;
0539 }
0540 #endif
0541 
0542 int WindowSystem::viewportToDesktop(const QPoint &pos)
0543 {
0544     Q_UNUSED(pos)
0545     qCDebug(KWAYLAND_KWS) << "This plugin does not support viewports";
0546     return 0;
0547 }
0548 
0549 int WindowSystem::viewportWindowToDesktop(const QRect &r)
0550 {
0551     Q_UNUSED(r)
0552     qCDebug(KWAYLAND_KWS) << "This plugin does not support viewports";
0553     return 0;
0554 }
0555 
0556 QList<WId> WindowSystem::windows()
0557 {
0558     return stackingOrder();
0559 }
0560 
0561 QRect WindowSystem::workArea(const QList<WId> &excludes, int desktop)
0562 {
0563     Q_UNUSED(excludes)
0564     Q_UNUSED(desktop)
0565     qCDebug(KWAYLAND_KWS) << "This plugin does not support work area";
0566     return QRect();
0567 }
0568 
0569 QRect WindowSystem::workArea(int desktop)
0570 {
0571     Q_UNUSED(desktop)
0572     qCDebug(KWAYLAND_KWS) << "This plugin does not support work area";
0573     return QRect();
0574 }