Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2917 - (hide annotations) (download)
Wed May 17 09:04:25 2017 UTC (7 years ago) by niro
File size: 48692 byte(s)
-fixed patches
1 niro 2917 Description: Introduce a plugin system for QSystemTrayIcon.
2 niro 2912 Designed to be used with sni-qt (https://launchpad.net/sni-qt)
3 niro 2917 Author: agateau@kde.org
4 niro 2912 Forwarded: no
5    
6     Introduce a plugin system for QSystemTrayIcon. Designed to be used with sni-qt
7     (https://launchpad.net/sni-qt)
8 niro 2917 ---
9 niro 2912 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 niro 2917 --- 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 niro 2912
29 niro 2917 showIconCheckBox = new QCheckBox(tr("Show icon"));
30     showIconCheckBox->setChecked(true);
31 niro 2912
32 niro 2917 +#if defined(Q_WS_X11)
33     + jitToolTipCheckBox = new QCheckBox(tr("Just In Time Tooltip"));
34     +#endif
35     +
36 niro 2912 QHBoxLayout *iconLayout = new QHBoxLayout;
37 niro 2917 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 niro 2912 }
46    
47 niro 2917 @@ -254,5 +262,37 @@
48     trayIconMenu->addAction(quitAction);
49 niro 2912
50     trayIcon = new QSystemTrayIcon(this);
51 niro 2917 + 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 niro 2912 }
84 niro 2917 +#endif
85     --- a/examples/desktop/systray/window.h
86     +++ b/examples/desktop/systray/window.h
87     @@ -69,6 +69,9 @@
88 niro 2912
89     protected:
90     void closeEvent(QCloseEvent *event);
91 niro 2917 +#if defined(Q_WS_X11)
92     + bool eventFilter(QObject *object, QEvent *event);
93     +#endif
94 niro 2912
95     private slots:
96     void setIcon(int index);
97 niro 2917 @@ -86,6 +89,9 @@
98 niro 2912 QLabel *iconLabel;
99     QComboBox *iconComboBox;
100     QCheckBox *showIconCheckBox;
101 niro 2917 +#if defined(Q_WS_X11)
102     + QCheckBox *jitToolTipCheckBox;
103     +#endif
104 niro 2912
105     QGroupBox *messageGroupBox;
106     QLabel *typeLabel;
107 niro 2917 --- /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 niro 2912 */
288     bool QSystemTrayIcon::event(QEvent *e)
289     {
290 niro 2917 -#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 niro 2912 return QObject::event(e);
297     }
298    
299 niro 2917 --- 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 niro 2912
309     QT_BEGIN_NAMESPACE
310    
311 niro 2917 +#if defined(Q_WS_X11)
312     +class QAbstractSystemTrayIconSys;
313     +#else
314 niro 2912 class QSystemTrayIconSys;
315 niro 2917 +#endif
316 niro 2912 class QToolButton;
317     class QLabel;
318    
319 niro 2917 @@ -75,6 +82,9 @@
320 niro 2912
321     public:
322     QSystemTrayIconPrivate() : sys(0), visible(false) { }
323 niro 2917 + #if defined(Q_WS_X11)
324     + ~QSystemTrayIconPrivate();
325     + #endif
326 niro 2912
327     void install_sys();
328     void remove_sys();
329 niro 2917 @@ -90,7 +100,11 @@
330     QPointer<QMenu> menu;
331 niro 2912 QIcon icon;
332     QString toolTip;
333 niro 2917 + #if defined(Q_WS_X11)
334     + QAbstractSystemTrayIconSys *sys;
335     + #else
336 niro 2912 QSystemTrayIconSys *sys;
337 niro 2917 + #endif
338 niro 2912 bool visible;
339     };
340    
341 niro 2917 @@ -123,60 +137,37 @@
342 niro 2912 };
343    
344     #if defined(Q_WS_X11)
345 niro 2917 -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 niro 2912
353 niro 2917 -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 niro 2912 {
362 niro 2917 - friend class QSystemTrayIconPrivate;
363     -
364     + Q_OBJECT
365 niro 2912 public:
366 niro 2917 - 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 niro 2912
394 niro 2917 -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 niro 2912
411     private:
412 niro 2917 - QPixmap background;
413     - QSystemTrayIcon *q;
414     - Colormap colormap;
415     + QSystemTrayIconSysFactoryInterface *factory() const;
416     + void loadPluginFactory();
417     +
418     + QSystemTrayIconSysFactoryInterface *pluginFactory;
419     + QSet<QSystemTrayIconPrivate *> trayIconPrivates;
420 niro 2912 };
421 niro 2917 -#endif // Q_WS_X11
422     +#endif
423 niro 2912
424     QT_END_NAMESPACE
425    
426 niro 2917 --- a/src/gui/util/qsystemtrayicon_x11.cpp
427     +++ b/src/gui/util/qsystemtrayicon_x11.cpp
428     @@ -38,311 +38,122 @@
429 niro 2912 ** $QT_END_LICENSE$
430     **
431     ****************************************************************************/
432 niro 2917 +#ifndef QT_NO_SYSTEMTRAYICON
433     +
434     +#include <private/qfactoryloader_p.h>
435 niro 2912
436 niro 2917 -#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 niro 2912
453 niro 2917 -#ifndef QT_NO_SYSTEMTRAYICON
454 niro 2912 QT_BEGIN_NAMESPACE
455    
456 niro 2917 -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 niro 2912
476 niro 2917 -XVisualInfo* QSystemTrayIconSys::getSysTrayVisualInfo()
477     +QSystemTrayIconSysFactory::QSystemTrayIconSysFactory()
478     +: pluginFactory(0)
479 niro 2912 {
480 niro 2917 - 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 niro 2912 }
517    
518 niro 2917 -bool QSystemTrayIconSys::sysTrayTracker(void *message, long *result)
519     +void QSystemTrayIconSysFactory::loadPluginFactory()
520 niro 2912 {
521 niro 2917 - 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 niro 2912 }
590 niro 2917 - 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 niro 2912 }
603 niro 2917 - 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 niro 2912 }
612    
613 niro 2917 -QSystemTrayIconSys::~QSystemTrayIconSys()
614     +QSystemTrayIconSysFactoryInterface *QSystemTrayIconSysFactory::factory() const
615 niro 2912 {
616 niro 2917 - 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 niro 2912 }
627 niro 2917 - 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 niro 2912 }
635    
636 niro 2917 -void QSystemTrayIconSys::addToTray()
637     +void QSystemTrayIconSysFactory::refreshTrayIconPrivates()
638 niro 2912 {
639 niro 2917 - 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 niro 2912 }
715     }
716    
717 niro 2917 -void QSystemTrayIconSys::mousePressEvent(QMouseEvent *ev)
718     +void QSystemTrayIconSysFactory::registerSystemTrayIconPrivate(QSystemTrayIconPrivate* trayIconPrivate)
719 niro 2912 {
720 niro 2917 - 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 niro 2912 }
737    
738 niro 2917 -void QSystemTrayIconSys::mouseDoubleClickEvent(QMouseEvent *ev)
739     +void QSystemTrayIconSysFactory::unregisterSystemTrayIconPrivate(QSystemTrayIconPrivate* trayIconPrivate)
740 niro 2912 {
741 niro 2917 - if (ev->button() == Qt::LeftButton)
742     - emit q->activated(QSystemTrayIcon::DoubleClick);
743     + trayIconPrivates.remove(trayIconPrivate);
744 niro 2912 }
745    
746 niro 2917 -#ifndef QT_NO_WHEELEVENT
747     -void QSystemTrayIconSys::wheelEvent(QWheelEvent *e)
748     +QAbstractSystemTrayIconSys *QSystemTrayIconSysFactory::create(QSystemTrayIcon *trayIcon) const
749 niro 2912 {
750 niro 2917 - 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 niro 2912 }
758 niro 2917 -#endif
759 niro 2912
760 niro 2917 -bool QSystemTrayIconSys::event(QEvent *e)
761     +bool QSystemTrayIconSysFactory::isAvailable() const
762 niro 2912 {
763 niro 2917 - if (e->type() == QEvent::ToolTip) {
764     - return QApplication::sendEvent(q, e);
765     - }
766     - return QWidget::event(e);
767     + return factory();
768 niro 2912 }
769    
770 niro 2917 -bool QSystemTrayIconSys::x11Event(XEvent *event)
771     +////////////////////////////////////////////////
772     +QSystemTrayIconPrivate::~QSystemTrayIconPrivate()
773 niro 2912 {
774 niro 2917 - if (event->type == ReparentNotify)
775     - show();
776     - return QWidget::x11Event(event);
777     + qt_guiSystemTrayIconSysFactory()->unregisterSystemTrayIconPrivate(this);
778     + delete sys;
779 niro 2912 }
780    
781 niro 2917 -////////////////////////////////////////////////////////////////////////////
782 niro 2912 void QSystemTrayIconPrivate::install_sys()
783     {
784     Q_Q(QSystemTrayIcon);
785 niro 2917 - 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 niro 2912 }
800    
801     QRect QSystemTrayIconPrivate::geometry_sys() const
802     {
803 niro 2917 - 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 niro 2912 }
810    
811     void QSystemTrayIconPrivate::remove_sys()
812 niro 2917 @@ -350,35 +161,35 @@
813 niro 2912 if (!sys)
814     return;
815     QBalloonTip::hideBalloon();
816 niro 2917 - 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 niro 2912 }
821    
822     void QSystemTrayIconPrivate::updateIcon_sys()
823     {
824 niro 2917 - if (!sys)
825     + if (!sys || !visible)
826 niro 2912 return;
827 niro 2917 sys->updateIcon();
828 niro 2912 }
829    
830     void QSystemTrayIconPrivate::updateMenu_sys()
831     {
832 niro 2917 -
833     + if (!sys || !visible)
834     + return;
835     + sys->updateMenu();
836 niro 2912 }
837    
838     void QSystemTrayIconPrivate::updateToolTip_sys()
839     {
840 niro 2917 - if (!sys)
841     + if (!sys || !visible)
842 niro 2912 return;
843     #ifndef QT_NO_TOOLTIP
844 niro 2917 - sys->setToolTip(toolTip);
845     + sys->updateToolTip();
846 niro 2912 #endif
847     }
848    
849     bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
850     {
851 niro 2917 - return QSystemTrayIconSys::locateSystemTray() != XNone;
852     + return qt_guiSystemTrayIconSysFactory()->isAvailable();
853 niro 2912 }
854    
855     bool QSystemTrayIconPrivate::supportsMessages_sys()
856 niro 2917 @@ -389,12 +200,9 @@
857     void QSystemTrayIconPrivate::showMessage_sys(const QString &message, const QString &title,
858 niro 2912 QSystemTrayIcon::MessageIcon icon, int msecs)
859     {
860 niro 2917 - if (!sys)
861     + if (!sys || !visible)
862 niro 2912 return;
863 niro 2917 - 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 niro 2912 }
869    
870     QT_END_NAMESPACE
871 niro 2917 --- /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 niro 2912 }
1454    
1455     unix:x11 {
1456 niro 2917 + HEADERS += \
1457     + util/qabstractsystemtrayiconsys_p.h \
1458     + util/qxembedsystemtrayicon_x11_p.h
1459 niro 2912 SOURCES += \
1460 niro 2917 - util/qsystemtrayicon_x11.cpp
1461     + util/qabstractsystemtrayiconsys.cpp \
1462     + util/qsystemtrayicon_x11.cpp \
1463     + util/qxembedsystemtrayicon_x11.cpp
1464 niro 2912 }
1465    
1466     embedded|qpa {