decoratedclient.cpp 10.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/********************************************************************
 KWin - the KDE window manager
 This file is part of the KDE project.

Copyright (C) 2014 Martin Gräßlin <mgraesslin@kde.org>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "decoratedclient.h"
21
#include "decorationbridge.h"
22
#include "decorationpalette.h"
23
#include "decorationrenderer.h"
24
#include "abstract_client.h"
25
26
27
#include "composite.h"
#include "cursor.h"
#include "options.h"
28
#include "platform.h"
29
30
31
32
33
34
#include "workspace.h"

#include <KDecoration2/DecoratedClient>
#include <KDecoration2/Decoration>

#include <QDebug>
35
#include <QStyle>
Martin Flöser's avatar
Martin Flöser committed
36
#include <QToolTip>
37
38
39
40
41
42

namespace KWin
{
namespace Decoration
{

43
DecoratedClientImpl::DecoratedClientImpl(AbstractClient *client, KDecoration2::DecoratedClient *decoratedClient, KDecoration2::Decoration *decoration)
44
    : QObject()
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
45
    , ApplicationMenuEnabledDecoratedClientPrivate(decoratedClient, decoration)
46
    , m_client(client)
47
    , m_clientSize(client->clientSize())
48
49
50
    , m_renderer(nullptr)
{
    createRenderer();
51
    client->setDecoratedClient(QPointer<DecoratedClientImpl>(this));
52
    connect(client, &AbstractClient::activeChanged, this,
53
54
55
56
        [decoratedClient, client]() {
            emit decoratedClient->activeChanged(client->isActive());
        }
    );
57
    connect(client, &AbstractClient::geometryChanged, this,
58
59
60
61
62
63
64
65
66
67
68
69
        [decoratedClient, this]() {
            if (m_client->clientSize() == m_clientSize) {
                return;
            }
            const auto oldSize = m_clientSize;
            m_clientSize = m_client->clientSize();
            if (oldSize.width() != m_clientSize.width()) {
                emit decoratedClient->widthChanged(m_clientSize.width());
            }
            if (oldSize.height() != m_clientSize.height()) {
                emit decoratedClient->heightChanged(m_clientSize.height());
            }
70
            emit decoratedClient->sizeChanged(m_clientSize);
71
72
        }
    );
73
    connect(client, &AbstractClient::desktopChanged, this,
74
75
76
77
        [decoratedClient, client]() {
            emit decoratedClient->onAllDesktopsChanged(client->isOnAllDesktops());
        }
    );
78
    connect(client, &AbstractClient::captionChanged, this,
79
80
81
82
        [decoratedClient, client]() {
            emit decoratedClient->captionChanged(client->caption());
        }
    );
83
    connect(client, &AbstractClient::iconChanged, this,
84
85
86
87
        [decoratedClient, client]() {
            emit decoratedClient->iconChanged(client->icon());
        }
    );
88
    connect(client, &AbstractClient::shadeChanged, this,
89
            &Decoration::DecoratedClientImpl::signalShadeChange);
90
91
    connect(client, &AbstractClient::keepAboveChanged, decoratedClient, &KDecoration2::DecoratedClient::keepAboveChanged);
    connect(client, &AbstractClient::keepBelowChanged, decoratedClient, &KDecoration2::DecoratedClient::keepBelowChanged);
92
    connect(Compositor::self(), &Compositor::aboutToToggleCompositing, this, &DecoratedClientImpl::destroyRenderer);
93
    m_compositorToggledConnection = connect(Compositor::self(), &Compositor::compositingToggled, this,
94
95
96
97
98
        [this, decoration]() {
            createRenderer();
            decoration->update();
        }
    );
99
100
101
102
103
104
    connect(Compositor::self(), &Compositor::aboutToDestroy, this,
        [this] {
            disconnect(m_compositorToggledConnection);
            m_compositorToggledConnection = QMetaObject::Connection();
        }
    );
105
    connect(client, &AbstractClient::quickTileModeChanged, decoratedClient,
106
        [this, decoratedClient]() {
107
            emit decoratedClient->adjacentScreenEdgesChanged(adjacentScreenEdges());
108
109
        }
    );
110
111
112
113
    connect(client, &AbstractClient::closeableChanged, decoratedClient, &KDecoration2::DecoratedClient::closeableChanged);
    connect(client, &AbstractClient::shadeableChanged, decoratedClient, &KDecoration2::DecoratedClient::shadeableChanged);
    connect(client, &AbstractClient::minimizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::minimizeableChanged);
    connect(client, &AbstractClient::maximizeableChanged, decoratedClient, &KDecoration2::DecoratedClient::maximizeableChanged);
114

115
    connect(client, &AbstractClient::paletteChanged, decoratedClient, &KDecoration2::DecoratedClient::paletteChanged);
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
116
117
118

    connect(client, &AbstractClient::hasApplicationMenuChanged, decoratedClient, &KDecoration2::DecoratedClient::hasApplicationMenuChanged);
    connect(client, &AbstractClient::applicationMenuActiveChanged, decoratedClient, &KDecoration2::DecoratedClient::applicationMenuActiveChanged);
119
120
121
122
123
124
125
126

    m_toolTipWakeUp.setSingleShot(true);
    connect(&m_toolTipWakeUp, &QTimer::timeout, this,
            [this]() {
                int fallAsleepDelay = QApplication::style()->styleHint(QStyle::SH_ToolTip_FallAsleepDelay);
                this->m_toolTipFallAsleep.setRemainingTime(fallAsleepDelay);

                QToolTip::showText(Cursor::pos(), this->m_toolTipText);
127
                m_toolTipShowing = true;
128
129
            }
    );
130
131
}

132
133
134
135
136
137
DecoratedClientImpl::~DecoratedClientImpl()
{
    if (m_toolTipShowing) {
        requestHideToolTip();
    }
}
138

139
140
141
142
void DecoratedClientImpl::signalShadeChange() {
    emit decoratedClient()->shadedChanged(m_client->isShade());
}

143
#define DELEGATE(type, name, clientName) \
144
145
    type DecoratedClientImpl::name() const \
    { \
146
        return m_client->clientName(); \
147
148
    }

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#define DELEGATE2(type, name) DELEGATE(type, name, name)

DELEGATE2(QString, caption)
DELEGATE2(bool, isActive)
DELEGATE2(bool, isCloseable)
DELEGATE(bool, isMaximizeable, isMaximizable)
DELEGATE(bool, isMinimizeable, isMinimizable)
DELEGATE2(bool, isModal)
DELEGATE(bool, isMoveable, isMovable)
DELEGATE(bool, isResizeable, isResizable)
DELEGATE2(bool, isShadeable)
DELEGATE2(bool, providesContextHelp)
DELEGATE2(int, desktop)
DELEGATE2(bool, isOnAllDesktops)
DELEGATE2(QPalette, palette)
DELEGATE2(QIcon, icon)
165

166
#undef DELEGATE2
167
168
169
170
171
172
173
174
175
176
177
#undef DELEGATE

#define DELEGATE(type, name, clientName) \
    type DecoratedClientImpl::name() const \
    { \
        return m_client->clientName(); \
    }

DELEGATE(bool, isKeepAbove, keepAbove)
DELEGATE(bool, isKeepBelow, keepBelow)
DELEGATE(bool, isShaded, isShade)
178
DELEGATE(WId, windowId, windowId)
179
180
181
182
183
184
185
DELEGATE(WId, decorationId, frameId)

#undef DELEGATE

#define DELEGATE(name, op) \
    void DecoratedClientImpl::name() \
    { \
186
        Workspace::self()->performWindowOperation(m_client, Options::op); \
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
    }

DELEGATE(requestToggleShade, ShadeOp)
DELEGATE(requestToggleOnAllDesktops, OnAllDesktopsOp)
DELEGATE(requestToggleKeepAbove, KeepAboveOp)
DELEGATE(requestToggleKeepBelow, KeepBelowOp)

#undef DELEGATE

#define DELEGATE(name, clientName) \
    void DecoratedClientImpl::name() \
    { \
        m_client->clientName(); \
    }

DELEGATE(requestContextHelp, showContextHelp)
DELEGATE(requestMinimize, minimize)

#undef DELEGATE

207
208
209
210
211
void DecoratedClientImpl::requestClose()
{
    QMetaObject::invokeMethod(m_client, "closeWindow", Qt::QueuedConnection);
}

212
213
214
215
216
217
218
219
220
221
QColor DecoratedClientImpl::color(KDecoration2::ColorGroup group, KDecoration2::ColorRole role) const
{
    auto dp = m_client->decorationPalette();
    if (dp) {
        return dp->color(group, role);
    }

    return QColor();
}

Martin Flöser's avatar
Martin Flöser committed
222
223
void DecoratedClientImpl::requestShowToolTip(const QString &text)
{
224
225
226
227
    if (!DecorationBridge::self()->showToolTips()) {
        return;
    }

228
229
230
231
    m_toolTipText = text;

    int wakeUpDelay = QApplication::style()->styleHint(QStyle::SH_ToolTip_WakeUpDelay);
    m_toolTipWakeUp.start(m_toolTipFallAsleep.hasExpired() ? wakeUpDelay : 20);
Martin Flöser's avatar
Martin Flöser committed
232
233
234
235
}

void DecoratedClientImpl::requestHideToolTip()
{
236
    m_toolTipWakeUp.stop();
Martin Flöser's avatar
Martin Flöser committed
237
    QToolTip::hideText();
238
    m_toolTipShowing = false;
Martin Flöser's avatar
Martin Flöser committed
239
240
}

241
242
243
244
245
246
void DecoratedClientImpl::requestShowWindowMenu()
{
    // TODO: add rect to requestShowWindowMenu
    Workspace::self()->showWindowMenu(QRect(Cursor::pos(), Cursor::pos()), m_client);
}

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
247
248
249
250
251
252
253
254
255
256
void DecoratedClientImpl::requestShowApplicationMenu(const QRect &rect, int actionId)
{
    Workspace::self()->showApplicationMenu(rect, m_client, actionId);
}

void DecoratedClientImpl::showApplicationMenu(int actionId)
{
    decoration()->showApplicationMenu(actionId);
}

257
void DecoratedClientImpl::requestToggleMaximization(Qt::MouseButtons buttons)
258
{
259
260
261
262
263
264
    QMetaObject::invokeMethod(this, "delayedRequestToggleMaximization", Qt::QueuedConnection, Q_ARG(Options::WindowOperation, options->operationMaxButtonClick(buttons)));
}

void DecoratedClientImpl::delayedRequestToggleMaximization(Options::WindowOperation operation)
{
    Workspace::self()->performWindowOperation(m_client, operation);
265
266
267
268
}

int DecoratedClientImpl::width() const
{
269
    return m_clientSize.width();
270
271
272
273
}

int DecoratedClientImpl::height() const
{
274
    return m_clientSize.height();
275
276
}

277
278
279
280
281
QSize DecoratedClientImpl::size() const
{
    return m_clientSize;
}

282
283
bool DecoratedClientImpl::isMaximizedVertically() const
{
284
    return m_client->requestedMaximizeMode() & MaximizeVertical;
285
286
287
288
289
290
291
292
293
}

bool DecoratedClientImpl::isMaximized() const
{
    return isMaximizedHorizontally() && isMaximizedVertically();
}

bool DecoratedClientImpl::isMaximizedHorizontally() const
{
294
    return m_client->requestedMaximizeMode() & MaximizeHorizontal;
295
296
}

297
Qt::Edges DecoratedClientImpl::adjacentScreenEdges() const
298
299
{
    Qt::Edges edges;
300
301
    const QuickTileMode mode = m_client->quickTileMode();
    if (mode.testFlag(QuickTileFlag::Left)) {
302
        edges |= Qt::LeftEdge;
303
        if (!mode.testFlag(QuickTileFlag::Top) && !mode.testFlag(QuickTileFlag::Bottom)) {
304
305
306
307
            // using complete side
            edges |= Qt::TopEdge | Qt::BottomEdge;
        }
    }
308
    if (mode.testFlag(QuickTileFlag::Top)) {
309
310
        edges |= Qt::TopEdge;
    }
311
    if (mode.testFlag(QuickTileFlag::Right)) {
312
        edges |= Qt::RightEdge;
313
        if (!mode.testFlag(QuickTileFlag::Top) && !mode.testFlag(QuickTileFlag::Bottom)) {
314
315
316
317
            // using complete side
            edges |= Qt::TopEdge | Qt::BottomEdge;
        }
    }
318
    if (mode.testFlag(QuickTileFlag::Bottom)) {
319
320
321
322
323
        edges |= Qt::BottomEdge;
    }
    return edges;
}

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
324
325
326
327
328
329
330
331
332
333
bool DecoratedClientImpl::hasApplicationMenu() const
{
    return m_client->hasApplicationMenu();
}

bool DecoratedClientImpl::isApplicationMenuActive() const
{
    return m_client->applicationMenuActive();
}

334
335
void DecoratedClientImpl::createRenderer()
{
336
    m_renderer = kwinApp()->platform()->createDecorationRenderer(this);
337
338
}

339
340
341
342
343
344
void DecoratedClientImpl::destroyRenderer()
{
    delete m_renderer;
    m_renderer = nullptr;
}

345
346
}
}