~gabriel1984sibiu/minitube/qt5.6

« back to all changes in this revision

Viewing changes to src/widgets/util/qsystemtrayicon_x11.cpp

  • Committer: Grevutiu Gabriel
  • Date: 2017-06-13 08:43:17 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20170613084317-ek0zqe0u9g3ocvi8
OriginalĀ upstreamĀ code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2016 The Qt Company Ltd.
 
4
** Contact: https://www.qt.io/licensing/
 
5
**
 
6
** This file is part of the QtWidgets module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and The Qt Company. For licensing terms
 
14
** and conditions see https://www.qt.io/terms-conditions. For further
 
15
** information use the contact form at https://www.qt.io/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 3 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL3 included in the
 
21
** packaging of this file. Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 3 requirements
 
23
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
 
24
**
 
25
** GNU General Public License Usage
 
26
** Alternatively, this file may be used under the terms of the GNU
 
27
** General Public License version 2.0 or (at your option) the GNU General
 
28
** Public license version 3 or any later version approved by the KDE Free
 
29
** Qt Foundation. The licenses are as published by the Free Software
 
30
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
 
31
** included in the packaging of this file. Please review the following
 
32
** information to ensure the GNU General Public License requirements will
 
33
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
 
34
** https://www.gnu.org/licenses/gpl-3.0.html.
 
35
**
 
36
** $QT_END_LICENSE$
 
37
**
 
38
****************************************************************************/
 
39
 
 
40
#include "qlabel.h"
 
41
#include "qpainter.h"
 
42
#include "qpixmap.h"
 
43
#include "qbitmap.h"
 
44
#include "qevent.h"
 
45
#include "qapplication.h"
 
46
#include "qlist.h"
 
47
#include "qmenu.h"
 
48
#include "qtimer.h"
 
49
#include "qsystemtrayicon_p.h"
 
50
#include "qpaintengine.h"
 
51
#include <qwindow.h>
 
52
#include <qguiapplication.h>
 
53
#include <qscreen.h>
 
54
#include <qbackingstore.h>
 
55
#include <qpa/qplatformnativeinterface.h>
 
56
#include <qpa/qplatformsystemtrayicon.h>
 
57
#include <qpa/qplatformtheme.h>
 
58
#include <private/qguiapplication_p.h>
 
59
#include <qdebug.h>
 
60
 
 
61
#include <QtPlatformHeaders/qxcbwindowfunctions.h>
 
62
#include <QtPlatformHeaders/qxcbintegrationfunctions.h>
 
63
#ifndef QT_NO_SYSTEMTRAYICON
 
64
QT_BEGIN_NAMESPACE
 
65
 
 
66
static inline unsigned long locateSystemTray()
 
67
{
 
68
    return (unsigned long)QGuiApplication::platformNativeInterface()->nativeResourceForScreen(QByteArrayLiteral("traywindow"), QGuiApplication::primaryScreen());
 
69
}
 
70
 
 
71
// System tray widget. Could be replaced by a QWindow with
 
72
// a backing store if it did not need tooltip handling.
 
73
class QSystemTrayIconSys : public QWidget
 
74
{
 
75
    Q_OBJECT
 
76
public:
 
77
    explicit QSystemTrayIconSys(QSystemTrayIcon *q);
 
78
 
 
79
    inline void updateIcon() { update(); }
 
80
    inline QSystemTrayIcon *systemTrayIcon() const { return q; }
 
81
 
 
82
    QRect globalGeometry() const;
 
83
 
 
84
protected:
 
85
    virtual void mousePressEvent(QMouseEvent *ev) Q_DECL_OVERRIDE;
 
86
    virtual void mouseDoubleClickEvent(QMouseEvent *ev) Q_DECL_OVERRIDE;
 
87
    virtual bool event(QEvent *) Q_DECL_OVERRIDE;
 
88
    virtual void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
 
89
    virtual void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE;
 
90
    virtual void moveEvent(QMoveEvent *) Q_DECL_OVERRIDE;
 
91
 
 
92
private slots:
 
93
    void systemTrayWindowChanged(QScreen *screen);
 
94
 
 
95
private:
 
96
    bool addToTray();
 
97
 
 
98
    QSystemTrayIcon *q;
 
99
    QPixmap background;
 
100
};
 
101
 
 
102
QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn)
 
103
    : QWidget(0, Qt::Window | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint)
 
104
    , q(qIn)
 
105
{
 
106
    setObjectName(QStringLiteral("QSystemTrayIconSys"));
 
107
    setToolTip(q->toolTip());
 
108
    setAttribute(Qt::WA_AlwaysShowToolTips, true);
 
109
    setAttribute(Qt::WA_QuitOnClose, false);
 
110
    const QSize size(22, 22); // Gnome, standard size
 
111
    setGeometry(QRect(QPoint(0, 0), size));
 
112
    setMinimumSize(size);
 
113
 
 
114
    // We need two different behaviors depending on whether the X11 visual for the system tray
 
115
    // (a) exists and (b) supports an alpha channel, i.e. is 32 bits.
 
116
    // If we have a visual that has an alpha channel, we can paint this widget with a transparent
 
117
    // background and it will work.
 
118
    // However, if there's no alpha channel visual, in order for transparent tray icons to work,
 
119
    // we do not have a transparent background on the widget, but set the BackPixmap property of our
 
120
    // window to ParentRelative (so that it inherits the background of its X11 parent window), call
 
121
    // xcb_clear_region before painting (so that the inherited background is visible) and then grab
 
122
    // the just-drawn background from the X11 server.
 
123
    bool hasAlphaChannel = QXcbIntegrationFunctions::xEmbedSystemTrayVisualHasAlphaChannel();
 
124
    setAttribute(Qt::WA_TranslucentBackground, hasAlphaChannel);
 
125
    if (!hasAlphaChannel) {
 
126
        createWinId();
 
127
        QXcbWindowFunctions::setParentRelativeBackPixmap(windowHandle());
 
128
 
 
129
        // XXX: This is actually required, but breaks things ("QWidget::paintEngine: Should no
 
130
        // longer be called"). Why is this needed? When the widget is drawn, we use tricks to grab
 
131
        // the tray icon's background from the server. If the tray icon isn't visible (because
 
132
        // another window is on top of it), the trick fails and instead uses the content of that
 
133
        // other window as the background.
 
134
        // setAttribute(Qt::WA_PaintOnScreen);
 
135
    }
 
136
 
 
137
    addToTray();
 
138
}
 
139
 
 
140
bool QSystemTrayIconSys::addToTray()
 
141
{
 
142
    if (!locateSystemTray())
 
143
        return false;
 
144
 
 
145
    createWinId();
 
146
    setMouseTracking(true);
 
147
 
 
148
    if (!QXcbWindowFunctions::requestSystemTrayWindowDock(windowHandle()))
 
149
        return false;
 
150
 
 
151
    if (!background.isNull())
 
152
        background = QPixmap();
 
153
    show();
 
154
    return true;
 
155
}
 
156
 
 
157
void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *)
 
158
{
 
159
    if (locateSystemTray()) {
 
160
        addToTray();
 
161
    } else {
 
162
        QBalloonTip::hideBalloon();
 
163
        hide(); // still no luck
 
164
        destroy();
 
165
    }
 
166
}
 
167
 
 
168
QRect QSystemTrayIconSys::globalGeometry() const
 
169
{
 
170
    return QXcbWindowFunctions::systemTrayWindowGlobalGeometry(windowHandle());
 
171
}
 
172
 
 
173
void QSystemTrayIconSys::mousePressEvent(QMouseEvent *ev)
 
174
{
 
175
    QPoint globalPos = ev->globalPos();
 
176
#ifndef QT_NO_CONTEXTMENU
 
177
    if (ev->button() == Qt::RightButton && q->contextMenu())
 
178
        q->contextMenu()->popup(globalPos);
 
179
#else
 
180
    Q_UNUSED(globalPos)
 
181
#endif // QT_NO_CONTEXTMENU
 
182
 
 
183
    if (QBalloonTip::isBalloonVisible()) {
 
184
        emit q->messageClicked();
 
185
        QBalloonTip::hideBalloon();
 
186
    }
 
187
 
 
188
    if (ev->button() == Qt::LeftButton)
 
189
        emit q->activated(QSystemTrayIcon::Trigger);
 
190
    else if (ev->button() == Qt::RightButton)
 
191
        emit q->activated(QSystemTrayIcon::Context);
 
192
    else if (ev->button() == Qt::MidButton)
 
193
        emit q->activated(QSystemTrayIcon::MiddleClick);
 
194
}
 
195
 
 
196
void QSystemTrayIconSys::mouseDoubleClickEvent(QMouseEvent *ev)
 
197
{
 
198
    if (ev->button() == Qt::LeftButton)
 
199
        emit q->activated(QSystemTrayIcon::DoubleClick);
 
200
}
 
201
 
 
202
bool QSystemTrayIconSys::event(QEvent *e)
 
203
{
 
204
    switch (e->type()) {
 
205
    case QEvent::ToolTip:
 
206
        QApplication::sendEvent(q, e);
 
207
        break;
 
208
#ifndef QT_NO_WHEELEVENT
 
209
    case QEvent::Wheel:
 
210
        return QApplication::sendEvent(q, e);
 
211
#endif
 
212
    default:
 
213
        break;
 
214
    }
 
215
    return QWidget::event(e);
 
216
}
 
217
 
 
218
void QSystemTrayIconSys::paintEvent(QPaintEvent *)
 
219
{
 
220
    const QRect rect(QPoint(0, 0), geometry().size());
 
221
    QPainter painter(this);
 
222
 
 
223
    // If we have Qt::WA_TranslucentBackground set, during widget creation
 
224
    // we detected the systray visual supported an alpha channel
 
225
    if (testAttribute(Qt::WA_TranslucentBackground)) {
 
226
        painter.setCompositionMode(QPainter::CompositionMode_Source);
 
227
        painter.fillRect(rect, Qt::transparent);
 
228
    } else {
 
229
        // clearRegion() was called on XEMBED_EMBEDDED_NOTIFY, so we hope that got done by now.
 
230
        // Grab the tray background pixmap, before rendering the icon for the first time.
 
231
        if (background.isNull()) {
 
232
            background = QGuiApplication::primaryScreen()->grabWindow(winId(),
 
233
                                0, 0, rect.size().width(), rect.size().height());
 
234
        }
 
235
        // Then paint over the icon area with the background before compositing the icon on top.
 
236
        painter.drawPixmap(QPoint(0, 0), background);
 
237
    }
 
238
    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
 
239
    q->icon().paint(&painter, rect);
 
240
}
 
241
 
 
242
void QSystemTrayIconSys::moveEvent(QMoveEvent *event)
 
243
{
 
244
    QWidget::moveEvent(event);
 
245
    if (QBalloonTip::isBalloonVisible())
 
246
        QBalloonTip::updateBalloonPosition(globalGeometry().center());
 
247
}
 
248
 
 
249
void QSystemTrayIconSys::resizeEvent(QResizeEvent *event)
 
250
{
 
251
    update();
 
252
    QWidget::resizeEvent(event);
 
253
    if (QBalloonTip::isBalloonVisible())
 
254
        QBalloonTip::updateBalloonPosition(globalGeometry().center());
 
255
}
 
256
////////////////////////////////////////////////////////////////////////////
 
257
 
 
258
QSystemTrayIconPrivate::QSystemTrayIconPrivate()
 
259
    : sys(0),
 
260
      qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()),
 
261
      visible(false)
 
262
{
 
263
}
 
264
 
 
265
QSystemTrayIconPrivate::~QSystemTrayIconPrivate()
 
266
{
 
267
    delete qpa_sys;
 
268
}
 
269
 
 
270
void QSystemTrayIconPrivate::install_sys()
 
271
{
 
272
    if (qpa_sys) {
 
273
        install_sys_qpa();
 
274
        return;
 
275
    }
 
276
    Q_Q(QSystemTrayIcon);
 
277
    if (!sys && locateSystemTray()) {
 
278
        sys = new QSystemTrayIconSys(q);
 
279
        QObject::connect(QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)),
 
280
                         sys, SLOT(systemTrayWindowChanged(QScreen*)));
 
281
    }
 
282
}
 
283
 
 
284
QRect QSystemTrayIconPrivate::geometry_sys() const
 
285
{
 
286
    if (qpa_sys)
 
287
        return geometry_sys_qpa();
 
288
    if (!sys)
 
289
        return QRect();
 
290
    return sys->globalGeometry();
 
291
}
 
292
 
 
293
void QSystemTrayIconPrivate::remove_sys()
 
294
{
 
295
    if (qpa_sys) {
 
296
        remove_sys_qpa();
 
297
        return;
 
298
    }
 
299
    if (!sys)
 
300
        return;
 
301
    QBalloonTip::hideBalloon();
 
302
    sys->hide(); // this should do the trick, but...
 
303
    delete sys; // wm may resize system tray only for DestroyEvents
 
304
    sys = 0;
 
305
}
 
306
 
 
307
void QSystemTrayIconPrivate::updateIcon_sys()
 
308
{
 
309
    if (qpa_sys) {
 
310
        updateIcon_sys_qpa();
 
311
        return;
 
312
    }
 
313
    if (sys)
 
314
        sys->updateIcon();
 
315
}
 
316
 
 
317
void QSystemTrayIconPrivate::updateMenu_sys()
 
318
{
 
319
    if (qpa_sys)
 
320
        updateMenu_sys_qpa();
 
321
}
 
322
 
 
323
void QSystemTrayIconPrivate::updateToolTip_sys()
 
324
{
 
325
    if (qpa_sys) {
 
326
        updateToolTip_sys_qpa();
 
327
        return;
 
328
    }
 
329
    if (!sys)
 
330
        return;
 
331
#ifndef QT_NO_TOOLTIP
 
332
    sys->setToolTip(toolTip);
 
333
#endif
 
334
}
 
335
 
 
336
bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
 
337
{
 
338
    QScopedPointer<QPlatformSystemTrayIcon> sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon());
 
339
    if (sys && sys->isSystemTrayAvailable())
 
340
        return true;
 
341
 
 
342
    // no QPlatformSystemTrayIcon so fall back to default xcb platform behavior
 
343
    const QString platform = QGuiApplication::platformName();
 
344
    if (platform.compare(QLatin1String("xcb"), Qt::CaseInsensitive) == 0)
 
345
       return locateSystemTray();
 
346
    return false;
 
347
}
 
348
 
 
349
bool QSystemTrayIconPrivate::supportsMessages_sys()
 
350
{
 
351
    QScopedPointer<QPlatformSystemTrayIcon> sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon());
 
352
    if (sys)
 
353
        return sys->supportsMessages();
 
354
 
 
355
    // no QPlatformSystemTrayIcon so fall back to default xcb platform behavior
 
356
    return true;
 
357
}
 
358
 
 
359
void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message,
 
360
                                   QSystemTrayIcon::MessageIcon icon, int msecs)
 
361
{
 
362
    if (qpa_sys) {
 
363
        showMessage_sys_qpa(title, message, icon, msecs);
 
364
        return;
 
365
    }
 
366
    if (!sys)
 
367
        return;
 
368
    QBalloonTip::showBalloon(icon, title, message, sys->systemTrayIcon(),
 
369
                             sys->globalGeometry().center(),
 
370
                             msecs);
 
371
}
 
372
 
 
373
QT_END_NAMESPACE
 
374
 
 
375
#include "qsystemtrayicon_x11.moc"
 
376
 
 
377
#endif //QT_NO_SYSTEMTRAYICON