source: trunk/src/gui/util/qsystemtrayicon_pm.cpp

Last change on this file was 871, checked in by Dmitry A. Kuminov, 14 years ago

gui: Fixed application crashes if the xsystray API DLL could not be loaded.

File size: 10.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** Copyright (C) 2010 netlabs.org. OS/2 parts.
8**
9** This file is part of the QtGui module of the Qt Toolkit.
10**
11** $QT_BEGIN_LICENSE:LGPL$
12** Commercial Usage
13** Licensees holding valid Qt Commercial licenses may use this file in
14** accordance with the Qt Commercial License Agreement provided with the
15** Software or, alternatively, in accordance with the terms contained in
16** a written agreement between you and Nokia.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 2.1 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 2.1 requirements
24** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** In addition, as a special exception, Nokia gives you certain additional
27** rights. These rights are described in the Nokia Qt LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file. Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you have questions regarding the use of this file, please contact
39** Nokia at qt-info@nokia.com.
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "qsystemtrayicon_p.h"
45
46#ifndef QT_NO_SYSTEMTRAYICON
47
48#include "qapplication.h"
49#include "qdesktopwidget.h"
50#include "qlibrary.h"
51#include "qt_os2.h"
52
53// declare function pointers for dynamic linking to xsystray DLL
54#define XSTAPI_FPTRS_STATIC
55#include "xsystray.h"
56
57QT_BEGIN_NAMESPACE
58
59#define WM_XST_MYNOTIFY (WM_USER + 1000)
60
61static ULONG WM_XST_CREATED = 0;
62static ULONG MaxTextLen = 0;
63
64class QSystemTrayIconSys : QWidget
65{
66public:
67 QSystemTrayIconSys(QSystemTrayIcon *object);
68 ~QSystemTrayIconSys();
69
70 void createIcon();
71
72 void addToTray();
73 void removeFromTray();
74 QRect geometry();
75 void updateIcon();
76 void setToolTip();
77 void showMessage(const QString &title, const QString &message,
78 QSystemTrayIcon::MessageIcon type, int timeOut);
79
80protected:
81 bool pmEvent(QMSG *msg, MRESULT *result);
82
83private:
84 HPOINTER hIcon;
85 QPoint globalPos;
86 QSystemTrayIcon *q;
87};
88
89QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object)
90 : hIcon(NULLHANDLE), q(object)
91{
92}
93
94QSystemTrayIconSys::~QSystemTrayIconSys()
95{
96 if (hIcon != NULLHANDLE)
97 WinDestroyPointer(hIcon);
98}
99
100void QSystemTrayIconSys::createIcon()
101{
102 HPOINTER hIconToDestroy = hIcon;
103
104 hIcon = QPixmap::toPmHPOINTER(q->icon());
105
106 if (hIconToDestroy != NULLHANDLE)
107 WinDestroyPointer(hIconToDestroy);
108}
109
110void QSystemTrayIconSys::addToTray()
111{
112 QByteArray toolTip = q->toolTip().toLocal8Bit();
113 xstAddSysTrayIcon(winId(), 0, hIcon, toolTip.constData(), WM_XST_MYNOTIFY, 0);
114}
115
116void QSystemTrayIconSys::removeFromTray()
117{
118 xstRemoveSysTrayIcon(winId(), 0);
119}
120
121QRect QSystemTrayIconSys::geometry()
122{
123 QRect rect;
124 RECTL rcl;
125 if (xstQuerySysTrayIconRect(winId(), 0, &rcl)) {
126 int sh = qt_display_height();
127 // flip y coordinates
128 rcl.yTop = sh - rcl.yTop;
129 rcl.yBottom = sh - rcl.yBottom;
130 rect.setCoords(rcl.xLeft, rcl.yTop, rcl.xRight, rcl.yBottom);
131 }
132 return rect;
133}
134
135void QSystemTrayIconSys::updateIcon()
136{
137 createIcon();
138 xstReplaceSysTrayIcon(winId(), 0, hIcon);
139}
140
141void QSystemTrayIconSys::setToolTip()
142{
143 QByteArray toolTip = q->toolTip().toLocal8Bit();
144 xstSetSysTrayIconToolTip(winId(), 0, toolTip.constData());
145}
146
147void QSystemTrayIconSys::showMessage(const QString &title, const QString &message,
148 QSystemTrayIcon::MessageIcon type, int timeOut)
149{
150 uint uSecs = 0;
151 if ( timeOut < 0)
152 uSecs = 10000; //10 sec default
153 else uSecs = (int)timeOut;
154
155 // so far, we use fallbacks
156 // @todo use xstShowSysTrayIconBalloon() when it's implemented
157 QRect iconPos = geometry();
158 if (iconPos.isValid()) {
159 QBalloonTip::showBalloon(type, title, message, q, iconPos.center(), uSecs, true);
160 }
161}
162
163static void closeNormalPopups()
164{
165 if (QApplication::activePopupWidget()) {
166 // The system tray area is actually another application so we close all
167 // normal popups for consistency (see qapplication_pm.cpp). In case some
168 // popup refuses to close, we give up after 1024 attempts (to avoid an
169 // infinite loop).
170 int maxiter = 1024;
171 QWidget *popup;
172 while ((popup = QApplication::activePopupWidget()) && maxiter--)
173 popup->close();
174 }
175}
176
177bool QSystemTrayIconSys::pmEvent(QMSG *msg, MRESULT *result)
178{
179 switch(msg->msg) {
180
181 case WM_XST_MYNOTIFY: {
182 switch (SHORT2FROMMP(msg->mp1)) {
183 case XST_IN_MOUSE: {
184 closeNormalPopups();
185 PXSTMOUSEMSG pMsg = (PXSTMOUSEMSG)msg->mp2;
186 switch (pMsg->ulMouseMsg) {
187 case WM_BUTTON1CLICK:
188 emit q->activated(QSystemTrayIcon::Trigger);
189 break;
190 case WM_BUTTON1DBLCLK:
191 emit q->activated(QSystemTrayIcon::DoubleClick);
192 break;
193 case WM_BUTTON3CLICK:
194 emit q->activated(QSystemTrayIcon::MiddleClick);
195 break;
196 default:
197 break;
198 }
199 break;
200 }
201 case XST_IN_CONTEXT: {
202 closeNormalPopups();
203 if (QApplication::activePopupWidget()) {
204 // The system tray area is actually another application
205 // so we close all normal popups for consistency (see
206 // qapplication_pm.cpp). In case some popup refuses to
207 // close, we give up after 1024 attempts (to avoid an
208 // infinite loop).
209 int maxiter = 1024;
210 QWidget *popup;
211 while ((popup=QApplication::activePopupWidget()) && maxiter--)
212 popup->close();
213 }
214 PXSTCONTEXTMSG pMsg = (PXSTCONTEXTMSG)msg->mp2;
215 if (q->contextMenu()) {
216 QPoint gpos(pMsg->ptsPointerPos.x,
217 // flip y coordinate
218 qt_display_height() - (pMsg->ptsPointerPos.y + 1));
219 q->contextMenu()->popup(gpos);
220 q->contextMenu()->activateWindow();
221 // Must be activated for proper keyboardfocus and
222 // menu closing on OS/2
223 }
224 emit q->activated(QSystemTrayIcon::Context);
225 break;
226 }
227 case XST_IN_WHEEL: {
228 closeNormalPopups();
229 }
230 default:
231 break;
232 }
233 break;
234 }
235
236 default: {
237 if (msg->msg == WM_XST_CREATED) {
238 addToTray();
239 return true;
240 }
241 break;
242 }
243 }
244
245 return QWidget::pmEvent(msg, result);
246}
247
248template <typename T>
249inline T AssignFromVoidPtr(T &var, void *val) { var = (T)val; return var; }
250
251static bool gotApis = false;
252
253static bool resolveApis()
254{
255 static bool tried = false;
256
257 if (!tried) {
258 tried = true;
259
260 do {
261 // link to the xsystray API DLL at runtime
262 QLibrary xsystray(QLatin1String("xsystray"));
263
264 #define R(f) if (AssignFromVoidPtr(f, xsystray.resolve(#f)) == NULL) break
265
266 R(xstQuerySysTrayVersion);
267 R(xstAddSysTrayIcon);
268 R(xstReplaceSysTrayIcon);
269 R(xstRemoveSysTrayIcon);
270 R(xstSetSysTrayIconToolTip);
271 R(xstQuerySysTrayIconRect);
272 R(xstShowSysTrayIconBalloon);
273 R(xstHideSysTrayIconBalloon);
274 R(xstGetSysTrayCreatedMsgId);
275 R(xstGetSysTrayMaxTextLen);
276
277 #undef R
278
279 // initialize some constants
280 WM_XST_CREATED = xstGetSysTrayCreatedMsgId();
281 MaxTextLen = xstGetSysTrayMaxTextLen();
282
283 gotApis = true;
284
285 } while (0);
286 }
287
288 return gotApis;
289}
290
291void QSystemTrayIconPrivate::install_sys()
292{
293 if (!gotApis && !resolveApis())
294 return;
295
296 Q_Q(QSystemTrayIcon);
297 if (!sys) {
298 // @todo make QSystemTrayIconSys a singleton and use different icon IDs
299 // to differentiate between icons (this will save us from creating a new
300 // HWND per each icon the application wants to show)
301 sys = new QSystemTrayIconSys(q);
302 sys->createIcon();
303 sys->addToTray();
304 }
305}
306
307void QSystemTrayIconPrivate::
308showMessage_sys(const QString &title, const QString &message,
309 QSystemTrayIcon::MessageIcon type, int timeOut)
310{
311 if (!sys)
312 return;
313
314 sys->showMessage(title, message, type, timeOut);
315}
316
317QRect QSystemTrayIconPrivate::geometry_sys() const
318{
319 if (!sys)
320 return QRect();
321
322 return sys->geometry();
323}
324
325void QSystemTrayIconPrivate::remove_sys()
326{
327 if (!sys)
328 return;
329
330 sys->removeFromTray();
331 delete sys;
332 sys = 0;
333}
334
335void QSystemTrayIconPrivate::updateIcon_sys()
336{
337 if (!sys)
338 return;
339
340 sys->updateIcon();
341}
342
343void QSystemTrayIconPrivate::updateMenu_sys()
344{
345 // nothing to do
346}
347
348void QSystemTrayIconPrivate::updateToolTip_sys()
349{
350 if (!sys)
351 return;
352
353 sys->setToolTip();
354}
355
356bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
357{
358 if (!gotApis && !resolveApis())
359 return false;
360 return xstQuerySysTrayVersion(0, 0, 0);
361}
362
363bool QSystemTrayIconPrivate::supportsMessages_sys()
364{
365 return true;
366}
367
368QT_END_NAMESPACE
369
370#endif // ifndef QT_NO_SYSTEMTRAYICON
371
Note: See TracBrowser for help on using the repository browser.