source: trunk/src/gui/util/qsystemtrayicon_win.cpp@ 67

Last change on this file since 67 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 21.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qsystemtrayicon_p.h"
43#ifndef QT_NO_SYSTEMTRAYICON
44//#define _WIN32_IE 0x0500
45#define _WIN32_IE 0x0600 //required for NOTIFYICONDATAW_V2_SIZE
46
47//missing defines for MINGW :
48#ifndef NIN_BALLOONTIMEOUT
49#define NIN_BALLOONTIMEOUT (WM_USER + 4)
50#endif
51#ifndef NIN_BALLOONUSERCLICK
52#define NIN_BALLOONUSERCLICK (WM_USER + 5)
53#endif
54
55#include <qt_windows.h>
56#include <commctrl.h>
57#include <shlwapi.h>
58#include <QBitmap>
59#include <QLibrary>
60#include <QApplication>
61#include <QToolTip>
62#include <QDesktopWidget>
63#include <QSettings>
64
65#if defined(Q_OS_WINCE) && !defined(STANDARDSHELL_UI_MODEL)
66# include <streams.h>
67#endif
68
69QT_BEGIN_NAMESPACE
70
71#if defined(Q_OS_WINCE)
72static const UINT q_uNOTIFYICONID = 13; // IDs from 0 to 12 are reserved on WinCE.
73#else
74static const UINT q_uNOTIFYICONID = 0;
75#endif
76
77static uint MYWM_TASKBARCREATED = 0;
78#define MYWM_NOTIFYICON (WM_APP+101)
79
80typedef BOOL (WINAPI *PtrShell_NotifyIcon)(DWORD,PNOTIFYICONDATA);
81static PtrShell_NotifyIcon ptrShell_NotifyIcon = 0;
82
83static void resolveLibs()
84{
85 static bool triedResolve = false;
86#if defined Q_OS_WINCE
87 QString libName(QLatin1String("coredll"));
88 const char* funcName = "Shell_NotifyIcon";
89#else
90 QString libName(QLatin1String("shell32"));
91 const char* funcName = "Shell_NotifyIconW";
92#endif
93 if (!triedResolve) {
94 QLibrary lib(libName);
95 triedResolve = true;
96 ptrShell_NotifyIcon = (PtrShell_NotifyIcon) lib.resolve(funcName);
97 }
98}
99
100class QSystemTrayIconSys : QWidget
101{
102public:
103 QSystemTrayIconSys(QSystemTrayIcon *object);
104 ~QSystemTrayIconSys();
105 bool winEvent( MSG *m, long *result );
106 bool trayMessageA(DWORD msg);
107 bool trayMessageW(DWORD msg);
108 bool trayMessage(DWORD msg);
109 bool iconDrawItem(LPDRAWITEMSTRUCT lpdi);
110 void setIconContentsW(NOTIFYICONDATAW &data);
111 void setIconContentsA(NOTIFYICONDATAA &data);
112 bool showMessageW(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs);
113 bool showMessageA(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs);
114 bool allowsMessages();
115 bool supportsMessages();
116 QRect findIconGeometry(const int a_iButtonID);
117 QRect findTrayGeometry();
118 HBITMAP createIconMask(const QBitmap &bitmap);
119 void createIcon();
120 int detectShellVersion() const;
121 HICON hIcon;
122 QPoint globalPos;
123 QSystemTrayIcon *q;
124private:
125 uint notifyIconSizeW;
126 uint notifyIconSizeA;
127 int currentShellVersion;
128 int maxTipLength;
129};
130
131// Checks for the shell32 dll version number, since only version
132// 5 or later of supports ballon messages
133bool QSystemTrayIconSys::allowsMessages()
134{
135#ifndef QT_NO_SETTINGS
136
137 QSettings settings(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft"
138 "\\Windows\\CurrentVersion\\Explorer\\Advanced"), QSettings::NativeFormat);
139 return settings.value(QLatin1String("EnableBalloonTips"), true).toBool();
140#else
141 return false;
142#endif
143}
144
145// Checks for the shell32 dll version number, since only version
146// 5 or later of supports ballon messages
147bool QSystemTrayIconSys::supportsMessages()
148{
149#if NOTIFYICON_VERSION >= 3
150 if (currentShellVersion >= 5)
151 return allowsMessages();
152 else
153#endif
154 return false;
155}
156
157//Returns the runtime major version of the shell32 dll
158int QSystemTrayIconSys::detectShellVersion() const
159{
160#ifndef Q_OS_WINCE
161 int shellVersion = 4; //NT 4.0 and W95
162 DLLGETVERSIONPROC pDllGetVersion = (DLLGETVERSIONPROC)QLibrary::resolve(
163 QLatin1String("shell32"), "DllGetVersion");
164 if (pDllGetVersion)
165 {
166 DLLVERSIONINFO dvi;
167 HRESULT hr;
168 ZeroMemory(&dvi, sizeof(dvi));
169 dvi.cbSize = sizeof(dvi);
170 hr = (*pDllGetVersion)(&dvi);
171 if (SUCCEEDED(hr)) {
172 if (dvi.dwMajorVersion >= 5)
173 {
174 shellVersion = dvi.dwMajorVersion;
175 }
176 }
177 }
178 return shellVersion;
179#endif
180 return 4; //No ballonMessages and MaxTipLength = 64 for WindowsCE
181}
182
183QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object)
184 : hIcon(0), q(object)
185{
186 currentShellVersion = detectShellVersion();
187 notifyIconSizeA = FIELD_OFFSET(NOTIFYICONDATAA, szTip[64]); // NOTIFYICONDATAA_V1_SIZE
188 notifyIconSizeW = FIELD_OFFSET(NOTIFYICONDATAW, szTip[64]); // NOTIFYICONDATAW_V1_SIZE;
189 maxTipLength = 64;
190
191#if NOTIFYICON_VERSION >= 3
192 if (currentShellVersion >=5) {
193 notifyIconSizeA = FIELD_OFFSET(NOTIFYICONDATAA, guidItem); // NOTIFYICONDATAA_V2_SIZE
194 notifyIconSizeW = FIELD_OFFSET(NOTIFYICONDATAW, guidItem); // NOTIFYICONDATAW_V2_SIZE;
195 maxTipLength = 128;
196 }
197#endif
198
199 // For restoring the tray icon after explorer crashes
200 if (!MYWM_TASKBARCREATED) {
201 MYWM_TASKBARCREATED = QT_WA_INLINE(RegisterWindowMessageW(L"TaskbarCreated"),RegisterWindowMessageA("TaskbarCreated"));
202 }
203}
204
205QSystemTrayIconSys::~QSystemTrayIconSys()
206{
207 if (hIcon)
208 DestroyIcon(hIcon);
209}
210
211void QSystemTrayIconSys::setIconContentsW(NOTIFYICONDATAW &tnd)
212{
213 tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
214 tnd.uCallbackMessage = MYWM_NOTIFYICON;
215 tnd.hIcon = hIcon;
216 QString tip = q->toolTip();
217
218 if (!tip.isNull()) {
219 // Tip is limited to maxTipLength - NULL; lstrcpyn appends a NULL terminator.
220 tip = tip.left(maxTipLength - 1) + QChar();
221#if defined(Q_OS_WINCE)
222 wcsncpy(tnd.szTip, reinterpret_cast<const wchar_t *> (tip.utf16()), qMin(tip.length()+1, maxTipLength));
223#else
224 lstrcpynW(tnd.szTip, (TCHAR*)tip.utf16(), qMin(tip.length()+1, maxTipLength));
225#endif
226 }
227}
228
229void QSystemTrayIconSys::setIconContentsA(NOTIFYICONDATAA &tnd)
230{
231 tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
232 tnd.uCallbackMessage = MYWM_NOTIFYICON;
233 tnd.hIcon = hIcon;
234 QString tip = q->toolTip();
235
236 if (!tip.isNull()) {
237 // Tip is limited to maxTipLength - NULL; lstrcpyn appends a NULL terminator.
238 tip = tip.left(maxTipLength - 1) + QChar();
239#if defined(Q_OS_WINCE)
240 strncpy(tnd.szTip, tip.toLocal8Bit().constData(), qMin(tip.length()+1, maxTipLength));
241#else
242 lstrcpynA(tnd.szTip, tip.toLocal8Bit().constData(), qMin(tip.length()+1, maxTipLength));
243#endif
244 }
245}
246
247int iconFlag( QSystemTrayIcon::MessageIcon icon )
248{
249 int flag = 0;
250#if NOTIFYICON_VERSION >= 3
251 switch (icon) {
252 case QSystemTrayIcon::NoIcon:
253 break;
254 case QSystemTrayIcon::Critical:
255 flag = NIIF_ERROR;
256 break;
257 case QSystemTrayIcon::Warning:
258 flag = NIIF_WARNING;
259 break;
260 case QSystemTrayIcon::Information:
261 default : // fall through
262 flag = NIIF_INFO;
263 }
264#else
265 Q_UNUSED(icon);
266#endif
267 return flag;
268}
269
270bool QSystemTrayIconSys::showMessageW(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs)
271{
272#if NOTIFYICON_VERSION>=3
273 NOTIFYICONDATA tnd;
274 memset(&tnd, 0, notifyIconSizeW);
275 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
276
277 setIconContentsW(tnd);
278#if defined(Q_OS_WINCE)
279 wcsncpy(tnd.szInfo, message.utf16(), qMin(message.length() + 1, 256));
280 wcsncpy(tnd.szInfoTitle, title.utf16(), qMin(title.length()+1, 64));
281#else
282 lstrcpynW(tnd.szInfo, (TCHAR*)message.utf16(), qMin(message.length() + 1, 256));
283 lstrcpynW(tnd.szInfoTitle, (TCHAR*)title.utf16(), qMin(title.length() + 1, 64));
284#endif
285 tnd.uID = q_uNOTIFYICONID;
286 tnd.dwInfoFlags = iconFlag(type);
287 tnd.cbSize = notifyIconSizeW;
288 tnd.hWnd = winId();
289 tnd.uTimeout = uSecs;
290 tnd.uFlags = NIF_INFO;
291 return ptrShell_NotifyIcon(NIM_MODIFY, &tnd);
292#else
293 Q_UNUSED(title);
294 Q_UNUSED(message);
295 Q_UNUSED(type);
296 Q_UNUSED(uSecs);
297 return false;
298#endif
299}
300
301bool QSystemTrayIconSys::showMessageA(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs)
302{
303#if NOTIFYICON_VERSION>=3
304 NOTIFYICONDATAA tnd;
305 memset(&tnd, 0, notifyIconSizeA);
306 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
307
308 setIconContentsA(tnd);
309#if defined(Q_OS_WINCE)
310 strncpy(tnd.szInfo, message.toLocal8Bit().constData(), qMin(message.length() + 1, 256));
311 strncpy(tnd.szInfoTitle, title.toLocal8Bit().constData(), qMin(title.length()+1, 64));
312#else
313 lstrcpynA(tnd.szInfo, message.toLocal8Bit().constData(), qMin(message.length() + 1, 256));
314 lstrcpynA(tnd.szInfoTitle, title.toLocal8Bit().constData(), qMin(title.length() + 1, 64));
315#endif
316 tnd.uID = q_uNOTIFYICONID;
317 tnd.dwInfoFlags = iconFlag(type);
318 tnd.cbSize = notifyIconSizeA;
319 tnd.hWnd = winId();
320 tnd.uTimeout = uSecs;
321 tnd.uFlags = NIF_INFO;
322 return Shell_NotifyIconA(NIM_MODIFY, &tnd);
323#else
324 Q_UNUSED(title);
325 Q_UNUSED(message);
326 Q_UNUSED(type);
327 Q_UNUSED(uSecs);
328 return false;
329#endif
330}
331
332bool QSystemTrayIconSys::trayMessageA(DWORD msg)
333{
334#if !defined(Q_OS_WINCE)
335 NOTIFYICONDATAA tnd;
336 memset(&tnd, 0, notifyIconSizeA);
337 tnd.uID = q_uNOTIFYICONID;
338 tnd.cbSize = notifyIconSizeA;
339 tnd.hWnd = winId();
340 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
341
342 if (msg != NIM_DELETE) {
343 setIconContentsA(tnd);
344 }
345 return Shell_NotifyIconA(msg, &tnd);
346#else
347 Q_UNUSED(msg);
348 return false;
349#endif
350}
351
352bool QSystemTrayIconSys::trayMessageW(DWORD msg)
353{
354 NOTIFYICONDATAW tnd;
355 memset(&tnd, 0, notifyIconSizeW);
356 tnd.uID = q_uNOTIFYICONID;
357 tnd.cbSize = notifyIconSizeW;
358 tnd.hWnd = winId();
359 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
360
361 if (msg != NIM_DELETE) {
362 setIconContentsW(tnd);
363 }
364 return ptrShell_NotifyIcon(msg, &tnd);
365}
366
367bool QSystemTrayIconSys::trayMessage(DWORD msg)
368{
369 resolveLibs();
370 if (!(ptrShell_NotifyIcon))
371 return false;
372
373 QT_WA({
374 return trayMessageW(msg);
375 },
376 {
377 return trayMessageA(msg);
378 });
379}
380
381bool QSystemTrayIconSys::iconDrawItem(LPDRAWITEMSTRUCT lpdi)
382{
383 if (!hIcon)
384 return false;
385
386 DrawIconEx(lpdi->hDC, lpdi->rcItem.left, lpdi->rcItem.top, hIcon, 0, 0, 0, 0, DI_NORMAL);
387 return true;
388}
389
390HBITMAP QSystemTrayIconSys::createIconMask(const QBitmap &bitmap)
391{
392 QImage bm = bitmap.toImage().convertToFormat(QImage::Format_Mono);
393 int w = bm.width();
394 int h = bm.height();
395 int bpl = ((w+15)/16)*2; // bpl, 16 bit alignment
396 uchar *bits = new uchar[bpl*h];
397 bm.invertPixels();
398 for (int y=0; y<h; y++)
399 memcpy(bits+y*bpl, bm.scanLine(y), bpl);
400 HBITMAP hbm = CreateBitmap(w, h, 1, 1, bits);
401 delete [] bits;
402 return hbm;
403}
404
405void QSystemTrayIconSys::createIcon()
406{
407 hIcon = 0;
408 QIcon icon = q->icon();
409 if (icon.isNull())
410 return;
411
412 const int iconSizeX = GetSystemMetrics(SM_CXSMICON);
413 const int iconSizeY = GetSystemMetrics(SM_CYSMICON);
414 QSize size = icon.actualSize(QSize(iconSizeX, iconSizeY));
415 QPixmap pm = icon.pixmap(size);
416 if (pm.isNull())
417 return;
418
419 QBitmap mask = pm.mask();
420 if (mask.isNull()) {
421 mask = QBitmap(pm.size());
422 mask.fill(Qt::color1);
423 }
424
425 HBITMAP im = createIconMask(mask);
426 ICONINFO ii;
427 ii.fIcon = true;
428 ii.hbmMask = im;
429 ii.hbmColor = pm.toWinHBITMAP(QPixmap::Alpha);
430 ii.xHotspot = 0;
431 ii.yHotspot = 0;
432 hIcon = CreateIconIndirect(&ii);
433
434 DeleteObject(ii.hbmColor);
435 DeleteObject(im);
436}
437
438bool QSystemTrayIconSys::winEvent( MSG *m, long *result )
439{
440 switch(m->message) {
441 case WM_CREATE:
442#ifdef GWLP_USERDATA
443 SetWindowLongPtr(winId(), GWLP_USERDATA, (LONG_PTR)((CREATESTRUCTW*)m->lParam)->lpCreateParams);
444#else
445 SetWindowLong(winId(), GWL_USERDATA, (LONG)((CREATESTRUCTW*)m->lParam)->lpCreateParams);
446#endif
447 break;
448
449 case WM_DRAWITEM:
450 return iconDrawItem((LPDRAWITEMSTRUCT)m->lParam);
451
452 case MYWM_NOTIFYICON:
453 {
454 RECT r;
455 GetWindowRect(winId(), &r);
456 QEvent *e = 0;
457 Qt::KeyboardModifiers keys = QApplication::keyboardModifiers();
458 QPoint gpos = QCursor::pos();
459
460 switch (m->lParam) {
461 case WM_LBUTTONUP:
462 emit q->activated(QSystemTrayIcon::Trigger);
463 break;
464
465#if !defined(Q_OS_WINCE)
466 case WM_LBUTTONDBLCLK:
467 emit q->activated(QSystemTrayIcon::DoubleClick);
468 break;
469
470 case WM_RBUTTONUP:
471 if (q->contextMenu()) {
472 q->contextMenu()->popup(gpos);
473 q->contextMenu()->activateWindow();
474 //Must be activated for proper keyboardfocus and menu closing on windows:
475 }
476 emit q->activated(QSystemTrayIcon::Context);
477 break;
478
479 case NIN_BALLOONUSERCLICK:
480 emit q->messageClicked();
481 break;
482
483 case WM_MBUTTONUP:
484 emit q->activated(QSystemTrayIcon::MiddleClick);
485 break;
486#endif
487 default:
488 break;
489 }
490 if (e) {
491 bool res = QApplication::sendEvent(q, e);
492 delete e;
493 return res;
494 }
495 break;
496 }
497 default:
498 if (m->message == MYWM_TASKBARCREATED)
499 trayMessage(NIM_ADD);
500 else
501 return QWidget::winEvent(m, result);
502 break;
503 }
504 return 0;
505}
506
507void QSystemTrayIconPrivate::install_sys()
508{
509 Q_Q(QSystemTrayIcon);
510 if (!sys) {
511 sys = new QSystemTrayIconSys(q);
512 sys->createIcon();
513 sys->trayMessage(NIM_ADD);
514 }
515}
516
517//fallback on win 95/98
518QRect QSystemTrayIconSys::findTrayGeometry()
519{
520 //Use lower right corner as fallback
521 QPoint brCorner = qApp->desktop()->screenGeometry().bottomRight();
522 QRect ret(brCorner.x() - 10, brCorner.y() - 10, 10, 10);
523#if defined(Q_OS_WINCE)
524 HWND trayHandle = FindWindowW(L"Shell_TrayWnd", NULL);
525#else
526 HWND trayHandle = FindWindowA("Shell_TrayWnd", NULL);
527#endif
528 if (trayHandle) {
529#if defined(Q_OS_WINCE)
530 trayHandle = FindWindowW(L"TrayNotifyWnd", NULL);
531#else
532 trayHandle = FindWindowExA(trayHandle, NULL, "TrayNotifyWnd", NULL);
533#endif
534 if (trayHandle) {
535 RECT r;
536 if (GetWindowRect(trayHandle, &r)) {
537 ret = QRect(r.left, r.top, r.right- r.left, r.bottom - r.top);
538 }
539 }
540 }
541 return ret;
542}
543
544/*
545* This function tries to determine the icon geometry from the tray
546*
547* If it fails an invalid rect is returned.
548*/
549QRect QSystemTrayIconSys::findIconGeometry(const int iconId)
550{
551 QRect ret;
552
553 TBBUTTON buttonData;
554 DWORD processID = 0;
555#if defined(Q_OS_WINCE)
556 HWND trayHandle = FindWindowW(L"Shell_TrayWnd", NULL);
557#else
558 HWND trayHandle = FindWindowA("Shell_TrayWnd", NULL);
559#endif
560
561 //find the toolbar used in the notification area
562 if (trayHandle) {
563#if defined(Q_OS_WINCE)
564 trayHandle = FindWindowW(L"TrayNotifyWnd", NULL);
565#else
566 trayHandle = FindWindowExA(trayHandle, NULL, "TrayNotifyWnd", NULL);
567#endif
568 if (trayHandle) {
569#if defined(Q_OS_WINCE)
570 HWND hwnd = FindWindowW(L"SysPager", NULL);
571#else
572 HWND hwnd = FindWindowEx(trayHandle, NULL, L"SysPager", NULL);
573#endif
574 if (hwnd) {
575#if defined(Q_OS_WINCE)
576 hwnd = FindWindow(L"ToolbarWindow32", NULL);
577#else
578 hwnd = FindWindowEx(hwnd, NULL, L"ToolbarWindow32", NULL);
579#endif
580 if (hwnd)
581 trayHandle = hwnd;
582 }
583 }
584 }
585
586 if (!trayHandle)
587 return ret;
588
589 GetWindowThreadProcessId(trayHandle, &processID);
590 if (processID <= 0)
591 return ret;
592
593 HANDLE trayProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ, 0, processID);
594 if (!trayProcess)
595 return ret;
596
597 int buttonCount = SendMessage(trayHandle, TB_BUTTONCOUNT, 0, 0);
598#if defined(Q_OS_WINCE)
599 LPVOID data = VirtualAlloc(NULL, sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);
600#else
601 LPVOID data = VirtualAllocEx(trayProcess, NULL, sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);
602#endif
603
604 if ( buttonCount < 1 || !data ) {
605 CloseHandle(trayProcess);
606 return ret;
607 }
608
609 //search for our icon among all toolbar buttons
610 for (int toolbarButton = 0; toolbarButton < buttonCount; ++toolbarButton ) {
611 SIZE_T numBytes = 0;
612 DWORD appData[2] = { 0, 0 };
613 SendMessage(trayHandle, TB_GETBUTTON, toolbarButton , (LPARAM)data);
614
615 if(!ReadProcessMemory(trayProcess, data, &buttonData, sizeof(TBBUTTON), &numBytes))
616 continue;
617
618 if(!ReadProcessMemory(trayProcess, (LPVOID) buttonData.dwData, appData, sizeof(appData), &numBytes))
619 continue;
620
621 int currentIconId = appData[1];
622 HWND currentIconHandle = (HWND) appData[0];
623 bool isHidden = buttonData.fsState & TBSTATE_HIDDEN;
624
625 if (currentIconHandle == winId() &&
626 currentIconId == iconId && !isHidden) {
627 SendMessage(trayHandle, TB_GETITEMRECT, toolbarButton , (LPARAM)data);
628 RECT iconRect = {0, 0};
629 if(ReadProcessMemory(trayProcess, data, &iconRect, sizeof(RECT), &numBytes)) {
630 MapWindowPoints(trayHandle, NULL, (LPPOINT)&iconRect, 2);
631 QRect geometry(iconRect.left + 1, iconRect.top + 1,
632 iconRect.right - iconRect.left - 2,
633 iconRect.bottom - iconRect.top - 2);
634 if (geometry.isValid())
635 ret = geometry;
636 break;
637 }
638 }
639 }
640#if defined(Q_OS_WINCE)
641 VirtualFree(data, 0, MEM_RELEASE);
642#else
643 VirtualFreeEx(trayProcess, data, 0, MEM_RELEASE);
644#endif
645 CloseHandle(trayProcess);
646 return ret;
647}
648
649
650void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, int timeOut)
651{
652 if (!sys || !sys->allowsMessages())
653 return;
654
655 uint uSecs = 0;
656 if ( timeOut < 0)
657 uSecs = 10000; //10 sec default
658 else uSecs = (int)timeOut;
659
660 resolveLibs();
661
662 //message is limited to 255 chars + NULL
663 QString messageString;
664 if (message.isEmpty() && !title.isEmpty())
665 messageString = QLatin1String(" "); //ensures that the message shows when only title is set
666 else
667 messageString = message.left(255) + QChar();
668
669 //title is limited to 63 chars + NULL
670 QString titleString = title.left(63) + QChar();
671
672 if (sys->supportsMessages()) {
673 QT_WA({
674 sys->showMessageW(titleString, messageString, type, (unsigned int)uSecs);
675 }, {
676 sys->showMessageA(titleString, messageString, type, (unsigned int)uSecs);
677 });
678 } else {
679 //use fallbacks
680 QRect iconPos = sys->findIconGeometry(0);
681 if (iconPos.isValid()) {
682 QBalloonTip::showBalloon(type, title, message, sys->q, iconPos.center(), uSecs, true);
683 } else {
684 QRect trayRect = sys->findTrayGeometry();
685 QBalloonTip::showBalloon(type, title, message, sys->q, QPoint(trayRect.left(),
686 trayRect.center().y()), uSecs, false);
687 }
688 }
689}
690
691QRect QSystemTrayIconPrivate::geometry_sys() const
692{
693 if (!sys)
694 return QRect();
695 return sys->findIconGeometry(0);
696}
697
698void QSystemTrayIconPrivate::remove_sys()
699{
700 if (!sys)
701 return;
702
703 sys->trayMessage(NIM_DELETE);
704 delete sys;
705 sys = 0;
706}
707
708void QSystemTrayIconPrivate::updateIcon_sys()
709{
710 if (!sys)
711 return;
712
713 HICON hIconToDestroy = sys->hIcon;
714
715 sys->createIcon();
716 sys->trayMessage(NIM_MODIFY);
717
718 if (hIconToDestroy)
719 DestroyIcon(hIconToDestroy);
720}
721
722void QSystemTrayIconPrivate::updateMenu_sys()
723{
724
725}
726
727void QSystemTrayIconPrivate::updateToolTip_sys()
728{
729#ifdef Q_OS_WINCE
730 // Calling sys->trayMessage(NIM_MODIFY) on an existing icon is broken on Windows CE.
731 // So we need to call updateIcon_sys() which creates a new icon handle.
732 updateIcon_sys();
733#else
734 if (!sys)
735 return;
736
737 sys->trayMessage(NIM_MODIFY);
738#endif
739}
740
741bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
742{
743 return true;
744}
745
746QT_END_NAMESPACE
747
748#endif
Note: See TracBrowser for help on using the repository browser.