Magellan Linux

Contents of /trunk/qt4/patches/qt-4.8.7-systemtrayicon.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2917 - (show annotations) (download)
Wed May 17 09:04:25 2017 UTC (6 years, 11 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 {