File indexing completed on 2024-05-19 16:34:02

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 
0016 #include <KDecoration2/DecoratedClient>
0017 #include <KDecoration2/Decoration>
0018 
0019 #include <QDebug>
0020 #include <QStyle>
0021 #include <QToolTip>
0022 
0023 namespace KWin
0024 {
0025 namespace Decoration
0026 {
0027 
0028 DecoratedClientImpl::DecoratedClientImpl(Window *window, KDecoration2::DecoratedClient *decoratedClient, KDecoration2::Decoration *decoration)
0029     : QObject()
0030     , ApplicationMenuEnabledDecoratedClientPrivate(decoratedClient, decoration)
0031     , m_window(window)
0032     , m_clientSize(window->clientSize().toSize())
0033 {
0034     window->setDecoratedClient(QPointer<DecoratedClientImpl>(this));
0035     connect(window, &Window::activeChanged, this, [decoratedClient, window]() {
0036         Q_EMIT decoratedClient->activeChanged(window->isActive());
0037     });
0038     connect(window, &Window::clientGeometryChanged, this, [decoratedClient, this]() {
0039         if (m_window->clientSize() == m_clientSize) {
0040             return;
0041         }
0042         const auto oldSize = m_clientSize;
0043         m_clientSize = m_window->clientSize().toSize();
0044         if (oldSize.width() != m_clientSize.width()) {
0045             Q_EMIT decoratedClient->widthChanged(m_clientSize.width());
0046         }
0047         if (oldSize.height() != m_clientSize.height()) {
0048             Q_EMIT decoratedClient->heightChanged(m_clientSize.height());
0049         }
0050         Q_EMIT decoratedClient->sizeChanged(m_clientSize);
0051     });
0052     connect(window, &Window::desktopChanged, this, [decoratedClient, window]() {
0053         Q_EMIT decoratedClient->onAllDesktopsChanged(window->isOnAllDesktops());
0054     });
0055     connect(window, &Window::captionChanged, this, [decoratedClient, window]() {
0056         Q_EMIT decoratedClient->captionChanged(window->caption());
0057     });
0058     connect(window, &Window::iconChanged, this, [decoratedClient, window]() {
0059         Q_EMIT decoratedClient->iconChanged(window->icon());
0060     });
0061     connect(window, &Window::shadeChanged, this, &Decoration::DecoratedClientImpl::signalShadeChange);
0062     connect(window, &Window::keepAboveChanged, decoratedClient, &KDecoration2::DecoratedClient::keepAboveChanged);
0063     connect(window, &Window::keepBelowChanged, decoratedClient, &KDecoration2::DecoratedClient::keepBelowChanged);
0064     connect(window, &Window::quickTileModeChanged, decoratedClient, [this, decoratedClient]() {
0065         Q_EMIT decoratedClient->adjacentScreenEdgesChanged(adjacentScreenEdges());
0066     });
0067     connect(window, &Window::closeableChanged, decoratedClient, &KDecoration2::DecoratedClient::closeableChanged);
0068     connect(window, &Window::shadeableChanged, decoratedClient, &KDecoration2::DecoratedClient::shadeableChanged);
0069     connect(window, &Window::minimizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::minimizeableChanged);
0070     connect(window, &Window::maximizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::maximizeableChanged);
0071 
0072     connect(window, &Window::paletteChanged, decoratedClient, &KDecoration2::DecoratedClient::paletteChanged);
0073 
0074     connect(window, &Window::hasApplicationMenuChanged, decoratedClient, &KDecoration2::DecoratedClient::hasApplicationMenuChanged);
0075     connect(window, &Window::applicationMenuActiveChanged, decoratedClient, &KDecoration2::DecoratedClient::applicationMenuActiveChanged);
0076 
0077     m_toolTipWakeUp.setSingleShot(true);
0078     connect(&m_toolTipWakeUp, &QTimer::timeout, this, [this]() {
0079         int fallAsleepDelay = QApplication::style()->styleHint(QStyle::SH_ToolTip_FallAsleepDelay);
0080         this->m_toolTipFallAsleep.setRemainingTime(fallAsleepDelay);
0081 
0082         QToolTip::showText(Cursors::self()->mouse()->pos(), this->m_toolTipText);
0083         m_toolTipShowing = true;
0084     });
0085 }
0086 
0087 DecoratedClientImpl::~DecoratedClientImpl()
0088 {
0089     if (m_toolTipShowing) {
0090         requestHideToolTip();
0091     }
0092 }
0093 
0094 void DecoratedClientImpl::signalShadeChange()
0095 {
0096     Q_EMIT decoratedClient()->shadedChanged(m_window->isShade());
0097 }
0098 
0099 #define DELEGATE(type, name, clientName)   \
0100     type DecoratedClientImpl::name() const \
0101     {                                      \
0102         return m_window->clientName();     \
0103     }
0104 
0105 #define DELEGATE2(type, name) DELEGATE(type, name, name)
0106 
0107 DELEGATE2(QString, caption)
0108 DELEGATE2(bool, isActive)
0109 DELEGATE2(bool, isCloseable)
0110 DELEGATE(bool, isMaximizeable, isMaximizable)
0111 DELEGATE(bool, isMinimizeable, isMinimizable)
0112 DELEGATE2(bool, isModal)
0113 DELEGATE(bool, isMoveable, isMovable)
0114 DELEGATE(bool, isResizeable, isResizable)
0115 DELEGATE2(bool, isShadeable)
0116 DELEGATE2(bool, providesContextHelp)
0117 DELEGATE2(int, desktop)
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 DELEGATE(WId, windowId, window)
0135 DELEGATE(WId, decorationId, frameId)
0136 
0137 #undef DELEGATE
0138 
0139 #define DELEGATE(name, op)                                                \
0140     void DecoratedClientImpl::name()                                      \
0141     {                                                                     \
0142         Workspace::self()->performWindowOperation(m_window, Options::op); \
0143     }
0144 
0145 DELEGATE(requestToggleShade, ShadeOp)
0146 DELEGATE(requestToggleOnAllDesktops, OnAllDesktopsOp)
0147 DELEGATE(requestToggleKeepAbove, KeepAboveOp)
0148 DELEGATE(requestToggleKeepBelow, KeepBelowOp)
0149 
0150 #undef DELEGATE
0151 
0152 #define DELEGATE(name, clientName)   \
0153     void DecoratedClientImpl::name() \
0154     {                                \
0155         m_window->clientName();      \
0156     }
0157 
0158 DELEGATE(requestContextHelp, showContextHelp)
0159 DELEGATE(requestMinimize, minimize)
0160 
0161 #undef DELEGATE
0162 
0163 void DecoratedClientImpl::requestClose()
0164 {
0165     QMetaObject::invokeMethod(m_window, &Window::closeWindow, Qt::QueuedConnection);
0166 }
0167 
0168 QColor DecoratedClientImpl::color(KDecoration2::ColorGroup group, KDecoration2::ColorRole role) const
0169 {
0170     auto dp = m_window->decorationPalette();
0171     if (dp) {
0172         return dp->color(group, role);
0173     }
0174 
0175     return QColor();
0176 }
0177 
0178 void DecoratedClientImpl::requestShowToolTip(const QString &text)
0179 {
0180     if (!workspace()->decorationBridge()->showToolTips()) {
0181         return;
0182     }
0183 
0184     m_toolTipText = text;
0185 
0186     int wakeUpDelay = QApplication::style()->styleHint(QStyle::SH_ToolTip_WakeUpDelay);
0187     m_toolTipWakeUp.start(m_toolTipFallAsleep.hasExpired() ? wakeUpDelay : 20);
0188 }
0189 
0190 void DecoratedClientImpl::requestHideToolTip()
0191 {
0192     m_toolTipWakeUp.stop();
0193     QToolTip::hideText();
0194     m_toolTipShowing = false;
0195 }
0196 
0197 void DecoratedClientImpl::requestShowWindowMenu(const QRect &rect)
0198 {
0199     Workspace::self()->showWindowMenu(QRectF(m_window->pos() + rect.topLeft(), m_window->pos() + rect.bottomRight()).toRect(), m_window);
0200 }
0201 
0202 void DecoratedClientImpl::requestShowApplicationMenu(const QRect &rect, int actionId)
0203 {
0204     Workspace::self()->showApplicationMenu(rect, m_window, actionId);
0205 }
0206 
0207 void DecoratedClientImpl::showApplicationMenu(int actionId)
0208 {
0209     decoration()->showApplicationMenu(actionId);
0210 }
0211 
0212 void DecoratedClientImpl::requestToggleMaximization(Qt::MouseButtons buttons)
0213 {
0214     auto operation = options->operationMaxButtonClick(buttons);
0215     QMetaObject::invokeMethod(
0216         this, [this, operation] {
0217             delayedRequestToggleMaximization(operation);
0218         },
0219         Qt::QueuedConnection);
0220 }
0221 
0222 void DecoratedClientImpl::delayedRequestToggleMaximization(Options::WindowOperation operation)
0223 {
0224     Workspace::self()->performWindowOperation(m_window, operation);
0225 }
0226 
0227 int DecoratedClientImpl::width() const
0228 {
0229     return m_clientSize.width();
0230 }
0231 
0232 int DecoratedClientImpl::height() const
0233 {
0234     return m_clientSize.height();
0235 }
0236 
0237 QSize DecoratedClientImpl::size() const
0238 {
0239     return m_clientSize;
0240 }
0241 
0242 bool DecoratedClientImpl::isMaximizedVertically() const
0243 {
0244     return m_window->requestedMaximizeMode() & MaximizeVertical;
0245 }
0246 
0247 bool DecoratedClientImpl::isMaximized() const
0248 {
0249     return isMaximizedHorizontally() && isMaximizedVertically();
0250 }
0251 
0252 bool DecoratedClientImpl::isMaximizedHorizontally() const
0253 {
0254     return m_window->requestedMaximizeMode() & MaximizeHorizontal;
0255 }
0256 
0257 Qt::Edges DecoratedClientImpl::adjacentScreenEdges() const
0258 {
0259     Qt::Edges edges;
0260     const QuickTileMode mode = m_window->quickTileMode();
0261     if (mode.testFlag(QuickTileFlag::Left)) {
0262         edges |= Qt::LeftEdge;
0263         if (!mode.testFlag(QuickTileFlag::Top) && !mode.testFlag(QuickTileFlag::Bottom)) {
0264             // using complete side
0265             edges |= Qt::TopEdge | Qt::BottomEdge;
0266         }
0267     }
0268     if (mode.testFlag(QuickTileFlag::Top)) {
0269         edges |= Qt::TopEdge;
0270     }
0271     if (mode.testFlag(QuickTileFlag::Right)) {
0272         edges |= Qt::RightEdge;
0273         if (!mode.testFlag(QuickTileFlag::Top) && !mode.testFlag(QuickTileFlag::Bottom)) {
0274             // using complete side
0275             edges |= Qt::TopEdge | Qt::BottomEdge;
0276         }
0277     }
0278     if (mode.testFlag(QuickTileFlag::Bottom)) {
0279         edges |= Qt::BottomEdge;
0280     }
0281     return edges;
0282 }
0283 
0284 bool DecoratedClientImpl::hasApplicationMenu() const
0285 {
0286     return m_window->hasApplicationMenu();
0287 }
0288 
0289 bool DecoratedClientImpl::isApplicationMenuActive() const
0290 {
0291     return m_window->applicationMenuActive();
0292 }
0293 
0294 QString DecoratedClientImpl::windowClass() const
0295 {
0296     return m_window->resourceName() + QLatin1Char(' ') + m_window->resourceClass();
0297 }
0298 
0299 }
0300 }