File indexing completed on 2024-12-22 05:15:19

0001 /*
0002     SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "dashboardwindow.h"
0008 
0009 #include <QCoreApplication>
0010 #include <QIcon>
0011 #include <QScreen>
0012 
0013 #include <KWayland/Client/connection_thread.h>
0014 #include <KWayland/Client/plasmashell.h>
0015 #include <KWayland/Client/registry.h>
0016 #include <KWayland/Client/surface.h>
0017 #include <KWindowEffects>
0018 #include <KWindowSystem>
0019 #include <KX11Extras>
0020 
0021 DashboardWindow::DashboardWindow(QQuickItem *parent)
0022     : QQuickWindow(parent ? parent->window() : nullptr)
0023     , m_mainItem(nullptr)
0024     , m_visualParentItem(nullptr)
0025     , m_visualParentWindow(nullptr)
0026 {
0027     setFlags(Qt::FramelessWindowHint);
0028 
0029     setIcon(QIcon::fromTheme(QStringLiteral("plasma")));
0030 
0031     connect(&m_theme, &Plasma::Theme::themeChanged, this, &DashboardWindow::updateTheme);
0032 
0033     if (KWindowSystem::isPlatformWayland()) {
0034         KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(this);
0035         Q_ASSERT(connection);
0036 
0037         KWayland::Client::Registry *registry = new KWayland::Client::Registry(this);
0038         registry->create(connection);
0039 
0040         connect(registry, &KWayland::Client::Registry::plasmaShellAnnounced, this, [this, registry](quint32 name, quint32 version) {
0041             m_plasmashell = registry->createPlasmaShell(name, version, this);
0042         });
0043 
0044         registry->setup();
0045         connection->roundtrip();
0046     }
0047 }
0048 
0049 DashboardWindow::~DashboardWindow()
0050 {
0051 }
0052 
0053 QQuickItem *DashboardWindow::mainItem() const
0054 {
0055     return m_mainItem;
0056 }
0057 
0058 void DashboardWindow::setMainItem(QQuickItem *item)
0059 {
0060     if (m_mainItem != item) {
0061         if (m_mainItem) {
0062             m_mainItem->setVisible(false);
0063         }
0064 
0065         m_mainItem = item;
0066 
0067         if (m_mainItem) {
0068             m_mainItem->setVisible(isVisible());
0069             m_mainItem->setParentItem(contentItem());
0070         }
0071 
0072         Q_EMIT mainItemChanged();
0073     }
0074 }
0075 
0076 QQuickItem *DashboardWindow::visualParent() const
0077 {
0078     return m_visualParentItem;
0079 }
0080 
0081 void DashboardWindow::setVisualParent(QQuickItem *item)
0082 {
0083     if (m_visualParentItem != item) {
0084         if (m_visualParentItem) {
0085             disconnect(m_visualParentItem.data(), &QQuickItem::windowChanged, this, &DashboardWindow::visualParentWindowChanged);
0086         }
0087 
0088         m_visualParentItem = item;
0089 
0090         if (m_visualParentItem) {
0091             if (m_visualParentItem->window()) {
0092                 visualParentWindowChanged(m_visualParentItem->window());
0093             }
0094 
0095             connect(m_visualParentItem.data(), &QQuickItem::windowChanged, this, &DashboardWindow::visualParentWindowChanged);
0096         }
0097 
0098         Q_EMIT visualParentChanged();
0099     }
0100 }
0101 
0102 QColor DashboardWindow::backgroundColor() const
0103 {
0104     return color();
0105 }
0106 
0107 void DashboardWindow::setBackgroundColor(const QColor &c)
0108 {
0109     if (color() != c) {
0110         setColor(c);
0111 
0112         Q_EMIT backgroundColorChanged();
0113     }
0114 }
0115 
0116 QQuickItem *DashboardWindow::keyEventProxy() const
0117 {
0118     return m_keyEventProxy;
0119 }
0120 
0121 void DashboardWindow::setKeyEventProxy(QQuickItem *item)
0122 {
0123     if (m_keyEventProxy != item) {
0124         m_keyEventProxy = item;
0125 
0126         Q_EMIT keyEventProxyChanged();
0127     }
0128 }
0129 
0130 void DashboardWindow::toggle()
0131 {
0132     if (isVisible()) {
0133         close();
0134     } else {
0135         resize(screen()->size());
0136         showFullScreen();
0137         KX11Extras::forceActiveWindow(winId());
0138     }
0139 }
0140 
0141 bool DashboardWindow::event(QEvent *event)
0142 {
0143     if (event->type() == QEvent::PlatformSurface) {
0144         const QPlatformSurfaceEvent *pSEvent = static_cast<QPlatformSurfaceEvent *>(event);
0145 
0146         if (pSEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) {
0147             if (KWindowSystem::isPlatformX11()) {
0148                 KX11Extras::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher);
0149             } else {
0150                 if (m_plasmashell) {
0151                     auto *surface = KWayland::Client::Surface::fromQtWinId(winId());
0152                     auto *plasmashellSurface = KWayland::Client::PlasmaShellSurface::get(surface);
0153 
0154                     if (!plasmashellSurface) {
0155                         plasmashellSurface = m_plasmashell->createSurface(surface, this);
0156                     }
0157 
0158                     plasmashellSurface->setSkipSwitcher(true);
0159                     plasmashellSurface->setSkipTaskbar(true);
0160                 }
0161             }
0162         }
0163     } else if (event->type() == QEvent::Show) {
0164         updateTheme();
0165 
0166         if (m_mainItem) {
0167             m_mainItem->setVisible(true);
0168         }
0169     } else if (event->type() == QEvent::Hide) {
0170         if (m_mainItem) {
0171             m_mainItem->setVisible(false);
0172         }
0173     } else if (event->type() == QEvent::FocusOut) {
0174         if (isVisible()) {
0175             KX11Extras::forceActiveWindow(winId());
0176         }
0177     }
0178 
0179     return QQuickWindow::event(event);
0180 }
0181 
0182 void DashboardWindow::keyPressEvent(QKeyEvent *e)
0183 {
0184     if (e->key() == Qt::Key_Escape) {
0185         Q_EMIT keyEscapePressed();
0186 
0187         return;
0188         // clang-format off
0189     } else if (m_keyEventProxy && !m_keyEventProxy->hasActiveFocus()
0190         && !(e->key() == Qt::Key_Home)
0191         && !(e->key() == Qt::Key_End)
0192         && !(e->key() == Qt::Key_Left)
0193         && !(e->key() == Qt::Key_Up)
0194         && !(e->key() == Qt::Key_Right)
0195         && !(e->key() == Qt::Key_Down)
0196         && !(e->key() == Qt::Key_PageUp)
0197         && !(e->key() == Qt::Key_PageDown)
0198         && !(e->key() == Qt::Key_Enter)
0199         && !(e->key() == Qt::Key_Return)
0200         && !(e->key() == Qt::Key_Menu)
0201         && !(e->key() == Qt::Key_Tab)
0202         && !(e->key() == Qt::Key_Backtab)) {
0203         // clang-format on
0204         QPointer<QQuickItem> previousFocusItem = activeFocusItem();
0205 
0206         m_keyEventProxy->forceActiveFocus();
0207         QEvent *eventCopy = new QKeyEvent(e->type(),
0208                                           e->key(),
0209                                           e->modifiers(),
0210                                           e->nativeScanCode(),
0211                                           e->nativeVirtualKey(),
0212                                           e->nativeModifiers(),
0213                                           e->text(),
0214                                           e->isAutoRepeat(),
0215                                           e->count());
0216         QCoreApplication::postEvent(this, eventCopy);
0217 
0218         // We _need_ to do it twice to make sure the event ping-pong needed
0219         // for delivery happens before we sap focus again.
0220         QCoreApplication::processEvents();
0221         QCoreApplication::processEvents();
0222 
0223         if (previousFocusItem) {
0224             previousFocusItem->forceActiveFocus();
0225         }
0226 
0227         return;
0228     }
0229 
0230     QQuickWindow::keyPressEvent(e);
0231 }
0232 
0233 void DashboardWindow::updateTheme()
0234 {
0235     KWindowEffects::enableBlurBehind(this, true);
0236 }
0237 
0238 void DashboardWindow::visualParentWindowChanged(QQuickWindow *window)
0239 {
0240     if (m_visualParentWindow) {
0241         disconnect(m_visualParentWindow.data(), &QQuickWindow::screenChanged, this, &DashboardWindow::visualParentScreenChanged);
0242     }
0243 
0244     m_visualParentWindow = window;
0245 
0246     if (m_visualParentWindow) {
0247         visualParentScreenChanged(m_visualParentWindow->screen());
0248 
0249         connect(m_visualParentWindow.data(), &QQuickWindow::screenChanged, this, &DashboardWindow::visualParentScreenChanged);
0250     }
0251 }
0252 
0253 void DashboardWindow::visualParentScreenChanged(QScreen *screen)
0254 {
0255     if (screen) {
0256         setScreen(screen);
0257         setGeometry(screen->geometry());
0258     }
0259 }