File indexing completed on 2024-11-10 04:56:41

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "decoratedclient.h"
0010 #include "cursor.h"
0011 #include "decorationbridge.h"
0012 #include "decorationpalette.h"
0013 #include "window.h"
0014 #include "workspace.h"
0015 #include "x11window.h"
0016 
0017 #include <KDecoration2/DecoratedClient>
0018 #include <KDecoration2/Decoration>
0019 
0020 #include <QDebug>
0021 #include <QStyle>
0022 #include <QToolTip>
0023 
0024 namespace KWin
0025 {
0026 namespace Decoration
0027 {
0028 
0029 DecoratedClientImpl::DecoratedClientImpl(Window *window, KDecoration2::DecoratedClient *decoratedClient, KDecoration2::Decoration *decoration)
0030     : QObject()
0031     , ApplicationMenuEnabledDecoratedClientPrivate(decoratedClient, decoration)
0032     , m_window(window)
0033     , m_clientSize(window->clientSize().toSize())
0034 {
0035     window->setDecoratedClient(this);
0036     connect(window, &Window::activeChanged, this, [decoratedClient, window]() {
0037         Q_EMIT decoratedClient->activeChanged(window->isActive());
0038     });
0039     connect(window, &Window::clientGeometryChanged, this, [decoratedClient, this]() {
0040         if (m_window->clientSize() == m_clientSize) {
0041             return;
0042         }
0043         const auto oldSize = m_clientSize;
0044         m_clientSize = m_window->clientSize().toSize();
0045         if (oldSize.width() != m_clientSize.width()) {
0046             Q_EMIT decoratedClient->widthChanged(m_clientSize.width());
0047         }
0048         if (oldSize.height() != m_clientSize.height()) {
0049             Q_EMIT decoratedClient->heightChanged(m_clientSize.height());
0050         }
0051         Q_EMIT decoratedClient->sizeChanged(m_clientSize);
0052     });
0053     connect(window, &Window::desktopsChanged, this, [decoratedClient, window]() {
0054         Q_EMIT decoratedClient->onAllDesktopsChanged(window->isOnAllDesktops());
0055     });
0056     connect(window, &Window::captionChanged, this, [decoratedClient, window]() {
0057         Q_EMIT decoratedClient->captionChanged(window->caption());
0058     });
0059     connect(window, &Window::iconChanged, this, [decoratedClient, window]() {
0060         Q_EMIT decoratedClient->iconChanged(window->icon());
0061     });
0062     connect(window, &Window::shadeChanged, this, &Decoration::DecoratedClientImpl::signalShadeChange);
0063     connect(window, &Window::keepAboveChanged, decoratedClient, &KDecoration2::DecoratedClient::keepAboveChanged);
0064     connect(window, &Window::keepBelowChanged, decoratedClient, &KDecoration2::DecoratedClient::keepBelowChanged);
0065     connect(window, &Window::quickTileModeChanged, decoratedClient, [this, decoratedClient]() {
0066         Q_EMIT decoratedClient->adjacentScreenEdgesChanged(adjacentScreenEdges());
0067     });
0068     connect(window, &Window::closeableChanged, decoratedClient, &KDecoration2::DecoratedClient::closeableChanged);
0069     connect(window, &Window::shadeableChanged, decoratedClient, &KDecoration2::DecoratedClient::shadeableChanged);
0070     connect(window, &Window::minimizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::minimizeableChanged);
0071     connect(window, &Window::maximizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::maximizeableChanged);
0072 
0073     connect(window, &Window::paletteChanged, decoratedClient, &KDecoration2::DecoratedClient::paletteChanged);
0074 
0075     connect(window, &Window::hasApplicationMenuChanged, decoratedClient, &KDecoration2::DecoratedClient::hasApplicationMenuChanged);
0076     connect(window, &Window::applicationMenuActiveChanged, decoratedClient, &KDecoration2::DecoratedClient::applicationMenuActiveChanged);
0077 
0078     m_toolTipWakeUp.setSingleShot(true);
0079     connect(&m_toolTipWakeUp, &QTimer::timeout, this, [this]() {
0080         int fallAsleepDelay = QApplication::style()->styleHint(QStyle::SH_ToolTip_FallAsleepDelay);
0081         this->m_toolTipFallAsleep.setRemainingTime(fallAsleepDelay);
0082 
0083         QToolTip::showText(Cursors::self()->mouse()->pos().toPoint(), this->m_toolTipText);
0084         m_toolTipShowing = true;
0085     });
0086 }
0087 
0088 DecoratedClientImpl::~DecoratedClientImpl()
0089 {
0090     if (m_toolTipShowing) {
0091         requestHideToolTip();
0092     }
0093 }
0094 
0095 void DecoratedClientImpl::signalShadeChange()
0096 {
0097     Q_EMIT decoratedClient()->shadedChanged(m_window->isShade());
0098 }
0099 
0100 #define DELEGATE(type, name, clientName)   \
0101     type DecoratedClientImpl::name() const \
0102     {                                      \
0103         return m_window->clientName();     \
0104     }
0105 
0106 #define DELEGATE2(type, name) DELEGATE(type, name, name)
0107 
0108 DELEGATE2(QString, caption)
0109 DELEGATE2(bool, isActive)
0110 DELEGATE2(bool, isCloseable)
0111 DELEGATE(bool, isMaximizeable, isMaximizable)
0112 DELEGATE(bool, isMinimizeable, isMinimizable)
0113 DELEGATE2(bool, isModal)
0114 DELEGATE(bool, isMoveable, isMovable)
0115 DELEGATE(bool, isResizeable, isResizable)
0116 DELEGATE2(bool, isShadeable)
0117 DELEGATE2(bool, providesContextHelp)
0118 DELEGATE2(bool, isOnAllDesktops)
0119 DELEGATE2(QPalette, palette)
0120 DELEGATE2(QIcon, icon)
0121 
0122 #undef DELEGATE2
0123 #undef DELEGATE
0124 
0125 #define DELEGATE(type, name, clientName)   \
0126     type DecoratedClientImpl::name() const \
0127     {                                      \
0128         return m_window->clientName();     \
0129     }
0130 
0131 DELEGATE(bool, isKeepAbove, keepAbove)
0132 DELEGATE(bool, isKeepBelow, keepBelow)
0133 DELEGATE(bool, isShaded, isShade)
0134 
0135 #undef DELEGATE
0136 
0137 WId DecoratedClientImpl::windowId() const
0138 {
0139     if (X11Window *x11Window = qobject_cast<X11Window *>(m_window)) {
0140         return x11Window->window();
0141     }
0142     return 0;
0143 }
0144 
0145 WId DecoratedClientImpl::decorationId() const
0146 {
0147     if (X11Window *x11Window = qobject_cast<X11Window *>(m_window)) {
0148         return x11Window->frameId();
0149     }
0150     return 0;
0151 }
0152 
0153 #define DELEGATE(name, op)                                                \
0154     void DecoratedClientImpl::name()                                      \
0155     {                                                                     \
0156         if (m_window->isDeleted()) {                                      \
0157             return;                                                       \
0158         }                                                                 \
0159         Workspace::self()->performWindowOperation(m_window, Options::op); \
0160     }
0161 
0162 DELEGATE(requestToggleShade, ShadeOp)
0163 DELEGATE(requestToggleOnAllDesktops, OnAllDesktopsOp)
0164 DELEGATE(requestToggleKeepAbove, KeepAboveOp)
0165 DELEGATE(requestToggleKeepBelow, KeepBelowOp)
0166 
0167 #undef DELEGATE
0168 
0169 #define DELEGATE(name, clientName)   \
0170     void DecoratedClientImpl::name() \
0171     {                                \
0172         if (m_window->isDeleted()) { \
0173             return;                  \
0174         }                            \
0175         m_window->clientName();      \
0176     }
0177 
0178 DELEGATE(requestContextHelp, showContextHelp)
0179 
0180 #undef DELEGATE
0181 
0182 void DecoratedClientImpl::requestMinimize()
0183 {
0184     m_window->setMinimized(true);
0185 }
0186 
0187 void DecoratedClientImpl::requestClose()
0188 {
0189     if (m_window->isDeleted()) {
0190         return;
0191     }
0192     QMetaObject::invokeMethod(m_window, &Window::closeWindow, Qt::QueuedConnection);
0193 }
0194 
0195 QColor DecoratedClientImpl::color(KDecoration2::ColorGroup group, KDecoration2::ColorRole role) const
0196 {
0197     auto dp = m_window->decorationPalette();
0198     if (dp) {
0199         return dp->color(group, role);
0200     }
0201 
0202     return QColor();
0203 }
0204 
0205 void DecoratedClientImpl::requestShowToolTip(const QString &text)
0206 {
0207     if (m_window->isDeleted()) {
0208         return;
0209     }
0210     if (!workspace()->decorationBridge()->showToolTips()) {
0211         return;
0212     }
0213 
0214     m_toolTipText = text;
0215 
0216     int wakeUpDelay = QApplication::style()->styleHint(QStyle::SH_ToolTip_WakeUpDelay);
0217     m_toolTipWakeUp.start(m_toolTipFallAsleep.hasExpired() ? wakeUpDelay : 20);
0218 }
0219 
0220 void DecoratedClientImpl::requestHideToolTip()
0221 {
0222     m_toolTipWakeUp.stop();
0223     QToolTip::hideText();
0224     m_toolTipShowing = false;
0225 }
0226 
0227 void DecoratedClientImpl::requestShowWindowMenu(const QRect &rect)
0228 {
0229     if (m_window->isDeleted()) {
0230         return;
0231     }
0232     Workspace::self()->showWindowMenu(QRectF(m_window->pos() + rect.topLeft(), m_window->pos() + rect.bottomRight()).toRect(), m_window);
0233 }
0234 
0235 void DecoratedClientImpl::requestShowApplicationMenu(const QRect &rect, int actionId)
0236 {
0237     if (m_window->isDeleted()) {
0238         return;
0239     }
0240     Workspace::self()->showApplicationMenu(rect, m_window, actionId);
0241 }
0242 
0243 void DecoratedClientImpl::showApplicationMenu(int actionId)
0244 {
0245     if (m_window->isDeleted()) {
0246         return;
0247     }
0248     decoration()->showApplicationMenu(actionId);
0249 }
0250 
0251 void DecoratedClientImpl::requestToggleMaximization(Qt::MouseButtons buttons)
0252 {
0253     if (m_window->isDeleted()) {
0254         return;
0255     }
0256     auto operation = options->operationMaxButtonClick(buttons);
0257     QMetaObject::invokeMethod(
0258         this, [this, operation] {
0259             delayedRequestToggleMaximization(operation);
0260         },
0261         Qt::QueuedConnection);
0262 }
0263 
0264 void DecoratedClientImpl::delayedRequestToggleMaximization(Options::WindowOperation operation)
0265 {
0266     if (m_window->isDeleted()) {
0267         return;
0268     }
0269     Workspace::self()->performWindowOperation(m_window, operation);
0270 }
0271 
0272 int DecoratedClientImpl::width() const
0273 {
0274     return m_clientSize.width();
0275 }
0276 
0277 int DecoratedClientImpl::height() const
0278 {
0279     return m_clientSize.height();
0280 }
0281 
0282 QSize DecoratedClientImpl::size() const
0283 {
0284     return m_clientSize;
0285 }
0286 
0287 bool DecoratedClientImpl::isMaximizedVertically() const
0288 {
0289     return m_window->requestedMaximizeMode() & MaximizeVertical;
0290 }
0291 
0292 bool DecoratedClientImpl::isMaximized() const
0293 {
0294     return isMaximizedHorizontally() && isMaximizedVertically();
0295 }
0296 
0297 bool DecoratedClientImpl::isMaximizedHorizontally() const
0298 {
0299     return m_window->requestedMaximizeMode() & MaximizeHorizontal;
0300 }
0301 
0302 Qt::Edges DecoratedClientImpl::adjacentScreenEdges() const
0303 {
0304     Qt::Edges edges;
0305     const QuickTileMode mode = m_window->quickTileMode();
0306     if (mode.testFlag(QuickTileFlag::Left)) {
0307         edges |= Qt::LeftEdge;
0308         if (!mode.testFlag(QuickTileFlag::Top) && !mode.testFlag(QuickTileFlag::Bottom)) {
0309             // using complete side
0310             edges |= Qt::TopEdge | Qt::BottomEdge;
0311         }
0312     }
0313     if (mode.testFlag(QuickTileFlag::Top)) {
0314         edges |= Qt::TopEdge;
0315     }
0316     if (mode.testFlag(QuickTileFlag::Right)) {
0317         edges |= Qt::RightEdge;
0318         if (!mode.testFlag(QuickTileFlag::Top) && !mode.testFlag(QuickTileFlag::Bottom)) {
0319             // using complete side
0320             edges |= Qt::TopEdge | Qt::BottomEdge;
0321         }
0322     }
0323     if (mode.testFlag(QuickTileFlag::Bottom)) {
0324         edges |= Qt::BottomEdge;
0325     }
0326     return edges;
0327 }
0328 
0329 bool DecoratedClientImpl::hasApplicationMenu() const
0330 {
0331     return m_window->hasApplicationMenu();
0332 }
0333 
0334 bool DecoratedClientImpl::isApplicationMenuActive() const
0335 {
0336     return m_window->applicationMenuActive();
0337 }
0338 
0339 QString DecoratedClientImpl::windowClass() const
0340 {
0341     return m_window->resourceName() + QLatin1Char(' ') + m_window->resourceClass();
0342 }
0343 
0344 }
0345 }
0346 
0347 #include "moc_decoratedclient.cpp"