Qt 4.8
qsystemtrayicon_x11.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "private/qt_x11_p.h"
43 #include "qlabel.h"
44 #include "qx11info_x11.h"
45 #include "qpainter.h"
46 #include "qpixmap.h"
47 #include "qbitmap.h"
48 #include "qevent.h"
49 #include "qapplication.h"
50 #include "qlist.h"
51 #include "qmenu.h"
52 #include "qtimer.h"
53 #include "qsystemtrayicon_p.h"
54 #include "qpaintengine.h"
55 
56 #ifndef QT_NO_SYSTEMTRAYICON
58 
63 XVisualInfo QSystemTrayIconSys::sysTrayVisual = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
64 
65 // Locate the system tray
67 {
69  if (sysTraySelection == XNone) {
70  int screen = QX11Info::appScreen();
71  QString net_sys_tray = QString::fromLatin1("_NET_SYSTEM_TRAY_S%1").arg(screen);
72  sysTraySelection = XInternAtom(display, net_sys_tray.toLatin1(), False);
73  }
74 
75  return XGetSelectionOwner(QX11Info::display(), sysTraySelection);
76 }
77 
79 {
81 
82  if (!sysTrayVisual.visual) {
83  Window win = locateSystemTray();
84  if (win != XNone) {
85  Atom actual_type;
86  int actual_format;
87  ulong nitems, bytes_remaining;
88  uchar *data = 0;
89  int result = XGetWindowProperty(display, win, ATOM(_NET_SYSTEM_TRAY_VISUAL), 0, 1,
90  False, XA_VISUALID, &actual_type,
91  &actual_format, &nitems, &bytes_remaining, &data);
92  VisualID vid = 0;
93  if (result == Success && data && actual_type == XA_VISUALID && actual_format == 32 &&
94  nitems == 1 && bytes_remaining == 0)
95  vid = *(VisualID*)data;
96  if (data)
97  XFree(data);
98  if (vid == 0)
99  return 0;
100 
101  uint mask = VisualIDMask;
102  XVisualInfo *vi, rvi;
103  int count;
104  rvi.visualid = vid;
105  vi = XGetVisualInfo(display, mask, &rvi, &count);
106  if (vi) {
107  sysTrayVisual = vi[0];
108  XFree((char*)vi);
109  }
110  if (sysTrayVisual.depth != 32)
111  memset(&sysTrayVisual, 0, sizeof(sysTrayVisual));
112  }
113  }
114 
115  return sysTrayVisual.visual ? &sysTrayVisual : 0;
116 }
117 
118 bool QSystemTrayIconSys::sysTrayTracker(void *message, long *result)
119 {
120  bool retval = false;
122  retval = QSystemTrayIconSys::oldEventFilter(message, result);
123 
124  if (trayIcons.isEmpty())
125  return retval;
126 
128  XEvent *ev = (XEvent *)message;
129  if (ev->type == DestroyNotify && ev->xany.window == sysTrayWindow) {
131  memset(&sysTrayVisual, 0, sizeof(sysTrayVisual));
132  for (int i = 0; i < trayIcons.count(); i++) {
133  if (sysTrayWindow == XNone) {
135  trayIcons[i]->hide(); // still no luck
136  trayIcons[i]->destroy();
137  trayIcons[i]->create();
138  } else
139  trayIcons[i]->addToTray(); // add it to the new tray
140  }
141  retval = true;
142  } else if (ev->type == ClientMessage && sysTrayWindow == XNone) {
143  static Atom manager_atom = XInternAtom(display, "MANAGER", False);
144  XClientMessageEvent *cm = (XClientMessageEvent *)message;
145  if ((cm->message_type == manager_atom) && ((Atom)cm->data.l[1] == sysTraySelection)) {
146  sysTrayWindow = cm->data.l[2];
147  memset(&sysTrayVisual, 0, sizeof(sysTrayVisual));
148  XSelectInput(display, sysTrayWindow, StructureNotifyMask);
149  for (int i = 0; i < trayIcons.count(); i++) {
150  trayIcons[i]->addToTray();
151  }
152  retval = true;
153  }
154  } else if (ev->type == PropertyNotify && ev->xproperty.atom == ATOM(_NET_SYSTEM_TRAY_VISUAL) &&
155  ev->xproperty.window == sysTrayWindow) {
156  memset(&sysTrayVisual, 0, sizeof(sysTrayVisual));
157  for (int i = 0; i < trayIcons.count(); i++) {
158  trayIcons[i]->addToTray();
159  }
160  }
161 
162  return retval;
163 }
164 
167  q(q), colormap(0)
168 {
173 
174  static bool eventFilterAdded = false;
176  if (!eventFilterAdded) {
177  oldEventFilter = qApp->setEventFilter(sysTrayTracker);
178  eventFilterAdded = true;
180  XWindowAttributes attr;
181  XGetWindowAttributes(display, root, &attr);
182  if ((attr.your_event_mask & StructureNotifyMask) != StructureNotifyMask) {
183  (void) QApplication::desktop(); // lame trick to ensure our event mask is not overridden
184  XSelectInput(display, root, attr.your_event_mask | StructureNotifyMask); // for MANAGER selection
185  }
186  }
187  if (trayIcons.isEmpty()) {
189  if (sysTrayWindow != XNone)
190  XSelectInput(display, sysTrayWindow, StructureNotifyMask); // track tray events
191  }
192  trayIcons.append(this);
193  setMouseTracking(true);
194 #ifndef QT_NO_TOOLTIP
195  setToolTip(q->toolTip());
196 #endif
197  if (sysTrayWindow != XNone)
198  addToTray();
199 }
200 
202 {
205  if (trayIcons.isEmpty()) {
206  if (sysTrayWindow == XNone)
207  return;
208  if (display)
209  XSelectInput(display, sysTrayWindow, 0); // stop tracking the tray
211  }
212  if (colormap)
213  XFreeColormap(display, colormap);
214 }
215 
217 {
220 
221  XVisualInfo *vi = getSysTrayVisualInfo();
222  if (vi && vi->visual) {
223  Window root = RootWindow(display, vi->screen);
224  Window p = root;
225  if (QWidget *pw = parentWidget())
226  p = pw->effectiveWinId();
227  colormap = XCreateColormap(display, root, vi->visual, AllocNone);
228  XSetWindowAttributes wsa;
229  wsa.background_pixmap = 0;
230  wsa.colormap = colormap;
231  wsa.background_pixel = 0;
232  wsa.border_pixel = 0;
233  Window wid = XCreateWindow(display, p, -1, -1, 1, 1,
234  0, vi->depth, InputOutput, vi->visual,
235  CWBackPixmap|CWBackPixel|CWBorderPixel|CWColormap, &wsa);
236  create(wid);
237  } else {
238  XSetWindowBackgroundPixmap(display, winId(), ParentRelative);
239  }
240 
241  // GNOME, NET WM Specification
242  static Atom netwm_tray_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False);
243  long l[5] = { CurrentTime, SYSTEM_TRAY_REQUEST_DOCK, static_cast<long>(winId()), 0, 0 };
244  XEvent ev;
245  memset(&ev, 0, sizeof(ev));
246  ev.xclient.type = ClientMessage;
247  ev.xclient.window = sysTrayWindow;
248  ev.xclient.message_type = netwm_tray_atom;
249  ev.xclient.format = 32;
250  memcpy((char *)&ev.xclient.data, (const char *) l, sizeof(l));
251  XSendEvent(display, sysTrayWindow, False, 0, &ev);
252  setMinimumSize(22, 22); // required at least on GNOME
253 }
254 
256 {
257  update();
258 }
259 
261 {
263  updateIcon();
264 }
265 
267 {
268  QPainter p(this);
269  if (!getSysTrayVisualInfo()) {
270  const QRegion oldSystemClip = p.paintEngine()->systemClip();
271  const QRect clearedRect = oldSystemClip.boundingRect();
272  XClearArea(QX11Info::display(), winId(), clearedRect.x(), clearedRect.y(),
273  clearedRect.width(), clearedRect.height(), False);
274  QPaintEngine *pe = p.paintEngine();
275  pe->setSystemClip(clearedRect);
276  q->icon().paint(&p, rect());
277  pe->setSystemClip(oldSystemClip);
278  } else {
282  q->icon().paint(&p, rect());
283  }
284 }
285 
287 {
288  QPoint globalPos = ev->globalPos();
289  if (ev->button() == Qt::RightButton && q->contextMenu())
290  q->contextMenu()->popup(globalPos);
291 
293  emit q->messageClicked();
295  }
296 
297  if (ev->button() == Qt::LeftButton)
299  else if (ev->button() == Qt::RightButton)
301  else if (ev->button() == Qt::MidButton)
303 }
304 
306 {
307  if (ev->button() == Qt::LeftButton)
309 }
310 
311 #ifndef QT_NO_WHEELEVENT
313 {
315 }
316 #endif
317 
319 {
320  if (e->type() == QEvent::ToolTip) {
321  return QApplication::sendEvent(q, e);
322  }
323  return QWidget::event(e);
324 }
325 
327 {
328  if (event->type == ReparentNotify)
329  show();
330  return QWidget::x11Event(event);
331 }
332 
335 {
337  if (!sys)
338  sys = new QSystemTrayIconSys(q);
339 }
340 
342 {
343  if (!sys)
344  return QRect();
345  return QRect(sys->mapToGlobal(QPoint(0, 0)), sys->size());
346 }
347 
349 {
350  if (!sys)
351  return;
353  sys->hide(); // this should do the trick, but...
354  delete sys; // wm may resize system tray only for DestroyEvents
355  sys = 0;
356 }
357 
359 {
360  if (!sys)
361  return;
362  sys->updateIcon();
363 }
364 
366 {
367 
368 }
369 
371 {
372  if (!sys)
373  return;
374 #ifndef QT_NO_TOOLTIP
375  sys->setToolTip(toolTip);
376 #endif
377 }
378 
380 {
382 }
383 
385 {
386  return true;
387 }
388 
389 void QSystemTrayIconPrivate::showMessage_sys(const QString &message, const QString &title,
390  QSystemTrayIcon::MessageIcon icon, int msecs)
391 {
392  if (!sys)
393  return;
394  QPoint g = sys->mapToGlobal(QPoint(0, 0));
395  QBalloonTip::showBalloon(icon, message, title, sys->q,
396  QPoint(g.x() + sys->width()/2, g.y() + sys->height()/2),
397  msecs);
398 }
399 
401 #endif //QT_NO_SYSTEMTRAYICON
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:86
QWidget * parentWidget() const
Returns the parent of this widget, or 0 if it does not have any parent widget.
Definition: qwidget.h:1035
void showMessage_sys(const QString &msg, const QString &title, QSystemTrayIcon::MessageIcon icon, int secs)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static int appScreen()
Returns the number of the screen where the application is being displayed.
The QWheelEvent class contains parameters that describe a wheel event.
Definition: qevent.h:139
void popup(const QPoint &pos, QAction *at=0)
Displays the menu so that the action atAction will be at the specified global position p...
Definition: qmenu.cpp:1847
void paintEvent(QPaintEvent *pe)
This event handler can be reimplemented in a subclass to receive paint events passed in event...
static Qt::HANDLE appRootWindow(int screen=-1)
Returns a handle for the applications root window on the given screen.
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
int width() const
Returns the width of the rectangle.
Definition: qrect.h:303
virtual void resizeEvent(QResizeEvent *)
This event handler can be reimplemented in a subclass to receive widget resize events which are passe...
Definition: qwidget.cpp:9587
void setMinimumSize(const QSize &)
Definition: qwidget.h:969
static void hideBalloon()
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
QRect boundingRect() const
Returns the bounding rectangle of this region.
Definition: qregion.cpp:4363
QSystemTrayIcon * q
int height() const
Returns the height of the rectangle.
Definition: qrect.h:306
static Window sysTrayWindow
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
void activated(QSystemTrayIcon::ActivationReason reason)
This signal is emitted when the user activates the system tray icon.
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
static void showBalloon(QSystemTrayIcon::MessageIcon icon, const QString &title, const QString &msg, QSystemTrayIcon *trayIcon, const QPoint &pos, int timeout, bool showArrow=true)
#define Q_Q(Class)
Definition: qglobal.h:2483
union _XEvent XEvent
Definition: qwindowdefs.h:116
#define ATOM(x)
Definition: qt_x11_p.h:723
void update()
Updates the widget unless updates are disabled or the widget is hidden.
Definition: qwidget.cpp:10883
unsigned char uchar
Definition: qglobal.h:994
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QString toolTip
the tooltip for the system tray entry
Q_GUI_EXPORT EGLDisplay display()
Definition: qegl.cpp:589
#define qApp
QWidget(QWidget *parent=0, Qt::WindowFlags f=0)
Constructs a widget which is a child of parent, with widget flags set to f.
Definition: qwidget.cpp:1189
static Window locateSystemTray()
static bool isSystemTrayAvailable_sys()
static QList< QSystemTrayIconSys * > trayIcons
#define emit
Definition: qobjectdefs.h:76
virtual bool x11Event(XEvent *)
This special event handler can be reimplemented in a subclass to receive native X11 events passed in ...
Definition: qwidget.cpp:9969
QWidgetData * data
Definition: qwidget.h:815
The QResizeEvent class contains event parameters for resize events.
Definition: qevent.h:349
unsigned int uint
Definition: qglobal.h:996
QMenu * contextMenu() const
Returns the current context menu for the system tray entry.
bool event(QEvent *e)
This is the main event handler; it handles event event.
QPaintEngine * paintEngine() const
Returns the paint engine that the painter is currently operating on if the painter is active; otherwi...
Definition: qpainter.cpp:1991
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
void create(WId=0, bool initializeWindow=true, bool destroyOldWindow=true)
Creates a new widget window if window is 0, otherwise sets the widget&#39;s window to window...
Definition: qwidget.cpp:1454
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:68
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
unsigned long ulong
Definition: qglobal.h:997
void show()
Shows the widget and its child widgets.
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:90
void setSystemClip(const QRegion &baseClip)
Sets the system clip for this engine.
Qt::MouseButton button() const
Returns the button that caused the event.
Definition: qevent.h:101
QIcon icon
the system tray icon
QRect rect() const
QRegion mask() const
Returns the mask currently set on a widget.
Definition: qwidget.cpp:10058
static bool sysTrayTracker(void *message, long *result)
void mouseDoubleClickEvent(QMouseEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive mouse double click...
void setToolTip(const QString &)
Definition: qwidget.cpp:11600
void setMouseTracking(bool enable)
Definition: qwidget.h:990
The QMouseEvent class contains parameters that describe a mouse event.
Definition: qevent.h:85
static QDesktopWidget * desktop()
Returns the desktop widget (also called the root window).
struct _XDisplay Display
Definition: qwindowdefs.h:115
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
bool x11Event(XEvent *event)
This special event handler can be reimplemented in a subclass to receive native X11 events passed in ...
QString toolTip() const
int indexOf(const T &t, int from=0) const
Returns the index position of the first occurrence of value in the list, searching forward from index...
Definition: qlist.h:847
void setCompositionMode(CompositionMode mode)
Sets the composition mode to the given mode.
Definition: qpainter.cpp:2422
void resizeEvent(QResizeEvent *re)
This event handler can be reimplemented in a subclass to receive widget resize events which are passe...
int y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:255
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
int x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:252
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
bool(* EventFilter)(void *message, long *result)
A function with the following signature that can be used as an event filter:
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
QFactoryLoader * l
int y() const
Returns the y coordinate of this point.
Definition: qpoint.h:131
void setAttribute(Qt::WidgetAttribute, bool on=true)
Sets the attribute attribute on this widget if on is true; otherwise clears the attribute.
Definition: qwidget.cpp:11087
XVisualInfo * getSysTrayVisualInfo()
WId winId() const
Returns the window system identifier of the widget.
Definition: qwidget.cpp:2557
int x() const
Returns the x coordinate of this point.
Definition: qpoint.h:128
bool event(QEvent *)
This is the main event handler; it handles event event.
Definition: qwidget.cpp:8636
static Atom sysTraySelection
MessageIcon
This enum describes the icon that is shown when a balloon message is displayed.
The QPaintEvent class contains event parameters for paint events.
Definition: qevent.h:298
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
const QPoint & globalPos() const
Returns the global position of the mouse cursor at the time of the event.
Definition: qevent.h:96
QRegion systemClip() const
Returns the system clip.
QSystemTrayIconSys(QSystemTrayIcon *icon, QSystemTrayIconPrivate *d)
static QCoreApplication::EventFilter oldEventFilter
static bool isBalloonVisible()
static Display * display()
Returns the default display for the application.
void wheelEvent(QWheelEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive wheel events for t...
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
Definition: qpainter.cpp:7420
The QSystemTrayIcon class provides an icon for an application in the system tray. ...
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
void paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment=Qt::AlignCenter, Mode mode=Normal, State state=Off) const
Uses the painter to paint the icon with specified alignment, required mode, and state into the rectan...
Definition: qicon.cpp:744
void mousePressEvent(QMouseEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive mouse press events...
void messageClicked()
This signal is emitted when the message displayed using showMessage() was clicked by the user...
static XVisualInfo sysTrayVisual
void removeAt(int i)
Removes the item at index position i.
Definition: qlist.h:480