39 ** |
39 ** |
40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include "qsystemtrayicon_p.h" |
42 #include "qsystemtrayicon_p.h" |
43 #ifndef QT_NO_SYSTEMTRAYICON |
43 #ifndef QT_NO_SYSTEMTRAYICON |
44 #define _WIN32_IE 0x0600 //required for NOTIFYICONDATA_V2_SIZE |
44 |
45 |
45 #ifndef _WIN32_WINNT |
46 //missing defines for MINGW : |
46 #define _WIN32_WINNT 0x0600 |
47 #ifndef NIN_BALLOONTIMEOUT |
47 #endif |
48 #define NIN_BALLOONTIMEOUT (WM_USER + 4) |
48 |
49 #endif |
49 #ifndef _WIN32_IE |
50 #ifndef NIN_BALLOONUSERCLICK |
50 #define _WIN32_IE 0x600 |
51 #define NIN_BALLOONUSERCLICK (WM_USER + 5) |
|
52 #endif |
51 #endif |
53 |
52 |
54 #include <qt_windows.h> |
53 #include <qt_windows.h> |
|
54 #include <windowsx.h> |
55 #include <commctrl.h> |
55 #include <commctrl.h> |
56 #include <QBitmap> |
56 |
57 #include <QLibrary> |
57 #include <QLibrary> |
58 #include <QApplication> |
58 #include <QApplication> |
59 #include <QToolTip> |
|
60 #include <QDesktopWidget> |
|
61 #include <QSettings> |
59 #include <QSettings> |
62 |
60 |
63 QT_BEGIN_NAMESPACE |
61 QT_BEGIN_NAMESPACE |
64 |
62 |
65 static const UINT q_uNOTIFYICONID = 0; |
63 static const UINT q_uNOTIFYICONID = 0; |
72 HWND hWnd; |
70 HWND hWnd; |
73 UINT uID; |
71 UINT uID; |
74 GUID guidItem; |
72 GUID guidItem; |
75 }; |
73 }; |
76 |
74 |
|
75 #ifndef NOTIFYICON_VERSION_4 |
|
76 #define NOTIFYICON_VERSION_4 4 |
|
77 #endif |
|
78 |
|
79 #ifndef NIN_SELECT |
|
80 #define NIN_SELECT (WM_USER + 0) |
|
81 #endif |
|
82 |
|
83 #ifndef NIN_KEYSELECT |
|
84 #define NIN_KEYSELECT (WM_USER + 1) |
|
85 #endif |
|
86 |
|
87 #ifndef NIN_BALLOONTIMEOUT |
|
88 #define NIN_BALLOONTIMEOUT (WM_USER + 4) |
|
89 #endif |
|
90 |
|
91 #ifndef NIN_BALLOONUSERCLICK |
|
92 #define NIN_BALLOONUSERCLICK (WM_USER + 5) |
|
93 #endif |
|
94 |
|
95 #ifndef NIF_SHOWTIP |
|
96 #define NIF_SHOWTIP 0x00000080 |
|
97 #endif |
|
98 |
77 #define Q_MSGFLT_ALLOW 1 |
99 #define Q_MSGFLT_ALLOW 1 |
78 |
100 |
79 typedef HRESULT (WINAPI *PtrShell_NotifyIconGetRect)(const Q_NOTIFYICONIDENTIFIER* identifier, RECT* iconLocation); |
101 typedef HRESULT (WINAPI *PtrShell_NotifyIconGetRect)(const Q_NOTIFYICONIDENTIFIER* identifier, RECT* iconLocation); |
80 typedef BOOL (WINAPI *PtrChangeWindowMessageFilter)(UINT message, DWORD dwFlag); |
102 typedef BOOL (WINAPI *PtrChangeWindowMessageFilter)(UINT message, DWORD dwFlag); |
81 typedef BOOL (WINAPI *PtrChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD action, void* pChangeFilterStruct); |
103 typedef BOOL (WINAPI *PtrChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD action, void* pChangeFilterStruct); |
85 public: |
107 public: |
86 QSystemTrayIconSys(QSystemTrayIcon *object); |
108 QSystemTrayIconSys(QSystemTrayIcon *object); |
87 ~QSystemTrayIconSys(); |
109 ~QSystemTrayIconSys(); |
88 bool winEvent( MSG *m, long *result ); |
110 bool winEvent( MSG *m, long *result ); |
89 bool trayMessage(DWORD msg); |
111 bool trayMessage(DWORD msg); |
90 bool iconDrawItem(LPDRAWITEMSTRUCT lpdi); |
|
91 void setIconContents(NOTIFYICONDATA &data); |
112 void setIconContents(NOTIFYICONDATA &data); |
92 bool showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs); |
113 bool showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs); |
93 bool allowsMessages(); |
|
94 bool supportsMessages(); |
|
95 QRect findIconGeometry(const int a_iButtonID); |
114 QRect findIconGeometry(const int a_iButtonID); |
96 void createIcon(); |
115 void createIcon(); |
97 HICON hIcon; |
116 HICON hIcon; |
98 QPoint globalPos; |
117 QPoint globalPos; |
99 QSystemTrayIcon *q; |
118 QSystemTrayIcon *q; |
100 private: |
119 private: |
101 uint notifyIconSize; |
120 uint notifyIconSize; |
102 int maxTipLength; |
121 int maxTipLength; |
|
122 int version; |
103 bool ignoreNextMouseRelease; |
123 bool ignoreNextMouseRelease; |
104 }; |
124 }; |
105 |
125 |
106 bool QSystemTrayIconSys::allowsMessages() |
126 static bool allowsMessages() |
107 { |
127 { |
108 #ifndef QT_NO_SETTINGS |
128 #ifndef QT_NO_SETTINGS |
109 QSettings settings(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft" |
129 QSettings settings(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft" |
110 "\\Windows\\CurrentVersion\\Explorer\\Advanced"), QSettings::NativeFormat); |
130 "\\Windows\\CurrentVersion\\Explorer\\Advanced"), QSettings::NativeFormat); |
111 return settings.value(QLatin1String("EnableBalloonTips"), true).toBool(); |
131 return settings.value(QLatin1String("EnableBalloonTips"), true).toBool(); |
112 #else |
132 #else |
113 return false; |
133 return false; |
114 #endif |
134 #endif |
115 } |
135 } |
116 |
136 |
117 bool QSystemTrayIconSys::supportsMessages() |
|
118 { |
|
119 return allowsMessages(); |
|
120 } |
|
121 |
|
122 QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object) |
137 QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object) |
123 : hIcon(0), q(object), ignoreNextMouseRelease(false) |
138 : hIcon(0), q(object), ignoreNextMouseRelease(false) |
124 |
139 |
125 { |
140 { |
126 notifyIconSize = FIELD_OFFSET(NOTIFYICONDATA, guidItem); // NOTIFYICONDATAW_V2_SIZE; |
141 if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { |
|
142 notifyIconSize = sizeof(NOTIFYICONDATA); |
|
143 version = NOTIFYICON_VERSION_4; |
|
144 } else { |
|
145 notifyIconSize = NOTIFYICONDATA_V2_SIZE; |
|
146 version = NOTIFYICON_VERSION; |
|
147 } |
|
148 |
127 maxTipLength = 128; |
149 maxTipLength = 128; |
128 |
150 |
129 // For restoring the tray icon after explorer crashes |
151 // For restoring the tray icon after explorer crashes |
130 if (!MYWM_TASKBARCREATED) { |
152 if (!MYWM_TASKBARCREATED) { |
131 MYWM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated"); |
153 MYWM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated"); |
182 return NIIF_NONE; |
203 return NIIF_NONE; |
183 default: |
204 default: |
184 Q_ASSERT_X(false, "QSystemTrayIconSys::showMessage", "Invalid QSystemTrayIcon::MessageIcon value"); |
205 Q_ASSERT_X(false, "QSystemTrayIconSys::showMessage", "Invalid QSystemTrayIcon::MessageIcon value"); |
185 return NIIF_NONE; |
206 return NIIF_NONE; |
186 } |
207 } |
187 #else |
|
188 Q_UNUSED(icon); |
|
189 return 0; |
|
190 #endif |
|
191 } |
208 } |
192 |
209 |
193 bool QSystemTrayIconSys::showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs) |
210 bool QSystemTrayIconSys::showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs) |
194 { |
211 { |
195 #if NOTIFYICON_VERSION >= 3 |
|
196 NOTIFYICONDATA tnd; |
212 NOTIFYICONDATA tnd; |
197 memset(&tnd, 0, notifyIconSize); |
213 memset(&tnd, 0, notifyIconSize); |
198 Q_ASSERT(testAttribute(Qt::WA_WState_Created)); |
214 |
199 |
|
200 setIconContents(tnd); |
|
201 memcpy(tnd.szInfo, message.utf16(), qMin(message.length() + 1, 256) * sizeof(wchar_t)); |
215 memcpy(tnd.szInfo, message.utf16(), qMin(message.length() + 1, 256) * sizeof(wchar_t)); |
202 memcpy(tnd.szInfoTitle, title.utf16(), qMin(title.length() + 1, 64) * sizeof(wchar_t)); |
216 memcpy(tnd.szInfoTitle, title.utf16(), qMin(title.length() + 1, 64) * sizeof(wchar_t)); |
203 |
217 |
204 tnd.uID = q_uNOTIFYICONID; |
218 tnd.uID = q_uNOTIFYICONID; |
205 tnd.dwInfoFlags = iconFlag(type); |
219 tnd.dwInfoFlags = iconFlag(type); |
206 tnd.cbSize = notifyIconSize; |
220 tnd.cbSize = notifyIconSize; |
207 tnd.hWnd = winId(); |
221 tnd.hWnd = winId(); |
208 tnd.uTimeout = uSecs; |
222 tnd.uTimeout = uSecs; |
209 tnd.uFlags = NIF_INFO; |
223 tnd.uFlags = NIF_INFO | NIF_SHOWTIP; |
|
224 |
|
225 Q_ASSERT(testAttribute(Qt::WA_WState_Created)); |
210 |
226 |
211 return Shell_NotifyIcon(NIM_MODIFY, &tnd); |
227 return Shell_NotifyIcon(NIM_MODIFY, &tnd); |
212 #else |
|
213 Q_UNUSED(title); |
|
214 Q_UNUSED(message); |
|
215 Q_UNUSED(type); |
|
216 Q_UNUSED(uSecs); |
|
217 return false; |
|
218 #endif |
|
219 } |
228 } |
220 |
229 |
221 bool QSystemTrayIconSys::trayMessage(DWORD msg) |
230 bool QSystemTrayIconSys::trayMessage(DWORD msg) |
222 { |
231 { |
223 NOTIFYICONDATA tnd; |
232 NOTIFYICONDATA tnd; |
224 memset(&tnd, 0, notifyIconSize); |
233 memset(&tnd, 0, notifyIconSize); |
|
234 |
225 tnd.uID = q_uNOTIFYICONID; |
235 tnd.uID = q_uNOTIFYICONID; |
226 tnd.cbSize = notifyIconSize; |
236 tnd.cbSize = notifyIconSize; |
227 tnd.hWnd = winId(); |
237 tnd.hWnd = winId(); |
|
238 tnd.uFlags = NIF_SHOWTIP; |
|
239 tnd.uVersion = version; |
228 |
240 |
229 Q_ASSERT(testAttribute(Qt::WA_WState_Created)); |
241 Q_ASSERT(testAttribute(Qt::WA_WState_Created)); |
230 |
242 |
231 if (msg != NIM_DELETE) { |
243 if (msg == NIM_ADD || msg == NIM_MODIFY) { |
232 setIconContents(tnd); |
244 setIconContents(tnd); |
233 } |
245 } |
234 |
246 |
235 return Shell_NotifyIcon(msg, &tnd); |
247 bool success = Shell_NotifyIcon(msg, &tnd); |
236 } |
248 |
237 |
249 if (msg == NIM_ADD) |
238 bool QSystemTrayIconSys::iconDrawItem(LPDRAWITEMSTRUCT lpdi) |
250 return success && Shell_NotifyIcon(NIM_SETVERSION, &tnd); |
239 { |
251 else |
240 if (!hIcon) |
252 return success; |
241 return false; |
|
242 |
|
243 DrawIconEx(lpdi->hDC, lpdi->rcItem.left, lpdi->rcItem.top, hIcon, 0, 0, 0, 0, DI_NORMAL); |
|
244 return true; |
|
245 } |
253 } |
246 |
254 |
247 void QSystemTrayIconSys::createIcon() |
255 void QSystemTrayIconSys::createIcon() |
248 { |
256 { |
249 hIcon = 0; |
257 hIcon = 0; |
262 } |
270 } |
263 |
271 |
264 bool QSystemTrayIconSys::winEvent( MSG *m, long *result ) |
272 bool QSystemTrayIconSys::winEvent( MSG *m, long *result ) |
265 { |
273 { |
266 switch(m->message) { |
274 switch(m->message) { |
267 case WM_CREATE: |
|
268 #ifdef GWLP_USERDATA |
|
269 SetWindowLongPtr(winId(), GWLP_USERDATA, (LONG_PTR)((CREATESTRUCTW*)m->lParam)->lpCreateParams); |
|
270 #else |
|
271 SetWindowLong(winId(), GWL_USERDATA, (LONG)((CREATESTRUCTW*)m->lParam)->lpCreateParams); |
|
272 #endif |
|
273 break; |
|
274 |
|
275 case WM_DRAWITEM: |
|
276 return iconDrawItem((LPDRAWITEMSTRUCT)m->lParam); |
|
277 |
|
278 case MYWM_NOTIFYICON: |
275 case MYWM_NOTIFYICON: |
279 { |
276 { |
280 RECT r; |
277 int message = 0; |
281 GetWindowRect(winId(), &r); |
278 QPoint gpos; |
282 QEvent *e = 0; |
279 |
283 Qt::KeyboardModifiers keys = QApplication::keyboardModifiers(); |
280 if (version == NOTIFYICON_VERSION_4) { |
284 QPoint gpos = QCursor::pos(); |
281 Q_ASSERT(q_uNOTIFYICONID == HIWORD(m->lParam)); |
285 |
282 message = LOWORD(m->lParam); |
286 switch (m->lParam) { |
283 gpos = QPoint(GET_X_LPARAM(m->wParam), GET_Y_LPARAM(m->wParam)); |
287 case WM_LBUTTONUP: |
284 } else { |
|
285 Q_ASSERT(q_uNOTIFYICONID == m->wParam); |
|
286 message = m->lParam; |
|
287 gpos = QCursor::pos(); |
|
288 } |
|
289 |
|
290 switch (message) { |
|
291 case NIN_SELECT: |
|
292 case NIN_KEYSELECT: |
288 if (ignoreNextMouseRelease) |
293 if (ignoreNextMouseRelease) |
289 ignoreNextMouseRelease = false; |
294 ignoreNextMouseRelease = false; |
290 else |
295 else |
291 emit q->activated(QSystemTrayIcon::Trigger); |
296 emit q->activated(QSystemTrayIcon::Trigger); |
292 break; |
297 break; |
457 messageString = message.left(255) + QChar(); |
458 messageString = message.left(255) + QChar(); |
458 |
459 |
459 //title is limited to 63 chars + NULL |
460 //title is limited to 63 chars + NULL |
460 QString titleString = title.left(63) + QChar(); |
461 QString titleString = title.left(63) + QChar(); |
461 |
462 |
462 if (sys->supportsMessages()) { |
463 sys->showMessage(titleString, messageString, type, uSecs); |
463 sys->showMessage(titleString, messageString, type, (unsigned int)uSecs); |
|
464 } else { |
|
465 //use fallback |
|
466 QRect iconPos = sys->findIconGeometry(q_uNOTIFYICONID); |
|
467 if (iconPos.isValid()) { |
|
468 QBalloonTip::showBalloon(type, title, message, sys->q, iconPos.center(), uSecs, true); |
|
469 } |
|
470 } |
|
471 } |
464 } |
472 |
465 |
473 QRect QSystemTrayIconPrivate::geometry_sys() const |
466 QRect QSystemTrayIconPrivate::geometry_sys() const |
474 { |
467 { |
475 if (!sys) |
468 if (!sys) |
476 return QRect(); |
469 return QRect(); |
|
470 |
477 return sys->findIconGeometry(q_uNOTIFYICONID); |
471 return sys->findIconGeometry(q_uNOTIFYICONID); |
478 } |
472 } |
479 |
473 |
480 void QSystemTrayIconPrivate::remove_sys() |
474 void QSystemTrayIconPrivate::remove_sys() |
481 { |
475 { |