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"