]> git.saurik.com Git - wxWidgets.git/blame - src/msw/taskbar.cpp
Fix text input and completion in wxComboCtrl and wxOwnerDrawnComboBox.
[wxWidgets.git] / src / msw / taskbar.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////
a71d815b 2// File: src/msw/taskbar.cpp
c42404a5 3// Purpose: Implements wxTaskBarIcon class for manipulating icons on
2bda0e17
KB
4// the Windows task bar.
5// Author: Julian Smart
1e6d9c20 6// Modified by: Vaclav Slavik
2bda0e17
KB
7// Created: 24/3/98
8// RCS-ID: $Id$
9// Copyright: (c)
65571936 10// Licence: wxWindows licence
2bda0e17
KB
11/////////////////////////////////////////////////////////////////////////
12
2bda0e17
KB
13// For compilers that support precompilation, includes "wx.h".
14#include "wx/wxprec.h"
15
16#ifdef __BORLANDC__
7520f3da 17 #pragma hdrstop
2bda0e17
KB
18#endif
19
4f167b46
VZ
20#if wxUSE_TASKBARICON
21
2bda0e17 22#ifndef WX_PRECOMP
7520f3da
WS
23 #include "wx/window.h"
24 #include "wx/frame.h"
25 #include "wx/utils.h"
26 #include "wx/menu.h"
2bda0e17
KB
27#endif
28
1032aee2 29#include "wx/msw/wrapshl.h"
c25a510b 30
2bda0e17 31#include <string.h>
6af507f7 32#include "wx/taskbar.h"
6f9822fa 33#include "wx/dynlib.h"
2bda0e17 34
c6e72bbf
VZ
35#ifndef NIN_BALLOONTIMEOUT
36 #define NIN_BALLOONTIMEOUT 0x0404
37 #define NIN_BALLOONUSERCLICK 0x0405
38#endif
39
4ad16c5f
CE
40#ifndef NIM_SETVERSION
41 #define NIM_SETVERSION 0x00000004
42#endif
43
44#ifndef NIF_INFO
45 #define NIF_INFO 0x00000010
46#endif
47
63d690d7
VZ
48#ifndef NOTIFYICONDATA_V1_SIZE
49 #ifdef UNICODE
50 #define NOTIFYICONDATA_V1_SIZE 0x0098
51 #else
52 #define NOTIFYICONDATA_V1_SIZE 0x0058
53 #endif
54#endif
55
56#ifndef NOTIFYICONDATA_V2_SIZE
57 #ifdef UNICODE
58 #define NOTIFYICONDATA_V2_SIZE 0x03A8;
59 #else
60 #define NOTIFYICONDATA_V2_SIZE 0x01E8;
61 #endif
62#endif
4ad16c5f 63
4d0d77af 64// initialized on demand
22c1dcbb
VZ
65static UINT gs_msgTaskbar = 0;
66static UINT gs_msgRestartTaskbar = 0;
2bda0e17 67
56194595
RD
68
69IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
56194595 70
4d0d77af
VZ
71// ============================================================================
72// implementation
73// ============================================================================
74
6f9822fa
VZ
75// wrapper around Shell_NotifyIcon(): this function is not present in Win95
76// shell32.dll so load it dynamically to allow programs using wxTaskBarIcon to
77// start under this OS
78static BOOL wxShellNotifyIcon(DWORD dwMessage, NOTIFYICONDATA *pData)
79{
80#if wxUSE_DYNLIB_CLASS
81 typedef BOOL (WINAPI *Shell_NotifyIcon_t)(DWORD, NOTIFYICONDATA *);
82
83 static Shell_NotifyIcon_t s_pfnShell_NotifyIcon = NULL;
84 static bool s_initialized = false;
85 if ( !s_initialized )
86 {
87 s_initialized = true;
88
89 wxLogNull noLog;
90 wxDynamicLibrary dllShell("shell32.dll");
91 if ( dllShell.IsLoaded() )
92 {
d0edb9da 93 wxDL_INIT_FUNC_AW(s_pfn, Shell_NotifyIcon, dllShell);
6f9822fa
VZ
94 }
95
96 // NB: it's ok to destroy dllShell here, we link to shell32.dll
97 // implicitly so it won't be unloaded
98 }
99
100 return s_pfnShell_NotifyIcon ? (*s_pfnShell_NotifyIcon)(dwMessage, pData)
101 : FALSE;
102#else // !wxUSE_DYNLIB_CLASS
103 return Shell_NotifyIcon(dwMessage, pData);
104#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
105}
106
1e6d9c20
VS
107// ----------------------------------------------------------------------------
108// wxTaskBarIconWindow: helper window
109// ----------------------------------------------------------------------------
110
111// NB: this class serves two purposes:
112// 1. win32 needs a HWND associated with taskbar icon, this provides it
113// 2. we need wxTopLevelWindow so that the app doesn't exit when
114// last frame is closed but there still is a taskbar icon
115class wxTaskBarIconWindow : public wxFrame
116{
117public:
118 wxTaskBarIconWindow(wxTaskBarIcon *icon)
bfbb0b4c 119 : wxFrame(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0),
1e6d9c20
VS
120 m_icon(icon)
121 {
122 }
bfbb0b4c 123
1e6d9c20
VS
124 WXLRESULT MSWWindowProc(WXUINT msg,
125 WXWPARAM wParam, WXLPARAM lParam)
126 {
127 if (msg == gs_msgRestartTaskbar || msg == gs_msgTaskbar)
128 {
dda36afd 129 return m_icon->WindowProc(msg, wParam, lParam);
1e6d9c20
VS
130 }
131 else
132 {
133 return wxFrame::MSWWindowProc(msg, wParam, lParam);
134 }
135 }
136
137private:
138 wxTaskBarIcon *m_icon;
139};
140
bfbb0b4c 141
4d0d77af
VZ
142// ----------------------------------------------------------------------------
143// NotifyIconData: wrapper around NOTIFYICONDATA
144// ----------------------------------------------------------------------------
56194595 145
4d0d77af
VZ
146struct NotifyIconData : public NOTIFYICONDATA
147{
148 NotifyIconData(WXHWND hwnd)
149 {
150 memset(this, 0, sizeof(NOTIFYICONDATA));
63d690d7
VZ
151
152 // Do _not_ use sizeof(NOTIFYICONDATA) here, it may be too big if we're
153 // compiled with newer headers but running on an older system and while
154 // we could do complicated tests for the exact system version it's
155 // easier to just use an old size which should be supported everywhere
156 // from Windows 2000 up and which is all we need as we don't use any
157 // newer features so far. But if we're running under a really ancient
158 // system (Win9x), fall back to even smaller size -- then the balloon
159 // related features won't be available but the rest will still work.
160 cbSize = wxTheApp->GetShell32Version() >= 500
161 ? NOTIFYICONDATA_V2_SIZE
162 : NOTIFYICONDATA_V1_SIZE;
163
4d0d77af
VZ
164 hWnd = (HWND) hwnd;
165 uCallbackMessage = gs_msgTaskbar;
166 uFlags = NIF_MESSAGE;
167
168 // we use the same id for all taskbar icons as we don't need it to
169 // distinguish between them
170 uID = 99;
171 }
172};
173
174// ----------------------------------------------------------------------------
175// wxTaskBarIcon
176// ----------------------------------------------------------------------------
177
178wxTaskBarIcon::wxTaskBarIcon()
2bda0e17 179{
1e6d9c20 180 m_win = NULL;
04cd30de 181 m_iconAdded = false;
1e6d9c20 182 RegisterWindowMessages();
2bda0e17
KB
183}
184
4d0d77af 185wxTaskBarIcon::~wxTaskBarIcon()
2bda0e17 186{
bebe622d 187 if ( m_iconAdded )
2bda0e17 188 RemoveIcon();
2bda0e17 189
bebe622d
VZ
190 if ( m_win )
191 {
192 // we must use delete and not Destroy() here because the latter will
193 // only schedule the window to be deleted during the next idle event
194 // processing but we may not get any idle events if there are no other
195 // windows left in the program
196 delete m_win;
197 }
2bda0e17
KB
198}
199
200// Operations
201bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
202{
3103e8a9
JS
203 // NB: we have to create the window lazily because of backward compatibility,
204 // old applications may create a wxTaskBarIcon instance before wxApp
1e6d9c20
VS
205 // is initialized (as samples/taskbar used to do)
206 if (!m_win)
207 {
208 m_win = new wxTaskBarIconWindow(this);
209 }
2bda0e17 210
4d0d77af
VZ
211 m_icon = icon;
212 m_strTooltip = tooltip;
213
63b3dc58 214 NotifyIconData notifyData(GetHwndOf(m_win));
2bda0e17 215
e96360ef 216 if (icon.Ok())
2bda0e17 217 {
e96360ef 218 notifyData.uFlags |= NIF_ICON;
4d0d77af 219 notifyData.hIcon = GetHiconOf(icon);
2bda0e17
KB
220 }
221
b2057360
VZ
222 // set NIF_TIP even for an empty tooltip: otherwise it would be impossible
223 // to remove an existing tooltip using this function
224 notifyData.uFlags |= NIF_TIP;
4d0d77af 225 if ( !tooltip.empty() )
2bda0e17 226 {
e408bf52 227 wxStrlcpy(notifyData.szTip, tooltip.wx_str(), WXSIZEOF(notifyData.szTip));
2bda0e17
KB
228 }
229
6f9822fa
VZ
230 bool ok = wxShellNotifyIcon(m_iconAdded ? NIM_MODIFY
231 : NIM_ADD, &notifyData) != 0;
2bda0e17 232
aea5b1c1
VZ
233 if ( !ok )
234 {
235 wxLogLastError(wxT("wxShellNotifyIcon(NIM_MODIFY/ADD)"));
236 }
237
4d0d77af
VZ
238 if ( !m_iconAdded && ok )
239 m_iconAdded = true;
240
241 return ok;
2bda0e17
KB
242}
243
23bd008a
VZ
244#if wxUSE_TASKBARICON_BALLOONS
245
cdcfde5d
VZ
246bool
247wxTaskBarIcon::ShowBalloon(const wxString& title,
248 const wxString& text,
249 unsigned msec,
250 int flags)
251{
252 wxCHECK_MSG( m_iconAdded, false,
9a83f860 253 wxT("can't be used before the icon is created") );
cdcfde5d 254
d3f12098
VZ
255 const HWND hwnd = GetHwndOf(m_win);
256
257 // we need to enable version 5.0 behaviour to receive notifications about
258 // the balloon disappearance
259 NotifyIconData notifyData(hwnd);
260 notifyData.uFlags = 0;
63d690d7 261 notifyData.uVersion = 3 /* NOTIFYICON_VERSION for Windows 2000/XP */;
d3f12098 262
aea5b1c1
VZ
263 if ( !wxShellNotifyIcon(NIM_SETVERSION, &notifyData) )
264 {
265 wxLogLastError(wxT("wxShellNotifyIcon(NIM_SETVERSION)"));
266 }
d3f12098
VZ
267
268 // do show the balloon now
269 notifyData = NotifyIconData(hwnd);
cdcfde5d
VZ
270 notifyData.uFlags |= NIF_INFO;
271 notifyData.uTimeout = msec;
e408bf52
VZ
272 wxStrlcpy(notifyData.szInfo, text.wx_str(), WXSIZEOF(notifyData.szInfo));
273 wxStrlcpy(notifyData.szInfoTitle, title.wx_str(),
cdcfde5d
VZ
274 WXSIZEOF(notifyData.szInfoTitle));
275
276 if ( flags & wxICON_INFORMATION )
277 notifyData.dwInfoFlags |= NIIF_INFO;
278 else if ( flags & wxICON_WARNING )
279 notifyData.dwInfoFlags |= NIIF_WARNING;
280 else if ( flags & wxICON_ERROR )
281 notifyData.dwInfoFlags |= NIIF_ERROR;
282
aea5b1c1
VZ
283 bool ok = wxShellNotifyIcon(NIM_MODIFY, &notifyData) != 0;
284 if ( !ok )
285 {
286 wxLogLastError(wxT("wxShellNotifyIcon(NIM_MODIFY)"));
287 }
288
289 return ok;
cdcfde5d
VZ
290}
291
23bd008a
VZ
292#endif // wxUSE_TASKBARICON_BALLOONS
293
4d0d77af 294bool wxTaskBarIcon::RemoveIcon()
2bda0e17
KB
295{
296 if (!m_iconAdded)
04cd30de 297 return false;
2bda0e17 298
04cd30de 299 m_iconAdded = false;
2bda0e17 300
63b3dc58 301 NotifyIconData notifyData(GetHwndOf(m_win));
4d0d77af 302
aea5b1c1
VZ
303 bool ok = wxShellNotifyIcon(NIM_DELETE, &notifyData) != 0;
304 if ( !ok )
305 {
306 wxLogLastError(wxT("wxShellNotifyIcon(NIM_DELETE)"));
307 }
308
309 return ok;
2bda0e17
KB
310}
311
53a118d6 312#if wxUSE_MENUS
4d0d77af 313bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
69ecd30f 314{
9a83f860 315 wxASSERT_MSG( m_win != NULL, wxT("taskbar icon not initialized") );
1e6d9c20 316
04cd30de 317 static bool s_inPopup = false;
c7527e3f
JS
318
319 if (s_inPopup)
04cd30de 320 return false;
c7527e3f 321
04cd30de 322 s_inPopup = true;
c7527e3f 323
69ecd30f
RD
324 int x, y;
325 wxGetMousePosition(&x, &y);
326
1e6d9c20 327 m_win->Move(x, y);
bfbb0b4c 328
1e6d9c20 329 m_win->PushEventHandler(this);
d66d9d5b 330
50bcd1ae
JS
331 menu->UpdateUI();
332
63b3dc58
VZ
333 // the SetForegroundWindow() and PostMessage() calls are needed to work
334 // around Win32 bug with the popup menus shown for the notifications as
335 // documented at http://support.microsoft.com/kb/q135788/
336 ::SetForegroundWindow(GetHwndOf(m_win));
f6bcfd97 337
1e6d9c20 338 bool rval = m_win->PopupMenu(menu, 0, 0);
69ecd30f 339
63b3dc58 340 ::PostMessage(GetHwndOf(m_win), WM_NULL, 0, 0L);
f6bcfd97 341
1e6d9c20 342 m_win->PopEventHandler(false);
c7527e3f 343
04cd30de 344 s_inPopup = false;
d66d9d5b 345
69ecd30f
RD
346 return rval;
347}
53a118d6 348#endif // wxUSE_MENUS
69ecd30f 349
1e6d9c20 350void wxTaskBarIcon::RegisterWindowMessages()
2bda0e17 351{
4d0d77af 352 static bool s_registered = false;
2bda0e17 353
1e6d9c20 354 if ( !s_registered )
bfbb0b4c 355 {
1e6d9c20
VS
356 // Taskbar restart msg will be sent to us if the icon needs to be redrawn
357 gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated"));
2bda0e17 358
1e6d9c20
VS
359 // Also register the taskbar message here
360 gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage"));
2bda0e17 361
1e6d9c20
VS
362 s_registered = true;
363 }
2bda0e17
KB
364}
365
4d0d77af
VZ
366// ----------------------------------------------------------------------------
367// wxTaskBarIcon window proc
368// ----------------------------------------------------------------------------
369
dda36afd
VS
370long wxTaskBarIcon::WindowProc(unsigned int msg,
371 unsigned int WXUNUSED(wParam),
4d0d77af 372 long lParam)
2bda0e17 373{
d3f12098 374 if ( msg == gs_msgRestartTaskbar ) // does the icon need to be redrawn?
4d0d77af
VZ
375 {
376 m_iconAdded = false;
377 SetIcon(m_icon, m_strTooltip);
ce4f741c 378 return 0;
4d0d77af
VZ
379 }
380
1e6d9c20 381 // this function should only be called for gs_msg(Restart)Taskbar messages
d3f12098 382 wxASSERT( msg == gs_msgTaskbar );
2bda0e17 383
d3f12098
VZ
384 wxEventType eventType = 0;
385 switch ( lParam )
2bda0e17 386 {
c42404a5 387 case WM_LBUTTONDOWN:
56194595
RD
388 eventType = wxEVT_TASKBAR_LEFT_DOWN;
389 break;
2bda0e17 390
c42404a5 391 case WM_LBUTTONUP:
56194595
RD
392 eventType = wxEVT_TASKBAR_LEFT_UP;
393 break;
2bda0e17 394
c42404a5 395 case WM_RBUTTONDOWN:
56194595
RD
396 eventType = wxEVT_TASKBAR_RIGHT_DOWN;
397 break;
2bda0e17 398
c42404a5 399 case WM_RBUTTONUP:
56194595
RD
400 eventType = wxEVT_TASKBAR_RIGHT_UP;
401 break;
2bda0e17 402
c42404a5 403 case WM_LBUTTONDBLCLK:
56194595
RD
404 eventType = wxEVT_TASKBAR_LEFT_DCLICK;
405 break;
2bda0e17 406
c42404a5 407 case WM_RBUTTONDBLCLK:
56194595
RD
408 eventType = wxEVT_TASKBAR_RIGHT_DCLICK;
409 break;
2bda0e17 410
c42404a5 411 case WM_MOUSEMOVE:
56194595
RD
412 eventType = wxEVT_TASKBAR_MOVE;
413 break;
2bda0e17 414
d3f12098
VZ
415 case NIN_BALLOONTIMEOUT:
416 eventType = wxEVT_TASKBAR_BALLOON_TIMEOUT;
417 break;
418
419 case NIN_BALLOONUSERCLICK:
420 eventType = wxEVT_TASKBAR_BALLOON_CLICK;
56194595 421 break;
4d0d77af 422 }
56194595 423
d3f12098 424 if ( eventType )
4d0d77af 425 {
fa1c12bd 426 wxTaskBarIconEvent event(eventType, this);
56194595
RD
427
428 ProcessEvent(event);
429 }
4d0d77af 430
2bda0e17
KB
431 return 0;
432}
4f167b46
VZ
433
434#endif // wxUSE_TASKBARICON
435