1 /*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 #include "decoratedclient.h"
10 #include "decorationbridge.h"
11 #include "decorationpalette.h"
12 #include "abstract_client.h"
13 #include "cursor.h"
14 #include "workspace.h"
15
16 #include <KDecoration2/DecoratedClient>
17 #include <KDecoration2/Decoration>
18
19 #include <QDebug>
20 #include <QStyle>
21 #include <QToolTip>
22
23 namespace KWin
24 {
25 namespace Decoration
26 {
27
DecoratedClientImpl(AbstractClient * client,KDecoration2::DecoratedClient * decoratedClient,KDecoration2::Decoration * decoration)28 DecoratedClientImpl::DecoratedClientImpl(AbstractClient *client, KDecoration2::DecoratedClient *decoratedClient, KDecoration2::Decoration *decoration)
29 : QObject()
30 , ApplicationMenuEnabledDecoratedClientPrivate(decoratedClient, decoration)
31 , m_client(client)
32 , m_clientSize(client->clientSize())
33 {
34 client->setDecoratedClient(QPointer<DecoratedClientImpl>(this));
35 connect(client, &AbstractClient::activeChanged, this,
36 [decoratedClient, client]() {
37 Q_EMIT decoratedClient->activeChanged(client->isActive());
38 }
39 );
40 connect(client, &AbstractClient::clientGeometryChanged, this,
41 [decoratedClient, this]() {
42 if (m_client->clientSize() == m_clientSize) {
43 return;
44 }
45 const auto oldSize = m_clientSize;
46 m_clientSize = m_client->clientSize();
47 if (oldSize.width() != m_clientSize.width()) {
48 Q_EMIT decoratedClient->widthChanged(m_clientSize.width());
49 }
50 if (oldSize.height() != m_clientSize.height()) {
51 Q_EMIT decoratedClient->heightChanged(m_clientSize.height());
52 }
53 Q_EMIT decoratedClient->sizeChanged(m_clientSize);
54 }
55 );
56 connect(client, &AbstractClient::desktopChanged, this,
57 [decoratedClient, client]() {
58 Q_EMIT decoratedClient->onAllDesktopsChanged(client->isOnAllDesktops());
59 }
60 );
61 connect(client, &AbstractClient::captionChanged, this,
62 [decoratedClient, client]() {
63 Q_EMIT decoratedClient->captionChanged(client->caption());
64 }
65 );
66 connect(client, &AbstractClient::iconChanged, this,
67 [decoratedClient, client]() {
68 Q_EMIT decoratedClient->iconChanged(client->icon());
69 }
70 );
71 connect(client, &AbstractClient::shadeChanged, this,
72 &Decoration::DecoratedClientImpl::signalShadeChange);
73 connect(client, &AbstractClient::keepAboveChanged, decoratedClient, &KDecoration2::DecoratedClient::keepAboveChanged);
74 connect(client, &AbstractClient::keepBelowChanged, decoratedClient, &KDecoration2::DecoratedClient::keepBelowChanged);
75 connect(client, &AbstractClient::quickTileModeChanged, decoratedClient,
76 [this, decoratedClient]() {
77 Q_EMIT decoratedClient->adjacentScreenEdgesChanged(adjacentScreenEdges());
78 }
79 );
80 connect(client, &AbstractClient::closeableChanged, decoratedClient, &KDecoration2::DecoratedClient::closeableChanged);
81 connect(client, &AbstractClient::shadeableChanged, decoratedClient, &KDecoration2::DecoratedClient::shadeableChanged);
82 connect(client, &AbstractClient::minimizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::minimizeableChanged);
83 connect(client, &AbstractClient::maximizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::maximizeableChanged);
84
85 connect(client, &AbstractClient::paletteChanged, decoratedClient, &KDecoration2::DecoratedClient::paletteChanged);
86
87 connect(client, &AbstractClient::hasApplicationMenuChanged, decoratedClient, &KDecoration2::DecoratedClient::hasApplicationMenuChanged);
88 connect(client, &AbstractClient::applicationMenuActiveChanged, decoratedClient, &KDecoration2::DecoratedClient::applicationMenuActiveChanged);
89
90 m_toolTipWakeUp.setSingleShot(true);
91 connect(&m_toolTipWakeUp, &QTimer::timeout, this,
92 [this]() {
93 int fallAsleepDelay = QApplication::style()->styleHint(QStyle::SH_ToolTip_FallAsleepDelay);
94 this->m_toolTipFallAsleep.setRemainingTime(fallAsleepDelay);
95
96 QToolTip::showText(Cursors::self()->mouse()->pos(), this->m_toolTipText);
97 m_toolTipShowing = true;
98 }
99 );
100 }
101
~DecoratedClientImpl()102 DecoratedClientImpl::~DecoratedClientImpl()
103 {
104 if (m_toolTipShowing) {
105 requestHideToolTip();
106 }
107 }
108
signalShadeChange()109 void DecoratedClientImpl::signalShadeChange() {
110 Q_EMIT decoratedClient()->shadedChanged(m_client->isShade());
111 }
112
113 #define DELEGATE(type, name, clientName) \
114 type DecoratedClientImpl::name() const \
115 { \
116 return m_client->clientName(); \
117 }
118
119 #define DELEGATE2(type, name) DELEGATE(type, name, name)
120
DELEGATE2(QString,caption)121 DELEGATE2(QString, caption)
122 DELEGATE2(bool, isActive)
123 DELEGATE2(bool, isCloseable)
124 DELEGATE(bool, isMaximizeable, isMaximizable)
125 DELEGATE(bool, isMinimizeable, isMinimizable)
126 DELEGATE2(bool, isModal)
127 DELEGATE(bool, isMoveable, isMovable)
128 DELEGATE(bool, isResizeable, isResizable)
129 DELEGATE2(bool, isShadeable)
130 DELEGATE2(bool, providesContextHelp)
131 DELEGATE2(int, desktop)
132 DELEGATE2(bool, isOnAllDesktops)
133 DELEGATE2(QPalette, palette)
134 DELEGATE2(QIcon, icon)
135
136 #undef DELEGATE2
137 #undef DELEGATE
138
139 #define DELEGATE(type, name, clientName) \
140 type DecoratedClientImpl::name() const \
141 { \
142 return m_client->clientName(); \
143 }
144
145 DELEGATE(bool, isKeepAbove, keepAbove)
146 DELEGATE(bool, isKeepBelow, keepBelow)
147 DELEGATE(bool, isShaded, isShade)
148 DELEGATE(WId, windowId, window)
149 DELEGATE(WId, decorationId, frameId)
150
151 #undef DELEGATE
152
153 #define DELEGATE(name, op) \
154 void DecoratedClientImpl::name() \
155 { \
156 Workspace::self()->performWindowOperation(m_client, Options::op); \
157 }
158
159 DELEGATE(requestToggleShade, ShadeOp)
160 DELEGATE(requestToggleOnAllDesktops, OnAllDesktopsOp)
161 DELEGATE(requestToggleKeepAbove, KeepAboveOp)
162 DELEGATE(requestToggleKeepBelow, KeepBelowOp)
163
164 #undef DELEGATE
165
166 #define DELEGATE(name, clientName) \
167 void DecoratedClientImpl::name() \
168 { \
169 m_client->clientName(); \
170 }
171
172 DELEGATE(requestContextHelp, showContextHelp)
173 DELEGATE(requestMinimize, minimize)
174
175 #undef DELEGATE
176
177 void DecoratedClientImpl::requestClose()
178 {
179 QMetaObject::invokeMethod(m_client, &AbstractClient::closeWindow, Qt::QueuedConnection);
180 }
181
color(KDecoration2::ColorGroup group,KDecoration2::ColorRole role) const182 QColor DecoratedClientImpl::color(KDecoration2::ColorGroup group, KDecoration2::ColorRole role) const
183 {
184 auto dp = m_client->decorationPalette();
185 if (dp) {
186 return dp->color(group, role);
187 }
188
189 return QColor();
190 }
191
requestShowToolTip(const QString & text)192 void DecoratedClientImpl::requestShowToolTip(const QString &text)
193 {
194 if (!DecorationBridge::self()->showToolTips()) {
195 return;
196 }
197
198 m_toolTipText = text;
199
200 int wakeUpDelay = QApplication::style()->styleHint(QStyle::SH_ToolTip_WakeUpDelay);
201 m_toolTipWakeUp.start(m_toolTipFallAsleep.hasExpired() ? wakeUpDelay : 20);
202 }
203
requestHideToolTip()204 void DecoratedClientImpl::requestHideToolTip()
205 {
206 m_toolTipWakeUp.stop();
207 QToolTip::hideText();
208 m_toolTipShowing = false;
209 }
210
requestShowWindowMenu(const QRect & rect)211 void DecoratedClientImpl::requestShowWindowMenu(const QRect &rect)
212 {
213 Workspace::self()->showWindowMenu(QRect(m_client->pos() + rect.topLeft(), m_client->pos() + rect.bottomRight()), m_client);
214 }
215
requestShowApplicationMenu(const QRect & rect,int actionId)216 void DecoratedClientImpl::requestShowApplicationMenu(const QRect &rect, int actionId)
217 {
218 Workspace::self()->showApplicationMenu(rect, m_client, actionId);
219 }
220
showApplicationMenu(int actionId)221 void DecoratedClientImpl::showApplicationMenu(int actionId)
222 {
223 decoration()->showApplicationMenu(actionId);
224 }
225
requestToggleMaximization(Qt::MouseButtons buttons)226 void DecoratedClientImpl::requestToggleMaximization(Qt::MouseButtons buttons)
227 {
228 QMetaObject::invokeMethod(this, "delayedRequestToggleMaximization", Qt::QueuedConnection, Q_ARG(Options::WindowOperation, options->operationMaxButtonClick(buttons)));
229 }
230
delayedRequestToggleMaximization(Options::WindowOperation operation)231 void DecoratedClientImpl::delayedRequestToggleMaximization(Options::WindowOperation operation)
232 {
233 Workspace::self()->performWindowOperation(m_client, operation);
234 }
235
width() const236 int DecoratedClientImpl::width() const
237 {
238 return m_clientSize.width();
239 }
240
height() const241 int DecoratedClientImpl::height() const
242 {
243 return m_clientSize.height();
244 }
245
size() const246 QSize DecoratedClientImpl::size() const
247 {
248 return m_clientSize;
249 }
250
isMaximizedVertically() const251 bool DecoratedClientImpl::isMaximizedVertically() const
252 {
253 return m_client->requestedMaximizeMode() & MaximizeVertical;
254 }
255
isMaximized() const256 bool DecoratedClientImpl::isMaximized() const
257 {
258 return isMaximizedHorizontally() && isMaximizedVertically();
259 }
260
isMaximizedHorizontally() const261 bool DecoratedClientImpl::isMaximizedHorizontally() const
262 {
263 return m_client->requestedMaximizeMode() & MaximizeHorizontal;
264 }
265
adjacentScreenEdges() const266 Qt::Edges DecoratedClientImpl::adjacentScreenEdges() const
267 {
268 Qt::Edges edges;
269 const QuickTileMode mode = m_client->quickTileMode();
270 if (mode.testFlag(QuickTileFlag::Left)) {
271 edges |= Qt::LeftEdge;
272 if (!mode.testFlag(QuickTileFlag::Top) && !mode.testFlag(QuickTileFlag::Bottom)) {
273 // using complete side
274 edges |= Qt::TopEdge | Qt::BottomEdge;
275 }
276 }
277 if (mode.testFlag(QuickTileFlag::Top)) {
278 edges |= Qt::TopEdge;
279 }
280 if (mode.testFlag(QuickTileFlag::Right)) {
281 edges |= Qt::RightEdge;
282 if (!mode.testFlag(QuickTileFlag::Top) && !mode.testFlag(QuickTileFlag::Bottom)) {
283 // using complete side
284 edges |= Qt::TopEdge | Qt::BottomEdge;
285 }
286 }
287 if (mode.testFlag(QuickTileFlag::Bottom)) {
288 edges |= Qt::BottomEdge;
289 }
290 return edges;
291 }
292
hasApplicationMenu() const293 bool DecoratedClientImpl::hasApplicationMenu() const
294 {
295 return m_client->hasApplicationMenu();
296 }
297
isApplicationMenuActive() const298 bool DecoratedClientImpl::isApplicationMenuActive() const
299 {
300 return m_client->applicationMenuActive();
301 }
302
303 }
304 }
305