Contents of /trunk/qt4/patches/qt-4.8.7-systemtrayicon.patch
Parent Directory | Revision Log
Revision 2917 -
(show annotations)
(download)
Wed May 17 09:04:25 2017 UTC (7 years, 4 months ago) by niro
File size: 48692 byte(s)
Wed May 17 09:04:25 2017 UTC (7 years, 4 months ago) by niro
File size: 48692 byte(s)
-fixed patches
1 | Description: Introduce a plugin system for QSystemTrayIcon. |
2 | Designed to be used with sni-qt (https://launchpad.net/sni-qt) |
3 | Author: agateau@kde.org |
4 | Forwarded: no |
5 | |
6 | Introduce a plugin system for QSystemTrayIcon. Designed to be used with sni-qt |
7 | (https://launchpad.net/sni-qt) |
8 | --- |
9 | examples/desktop/systray/window.cpp | 40 ++ |
10 | examples/desktop/systray/window.h | 6 |
11 | src/gui/util/qabstractsystemtrayiconsys.cpp | 65 +++ |
12 | src/gui/util/qabstractsystemtrayiconsys_p.h | 106 ++++++ |
13 | src/gui/util/qsystemtrayicon.cpp | 6 |
14 | src/gui/util/qsystemtrayicon_p.h | 85 ++--- |
15 | src/gui/util/qsystemtrayicon_x11.cpp | 356 ++++----------------- |
16 | src/gui/util/qxembedsystemtrayicon_x11.cpp | 469 ++++++++++++++++++++++++++++ |
17 | src/gui/util/qxembedsystemtrayicon_x11_p.h | 104 ++++++ |
18 | src/gui/util/util.pri | 7 |
19 | 10 files changed, 916 insertions(+), 328 deletions(-) |
20 | |
21 | --- a/examples/desktop/systray/window.cpp |
22 | +++ b/examples/desktop/systray/window.cpp |
23 | @@ -158,15 +158,23 @@ |
24 | iconComboBox->addItem(QIcon(":/images/bad.svg"), tr("Bad")); |
25 | iconComboBox->addItem(QIcon(":/images/heart.svg"), tr("Heart")); |
26 | iconComboBox->addItem(QIcon(":/images/trash.svg"), tr("Trash")); |
27 | + iconComboBox->addItem(QIcon::fromTheme("system-file-manager"), tr("File Manager")); |
28 | |
29 | showIconCheckBox = new QCheckBox(tr("Show icon")); |
30 | showIconCheckBox->setChecked(true); |
31 | |
32 | +#if defined(Q_WS_X11) |
33 | + jitToolTipCheckBox = new QCheckBox(tr("Just In Time Tooltip")); |
34 | +#endif |
35 | + |
36 | QHBoxLayout *iconLayout = new QHBoxLayout; |
37 | iconLayout->addWidget(iconLabel); |
38 | iconLayout->addWidget(iconComboBox); |
39 | iconLayout->addStretch(); |
40 | iconLayout->addWidget(showIconCheckBox); |
41 | +#if defined(Q_WS_X11) |
42 | + iconLayout->addWidget(jitToolTipCheckBox); |
43 | +#endif |
44 | iconGroupBox->setLayout(iconLayout); |
45 | } |
46 | |
47 | @@ -254,5 +262,37 @@ |
48 | trayIconMenu->addAction(quitAction); |
49 | |
50 | trayIcon = new QSystemTrayIcon(this); |
51 | + QByteArray category = qgetenv("SNI_CATEGORY"); |
52 | + if (!category.isEmpty()) { |
53 | + trayIcon->setProperty("_qt_sni_category", QString::fromLocal8Bit(category)); |
54 | + } |
55 | trayIcon->setContextMenu(trayIconMenu); |
56 | + |
57 | +#if defined(Q_WS_X11) |
58 | + trayIcon->installEventFilter(this); |
59 | +#endif |
60 | +} |
61 | + |
62 | +#if defined(Q_WS_X11) |
63 | +bool Window::eventFilter(QObject *, QEvent *event) |
64 | +{ |
65 | + switch(event->type()) { |
66 | + case QEvent::ToolTip: |
67 | + if (jitToolTipCheckBox->isChecked()) { |
68 | + QString timeString = QTime::currentTime().toString(); |
69 | + trayIcon->setToolTip(tr("Current Time: %1").arg(timeString)); |
70 | + } |
71 | + break; |
72 | + case QEvent::Wheel: { |
73 | + QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event); |
74 | + int delta = wheelEvent->delta() > 0 ? 1 : -1; |
75 | + int index = (iconComboBox->currentIndex() + delta) % iconComboBox->count(); |
76 | + iconComboBox->setCurrentIndex(index); |
77 | + break; |
78 | + } |
79 | + default: |
80 | + break; |
81 | + } |
82 | + return false; |
83 | } |
84 | +#endif |
85 | --- a/examples/desktop/systray/window.h |
86 | +++ b/examples/desktop/systray/window.h |
87 | @@ -69,6 +69,9 @@ |
88 | |
89 | protected: |
90 | void closeEvent(QCloseEvent *event); |
91 | +#if defined(Q_WS_X11) |
92 | + bool eventFilter(QObject *object, QEvent *event); |
93 | +#endif |
94 | |
95 | private slots: |
96 | void setIcon(int index); |
97 | @@ -86,6 +89,9 @@ |
98 | QLabel *iconLabel; |
99 | QComboBox *iconComboBox; |
100 | QCheckBox *showIconCheckBox; |
101 | +#if defined(Q_WS_X11) |
102 | + QCheckBox *jitToolTipCheckBox; |
103 | +#endif |
104 | |
105 | QGroupBox *messageGroupBox; |
106 | QLabel *typeLabel; |
107 | --- /dev/null |
108 | +++ b/src/gui/util/qabstractsystemtrayiconsys.cpp |
109 | @@ -0,0 +1,65 @@ |
110 | +/**************************************************************************** |
111 | +** |
112 | +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
113 | +** All rights reserved. |
114 | +** Contact: Nokia Corporation (qt-info@nokia.com) |
115 | +** |
116 | +** This file is part of the QtGui module of the Qt Toolkit. |
117 | +** |
118 | +** $QT_BEGIN_LICENSE:LGPL$ |
119 | +** GNU Lesser General Public License Usage |
120 | +** This file may be used under the terms of the GNU Lesser General Public |
121 | +** License version 2.1 as published by the Free Software Foundation and |
122 | +** appearing in the file LICENSE.LGPL included in the packaging of this |
123 | +** file. Please review the following information to ensure the GNU Lesser |
124 | +** General Public License version 2.1 requirements will be met: |
125 | +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
126 | +** |
127 | +** In addition, as a special exception, Nokia gives you certain additional |
128 | +** rights. These rights are described in the Nokia Qt LGPL Exception |
129 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
130 | +** |
131 | +** GNU General Public License Usage |
132 | +** Alternatively, this file may be used under the terms of the GNU General |
133 | +** Public License version 3.0 as published by the Free Software Foundation |
134 | +** and appearing in the file LICENSE.GPL included in the packaging of this |
135 | +** file. Please review the following information to ensure the GNU General |
136 | +** Public License version 3.0 requirements will be met: |
137 | +** http://www.gnu.org/copyleft/gpl.html. |
138 | +** |
139 | +** Other Usage |
140 | +** Alternatively, this file may be used in accordance with the terms and |
141 | +** conditions contained in a signed written agreement between you and Nokia. |
142 | +** |
143 | +** |
144 | +** |
145 | +** |
146 | +** |
147 | +** $QT_END_LICENSE$ |
148 | +** |
149 | +****************************************************************************/ |
150 | +#ifndef QT_NO_SYSTEMTRAYICON |
151 | + |
152 | +#include "qabstractsystemtrayiconsys_p.h" |
153 | + |
154 | + |
155 | +QSystemTrayIconSysFactoryInterface::QSystemTrayIconSysFactoryInterface() |
156 | +{ |
157 | +} |
158 | + |
159 | +///////////////////////////////////////////////// |
160 | +QAbstractSystemTrayIconSys::QAbstractSystemTrayIconSys(QSystemTrayIcon *icon) |
161 | +: trayIcon(icon) |
162 | +{ |
163 | +} |
164 | + |
165 | +QAbstractSystemTrayIconSys::~QAbstractSystemTrayIconSys() |
166 | +{ |
167 | +} |
168 | + |
169 | +void QAbstractSystemTrayIconSys::sendActivated(QSystemTrayIcon::ActivationReason reason) |
170 | +{ |
171 | + qtsystray_sendActivated(trayIcon, reason); |
172 | +} |
173 | + |
174 | +#endif |
175 | --- /dev/null |
176 | +++ b/src/gui/util/qabstractsystemtrayiconsys_p.h |
177 | @@ -0,0 +1,106 @@ |
178 | +/**************************************************************************** |
179 | +** |
180 | +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
181 | +** All rights reserved. |
182 | +** Contact: Nokia Corporation (qt-info@nokia.com) |
183 | +** |
184 | +** This file is part of the QtGui module of the Qt Toolkit. |
185 | +** |
186 | +** $QT_BEGIN_LICENSE:LGPL$ |
187 | +** GNU Lesser General Public License Usage |
188 | +** This file may be used under the terms of the GNU Lesser General Public |
189 | +** License version 2.1 as published by the Free Software Foundation and |
190 | +** appearing in the file LICENSE.LGPL included in the packaging of this |
191 | +** file. Please review the following information to ensure the GNU Lesser |
192 | +** General Public License version 2.1 requirements will be met: |
193 | +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
194 | +** |
195 | +** In addition, as a special exception, Nokia gives you certain additional |
196 | +** rights. These rights are described in the Nokia Qt LGPL Exception |
197 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
198 | +** |
199 | +** GNU General Public License Usage |
200 | +** Alternatively, this file may be used under the terms of the GNU General |
201 | +** Public License version 3.0 as published by the Free Software Foundation |
202 | +** and appearing in the file LICENSE.GPL included in the packaging of this |
203 | +** file. Please review the following information to ensure the GNU General |
204 | +** Public License version 3.0 requirements will be met: |
205 | +** http://www.gnu.org/copyleft/gpl.html. |
206 | +** |
207 | +** Other Usage |
208 | +** Alternatively, this file may be used in accordance with the terms and |
209 | +** conditions contained in a signed written agreement between you and Nokia. |
210 | +** |
211 | +** |
212 | +** |
213 | +** |
214 | +** |
215 | +** $QT_END_LICENSE$ |
216 | +** |
217 | +****************************************************************************/ |
218 | + |
219 | +#ifndef QABSTRACTSYSTEMTRAYICONSYS_P_H |
220 | +#define QABSTRACTSYSTEMTRAYICONSYS_P_H |
221 | + |
222 | +// |
223 | +// W A R N I N G |
224 | +// ------------- |
225 | +// |
226 | +// This file is not part of the Qt API. It exists for the convenience |
227 | +// of a number of Qt sources files. This header file may change from |
228 | +// version to version without notice, or even be removed. |
229 | +// |
230 | +// We mean it. |
231 | +// |
232 | + |
233 | +#ifndef QT_NO_SYSTEMTRAYICON |
234 | + |
235 | +#include <qfactoryinterface.h> |
236 | +#include <qsystemtrayicon.h> |
237 | + |
238 | +class QAbstractSystemTrayIconSys; |
239 | + |
240 | +class Q_GUI_EXPORT QSystemTrayIconSysFactoryInterface : public QObject, public QFactoryInterface |
241 | +{ |
242 | + Q_OBJECT |
243 | +public: |
244 | + QSystemTrayIconSysFactoryInterface(); |
245 | + virtual QAbstractSystemTrayIconSys * create(QSystemTrayIcon *) = 0; |
246 | + virtual bool isAvailable() const = 0; |
247 | + |
248 | + // \reimp |
249 | + virtual QStringList keys() const { return QStringList() << QLatin1String("default"); } |
250 | + |
251 | +Q_SIGNALS: |
252 | + void availableChanged(bool); |
253 | +}; |
254 | + |
255 | +#define QSystemTrayIconSysFactoryInterface_iid "com.nokia.qt.QSystemTrayIconSysFactoryInterface" |
256 | +Q_DECLARE_INTERFACE(QSystemTrayIconSysFactoryInterface, QSystemTrayIconSysFactoryInterface_iid) |
257 | + |
258 | +class QRect; |
259 | + |
260 | +class Q_GUI_EXPORT QAbstractSystemTrayIconSys |
261 | +{ |
262 | +public: |
263 | + QAbstractSystemTrayIconSys(QSystemTrayIcon *icon); |
264 | + virtual ~QAbstractSystemTrayIconSys(); |
265 | + |
266 | + virtual QRect geometry() const = 0; |
267 | + virtual void updateVisibility() = 0; |
268 | + virtual void updateIcon() = 0; |
269 | + virtual void updateToolTip() = 0; |
270 | + virtual void updateMenu() = 0; |
271 | + virtual void showMessage(const QString &title, const QString &message, |
272 | + QSystemTrayIcon::MessageIcon icon, int msecs) = 0; |
273 | + |
274 | + void sendActivated(QSystemTrayIcon::ActivationReason); |
275 | + |
276 | +protected: |
277 | + QSystemTrayIcon *trayIcon; |
278 | +}; |
279 | + |
280 | +#endif // QT_NO_SYSTEMTRAYICON |
281 | + |
282 | +#endif // QABSTRACTSYSTEMTRAYICONSYS_P_H |
283 | + |
284 | --- a/src/gui/util/qsystemtrayicon.cpp |
285 | +++ b/src/gui/util/qsystemtrayicon.cpp |
286 | @@ -287,12 +287,6 @@ |
287 | */ |
288 | bool QSystemTrayIcon::event(QEvent *e) |
289 | { |
290 | -#if defined(Q_WS_X11) |
291 | - if (e->type() == QEvent::ToolTip) { |
292 | - Q_D(QSystemTrayIcon); |
293 | - return d->sys->deliverToolTipEvent(e); |
294 | - } |
295 | -#endif |
296 | return QObject::event(e); |
297 | } |
298 | |
299 | --- a/src/gui/util/qsystemtrayicon_p.h |
300 | +++ b/src/gui/util/qsystemtrayicon_p.h |
301 | @@ -62,10 +62,17 @@ |
302 | #include "QtGui/qpixmap.h" |
303 | #include "QtCore/qstring.h" |
304 | #include "QtCore/qpointer.h" |
305 | +#if defined(Q_WS_X11) |
306 | +#include "QtCore/qset.h" |
307 | +#endif |
308 | |
309 | QT_BEGIN_NAMESPACE |
310 | |
311 | +#if defined(Q_WS_X11) |
312 | +class QAbstractSystemTrayIconSys; |
313 | +#else |
314 | class QSystemTrayIconSys; |
315 | +#endif |
316 | class QToolButton; |
317 | class QLabel; |
318 | |
319 | @@ -75,6 +82,9 @@ |
320 | |
321 | public: |
322 | QSystemTrayIconPrivate() : sys(0), visible(false) { } |
323 | + #if defined(Q_WS_X11) |
324 | + ~QSystemTrayIconPrivate(); |
325 | + #endif |
326 | |
327 | void install_sys(); |
328 | void remove_sys(); |
329 | @@ -90,7 +100,11 @@ |
330 | QPointer<QMenu> menu; |
331 | QIcon icon; |
332 | QString toolTip; |
333 | + #if defined(Q_WS_X11) |
334 | + QAbstractSystemTrayIconSys *sys; |
335 | + #else |
336 | QSystemTrayIconSys *sys; |
337 | + #endif |
338 | bool visible; |
339 | }; |
340 | |
341 | @@ -123,60 +137,37 @@ |
342 | }; |
343 | |
344 | #if defined(Q_WS_X11) |
345 | -QT_BEGIN_INCLUDE_NAMESPACE |
346 | -#include <QtCore/qcoreapplication.h> |
347 | -#include <X11/Xlib.h> |
348 | -#include <X11/Xatom.h> |
349 | -#include <X11/Xutil.h> |
350 | -QT_END_INCLUDE_NAMESPACE |
351 | +class QSystemTrayIconSysFactoryInterface; |
352 | |
353 | -class QSystemTrayIconSys : public QWidget |
354 | +/** |
355 | + * This class acts as a composite QSystemTrayIconSysFactory: It can create |
356 | + * instances of QAbstractSystemTrayIconSys* using either a plugin or the |
357 | + * builtin factory and will cause QSystemTrayIconPrivate to recreate their |
358 | + * 'sys' instances if the plugin availability changes. |
359 | + */ |
360 | +class QSystemTrayIconSysFactory : public QObject |
361 | { |
362 | - friend class QSystemTrayIconPrivate; |
363 | - |
364 | + Q_OBJECT |
365 | public: |
366 | - QSystemTrayIconSys(QSystemTrayIcon *q); |
367 | - ~QSystemTrayIconSys(); |
368 | - enum { |
369 | - SYSTEM_TRAY_REQUEST_DOCK = 0, |
370 | - SYSTEM_TRAY_BEGIN_MESSAGE = 1, |
371 | - SYSTEM_TRAY_CANCEL_MESSAGE =2 |
372 | - }; |
373 | - |
374 | - void addToTray(); |
375 | - void updateIcon(); |
376 | - XVisualInfo* getSysTrayVisualInfo(); |
377 | - |
378 | - // QObject::event is public but QWidget's ::event() re-implementation |
379 | - // is protected ;( |
380 | - inline bool deliverToolTipEvent(QEvent *e) |
381 | - { return QWidget::event(e); } |
382 | - |
383 | - static Window sysTrayWindow; |
384 | - static QList<QSystemTrayIconSys *> trayIcons; |
385 | - static QCoreApplication::EventFilter oldEventFilter; |
386 | - static bool sysTrayTracker(void *message, long *result); |
387 | - static Window locateSystemTray(); |
388 | - static Atom sysTraySelection; |
389 | - static XVisualInfo sysTrayVisual; |
390 | + QSystemTrayIconSysFactory(); |
391 | + void registerSystemTrayIconPrivate(QSystemTrayIconPrivate *iconPrivate); |
392 | + void unregisterSystemTrayIconPrivate(QSystemTrayIconPrivate *iconPrivate); |
393 | |
394 | -protected: |
395 | - void paintEvent(QPaintEvent *pe); |
396 | - void resizeEvent(QResizeEvent *re); |
397 | - bool x11Event(XEvent *event); |
398 | - void mousePressEvent(QMouseEvent *event); |
399 | - void mouseDoubleClickEvent(QMouseEvent *event); |
400 | -#ifndef QT_NO_WHEELEVENT |
401 | - void wheelEvent(QWheelEvent *event); |
402 | -#endif |
403 | - bool event(QEvent *e); |
404 | + QAbstractSystemTrayIconSys *create(QSystemTrayIcon *) const; |
405 | + |
406 | + bool isAvailable() const; |
407 | + |
408 | +private Q_SLOTS: |
409 | + void refreshTrayIconPrivates(); |
410 | |
411 | private: |
412 | - QPixmap background; |
413 | - QSystemTrayIcon *q; |
414 | - Colormap colormap; |
415 | + QSystemTrayIconSysFactoryInterface *factory() const; |
416 | + void loadPluginFactory(); |
417 | + |
418 | + QSystemTrayIconSysFactoryInterface *pluginFactory; |
419 | + QSet<QSystemTrayIconPrivate *> trayIconPrivates; |
420 | }; |
421 | -#endif // Q_WS_X11 |
422 | +#endif |
423 | |
424 | QT_END_NAMESPACE |
425 | |
426 | --- a/src/gui/util/qsystemtrayicon_x11.cpp |
427 | +++ b/src/gui/util/qsystemtrayicon_x11.cpp |
428 | @@ -38,311 +38,122 @@ |
429 | ** $QT_END_LICENSE$ |
430 | ** |
431 | ****************************************************************************/ |
432 | +#ifndef QT_NO_SYSTEMTRAYICON |
433 | + |
434 | +#include <private/qfactoryloader_p.h> |
435 | |
436 | -#include "private/qt_x11_p.h" |
437 | -#include "qlabel.h" |
438 | -#include "qx11info_x11.h" |
439 | -#include "qpainter.h" |
440 | -#include "qpixmap.h" |
441 | -#include "qbitmap.h" |
442 | -#include "qevent.h" |
443 | -#include "qapplication.h" |
444 | -#include "qlist.h" |
445 | -#include "qmenu.h" |
446 | -#include "qtimer.h" |
447 | #include "qsystemtrayicon_p.h" |
448 | -#include "qpaintengine.h" |
449 | +#include "qabstractsystemtrayiconsys_p.h" |
450 | +#include "qcoreapplication.h" |
451 | +#include "qxembedsystemtrayicon_x11_p.h" |
452 | |
453 | -#ifndef QT_NO_SYSTEMTRAYICON |
454 | QT_BEGIN_NAMESPACE |
455 | |
456 | -Window QSystemTrayIconSys::sysTrayWindow = XNone; |
457 | -QList<QSystemTrayIconSys *> QSystemTrayIconSys::trayIcons; |
458 | -QCoreApplication::EventFilter QSystemTrayIconSys::oldEventFilter = 0; |
459 | -Atom QSystemTrayIconSys::sysTraySelection = XNone; |
460 | -XVisualInfo QSystemTrayIconSys::sysTrayVisual = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
461 | - |
462 | -// Locate the system tray |
463 | -Window QSystemTrayIconSys::locateSystemTray() |
464 | -{ |
465 | - Display *display = QX11Info::display(); |
466 | - if (sysTraySelection == XNone) { |
467 | - int screen = QX11Info::appScreen(); |
468 | - QString net_sys_tray = QString::fromLatin1("_NET_SYSTEM_TRAY_S%1").arg(screen); |
469 | - sysTraySelection = XInternAtom(display, net_sys_tray.toLatin1(), False); |
470 | - } |
471 | - |
472 | - return XGetSelectionOwner(QX11Info::display(), sysTraySelection); |
473 | -} |
474 | +Q_GLOBAL_STATIC(QSystemTrayIconSysFactory, qt_guiSystemTrayIconSysFactory) |
475 | |
476 | -XVisualInfo* QSystemTrayIconSys::getSysTrayVisualInfo() |
477 | +QSystemTrayIconSysFactory::QSystemTrayIconSysFactory() |
478 | +: pluginFactory(0) |
479 | { |
480 | - Display *display = QX11Info::display(); |
481 | - |
482 | - if (!sysTrayVisual.visual) { |
483 | - Window win = locateSystemTray(); |
484 | - if (win != XNone) { |
485 | - Atom actual_type; |
486 | - int actual_format; |
487 | - ulong nitems, bytes_remaining; |
488 | - uchar *data = 0; |
489 | - int result = XGetWindowProperty(display, win, ATOM(_NET_SYSTEM_TRAY_VISUAL), 0, 1, |
490 | - False, XA_VISUALID, &actual_type, |
491 | - &actual_format, &nitems, &bytes_remaining, &data); |
492 | - VisualID vid = 0; |
493 | - if (result == Success && data && actual_type == XA_VISUALID && actual_format == 32 && |
494 | - nitems == 1 && bytes_remaining == 0) |
495 | - vid = *(VisualID*)data; |
496 | - if (data) |
497 | - XFree(data); |
498 | - if (vid == 0) |
499 | - return 0; |
500 | - |
501 | - uint mask = VisualIDMask; |
502 | - XVisualInfo *vi, rvi; |
503 | - int count; |
504 | - rvi.visualid = vid; |
505 | - vi = XGetVisualInfo(display, mask, &rvi, &count); |
506 | - if (vi) { |
507 | - sysTrayVisual = vi[0]; |
508 | - XFree((char*)vi); |
509 | - } |
510 | - if (sysTrayVisual.depth != 32) |
511 | - memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); |
512 | - } |
513 | - } |
514 | - |
515 | - return sysTrayVisual.visual ? &sysTrayVisual : 0; |
516 | } |
517 | |
518 | -bool QSystemTrayIconSys::sysTrayTracker(void *message, long *result) |
519 | +void QSystemTrayIconSysFactory::loadPluginFactory() |
520 | { |
521 | - bool retval = false; |
522 | - if (QSystemTrayIconSys::oldEventFilter) |
523 | - retval = QSystemTrayIconSys::oldEventFilter(message, result); |
524 | - |
525 | - if (trayIcons.isEmpty()) |
526 | - return retval; |
527 | - |
528 | - Display *display = QX11Info::display(); |
529 | - XEvent *ev = (XEvent *)message; |
530 | - if (ev->type == DestroyNotify && ev->xany.window == sysTrayWindow) { |
531 | - sysTrayWindow = locateSystemTray(); |
532 | - memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); |
533 | - for (int i = 0; i < trayIcons.count(); i++) { |
534 | - if (sysTrayWindow == XNone) { |
535 | - QBalloonTip::hideBalloon(); |
536 | - trayIcons[i]->hide(); // still no luck |
537 | - trayIcons[i]->destroy(); |
538 | - trayIcons[i]->create(); |
539 | - } else |
540 | - trayIcons[i]->addToTray(); // add it to the new tray |
541 | - } |
542 | - retval = true; |
543 | - } else if (ev->type == ClientMessage && sysTrayWindow == XNone) { |
544 | - static Atom manager_atom = XInternAtom(display, "MANAGER", False); |
545 | - XClientMessageEvent *cm = (XClientMessageEvent *)message; |
546 | - if ((cm->message_type == manager_atom) && ((Atom)cm->data.l[1] == sysTraySelection)) { |
547 | - sysTrayWindow = cm->data.l[2]; |
548 | - memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); |
549 | - XSelectInput(display, sysTrayWindow, StructureNotifyMask); |
550 | - for (int i = 0; i < trayIcons.count(); i++) { |
551 | - trayIcons[i]->addToTray(); |
552 | - } |
553 | - retval = true; |
554 | - } |
555 | - } else if (ev->type == PropertyNotify && ev->xproperty.atom == ATOM(_NET_SYSTEM_TRAY_VISUAL) && |
556 | - ev->xproperty.window == sysTrayWindow) { |
557 | - memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); |
558 | - for (int i = 0; i < trayIcons.count(); i++) { |
559 | - trayIcons[i]->addToTray(); |
560 | - } |
561 | - } |
562 | - |
563 | - return retval; |
564 | -} |
565 | - |
566 | -QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *q) |
567 | - : QWidget(0, Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint), |
568 | - q(q), colormap(0) |
569 | -{ |
570 | - setAttribute(Qt::WA_AlwaysShowToolTips); |
571 | - setAttribute(Qt::WA_QuitOnClose, false); |
572 | - setAttribute(Qt::WA_NoSystemBackground, true); |
573 | - setAttribute(Qt::WA_PaintOnScreen); |
574 | - |
575 | - static bool eventFilterAdded = false; |
576 | - Display *display = QX11Info::display(); |
577 | - if (!eventFilterAdded) { |
578 | - oldEventFilter = qApp->setEventFilter(sysTrayTracker); |
579 | - eventFilterAdded = true; |
580 | - Window root = QX11Info::appRootWindow(); |
581 | - XWindowAttributes attr; |
582 | - XGetWindowAttributes(display, root, &attr); |
583 | - if ((attr.your_event_mask & StructureNotifyMask) != StructureNotifyMask) { |
584 | - (void) QApplication::desktop(); // lame trick to ensure our event mask is not overridden |
585 | - XSelectInput(display, root, attr.your_event_mask | StructureNotifyMask); // for MANAGER selection |
586 | - } |
587 | + if (pluginFactory) { |
588 | + return; |
589 | } |
590 | - if (trayIcons.isEmpty()) { |
591 | - sysTrayWindow = locateSystemTray(); |
592 | - if (sysTrayWindow != XNone) |
593 | - XSelectInput(display, sysTrayWindow, StructureNotifyMask); // track tray events |
594 | +#ifndef QT_NO_LIBRARY |
595 | + QFactoryLoader loader(QSystemTrayIconSysFactoryInterface_iid, QLatin1String("/systemtrayicon")); |
596 | + pluginFactory = qobject_cast<QSystemTrayIconSysFactoryInterface *>(loader.instance(QLatin1String("default"))); |
597 | + if (pluginFactory) { |
598 | + // Set parent to ensure factory destructor is called when application |
599 | + // is closed |
600 | + pluginFactory->setParent(QCoreApplication::instance()); |
601 | + connect(pluginFactory, SIGNAL(availableChanged(bool)), SLOT(refreshTrayIconPrivates())); |
602 | } |
603 | - trayIcons.append(this); |
604 | - setMouseTracking(true); |
605 | -#ifndef QT_NO_TOOLTIP |
606 | - setToolTip(q->toolTip()); |
607 | -#endif |
608 | - if (sysTrayWindow != XNone) |
609 | - addToTray(); |
610 | +#endif // QT_NO_LIBRARY |
611 | } |
612 | |
613 | -QSystemTrayIconSys::~QSystemTrayIconSys() |
614 | +QSystemTrayIconSysFactoryInterface *QSystemTrayIconSysFactory::factory() const |
615 | { |
616 | - trayIcons.removeAt(trayIcons.indexOf(this)); |
617 | - Display *display = QX11Info::display(); |
618 | - if (trayIcons.isEmpty()) { |
619 | - if (sysTrayWindow == XNone) |
620 | - return; |
621 | - if (display) |
622 | - XSelectInput(display, sysTrayWindow, 0); // stop tracking the tray |
623 | - sysTrayWindow = XNone; |
624 | + if (!pluginFactory) { |
625 | + const_cast<QSystemTrayIconSysFactory*>(this)->loadPluginFactory(); |
626 | } |
627 | - if (colormap) |
628 | - XFreeColormap(display, colormap); |
629 | + if (pluginFactory && pluginFactory->isAvailable()) { |
630 | + return pluginFactory; |
631 | + } |
632 | + static QXEmbedSystemTrayIconSysFactory def; |
633 | + return def.isAvailable() ? &def : 0; |
634 | } |
635 | |
636 | -void QSystemTrayIconSys::addToTray() |
637 | +void QSystemTrayIconSysFactory::refreshTrayIconPrivates() |
638 | { |
639 | - Q_ASSERT(sysTrayWindow != XNone); |
640 | - Display *display = QX11Info::display(); |
641 | - |
642 | - XVisualInfo *vi = getSysTrayVisualInfo(); |
643 | - if (vi && vi->visual) { |
644 | - Window root = RootWindow(display, vi->screen); |
645 | - Window p = root; |
646 | - if (QWidget *pw = parentWidget()) |
647 | - p = pw->effectiveWinId(); |
648 | - colormap = XCreateColormap(display, root, vi->visual, AllocNone); |
649 | - XSetWindowAttributes wsa; |
650 | - wsa.background_pixmap = 0; |
651 | - wsa.colormap = colormap; |
652 | - wsa.background_pixel = 0; |
653 | - wsa.border_pixel = 0; |
654 | - Window wid = XCreateWindow(display, p, -1, -1, 1, 1, |
655 | - 0, vi->depth, InputOutput, vi->visual, |
656 | - CWBackPixmap|CWBackPixel|CWBorderPixel|CWColormap, &wsa); |
657 | - create(wid); |
658 | - } else { |
659 | - XSetWindowBackgroundPixmap(display, winId(), ParentRelative); |
660 | - } |
661 | - |
662 | - // GNOME, NET WM Specification |
663 | - static Atom netwm_tray_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False); |
664 | - long l[5] = { CurrentTime, SYSTEM_TRAY_REQUEST_DOCK, static_cast<long>(winId()), 0, 0 }; |
665 | - XEvent ev; |
666 | - memset(&ev, 0, sizeof(ev)); |
667 | - ev.xclient.type = ClientMessage; |
668 | - ev.xclient.window = sysTrayWindow; |
669 | - ev.xclient.message_type = netwm_tray_atom; |
670 | - ev.xclient.format = 32; |
671 | - memcpy((char *)&ev.xclient.data, (const char *) l, sizeof(l)); |
672 | - XSendEvent(display, sysTrayWindow, False, 0, &ev); |
673 | - setMinimumSize(22, 22); // required at least on GNOME |
674 | -} |
675 | - |
676 | -void QSystemTrayIconSys::updateIcon() |
677 | -{ |
678 | - update(); |
679 | -} |
680 | - |
681 | -void QSystemTrayIconSys::resizeEvent(QResizeEvent *re) |
682 | -{ |
683 | - QWidget::resizeEvent(re); |
684 | - updateIcon(); |
685 | -} |
686 | - |
687 | -void QSystemTrayIconSys::paintEvent(QPaintEvent*) |
688 | -{ |
689 | - QPainter p(this); |
690 | - if (!getSysTrayVisualInfo()) { |
691 | - const QRegion oldSystemClip = p.paintEngine()->systemClip(); |
692 | - const QRect clearedRect = oldSystemClip.boundingRect(); |
693 | - XClearArea(QX11Info::display(), winId(), clearedRect.x(), clearedRect.y(), |
694 | - clearedRect.width(), clearedRect.height(), False); |
695 | - QPaintEngine *pe = p.paintEngine(); |
696 | - pe->setSystemClip(clearedRect); |
697 | - q->icon().paint(&p, rect()); |
698 | - pe->setSystemClip(oldSystemClip); |
699 | - } else { |
700 | - p.setCompositionMode(QPainter::CompositionMode_Source); |
701 | - p.fillRect(rect(), Qt::transparent); |
702 | - p.setCompositionMode(QPainter::CompositionMode_SourceOver); |
703 | - q->icon().paint(&p, rect()); |
704 | + Q_FOREACH(QSystemTrayIconPrivate *trayIconPrivate, trayIconPrivates) { |
705 | + if (trayIconPrivate->sys) { |
706 | + delete trayIconPrivate->sys; |
707 | + trayIconPrivate->sys = 0; |
708 | + } |
709 | + // When visible is true, sys is usually not 0 but it can be 0 if the |
710 | + // call to install_sys() failed. |
711 | + if (trayIconPrivate->visible) { |
712 | + trayIconPrivate->install_sys(); |
713 | + } |
714 | } |
715 | } |
716 | |
717 | -void QSystemTrayIconSys::mousePressEvent(QMouseEvent *ev) |
718 | +void QSystemTrayIconSysFactory::registerSystemTrayIconPrivate(QSystemTrayIconPrivate* trayIconPrivate) |
719 | { |
720 | - QPoint globalPos = ev->globalPos(); |
721 | - if (ev->button() == Qt::RightButton && q->contextMenu()) |
722 | - q->contextMenu()->popup(globalPos); |
723 | - |
724 | - if (QBalloonTip::isBalloonVisible()) { |
725 | - emit q->messageClicked(); |
726 | - QBalloonTip::hideBalloon(); |
727 | - } |
728 | - |
729 | - if (ev->button() == Qt::LeftButton) |
730 | - emit q->activated(QSystemTrayIcon::Trigger); |
731 | - else if (ev->button() == Qt::RightButton) |
732 | - emit q->activated(QSystemTrayIcon::Context); |
733 | - else if (ev->button() == Qt::MidButton) |
734 | - emit q->activated(QSystemTrayIcon::MiddleClick); |
735 | + trayIconPrivates.insert(trayIconPrivate); |
736 | } |
737 | |
738 | -void QSystemTrayIconSys::mouseDoubleClickEvent(QMouseEvent *ev) |
739 | +void QSystemTrayIconSysFactory::unregisterSystemTrayIconPrivate(QSystemTrayIconPrivate* trayIconPrivate) |
740 | { |
741 | - if (ev->button() == Qt::LeftButton) |
742 | - emit q->activated(QSystemTrayIcon::DoubleClick); |
743 | + trayIconPrivates.remove(trayIconPrivate); |
744 | } |
745 | |
746 | -#ifndef QT_NO_WHEELEVENT |
747 | -void QSystemTrayIconSys::wheelEvent(QWheelEvent *e) |
748 | +QAbstractSystemTrayIconSys *QSystemTrayIconSysFactory::create(QSystemTrayIcon *trayIcon) const |
749 | { |
750 | - QApplication::sendEvent(q, e); |
751 | + QSystemTrayIconSysFactoryInterface *f = factory(); |
752 | + if (!f) { |
753 | + qWarning("No systemtrayicon available"); |
754 | + return 0; |
755 | + } |
756 | + return f->create(trayIcon); |
757 | } |
758 | -#endif |
759 | |
760 | -bool QSystemTrayIconSys::event(QEvent *e) |
761 | +bool QSystemTrayIconSysFactory::isAvailable() const |
762 | { |
763 | - if (e->type() == QEvent::ToolTip) { |
764 | - return QApplication::sendEvent(q, e); |
765 | - } |
766 | - return QWidget::event(e); |
767 | + return factory(); |
768 | } |
769 | |
770 | -bool QSystemTrayIconSys::x11Event(XEvent *event) |
771 | +//////////////////////////////////////////////// |
772 | +QSystemTrayIconPrivate::~QSystemTrayIconPrivate() |
773 | { |
774 | - if (event->type == ReparentNotify) |
775 | - show(); |
776 | - return QWidget::x11Event(event); |
777 | + qt_guiSystemTrayIconSysFactory()->unregisterSystemTrayIconPrivate(this); |
778 | + delete sys; |
779 | } |
780 | |
781 | -//////////////////////////////////////////////////////////////////////////// |
782 | void QSystemTrayIconPrivate::install_sys() |
783 | { |
784 | Q_Q(QSystemTrayIcon); |
785 | - if (!sys) |
786 | - sys = new QSystemTrayIconSys(q); |
787 | + if (!sys) { |
788 | + // Register ourself even if create() fails: our "sys" will get created |
789 | + // later by refreshTrayIconPrivates() if a systemtray becomes |
790 | + // available. This situation can happen for applications which are |
791 | + // started at login time, while the desktop itself is starting up. |
792 | + qt_guiSystemTrayIconSysFactory()->registerSystemTrayIconPrivate(this); |
793 | + sys = qt_guiSystemTrayIconSysFactory()->create(q); |
794 | + if (!sys) { |
795 | + return; |
796 | + } |
797 | + } |
798 | + sys->updateVisibility(); |
799 | } |
800 | |
801 | QRect QSystemTrayIconPrivate::geometry_sys() const |
802 | { |
803 | - if (!sys) |
804 | - return QRect(); |
805 | - return QRect(sys->mapToGlobal(QPoint(0, 0)), sys->size()); |
806 | + if (!sys || !visible) |
807 | + return QRect(); |
808 | + return sys->geometry(); |
809 | } |
810 | |
811 | void QSystemTrayIconPrivate::remove_sys() |
812 | @@ -350,35 +161,35 @@ |
813 | if (!sys) |
814 | return; |
815 | QBalloonTip::hideBalloon(); |
816 | - sys->hide(); // this should do the trick, but... |
817 | - delete sys; // wm may resize system tray only for DestroyEvents |
818 | - sys = 0; |
819 | + sys->updateVisibility(); |
820 | } |
821 | |
822 | void QSystemTrayIconPrivate::updateIcon_sys() |
823 | { |
824 | - if (!sys) |
825 | + if (!sys || !visible) |
826 | return; |
827 | sys->updateIcon(); |
828 | } |
829 | |
830 | void QSystemTrayIconPrivate::updateMenu_sys() |
831 | { |
832 | - |
833 | + if (!sys || !visible) |
834 | + return; |
835 | + sys->updateMenu(); |
836 | } |
837 | |
838 | void QSystemTrayIconPrivate::updateToolTip_sys() |
839 | { |
840 | - if (!sys) |
841 | + if (!sys || !visible) |
842 | return; |
843 | #ifndef QT_NO_TOOLTIP |
844 | - sys->setToolTip(toolTip); |
845 | + sys->updateToolTip(); |
846 | #endif |
847 | } |
848 | |
849 | bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys() |
850 | { |
851 | - return QSystemTrayIconSys::locateSystemTray() != XNone; |
852 | + return qt_guiSystemTrayIconSysFactory()->isAvailable(); |
853 | } |
854 | |
855 | bool QSystemTrayIconPrivate::supportsMessages_sys() |
856 | @@ -389,12 +200,9 @@ |
857 | void QSystemTrayIconPrivate::showMessage_sys(const QString &message, const QString &title, |
858 | QSystemTrayIcon::MessageIcon icon, int msecs) |
859 | { |
860 | - if (!sys) |
861 | + if (!sys || !visible) |
862 | return; |
863 | - QPoint g = sys->mapToGlobal(QPoint(0, 0)); |
864 | - QBalloonTip::showBalloon(icon, message, title, sys->q, |
865 | - QPoint(g.x() + sys->width()/2, g.y() + sys->height()/2), |
866 | - msecs); |
867 | + sys->showMessage(message, title, icon, msecs); |
868 | } |
869 | |
870 | QT_END_NAMESPACE |
871 | --- /dev/null |
872 | +++ b/src/gui/util/qxembedsystemtrayicon_x11.cpp |
873 | @@ -0,0 +1,469 @@ |
874 | +/**************************************************************************** |
875 | +** |
876 | +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
877 | +** All rights reserved. |
878 | +** Contact: Nokia Corporation (qt-info@nokia.com) |
879 | +** |
880 | +** This file is part of the QtGui module of the Qt Toolkit. |
881 | +** |
882 | +** $QT_BEGIN_LICENSE:LGPL$ |
883 | +** GNU Lesser General Public License Usage |
884 | +** This file may be used under the terms of the GNU Lesser General Public |
885 | +** License version 2.1 as published by the Free Software Foundation and |
886 | +** appearing in the file LICENSE.LGPL included in the packaging of this |
887 | +** file. Please review the following information to ensure the GNU Lesser |
888 | +** General Public License version 2.1 requirements will be met: |
889 | +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
890 | +** |
891 | +** In addition, as a special exception, Nokia gives you certain additional |
892 | +** rights. These rights are described in the Nokia Qt LGPL Exception |
893 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
894 | +** |
895 | +** GNU General Public License Usage |
896 | +** Alternatively, this file may be used under the terms of the GNU General |
897 | +** Public License version 3.0 as published by the Free Software Foundation |
898 | +** and appearing in the file LICENSE.GPL included in the packaging of this |
899 | +** file. Please review the following information to ensure the GNU General |
900 | +** Public License version 3.0 requirements will be met: |
901 | +** http://www.gnu.org/copyleft/gpl.html. |
902 | +** |
903 | +** Other Usage |
904 | +** Alternatively, this file may be used in accordance with the terms and |
905 | +** conditions contained in a signed written agreement between you and Nokia. |
906 | +** |
907 | +** |
908 | +** |
909 | +** |
910 | +** |
911 | +** $QT_END_LICENSE$ |
912 | +** |
913 | +****************************************************************************/ |
914 | +#include "qxembedsystemtrayicon_x11_p.h" |
915 | + |
916 | +#ifndef QT_NO_SYSTEMTRAYICON |
917 | + |
918 | +#include "private/qt_x11_p.h" |
919 | +#include "qapplication.h" |
920 | +#include "qevent.h" |
921 | +#include "qlist.h" |
922 | +#include "qmenu.h" |
923 | +#include "qpainter.h" |
924 | +#include "qpaintengine.h" |
925 | +#include "qsystemtrayicon_p.h" |
926 | +#include "qx11info_x11.h" |
927 | + |
928 | +QT_BEGIN_INCLUDE_NAMESPACE |
929 | +#include <QtCore/qcoreapplication.h> |
930 | +#include <X11/Xlib.h> |
931 | +#include <X11/Xatom.h> |
932 | +#include <X11/Xutil.h> |
933 | +QT_END_INCLUDE_NAMESPACE |
934 | + |
935 | +QT_BEGIN_NAMESPACE |
936 | + |
937 | +class QSystemTrayIconWidget : public QWidget |
938 | +{ |
939 | +public: |
940 | + QSystemTrayIconWidget(QSystemTrayIcon *q, QXEmbedSystemTrayIconSys *s); |
941 | + ~QSystemTrayIconWidget(); |
942 | + |
943 | + static Window locateSystemTray(); |
944 | + |
945 | +protected: |
946 | + void paintEvent(QPaintEvent *pe); |
947 | + void resizeEvent(QResizeEvent *re); |
948 | + bool x11Event(XEvent *event); |
949 | + void mousePressEvent(QMouseEvent *event); |
950 | + void mouseDoubleClickEvent(QMouseEvent *event); |
951 | +#ifndef QT_NO_WHEELEVENT |
952 | + void wheelEvent(QWheelEvent *event); |
953 | +#endif |
954 | + bool event(QEvent *e); |
955 | + |
956 | +private: |
957 | + enum { |
958 | + SYSTEM_TRAY_REQUEST_DOCK = 0, |
959 | + SYSTEM_TRAY_BEGIN_MESSAGE = 1, |
960 | + SYSTEM_TRAY_CANCEL_MESSAGE =2 |
961 | + }; |
962 | + |
963 | + void addToTray(); |
964 | + static XVisualInfo* getSysTrayVisualInfo(); |
965 | + |
966 | + static Window sysTrayWindow; |
967 | + static QList<QSystemTrayIconWidget *> trayIcons; |
968 | + static QCoreApplication::EventFilter oldEventFilter; |
969 | + static bool sysTrayTracker(void *message, long *result); |
970 | + static Atom sysTraySelection; |
971 | + static XVisualInfo sysTrayVisual; |
972 | + |
973 | + QSystemTrayIcon *q; |
974 | + QXEmbedSystemTrayIconSys *sys; |
975 | + Colormap colormap; |
976 | +}; |
977 | + |
978 | +Window QSystemTrayIconWidget::sysTrayWindow = XNone; |
979 | +QList<QSystemTrayIconWidget *> QSystemTrayIconWidget::trayIcons; |
980 | +QCoreApplication::EventFilter QSystemTrayIconWidget::oldEventFilter = 0; |
981 | +Atom QSystemTrayIconWidget::sysTraySelection = XNone; |
982 | +XVisualInfo QSystemTrayIconWidget::sysTrayVisual = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
983 | + |
984 | +QSystemTrayIconWidget::QSystemTrayIconWidget(QSystemTrayIcon* q, QXEmbedSystemTrayIconSys* sys) |
985 | +: QWidget(0, Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint) |
986 | +, q(q) |
987 | +, sys(sys) |
988 | +, colormap(0) |
989 | +{ |
990 | + setAttribute(Qt::WA_AlwaysShowToolTips); |
991 | + setAttribute(Qt::WA_QuitOnClose, false); |
992 | + setAttribute(Qt::WA_NoSystemBackground, true); |
993 | + setAttribute(Qt::WA_PaintOnScreen); |
994 | + setMouseTracking(true); |
995 | +#ifndef QT_NO_TOOLTIP |
996 | + setToolTip(q->toolTip()); |
997 | +#endif |
998 | + |
999 | + static bool eventFilterAdded = false; |
1000 | + Display *display = QX11Info::display(); |
1001 | + if (!eventFilterAdded) { |
1002 | + oldEventFilter = qApp->setEventFilter(sysTrayTracker); |
1003 | + eventFilterAdded = true; |
1004 | + Window root = QX11Info::appRootWindow(); |
1005 | + XWindowAttributes attr; |
1006 | + XGetWindowAttributes(display, root, &attr); |
1007 | + if ((attr.your_event_mask & StructureNotifyMask) != StructureNotifyMask) { |
1008 | + (void) QApplication::desktop(); // lame trick to ensure our event mask is not overridden |
1009 | + XSelectInput(display, root, attr.your_event_mask | StructureNotifyMask); // for MANAGER selection |
1010 | + } |
1011 | + } |
1012 | + if (trayIcons.isEmpty()) { |
1013 | + sysTrayWindow = locateSystemTray(); |
1014 | + if (sysTrayWindow != XNone) |
1015 | + XSelectInput(display, sysTrayWindow, StructureNotifyMask); // track tray events |
1016 | + } |
1017 | + trayIcons.append(this); |
1018 | + if (sysTrayWindow != XNone) |
1019 | + addToTray(); |
1020 | +} |
1021 | + |
1022 | +QSystemTrayIconWidget::~QSystemTrayIconWidget() |
1023 | +{ |
1024 | + trayIcons.removeAt(trayIcons.indexOf(this)); |
1025 | + Display *display = QX11Info::display(); |
1026 | + if (trayIcons.isEmpty()) { |
1027 | + if (sysTrayWindow == XNone) |
1028 | + return; |
1029 | + if (display) |
1030 | + XSelectInput(display, sysTrayWindow, 0); // stop tracking the tray |
1031 | + sysTrayWindow = XNone; |
1032 | + } |
1033 | + if (colormap) |
1034 | + XFreeColormap(display, colormap); |
1035 | +} |
1036 | + |
1037 | +void QSystemTrayIconWidget::resizeEvent(QResizeEvent *re) |
1038 | +{ |
1039 | + QWidget::resizeEvent(re); |
1040 | + update(); |
1041 | +} |
1042 | + |
1043 | +void QSystemTrayIconWidget::paintEvent(QPaintEvent*) |
1044 | +{ |
1045 | + QPainter p(this); |
1046 | + if (!getSysTrayVisualInfo()) { |
1047 | + const QRegion oldSystemClip = p.paintEngine()->systemClip(); |
1048 | + const QRect clearedRect = oldSystemClip.boundingRect(); |
1049 | + XClearArea(QX11Info::display(), winId(), clearedRect.x(), clearedRect.y(), |
1050 | + clearedRect.width(), clearedRect.height(), False); |
1051 | + QPaintEngine *pe = p.paintEngine(); |
1052 | + pe->setSystemClip(clearedRect); |
1053 | + q->icon().paint(&p, rect()); |
1054 | + pe->setSystemClip(oldSystemClip); |
1055 | + } else { |
1056 | + p.setCompositionMode(QPainter::CompositionMode_Source); |
1057 | + p.fillRect(rect(), Qt::transparent); |
1058 | + p.setCompositionMode(QPainter::CompositionMode_SourceOver); |
1059 | + q->icon().paint(&p, rect()); |
1060 | + } |
1061 | +} |
1062 | + |
1063 | +void QSystemTrayIconWidget::mousePressEvent(QMouseEvent *ev) |
1064 | +{ |
1065 | + QPoint globalPos = ev->globalPos(); |
1066 | + if (ev->button() == Qt::RightButton && q->contextMenu()) |
1067 | + q->contextMenu()->popup(globalPos); |
1068 | + |
1069 | + if (QBalloonTip::isBalloonVisible()) { |
1070 | + QMetaObject::invokeMethod(q, "messageClicked"); |
1071 | + QBalloonTip::hideBalloon(); |
1072 | + } |
1073 | + |
1074 | + if (ev->button() == Qt::LeftButton) |
1075 | + qtsystray_sendActivated(q, QSystemTrayIcon::Trigger); |
1076 | + else if (ev->button() == Qt::RightButton) |
1077 | + qtsystray_sendActivated(q, QSystemTrayIcon::Context); |
1078 | + else if (ev->button() == Qt::MidButton) |
1079 | + qtsystray_sendActivated(q, QSystemTrayIcon::MiddleClick); |
1080 | +} |
1081 | + |
1082 | +void QSystemTrayIconWidget::mouseDoubleClickEvent(QMouseEvent *ev) |
1083 | +{ |
1084 | + if (ev->button() == Qt::LeftButton) |
1085 | + qtsystray_sendActivated(q, QSystemTrayIcon::DoubleClick); |
1086 | +} |
1087 | + |
1088 | +#ifndef QT_NO_WHEELEVENT |
1089 | +void QSystemTrayIconWidget::wheelEvent(QWheelEvent *e) |
1090 | +{ |
1091 | + sys->sendWheelEventToTrayIcon(e->delta(), e->orientation()); |
1092 | +} |
1093 | +#endif |
1094 | + |
1095 | +bool QSystemTrayIconWidget::event(QEvent *e) |
1096 | +{ |
1097 | + if (e->type() == QEvent::ToolTip) { |
1098 | + sys->sendToolTipEventToTrayIcon(); |
1099 | + } |
1100 | + return QWidget::event(e); |
1101 | +} |
1102 | + |
1103 | +bool QSystemTrayIconWidget::x11Event(XEvent *event) |
1104 | +{ |
1105 | + if (event->type == ReparentNotify) |
1106 | + show(); |
1107 | + return QWidget::x11Event(event); |
1108 | +} |
1109 | + |
1110 | +// Locate the system tray |
1111 | +Window QSystemTrayIconWidget::locateSystemTray() |
1112 | +{ |
1113 | + Display *display = QX11Info::display(); |
1114 | + if (sysTraySelection == XNone) { |
1115 | + int screen = QX11Info::appScreen(); |
1116 | + QString net_sys_tray = QString::fromLatin1("_NET_SYSTEM_TRAY_S%1").arg(screen); |
1117 | + sysTraySelection = XInternAtom(display, net_sys_tray.toLatin1(), False); |
1118 | + } |
1119 | + |
1120 | + return XGetSelectionOwner(QX11Info::display(), sysTraySelection); |
1121 | +} |
1122 | + |
1123 | +XVisualInfo* QSystemTrayIconWidget::getSysTrayVisualInfo() |
1124 | +{ |
1125 | + Display *display = QX11Info::display(); |
1126 | + |
1127 | + if (!sysTrayVisual.visual) { |
1128 | + Window win = locateSystemTray(); |
1129 | + if (win != XNone) { |
1130 | + Atom actual_type; |
1131 | + int actual_format; |
1132 | + ulong nitems, bytes_remaining; |
1133 | + uchar *data = 0; |
1134 | + int result = XGetWindowProperty(display, win, ATOM(_NET_SYSTEM_TRAY_VISUAL), 0, 1, |
1135 | + False, XA_VISUALID, &actual_type, |
1136 | + &actual_format, &nitems, &bytes_remaining, &data); |
1137 | + VisualID vid = 0; |
1138 | + if (result == Success && data && actual_type == XA_VISUALID && actual_format == 32 && |
1139 | + nitems == 1 && bytes_remaining == 0) |
1140 | + vid = *(VisualID*)data; |
1141 | + if (data) |
1142 | + XFree(data); |
1143 | + if (vid == 0) |
1144 | + return 0; |
1145 | + |
1146 | + uint mask = VisualIDMask; |
1147 | + XVisualInfo *vi, rvi; |
1148 | + int count; |
1149 | + rvi.visualid = vid; |
1150 | + vi = XGetVisualInfo(display, mask, &rvi, &count); |
1151 | + if (vi) { |
1152 | + sysTrayVisual = vi[0]; |
1153 | + XFree((char*)vi); |
1154 | + } |
1155 | + if (sysTrayVisual.depth != 32) |
1156 | + memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); |
1157 | + } |
1158 | + } |
1159 | + |
1160 | + return sysTrayVisual.visual ? &sysTrayVisual : 0; |
1161 | +} |
1162 | + |
1163 | +bool QSystemTrayIconWidget::sysTrayTracker(void *message, long *result) |
1164 | +{ |
1165 | + bool retval = false; |
1166 | + if (QSystemTrayIconWidget::oldEventFilter) |
1167 | + retval = QSystemTrayIconWidget::oldEventFilter(message, result); |
1168 | + |
1169 | + if (trayIcons.isEmpty()) |
1170 | + return retval; |
1171 | + |
1172 | + Display *display = QX11Info::display(); |
1173 | + XEvent *ev = (XEvent *)message; |
1174 | + if (ev->type == DestroyNotify && ev->xany.window == sysTrayWindow) { |
1175 | + sysTrayWindow = locateSystemTray(); |
1176 | + memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); |
1177 | + for (int i = 0; i < trayIcons.count(); i++) { |
1178 | + if (sysTrayWindow == XNone) { |
1179 | + QBalloonTip::hideBalloon(); |
1180 | + trayIcons[i]->hide(); // still no luck |
1181 | + trayIcons[i]->destroy(); |
1182 | + trayIcons[i]->create(); |
1183 | + } else |
1184 | + trayIcons[i]->addToTray(); // add it to the new tray |
1185 | + } |
1186 | + retval = true; |
1187 | + } else if (ev->type == ClientMessage && sysTrayWindow == XNone) { |
1188 | + static Atom manager_atom = XInternAtom(display, "MANAGER", False); |
1189 | + XClientMessageEvent *cm = (XClientMessageEvent *)message; |
1190 | + if ((cm->message_type == manager_atom) && ((Atom)cm->data.l[1] == sysTraySelection)) { |
1191 | + sysTrayWindow = cm->data.l[2]; |
1192 | + memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); |
1193 | + XSelectInput(display, sysTrayWindow, StructureNotifyMask); |
1194 | + for (int i = 0; i < trayIcons.count(); i++) { |
1195 | + trayIcons[i]->addToTray(); |
1196 | + } |
1197 | + retval = true; |
1198 | + } |
1199 | + } else if (ev->type == PropertyNotify && ev->xproperty.atom == ATOM(_NET_SYSTEM_TRAY_VISUAL) && |
1200 | + ev->xproperty.window == sysTrayWindow) { |
1201 | + memset(&sysTrayVisual, 0, sizeof(sysTrayVisual)); |
1202 | + for (int i = 0; i < trayIcons.count(); i++) { |
1203 | + trayIcons[i]->addToTray(); |
1204 | + } |
1205 | + } |
1206 | + |
1207 | + return retval; |
1208 | +} |
1209 | + |
1210 | +void QSystemTrayIconWidget::addToTray() |
1211 | +{ |
1212 | + Q_ASSERT(sysTrayWindow != XNone); |
1213 | + Display *display = QX11Info::display(); |
1214 | + |
1215 | + XVisualInfo *vi = getSysTrayVisualInfo(); |
1216 | + if (vi && vi->visual) { |
1217 | + Window root = RootWindow(display, vi->screen); |
1218 | + Window p = root; |
1219 | + if (QWidget *pw = parentWidget()) |
1220 | + p = pw->effectiveWinId(); |
1221 | + colormap = XCreateColormap(display, root, vi->visual, AllocNone); |
1222 | + XSetWindowAttributes wsa; |
1223 | + wsa.background_pixmap = 0; |
1224 | + wsa.colormap = colormap; |
1225 | + wsa.background_pixel = 0; |
1226 | + wsa.border_pixel = 0; |
1227 | + Window wid = XCreateWindow(display, p, -1, -1, 1, 1, |
1228 | + 0, vi->depth, InputOutput, vi->visual, |
1229 | + CWBackPixmap|CWBackPixel|CWBorderPixel|CWColormap, &wsa); |
1230 | + create(wid); |
1231 | + } else { |
1232 | + XSetWindowBackgroundPixmap(display, winId(), ParentRelative); |
1233 | + } |
1234 | + |
1235 | + // GNOME, NET WM Specification |
1236 | + static Atom netwm_tray_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False); |
1237 | + long l[5] = { CurrentTime, SYSTEM_TRAY_REQUEST_DOCK, static_cast<long>(winId()), 0, 0 }; |
1238 | + XEvent ev; |
1239 | + memset(&ev, 0, sizeof(ev)); |
1240 | + ev.xclient.type = ClientMessage; |
1241 | + ev.xclient.window = sysTrayWindow; |
1242 | + ev.xclient.message_type = netwm_tray_atom; |
1243 | + ev.xclient.format = 32; |
1244 | + memcpy((char *)&ev.xclient.data, (const char *) l, sizeof(l)); |
1245 | + XSendEvent(display, sysTrayWindow, False, 0, &ev); |
1246 | + setMinimumSize(22, 22); // required at least on GNOME |
1247 | +} |
1248 | + |
1249 | +//////////////////////////////////////////////////////////////////////////// |
1250 | +QXEmbedSystemTrayIconSys::QXEmbedSystemTrayIconSys(QSystemTrayIcon *q) |
1251 | +: QAbstractSystemTrayIconSys(q) |
1252 | +, widget(0) |
1253 | +{ |
1254 | +} |
1255 | + |
1256 | +QXEmbedSystemTrayIconSys::~QXEmbedSystemTrayIconSys() |
1257 | +{ |
1258 | + delete widget; |
1259 | +} |
1260 | + |
1261 | +QRect QXEmbedSystemTrayIconSys::geometry() const |
1262 | +{ |
1263 | + if (!widget) |
1264 | + return QRect(); |
1265 | + return QRect(widget->mapToGlobal(QPoint(0, 0)), widget->size()); |
1266 | +} |
1267 | + |
1268 | +void QXEmbedSystemTrayIconSys::updateIcon() |
1269 | +{ |
1270 | + if (!widget) |
1271 | + return; |
1272 | + widget->update(); |
1273 | +} |
1274 | + |
1275 | +void QXEmbedSystemTrayIconSys::updateToolTip() |
1276 | +{ |
1277 | + if (!widget) |
1278 | + return; |
1279 | + widget->setToolTip(trayIcon->toolTip()); |
1280 | +} |
1281 | + |
1282 | +void QXEmbedSystemTrayIconSys::showMessage(const QString &message, const QString &title, |
1283 | + QSystemTrayIcon::MessageIcon icon, int msecs) |
1284 | +{ |
1285 | + if (!widget) |
1286 | + return; |
1287 | + QPoint point = geometry().center(); |
1288 | + QBalloonTip::showBalloon(icon, message, title, trayIcon, point, msecs); |
1289 | +} |
1290 | + |
1291 | +void QXEmbedSystemTrayIconSys::updateVisibility() |
1292 | +{ |
1293 | + bool visible = trayIcon->isVisible(); |
1294 | + if (visible && !widget) |
1295 | + widget = new QSystemTrayIconWidget(trayIcon, this); |
1296 | + else if (!visible && widget) { |
1297 | + delete widget; |
1298 | + widget = 0; |
1299 | + } |
1300 | +} |
1301 | + |
1302 | +void QXEmbedSystemTrayIconSys::sendToolTipEventToTrayIcon() |
1303 | +{ |
1304 | +#ifndef QT_NO_TOOLTIP |
1305 | + // Pass the event through QSystemTrayIcon so that it gets a chance to |
1306 | + // update the tooltip, then asks widget to show the tooltip |
1307 | + Q_ASSERT(widget); |
1308 | + QPoint globalPos = QCursor::pos(); |
1309 | + QPoint pos = widget->mapFromGlobal(globalPos); |
1310 | + QHelpEvent event(QEvent::ToolTip, pos, globalPos); |
1311 | + QApplication::sendEvent(trayIcon, &event); |
1312 | +#endif |
1313 | +} |
1314 | + |
1315 | +void QXEmbedSystemTrayIconSys::sendWheelEventToTrayIcon(int delta, Qt::Orientation orientation) |
1316 | +{ |
1317 | +#ifndef QT_NO_WHEELEVENT |
1318 | + Q_ASSERT(widget); |
1319 | + QPoint globalPos = QCursor::pos(); |
1320 | + QPoint pos = widget->mapFromGlobal(globalPos); |
1321 | + QWheelEvent event(pos, globalPos, delta, Qt::NoButton, Qt::NoModifier, orientation); |
1322 | + QApplication::sendEvent(trayIcon, &event); |
1323 | +#endif |
1324 | +} |
1325 | + |
1326 | +void QXEmbedSystemTrayIconSys::updateMenu() |
1327 | +{ |
1328 | +} |
1329 | + |
1330 | +///////////////////////////////////////////////////////////// |
1331 | +QAbstractSystemTrayIconSys * QXEmbedSystemTrayIconSysFactory::create(QSystemTrayIcon *icon) |
1332 | +{ |
1333 | + return new QXEmbedSystemTrayIconSys(icon); |
1334 | +} |
1335 | + |
1336 | +bool QXEmbedSystemTrayIconSysFactory::isAvailable() const |
1337 | +{ |
1338 | + return QSystemTrayIconWidget::locateSystemTray() != XNone; |
1339 | +} |
1340 | + |
1341 | +QT_END_NAMESPACE |
1342 | +#endif //QT_NO_SYSTEMTRAYICON |
1343 | --- /dev/null |
1344 | +++ b/src/gui/util/qxembedsystemtrayicon_x11_p.h |
1345 | @@ -0,0 +1,104 @@ |
1346 | +/**************************************************************************** |
1347 | +** |
1348 | +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
1349 | +** All rights reserved. |
1350 | +** Contact: Nokia Corporation (qt-info@nokia.com) |
1351 | +** |
1352 | +** This file is part of the QtGui module of the Qt Toolkit. |
1353 | +** |
1354 | +** $QT_BEGIN_LICENSE:LGPL$ |
1355 | +** GNU Lesser General Public License Usage |
1356 | +** This file may be used under the terms of the GNU Lesser General Public |
1357 | +** License version 2.1 as published by the Free Software Foundation and |
1358 | +** appearing in the file LICENSE.LGPL included in the packaging of this |
1359 | +** file. Please review the following information to ensure the GNU Lesser |
1360 | +** General Public License version 2.1 requirements will be met: |
1361 | +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
1362 | +** |
1363 | +** In addition, as a special exception, Nokia gives you certain additional |
1364 | +** rights. These rights are described in the Nokia Qt LGPL Exception |
1365 | +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
1366 | +** |
1367 | +** GNU General Public License Usage |
1368 | +** Alternatively, this file may be used under the terms of the GNU General |
1369 | +** Public License version 3.0 as published by the Free Software Foundation |
1370 | +** and appearing in the file LICENSE.GPL included in the packaging of this |
1371 | +** file. Please review the following information to ensure the GNU General |
1372 | +** Public License version 3.0 requirements will be met: |
1373 | +** http://www.gnu.org/copyleft/gpl.html. |
1374 | +** |
1375 | +** Other Usage |
1376 | +** Alternatively, this file may be used in accordance with the terms and |
1377 | +** conditions contained in a signed written agreement between you and Nokia. |
1378 | +** |
1379 | +** |
1380 | +** |
1381 | +** |
1382 | +** |
1383 | +** $QT_END_LICENSE$ |
1384 | +** |
1385 | +****************************************************************************/ |
1386 | + |
1387 | +#ifndef QXEMBEDSYSTEMTRAYICON_X11_P_H |
1388 | +#define QXEMBEDSYSTEMTRAYICON_X11_P_H |
1389 | + |
1390 | +// |
1391 | +// W A R N I N G |
1392 | +// ------------- |
1393 | +// |
1394 | +// This file is not part of the Qt API. It exists for the convenience |
1395 | +// of a number of Qt sources files. This header file may change from |
1396 | +// version to version without notice, or even be removed. |
1397 | +// |
1398 | +// We mean it. |
1399 | +// |
1400 | + |
1401 | +#ifndef QT_NO_SYSTEMTRAYICON |
1402 | + |
1403 | +#include "qabstractsystemtrayiconsys_p.h" |
1404 | + |
1405 | +QT_BEGIN_NAMESPACE |
1406 | + |
1407 | +class QSystemTrayIconWidget; |
1408 | + |
1409 | +class QXEmbedSystemTrayIconSys : public QAbstractSystemTrayIconSys |
1410 | +{ |
1411 | +public: |
1412 | + QXEmbedSystemTrayIconSys(QSystemTrayIcon *); |
1413 | + ~QXEmbedSystemTrayIconSys(); |
1414 | + |
1415 | + QRect geometry() const; |
1416 | + |
1417 | + void updateVisibility(); |
1418 | + |
1419 | + void updateIcon(); |
1420 | + |
1421 | + void updateToolTip(); |
1422 | + |
1423 | + void updateMenu(); |
1424 | + |
1425 | + void showMessage(const QString &message, const QString &title, |
1426 | + QSystemTrayIcon::MessageIcon icon, int msecs); |
1427 | + |
1428 | +private: |
1429 | + friend class QSystemTrayIconWidget; |
1430 | + QSystemTrayIconWidget *widget; |
1431 | + |
1432 | + void sendToolTipEventToTrayIcon(); |
1433 | + |
1434 | + void sendWheelEventToTrayIcon(int delta, Qt::Orientation orientation); |
1435 | +}; |
1436 | + |
1437 | +struct QXEmbedSystemTrayIconSysFactory : public QSystemTrayIconSysFactoryInterface |
1438 | +{ |
1439 | + QAbstractSystemTrayIconSys * create(QSystemTrayIcon *trayIcon); |
1440 | + bool isAvailable() const; |
1441 | +}; |
1442 | + |
1443 | + |
1444 | +QT_END_NAMESPACE |
1445 | + |
1446 | +#endif // QT_NO_SYSTEMTRAYICON |
1447 | + |
1448 | +#endif // QXEMBEDSYSTEMTRAYICON_X11_P_H |
1449 | + |
1450 | --- a/src/gui/util/util.pri |
1451 | +++ b/src/gui/util/util.pri |
1452 | @@ -29,8 +29,13 @@ |
1453 | } |
1454 | |
1455 | unix:x11 { |
1456 | + HEADERS += \ |
1457 | + util/qabstractsystemtrayiconsys_p.h \ |
1458 | + util/qxembedsystemtrayicon_x11_p.h |
1459 | SOURCES += \ |
1460 | - util/qsystemtrayicon_x11.cpp |
1461 | + util/qabstractsystemtrayiconsys.cpp \ |
1462 | + util/qsystemtrayicon_x11.cpp \ |
1463 | + util/qxembedsystemtrayicon_x11.cpp |
1464 | } |
1465 | |
1466 | embedded|qpa { |