1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/taskbarbutton.cpp
3 // Purpose: Implements wxTaskBarButtonImpl class for manipulating buttons on
4 // the Windows taskbar.
5 // Author: Chaobin Zhang <zhchbin@gmail.com>
6 // Created: 2014-06-01
7 // Copyright: (c) 2014 wxWidgets development team
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13
14 #ifndef WX_PRECOMP
15 #include "wx/icon.h"
16 #include "wx/toplevel.h"
17 #endif
18
19 #if wxUSE_TASKBARBUTTON
20
21 #ifdef _MSC_VER
22 #pragma comment( lib, "shlwapi" )
23 #endif
24
25 #include "wx/msw/private.h"
26 #include "wx/msw/taskbarbutton.h"
27 #include "wx/scopedptr.h"
28 #include "wx/msw/private/comptr.h"
29 #include "wx/msw/private/cotaskmemptr.h"
30
31 #include <shlwapi.h>
32 #include <initguid.h>
33
34 #if wxUSE_DYNLIB_CLASS
35 #include "wx/dynlib.h"
36 #endif // wxUSE_DYNLIB_CLASS
37
38 // ----------------------------------------------------------------------------
39 // Redefine the interfaces: ITaskbarList3, IObjectCollection,
40 // ICustomDestinationList, IShellLink, IShellItem, IApplicationDocumentLists
41 // etc.
42 // ----------------------------------------------------------------------------
43
44 WINOLEAPI PropVariantClear(PROPVARIANT* pvar);
45
46 #ifndef PropVariantInit
47 #define PropVariantInit(pvar) memset ( (pvar), 0, sizeof(PROPVARIANT) )
48 #endif
49
50 #ifndef INFOTIPSIZE
51 #define INFOTIPSIZE 1024
52 #endif
53
54 namespace {
55
56 // The maximum number of thumbnail toolbar buttons allowed on windows is 7.
57 static const int MAX_BUTTON_COUNT = 7;
58
59 DEFINE_GUID(wxCLSID_TaskbarList,
60 0x56fdf344, 0xfd6d, 0x11d0, 0x95, 0x8a, 0x0, 0x60, 0x97, 0xc9, 0xa0, 0x90);
61 DEFINE_GUID(wxCLSID_DestinationList,
62 0x77f10cf0, 0x3db5, 0x4966, 0xb5, 0x20, 0xb7, 0xc5, 0x4f, 0xd3,0x5e, 0xd6);
63 DEFINE_GUID(wxCLSID_EnumerableObjectCollection,
64 0x2d3468c1, 0x36a7, 0x43b6, 0xac, 0x24, 0xd3, 0xf0, 0x2f, 0xd9, 0x60, 0x7a);
65 DEFINE_GUID(wxCLSID_ShellLink,
66 0x00021401, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
67 DEFINE_GUID(wxIID_ICustomDestinationList,
68 0x6332debf, 0x87b5, 0x4670, 0x90, 0xc0, 0x5e, 0x57, 0xb4, 0x08, 0xa4, 0x9e);
69 DEFINE_GUID(wxIID_ITaskbarList3,
70 0xea1afb91, 0x9e28, 0x4b86, 0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf);
71 DEFINE_GUID(wxIID_IPropertyStore,
72 0x886d8eeb, 0x8cf2, 0x4446, 0x8d, 0x02, 0xcd, 0xba, 0x1d, 0xbd, 0xcf, 0x99);
73 DEFINE_GUID(wxIID_IObjectArray,
74 0x92ca9dcd, 0x5622, 0x4bba, 0xa8, 0x05, 0x5e, 0x9f, 0x54, 0x1b, 0xd8, 0xc9);
75 DEFINE_GUID(wxIID_IObjectCollection,
76 0x5632b1a4, 0xe38a, 0x400a, 0x92, 0x8a, 0xd4, 0xcd, 0x63, 0x23, 0x02, 0x95);
77 DEFINE_GUID(wxIID_IApplicationDocumentLists,
78 0x3c594f9f, 0x9f30, 0x47a1, 0x97, 0x9a, 0xc9, 0xe8, 0x3d, 0x3d, 0x0a, 0x06);
79 DEFINE_GUID(wxCLSID_ApplicationDocumentLists,
80 0x86bec222, 0x30f2, 0x47e0, 0x9f, 0x25, 0x60, 0xd1, 0x1c, 0xd7, 0x5c, 0x28);
81 DEFINE_GUID(wxIID_IUnknown,
82 0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
83 DEFINE_GUID(wxIID_IShellItem,
84 0x43826d1e, 0xe718, 0x42ee, 0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe);
85
86 typedef IUnknown *HIMAGELIST;
87
88 typedef enum THUMBBUTTONFLAGS
89 {
90 THBF_ENABLED = 0,
91 THBF_DISABLED = 0x1,
92 THBF_DISMISSONCLICK = 0x2,
93 THBF_NOBACKGROUND = 0x4,
94 THBF_HIDDEN = 0x8,
95 THBF_NONINTERACTIVE = 0x10
96 } THUMBBUTTONFLAGS;
97
98 typedef enum THUMBBUTTONMASK
99 {
100 THB_BITMAP = 0x1,
101 THB_ICON = 0x2,
102 THB_TOOLTIP = 0x4,
103 THB_FLAGS = 0x8
104 } THUMBBUTTONMASK;
105
106 typedef struct THUMBBUTTON
107 {
108 THUMBBUTTONMASK dwMask;
109 UINT iId;
110 UINT iBitmap;
111 HICON hIcon;
112 WCHAR szTip[260];
113 THUMBBUTTONFLAGS dwFlags;
114 } THUMBBUTTON;
115
116 typedef struct THUMBBUTTON *LPTHUMBBUTTON;
117
118 typedef enum TBPFLAG
119 {
120 TBPF_NOPROGRESS = 0,
121 TBPF_INDETERMINATE = 0x1,
122 TBPF_NORMAL = 0x2,
123 TBPF_ERROR = 0x4,
124 TBPF_PAUSED = 0x8
125 } TBPFLAG;
126
127 #ifndef PROPERTYKEY_DEFINED
128 typedef struct _tagpropertykey
129 {
130 GUID fmtid;
131 DWORD pid;
132 } PROPERTYKEY;
133 #endif // !PROPERTYKEY_DEFINED
134
135 #define REFPROPERTYKEY const PROPERTYKEY &
136
137 #define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) \
138 const PROPERTYKEY name = \
139 { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
140
141 DEFINE_PROPERTYKEY(PKEY_Title,
142 0xf29f85e0, 0x4ff9, 0x1068, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9, 2);
143 DEFINE_PROPERTYKEY(PKEY_AppUserModel_IsDestListSeparator,
144 0x9f4c2855, 0x9f79, 0x4b39, 0xa8, 0xd0, 0xe1, 0xd4, 0x2d, 0xe1, 0xd5, 0xf3, 6);
145 DEFINE_PROPERTYKEY(PKEY_Link_Arguments,
146 0x436f2667, 0x14e2, 0x4feb, 0xb3, 0x0a, 0x14, 0x6c, 0x53, 0xb5, 0xb6, 0x74, 100);
147
148 #ifdef wxUSE_UNICODE
149 #define IShellLink wxIShellLinkW
150
151 DEFINE_GUID(wxIID_IShellLink,
152 0x000214F9, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
153 #else
154 #define IShellLink wxIShellLinkA
155
156 DEFINE_GUID(wxIID_IShellLink,
157 0x000214EE, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
158 #endif // wxUSE_UNICODE
159
160 typedef enum _SIGDN
161 {
162 SIGDN_NORMALDISPLAY = 0,
163 SIGDN_PARENTRELATIVEPARSING = (int)0x80018001,
164 SIGDN_DESKTOPABSOLUTEPARSING = (int)0x80028000,
165 SIGDN_PARENTRELATIVEEDITING = (int)0x80031001,
166 SIGDN_DESKTOPABSOLUTEEDITING = (int)0x8004c000,
167 SIGDN_FILESYSPATH = (int)0x80058000,
168 SIGDN_URL = (int)0x80068000,
169 SIGDN_PARENTRELATIVEFORADDRESSBAR = (int)0x8007c001,
170 SIGDN_PARENTRELATIVE = (int)0x80080001
171 } SIGDN;
172
173 enum _SICHINTF
174 {
175 SICHINT_DISPLAY = 0,
176 SICHINT_ALLFIELDS = (int)0x80000000,
177 SICHINT_CANONICAL = 0x10000000,
178 SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000
179 };
180
181 typedef DWORD SICHINTF;
182 typedef ULONG SFGAOF;
183
184 typedef enum KNOWNDESTCATEGORY
185 {
186 KDC_FREQUENT = 1,
187 KDC_RECENT = ( KDC_FREQUENT + 1 )
188 } KNOWNDESTCATEGORY;
189
190 typedef enum APPDOCLISTTYPE
191 {
192 ADLT_RECENT = 0,
193 ADLT_FREQUENT = ( ADLT_RECENT + 1 )
194 } APPDOCLISTTYPE;
195
196 } // anonymous namespace
197
198 class wxITaskbarList : public IUnknown
199 {
200 public:
201 virtual HRESULT wxSTDCALL HrInit() = 0;
202 virtual HRESULT wxSTDCALL AddTab(HWND) = 0;
203 virtual HRESULT wxSTDCALL DeleteTab(HWND) = 0;
204 virtual HRESULT wxSTDCALL ActivateTab(HWND) = 0;
205 virtual HRESULT wxSTDCALL SetActiveAlt(HWND) = 0;
206 };
207
208 class wxITaskbarList2 : public wxITaskbarList
209 {
210 public:
211 virtual HRESULT wxSTDCALL MarkFullscreenWindow(HWND, BOOL) = 0;
212 };
213
214 class wxIShellLinkA : public IUnknown
215 {
216 public:
217 virtual HRESULT wxSTDCALL GetPath(LPSTR, int, WIN32_FIND_DATAA*, DWORD) = 0;
218 virtual HRESULT wxSTDCALL GetIDList(LPITEMIDLIST *ppidl) = 0;
219 virtual HRESULT wxSTDCALL SetIDList(LPCITEMIDLIST pidl) = 0;
220 virtual HRESULT wxSTDCALL GetDescription(LPSTR, int) = 0;
221 virtual HRESULT wxSTDCALL SetDescription(LPCSTR) = 0;
222 virtual HRESULT wxSTDCALL GetWorkingDirectory(LPSTR, int) = 0;
223 virtual HRESULT wxSTDCALL SetWorkingDirectory(LPCSTR) = 0;
224 virtual HRESULT wxSTDCALL GetArguments(LPSTR, int) = 0;
225 virtual HRESULT wxSTDCALL SetArguments(LPCSTR) = 0;
226 virtual HRESULT wxSTDCALL GetHotkey(WORD*) = 0;
227 virtual HRESULT wxSTDCALL SetHotkey(WORD) = 0;
228 virtual HRESULT wxSTDCALL GetShowCmd(int*) = 0;
229 virtual HRESULT wxSTDCALL SetShowCmd(int) = 0;
230 virtual HRESULT wxSTDCALL GetIconLocation(LPSTR, int, int*) = 0;
231 virtual HRESULT wxSTDCALL SetIconLocation(LPCSTR, int) = 0;
232 virtual HRESULT wxSTDCALL SetRelativePath(LPCSTR, DWORD) = 0;
233 virtual HRESULT wxSTDCALL Resolve(HWND, DWORD) = 0;
234 virtual HRESULT wxSTDCALL SetPath(LPCSTR) = 0;
235 };
236
237 class wxIShellLinkW : public IUnknown
238 {
239 public:
240 virtual HRESULT wxSTDCALL GetPath(LPWSTR, int, WIN32_FIND_DATAW*, DWORD) = 0;
241 virtual HRESULT wxSTDCALL GetIDList(LPITEMIDLIST *ppidl) = 0;
242 virtual HRESULT wxSTDCALL SetIDList(LPCITEMIDLIST pidl) = 0;
243 virtual HRESULT wxSTDCALL GetDescription(LPWSTR, int) = 0;
244 virtual HRESULT wxSTDCALL SetDescription(LPCWSTR) = 0;
245 virtual HRESULT wxSTDCALL GetWorkingDirectory(LPWSTR, int) = 0;
246 virtual HRESULT wxSTDCALL SetWorkingDirectory(LPCWSTR) = 0;
247 virtual HRESULT wxSTDCALL GetArguments(LPWSTR, int) = 0;
248 virtual HRESULT wxSTDCALL SetArguments(LPCWSTR) = 0;
249 virtual HRESULT wxSTDCALL GetHotkey(WORD*) = 0;
250 virtual HRESULT wxSTDCALL SetHotkey(WORD) = 0;
251 virtual HRESULT wxSTDCALL GetShowCmd(int*) = 0;
252 virtual HRESULT wxSTDCALL SetShowCmd(int) = 0;
253 virtual HRESULT wxSTDCALL GetIconLocation(LPWSTR, int, int*) = 0;
254 virtual HRESULT wxSTDCALL SetIconLocation(LPCWSTR, int) = 0;
255 virtual HRESULT wxSTDCALL SetRelativePath(LPCWSTR, DWORD) = 0;
256 virtual HRESULT wxSTDCALL Resolve(HWND, DWORD) = 0;
257 virtual HRESULT wxSTDCALL SetPath(LPCWSTR) = 0;
258 };
259
260 class IShellItem : public IUnknown
261 {
262 public:
263 virtual HRESULT wxSTDCALL BindToHandler(IBindCtx*, REFGUID, REFIID, void **) = 0;
264 virtual HRESULT wxSTDCALL GetParent(IShellItem **) = 0;
265 virtual HRESULT wxSTDCALL GetDisplayName(SIGDN, LPWSTR*) = 0;
266 virtual HRESULT wxSTDCALL GetAttributes(SFGAOF, SFGAOF*) = 0;
267 virtual HRESULT wxSTDCALL Compare(IShellItem *, SICHINTF, int *) = 0;
268 };
269
270 class IObjectArray : public IUnknown
271 {
272 public:
273 virtual HRESULT wxSTDCALL GetCount(UINT*) = 0;
274 virtual HRESULT wxSTDCALL GetAt(UINT, REFIID, void **) = 0;
275 };
276
277 class IObjectCollection : public IObjectArray
278 {
279 public:
280 virtual HRESULT wxSTDCALL AddObject(IUnknown *) = 0;
281 virtual HRESULT wxSTDCALL AddFromArray(IObjectArray *) = 0;
282 virtual HRESULT wxSTDCALL RemoveObjectAt(UINT) = 0;
283 virtual HRESULT wxSTDCALL Clear() = 0;
284 };
285
286 class IPropertyStore : public IUnknown
287 {
288 public:
289 virtual HRESULT wxSTDCALL GetCount(DWORD *) = 0;
290 virtual HRESULT wxSTDCALL GetAt(DWORD, PROPERTYKEY *) = 0;
291 virtual HRESULT wxSTDCALL GetValue(REFPROPERTYKEY, PROPVARIANT *) = 0;
292 virtual HRESULT wxSTDCALL SetValue(REFPROPERTYKEY, const PROPVARIANT&) = 0;
293 virtual HRESULT wxSTDCALL Commit() = 0;
294 };
295
296 class ICustomDestinationList : public IUnknown
297 {
298 public:
299 virtual HRESULT wxSTDCALL SetAppID(LPCWSTR) = 0;
300 virtual HRESULT wxSTDCALL BeginList(UINT*, REFIID, void**) = 0;
301 virtual HRESULT wxSTDCALL AppendCategory(LPCWSTR, IObjectArray *) = 0;
302 virtual HRESULT wxSTDCALL AppendKnownCategory(KNOWNDESTCATEGORY) = 0;
303 virtual HRESULT wxSTDCALL AddUserTasks(IObjectArray *) = 0;
304 virtual HRESULT wxSTDCALL CommitList() = 0;
305 virtual HRESULT wxSTDCALL GetRemovedDestinations(REFIID, void**) = 0;
306 virtual HRESULT wxSTDCALL DeleteList(LPCWSTR) = 0;
307 virtual HRESULT wxSTDCALL AbortList() = 0;
308 };
309
310 class IApplicationDocumentLists : public IUnknown
311 {
312 public:
313 virtual HRESULT wxSTDCALL SetAppID(LPCWSTR) = 0;
314 virtual HRESULT wxSTDCALL GetList(APPDOCLISTTYPE, UINT, REFIID, void**) = 0;
315 };
316
317 namespace
318 {
319
InitPropVariantFromBoolean(BOOL fVal,PROPVARIANT * ppropvar)320 inline HRESULT InitPropVariantFromBoolean(BOOL fVal, PROPVARIANT *ppropvar)
321 {
322 ppropvar->vt = VT_BOOL;
323 ppropvar->boolVal = fVal ? VARIANT_TRUE : VARIANT_FALSE;
324 return S_OK;
325 }
326
InitPropVariantFromString(PCWSTR psz,PROPVARIANT * ppropvar)327 inline HRESULT InitPropVariantFromString(PCWSTR psz, PROPVARIANT *ppropvar)
328 {
329 HRESULT hr = E_FAIL;
330 ppropvar->vt = VT_LPWSTR;
331
332 #if wxUSE_DYNLIB_CLASS
333 typedef HRESULT (WINAPI *SHStrDupW_t)(LPCWSTR, LPWSTR*);
334 static SHStrDupW_t s_pfnSHStrDupW = NULL;
335 if ( !s_pfnSHStrDupW )
336 {
337 wxDynamicLibrary dll(wxT("shlwapi.dll"));
338 if ( dll.IsLoaded() )
339 {
340 s_pfnSHStrDupW = (SHStrDupW_t)dll.GetSymbol(wxT("SHStrDupW"));
341 }
342 }
343
344 if ( s_pfnSHStrDupW )
345 {
346 hr = s_pfnSHStrDupW(psz, &ppropvar->pwszVal);
347 }
348 #elif defined (_MSC_VER)
349 hr = SHStrDupW(psz, &ppropvar->pwszVal);
350 #else
351 wxUnusedVar(psz);
352 #endif
353
354 if ( FAILED(hr) )
355 {
356 PropVariantInit(ppropvar);
357 }
358 return hr;
359 }
360
GetNativeThumbButtonFlags(const wxThumbBarButton & button)361 THUMBBUTTONFLAGS GetNativeThumbButtonFlags(const wxThumbBarButton& button)
362 {
363 WXUINT flags = 0;
364 flags |= (button.IsEnable() ? THBF_ENABLED : THBF_DISABLED);
365 if ( button.IsDismissOnClick() )
366 flags |= THBF_DISMISSONCLICK;
367 if ( !button.HasBackground() )
368 flags |= THBF_NOBACKGROUND;
369 if ( !button.IsShown() )
370 flags |= THBF_HIDDEN;
371 if ( !button.IsInteractive() )
372 flags |= THBF_NONINTERACTIVE;
373 return static_cast<THUMBBUTTONFLAGS>(flags);
374 }
375
AddShellLink(IObjectCollection * collection,const wxTaskBarJumpListItem & item)376 bool AddShellLink(IObjectCollection *collection,
377 const wxTaskBarJumpListItem& item)
378 {
379 wxCOMPtr<IShellLink> shellLink;
380 wxCOMPtr<IPropertyStore> propertyStore;
381
382 HRESULT hr = CoCreateInstance
383 (
384 wxCLSID_ShellLink,
385 NULL,
386 CLSCTX_INPROC_SERVER,
387 wxIID_IShellLink,
388 reinterpret_cast<void**> (&(shellLink))
389 );
390 if ( FAILED(hr) )
391 {
392 wxLogApiError("CoCreateInstance(wxCLSID_ShellLink)", hr);
393 return false;
394 }
395
396 if ( item.GetType() == wxTASKBAR_JUMP_LIST_TASK ||
397 item.GetType() == wxTASKBAR_JUMP_LIST_DESTINATION )
398 {
399 if ( !item.GetFilePath().IsEmpty() )
400 shellLink->SetPath(item.GetFilePath().wc_str());
401 if ( !item.GetArguments().IsEmpty() )
402 shellLink->SetArguments(item.GetArguments().wc_str());
403 if ( !item.GetIconPath().IsEmpty() )
404 {
405 shellLink->SetIconLocation(item.GetIconPath().wc_str(),
406 item.GetIconIndex());
407 }
408 if ( !item.GetTooltip().IsEmpty() )
409 shellLink->SetDescription(item.GetTooltip().wc_str());
410 }
411
412 hr = shellLink->QueryInterface(wxIID_IPropertyStore,
413 reinterpret_cast<void**>(&(propertyStore)));
414 if ( FAILED(hr) )
415 {
416 wxLogApiError("IShellLink(QueryInterface)", hr);
417 return false;
418 }
419
420 PROPVARIANT pv;
421 if ( item.GetType() == wxTASKBAR_JUMP_LIST_TASK ||
422 item.GetType() == wxTASKBAR_JUMP_LIST_DESTINATION )
423 {
424 hr = InitPropVariantFromString(item.GetTitle().wc_str(), &pv);
425 if ( SUCCEEDED(hr) )
426 {
427 hr = propertyStore->SetValue(PKEY_Title, pv);
428 }
429 }
430 else if ( item.GetType() == wxTASKBAR_JUMP_LIST_SEPARATOR )
431 {
432 hr = InitPropVariantFromBoolean(TRUE, &pv);
433 if ( SUCCEEDED(hr) )
434 {
435 hr = propertyStore->SetValue(PKEY_AppUserModel_IsDestListSeparator,
436 pv);
437 }
438 }
439
440 // Save the changes we made to the property store.
441 propertyStore->Commit();
442 PropVariantClear(&pv);
443
444 // Add this IShellLink object to the given collection.
445 hr = collection->AddObject(shellLink);
446
447 return SUCCEEDED(hr);
448 }
449
GetItemFromIShellLink(IShellLink * link)450 wxTaskBarJumpListItem* GetItemFromIShellLink(IShellLink* link)
451 {
452 if ( !link )
453 return NULL;
454
455 wxTaskBarJumpListItem* item =
456 new wxTaskBarJumpListItem(NULL, wxTASKBAR_JUMP_LIST_DESTINATION);
457
458 wxCOMPtr<IPropertyStore> linkProps;
459 HRESULT hr = link->QueryInterface
460 (
461 wxIID_IPropertyStore,
462 reinterpret_cast<void **>(&linkProps)
463 );
464 if ( FAILED(hr) )
465 {
466 wxLogApiError("IShellLink::QueryInterface", hr);
467 return NULL;
468 }
469
470 PROPVARIANT var;
471 linkProps->GetValue(PKEY_Link_Arguments, &var);
472 item->SetArguments(wxString(var.pwszVal));
473 PropVariantClear(&var);
474
475 const int bufferSize = 2048;
476 wchar_t buffer[bufferSize];
477
478 link->GetDescription(buffer, INFOTIPSIZE);
479 item->SetTooltip(wxString(buffer));
480
481 int dummyIndex;
482 link->GetIconLocation(buffer, bufferSize - 1, &dummyIndex);
483 item->SetIconPath(wxString(buffer));
484
485 link->GetPath(buffer, bufferSize - 1, NULL, 0x1);
486 item->SetFilePath(wxString(buffer));
487
488 return item;
489 }
490
GetItemFromIShellItem(IShellItem * shellItem)491 wxTaskBarJumpListItem* GetItemFromIShellItem(IShellItem *shellItem)
492 {
493 if ( !shellItem )
494 return NULL;
495
496 wxTaskBarJumpListItem *item =
497 new wxTaskBarJumpListItem(NULL, wxTASKBAR_JUMP_LIST_DESTINATION);
498
499 wxCoTaskMemPtr<wchar_t> name;
500 shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name);
501 item->SetFilePath(wxString(name));
502 return item;
503 }
504
CreateObjectCollection()505 IObjectCollection* CreateObjectCollection()
506 {
507 IObjectCollection* collection;
508
509 HRESULT hr;
510 hr = CoCreateInstance
511 (
512 wxCLSID_EnumerableObjectCollection,
513 NULL,
514 CLSCTX_INPROC,
515 wxIID_IObjectCollection,
516 reinterpret_cast<void**>(&(collection))
517 );
518 if ( FAILED(hr) )
519 {
520 wxLogApiError("CoCreateInstance(wxCLSID_EnumerableObjectCollection)",
521 hr);
522 return NULL;
523 }
524
525 return collection;
526 }
527
528 } // namespace
529
530 class wxITaskbarList3 : public wxITaskbarList2
531 {
532 public:
533 virtual HRESULT wxSTDCALL SetProgressValue(HWND, ULONGLONG, ULONGLONG) = 0;
534 virtual HRESULT wxSTDCALL SetProgressState(HWND, TBPFLAG) = 0;
535 virtual HRESULT wxSTDCALL RegisterTab(HWND, HWND) = 0;
536 virtual HRESULT wxSTDCALL UnregisterTab(HWND) = 0;
537 virtual HRESULT wxSTDCALL SetTabOrder(HWND, HWND) = 0;
538 virtual HRESULT wxSTDCALL SetTabActive(HWND, HWND, DWORD) = 0;
539 virtual HRESULT wxSTDCALL ThumbBarAddButtons(HWND, UINT, LPTHUMBBUTTON) = 0;
540 virtual
541 HRESULT wxSTDCALL ThumbBarUpdateButtons(HWND, UINT, LPTHUMBBUTTON) = 0;
542 virtual HRESULT wxSTDCALL ThumbBarSetImageList(HWND, ::HIMAGELIST) = 0;
543 virtual HRESULT wxSTDCALL SetOverlayIcon(HWND, HICON, LPCWSTR) = 0;
544 virtual HRESULT wxSTDCALL SetThumbnailTooltip(HWND, LPCWSTR pszTip) = 0;
545 virtual HRESULT wxSTDCALL SetThumbnailClip(HWND, RECT *) = 0;
546 };
547
548 // ----------------------------------------------------------------------------
549 // wxTaskBarJumpListImpl: definition of class for internal taskbar jump list
550 // implementation.
551 // ----------------------------------------------------------------------------
552 class wxTaskBarJumpListImpl
553 {
554 public:
555 wxTaskBarJumpListImpl(wxTaskBarJumpList *jumpList = NULL,
556 const wxString& appID = wxEmptyString);
557 virtual ~wxTaskBarJumpListImpl();
558 void ShowRecentCategory(bool shown = true);
559 void HideRecentCategory();
560 void ShowFrequentCategory(bool shown = true);
561 void HideFrequentCategory();
562
563 wxTaskBarJumpListCategory& GetTasks();
564 const wxTaskBarJumpListCategory& GetFrequentCategory();
565 const wxTaskBarJumpListCategory& GetRecentCategory();
566 const wxTaskBarJumpListCategories& GetCustomCategories() const;
567
568 void AddCustomCategory(wxTaskBarJumpListCategory* category);
569 wxTaskBarJumpListCategory* RemoveCustomCategory(const wxString& title);
570 void DeleteCustomCategory(const wxString& title);
571 void Update();
572
573 private:
574 bool BeginUpdate();
575 bool CommitUpdate();
576 void AddTasksToDestinationList();
577 void AddCustomCategoriesToDestinationList();
578 void LoadKnownCategory(const wxString& title);
579
580 wxTaskBarJumpList *m_jumpList;
581
582 wxCOMPtr<ICustomDestinationList> m_destinationList;
583 wxCOMPtr<IObjectArray> m_objectArray;
584
585 wxScopedPtr<wxTaskBarJumpListCategory> m_tasks;
586 wxScopedPtr<wxTaskBarJumpListCategory> m_frequent;
587 wxScopedPtr<wxTaskBarJumpListCategory> m_recent;
588 wxTaskBarJumpListCategories m_customCategories;
589 bool m_recent_visible;
590 bool m_frequent_visible;
591
592 // Application User Model ID.
593 wxString m_appID;
594 };
595
596 // ----------------------------------------------------------------------------
597 // wxThumbBarButton Implementation.
598 // ----------------------------------------------------------------------------
599 wxIMPLEMENT_DYNAMIC_CLASS(wxThumbBarButton, wxObject);
600
wxThumbBarButton(int id,const wxIcon & icon,const wxString & tooltip,bool enable,bool dismissOnClick,bool hasBackground,bool shown,bool interactive)601 wxThumbBarButton::wxThumbBarButton(int id,
602 const wxIcon& icon,
603 const wxString& tooltip,
604 bool enable,
605 bool dismissOnClick,
606 bool hasBackground,
607 bool shown,
608 bool interactive)
609 : m_id(id),
610 m_icon(icon),
611 m_tooltip(tooltip),
612 m_enable(enable),
613 m_dismissOnClick(dismissOnClick),
614 m_hasBackground(hasBackground),
615 m_shown(shown),
616 m_interactive(interactive),
617 m_taskBarButtonParent(NULL)
618 {
619 }
620
Create(int id,const wxIcon & icon,const wxString & tooltip,bool enable,bool dismissOnClick,bool hasBackground,bool shown,bool interactive)621 bool wxThumbBarButton::Create(int id,
622 const wxIcon& icon,
623 const wxString& tooltip,
624 bool enable,
625 bool dismissOnClick,
626 bool hasBackground,
627 bool shown,
628 bool interactive)
629 {
630 m_id = id;
631 m_icon = icon;
632 m_tooltip = tooltip;
633 m_enable = enable;
634 m_dismissOnClick = dismissOnClick;
635 m_hasBackground = hasBackground;
636 m_shown = shown;
637 m_interactive = interactive;
638 return true;
639 }
640
Enable(bool enable)641 void wxThumbBarButton::Enable(bool enable)
642 {
643 if ( m_enable != enable )
644 {
645 m_enable = enable;
646 UpdateParentTaskBarButton();
647 }
648 }
649
SetHasBackground(bool has)650 void wxThumbBarButton::SetHasBackground(bool has)
651 {
652 if ( m_hasBackground != has )
653 {
654 m_hasBackground = has;
655 UpdateParentTaskBarButton();
656 }
657 }
658
EnableDismissOnClick(bool enable)659 void wxThumbBarButton::EnableDismissOnClick(bool enable)
660 {
661 if ( m_dismissOnClick != enable )
662 {
663 m_dismissOnClick = enable;
664 UpdateParentTaskBarButton();
665 }
666 }
667
Show(bool shown)668 void wxThumbBarButton::Show(bool shown)
669 {
670 if ( m_shown != shown )
671 {
672 m_shown = shown;
673 UpdateParentTaskBarButton();
674 }
675 }
676
SetInteractive(bool interactive)677 void wxThumbBarButton::SetInteractive(bool interactive)
678 {
679 if ( m_interactive != interactive )
680 {
681 m_interactive = interactive;
682 UpdateParentTaskBarButton();
683 }
684 }
685
UpdateParentTaskBarButton()686 bool wxThumbBarButton::UpdateParentTaskBarButton()
687 {
688 if ( !m_taskBarButtonParent )
689 return false;
690
691 return static_cast<wxTaskBarButtonImpl*>(
692 m_taskBarButtonParent)->InitOrUpdateThumbBarButtons();
693 }
694
695 // ----------------------------------------------------------------------------
696 // wxTaskBarButtonImpl Implementation.
697 // ----------------------------------------------------------------------------
698
699 /* static */
New(wxWindow * parent)700 wxTaskBarButton* wxTaskBarButton::New(wxWindow* parent)
701 {
702 wxITaskbarList3* taskbarList = NULL;
703
704 HRESULT hr = CoCreateInstance
705 (
706 wxCLSID_TaskbarList,
707 NULL,
708 CLSCTX_INPROC_SERVER,
709 wxIID_ITaskbarList3,
710 reinterpret_cast<void **>(&taskbarList)
711 );
712 if ( FAILED(hr) )
713 {
714 // Don't log this error, it may be normal when running under XP.
715 return NULL;
716 }
717
718 hr = taskbarList->HrInit();
719 if ( FAILED(hr) )
720 {
721 // This is however unexpected.
722 wxLogApiError(wxT("ITaskbarList3::Init"), hr);
723
724 taskbarList->Release();
725 return NULL;
726 }
727
728 return new wxTaskBarButtonImpl(taskbarList, parent);
729 }
730
wxTaskBarButtonImpl(wxITaskbarList3 * taskbarList,wxWindow * parent)731 wxTaskBarButtonImpl::wxTaskBarButtonImpl(wxITaskbarList3* taskbarList,
732 wxWindow* parent)
733 : m_parent(parent),
734 m_taskbarList(taskbarList),
735 m_progressRange(0),
736 m_progressValue(0),
737 m_progressState(wxTASKBAR_BUTTON_NO_PROGRESS),
738 m_hasInitThumbnailToolbar(false)
739 {
740 }
741
~wxTaskBarButtonImpl()742 wxTaskBarButtonImpl::~wxTaskBarButtonImpl()
743 {
744 if ( m_taskbarList )
745 m_taskbarList->Release();
746
747 for ( wxThumbBarButtons::iterator iter = m_thumbBarButtons.begin();
748 iter != m_thumbBarButtons.end();
749 ++iter)
750 {
751 delete (*iter);
752 }
753 m_thumbBarButtons.clear();
754 }
755
Realize()756 void wxTaskBarButtonImpl::Realize()
757 {
758 // (Re-)apply all settings: this is needed if settings were made before the
759 // create message was sent, taskbar icon is hidden and shown again or
760 // explorer is restarted
761 SetProgressRange(m_progressRange);
762 SetProgressState(m_progressState);
763 if ( m_progressValue > 0 )
764 SetProgressValue(m_progressValue);
765 SetThumbnailTooltip(m_thumbnailTooltip);
766 SetOverlayIcon(m_overlayIcon, m_overlayIconDescription);
767 if ( !m_thumbnailClipRect.IsEmpty() )
768 SetThumbnailClip(m_thumbnailClipRect);
769 m_hasInitThumbnailToolbar = false;
770 InitOrUpdateThumbBarButtons();
771 }
772
SetProgressRange(int range)773 void wxTaskBarButtonImpl::SetProgressRange(int range)
774 {
775 m_progressRange = range;
776 if ( m_progressRange == 0 )
777 SetProgressState(wxTASKBAR_BUTTON_NO_PROGRESS);
778 }
779
SetProgressValue(int value)780 void wxTaskBarButtonImpl::SetProgressValue(int value)
781 {
782 m_progressValue = value;
783 m_taskbarList->SetProgressValue(m_parent->GetHWND(), value, m_progressRange);
784 }
785
PulseProgress()786 void wxTaskBarButtonImpl::PulseProgress()
787 {
788 SetProgressState(wxTASKBAR_BUTTON_INDETERMINATE);
789 }
790
Show(bool show)791 void wxTaskBarButtonImpl::Show(bool show)
792 {
793 if ( show )
794 m_taskbarList->AddTab(m_parent->GetHWND());
795 else
796 m_taskbarList->DeleteTab(m_parent->GetHWND());
797 }
798
Hide()799 void wxTaskBarButtonImpl::Hide()
800 {
801 Show(false);
802 }
803
SetThumbnailTooltip(const wxString & tooltip)804 void wxTaskBarButtonImpl::SetThumbnailTooltip(const wxString& tooltip)
805 {
806 m_thumbnailTooltip = tooltip;
807 m_taskbarList->SetThumbnailTooltip(m_parent->GetHWND(), tooltip.wc_str());
808 }
809
SetProgressState(wxTaskBarButtonState state)810 void wxTaskBarButtonImpl::SetProgressState(wxTaskBarButtonState state)
811 {
812 m_progressState = state;
813 m_taskbarList->SetProgressState(m_parent->GetHWND(), static_cast<TBPFLAG>(state));
814 }
815
SetOverlayIcon(const wxIcon & icon,const wxString & description)816 void wxTaskBarButtonImpl::SetOverlayIcon(const wxIcon& icon,
817 const wxString& description)
818 {
819 m_overlayIcon = icon;
820 m_overlayIconDescription = description;
821 m_taskbarList->SetOverlayIcon(m_parent->GetHWND(),
822 GetHiconOf(icon),
823 description.wc_str());
824 }
825
SetThumbnailClip(const wxRect & rect)826 void wxTaskBarButtonImpl::SetThumbnailClip(const wxRect& rect)
827 {
828 m_thumbnailClipRect = rect;
829 RECT rc;
830 wxCopyRectToRECT(rect, rc);
831 m_taskbarList->SetThumbnailClip(m_parent->GetHWND(), rect.IsEmpty() ? NULL : &rc);
832 }
833
SetThumbnailContents(const wxWindow * child)834 void wxTaskBarButtonImpl::SetThumbnailContents(const wxWindow *child)
835 {
836 SetThumbnailClip(child->GetRect());
837 }
838
AppendThumbBarButton(wxThumbBarButton * button)839 bool wxTaskBarButtonImpl::AppendThumbBarButton(wxThumbBarButton *button)
840 {
841 wxASSERT_MSG( m_thumbBarButtons.size() < MAX_BUTTON_COUNT,
842 "Number of ThumbBarButtons and separators is limited to 7" );
843
844 button->SetParent(this);
845 m_thumbBarButtons.push_back(button);
846 return InitOrUpdateThumbBarButtons();
847 }
848
AppendSeparatorInThumbBar()849 bool wxTaskBarButtonImpl::AppendSeparatorInThumbBar()
850 {
851 wxASSERT_MSG( m_thumbBarButtons.size() < MAX_BUTTON_COUNT,
852 "Number of ThumbBarButtons and separators is limited to 7" );
853
854 // Append a disable ThumbBarButton without background can simulate the
855 // behavior of appending a separator.
856 wxThumbBarButton *separator = new wxThumbBarButton(wxID_ANY,
857 wxNullIcon,
858 wxEmptyString,
859 false,
860 false,
861 false);
862 m_thumbBarButtons.push_back(separator);
863 return InitOrUpdateThumbBarButtons();
864 }
865
InsertThumbBarButton(size_t pos,wxThumbBarButton * button)866 bool wxTaskBarButtonImpl::InsertThumbBarButton(size_t pos,
867 wxThumbBarButton *button)
868 {
869 wxASSERT_MSG( m_thumbBarButtons.size() < MAX_BUTTON_COUNT,
870 "Number of ThumbBarButtons and separators is limited to 7" );
871 wxASSERT_MSG( pos <= m_thumbBarButtons.size(),
872 "Invalid index when inserting the button" );
873
874 button->SetParent(this);
875 m_thumbBarButtons.insert(m_thumbBarButtons.begin() + pos, button);
876 return InitOrUpdateThumbBarButtons();
877 }
878
RemoveThumbBarButton(wxThumbBarButton * button)879 wxThumbBarButton* wxTaskBarButtonImpl::RemoveThumbBarButton(
880 wxThumbBarButton *button)
881 {
882 return RemoveThumbBarButton(button->GetID());
883 }
884
RemoveThumbBarButton(int id)885 wxThumbBarButton* wxTaskBarButtonImpl::RemoveThumbBarButton(int id)
886 {
887 for ( wxThumbBarButtons::iterator iter = m_thumbBarButtons.begin();
888 iter != m_thumbBarButtons.end();
889 ++iter )
890 {
891 wxThumbBarButton* button = *iter;
892 if ( id == button->GetID() )
893 {
894 m_thumbBarButtons.erase(iter);
895 button->SetParent(NULL);
896 InitOrUpdateThumbBarButtons();
897 return button;
898 }
899 }
900
901 return NULL;
902 }
903
InitOrUpdateThumbBarButtons()904 bool wxTaskBarButtonImpl::InitOrUpdateThumbBarButtons()
905 {
906 THUMBBUTTON buttons[MAX_BUTTON_COUNT];
907 HRESULT hr;
908
909 for ( size_t i = 0; i < MAX_BUTTON_COUNT; ++i )
910 {
911 memset(&buttons[i], 0, sizeof buttons[i]);
912 buttons[i].iId = i;
913 buttons[i].dwFlags = THBF_HIDDEN;
914 buttons[i].dwMask = static_cast<THUMBBUTTONMASK>(THB_FLAGS);
915 }
916
917 for ( size_t i = 0; i < m_thumbBarButtons.size(); ++i )
918 {
919 buttons[i].hIcon = GetHiconOf(m_thumbBarButtons[i]->GetIcon());
920 buttons[i].dwFlags = GetNativeThumbButtonFlags(*m_thumbBarButtons[i]);
921 buttons[i].dwMask = static_cast<THUMBBUTTONMASK>(THB_ICON | THB_FLAGS);
922 wxString tooltip = m_thumbBarButtons[i]->GetTooltip();
923 if ( tooltip.empty() )
924 continue;
925
926 // Truncate the tooltip if its length longer than szTip(THUMBBUTTON)
927 // allowed length (260).
928 tooltip.Truncate(260);
929 wxStrlcpy(buttons[i].szTip, tooltip.wc_str(), tooltip.length());
930 buttons[i].dwMask =
931 static_cast<THUMBBUTTONMASK>(buttons[i].dwMask | THB_TOOLTIP);
932 }
933
934 if ( !m_hasInitThumbnailToolbar )
935 {
936 hr = m_taskbarList->ThumbBarAddButtons(m_parent->GetHWND(),
937 MAX_BUTTON_COUNT,
938 buttons);
939 if ( FAILED(hr) )
940 {
941 wxLogApiError(wxT("ITaskbarList3::ThumbBarAddButtons"), hr);
942 }
943 m_hasInitThumbnailToolbar = true;
944 }
945 else
946 {
947 hr = m_taskbarList->ThumbBarUpdateButtons(m_parent->GetHWND(),
948 MAX_BUTTON_COUNT,
949 buttons);
950 if ( FAILED(hr) )
951 {
952 wxLogApiError(wxT("ITaskbarList3::ThumbBarUpdateButtons"), hr);
953 }
954 }
955
956 return SUCCEEDED(hr);
957 }
958
GetThumbBarButtonByIndex(size_t index)959 wxThumbBarButton* wxTaskBarButtonImpl::GetThumbBarButtonByIndex(size_t index)
960 {
961 if ( index >= m_thumbBarButtons.size() )
962 return NULL;
963
964 return m_thumbBarButtons[index];
965 }
966
967 // ----------------------------------------------------------------------------
968 // wxTaskBarJumpListItem Implementation.
969 // ----------------------------------------------------------------------------
wxTaskBarJumpListItem(wxTaskBarJumpListCategory * parent,wxTaskBarJumpListItemType type,const wxString & title,const wxString & filePath,const wxString & arguments,const wxString & tooltip,const wxString & iconPath,int iconIndex)970 wxTaskBarJumpListItem::wxTaskBarJumpListItem(wxTaskBarJumpListCategory *parent,
971 wxTaskBarJumpListItemType type,
972 const wxString& title,
973 const wxString& filePath,
974 const wxString& arguments,
975 const wxString& tooltip,
976 const wxString& iconPath,
977 int iconIndex)
978 : m_parentCategory(parent),
979 m_type(type),
980 m_title(title),
981 m_filePath(filePath),
982 m_arguments(arguments),
983 m_tooltip(tooltip),
984 m_iconPath(iconPath),
985 m_iconIndex(iconIndex)
986 {
987 }
988
GetType() const989 wxTaskBarJumpListItemType wxTaskBarJumpListItem::GetType() const
990 {
991 return m_type;
992 }
993
SetType(wxTaskBarJumpListItemType type)994 void wxTaskBarJumpListItem::SetType(wxTaskBarJumpListItemType type)
995 {
996 m_type = type;
997 if ( m_parentCategory )
998 m_parentCategory->Update();
999 }
1000
GetTitle() const1001 const wxString& wxTaskBarJumpListItem::GetTitle() const
1002 {
1003 return m_title;
1004 }
1005
SetTitle(const wxString & title)1006 void wxTaskBarJumpListItem::SetTitle(const wxString& title)
1007 {
1008 m_title = title;
1009 if ( m_parentCategory )
1010 m_parentCategory->Update();
1011 }
1012
GetFilePath() const1013 const wxString& wxTaskBarJumpListItem::GetFilePath() const
1014 {
1015 return m_filePath;
1016 }
1017
SetFilePath(const wxString & filePath)1018 void wxTaskBarJumpListItem::SetFilePath(const wxString& filePath)
1019 {
1020 m_filePath = filePath;
1021 if ( m_parentCategory )
1022 m_parentCategory->Update();
1023 }
1024
GetArguments() const1025 const wxString& wxTaskBarJumpListItem::GetArguments() const
1026 {
1027 return m_arguments;
1028 }
1029
SetArguments(const wxString & arguments)1030 void wxTaskBarJumpListItem::SetArguments(const wxString& arguments)
1031 {
1032 m_arguments = arguments;
1033 if ( m_parentCategory )
1034 m_parentCategory->Update();
1035 }
1036
GetTooltip() const1037 const wxString& wxTaskBarJumpListItem::GetTooltip() const
1038 {
1039 return m_tooltip;
1040 }
1041
SetTooltip(const wxString & tooltip)1042 void wxTaskBarJumpListItem::SetTooltip(const wxString& tooltip)
1043 {
1044 m_tooltip = tooltip;
1045 if ( m_parentCategory )
1046 m_parentCategory->Update();
1047 }
1048
GetIconPath() const1049 const wxString& wxTaskBarJumpListItem::GetIconPath() const
1050 {
1051 return m_iconPath;
1052 }
1053
SetIconPath(const wxString & iconPath)1054 void wxTaskBarJumpListItem::SetIconPath(const wxString& iconPath)
1055 {
1056 m_iconPath = iconPath;
1057 if ( m_parentCategory )
1058 m_parentCategory->Update();
1059 }
1060
GetIconIndex() const1061 int wxTaskBarJumpListItem::GetIconIndex() const
1062 {
1063 return m_iconIndex;
1064 }
1065
SetIconIndex(int iconIndex)1066 void wxTaskBarJumpListItem::SetIconIndex(int iconIndex)
1067 {
1068 m_iconIndex = iconIndex;
1069 if ( m_parentCategory )
1070 m_parentCategory->Update();
1071 }
1072
GetCategory() const1073 wxTaskBarJumpListCategory* wxTaskBarJumpListItem::GetCategory() const
1074 {
1075 return m_parentCategory;
1076 }
1077
SetCategory(wxTaskBarJumpListCategory * category)1078 void wxTaskBarJumpListItem::SetCategory(wxTaskBarJumpListCategory *category)
1079 {
1080 m_parentCategory = category;
1081 }
1082
1083 // ----------------------------------------------------------------------------
1084 // wxTaskBarJumpListCategory Implementation.
1085 // ----------------------------------------------------------------------------
wxTaskBarJumpListCategory(wxTaskBarJumpList * parent,const wxString & title)1086 wxTaskBarJumpListCategory::wxTaskBarJumpListCategory(wxTaskBarJumpList *parent,
1087 const wxString& title)
1088 : m_parent(parent),
1089 m_title(title)
1090 {
1091 }
1092
~wxTaskBarJumpListCategory()1093 wxTaskBarJumpListCategory::~wxTaskBarJumpListCategory()
1094 {
1095 for ( wxTaskBarJumpListItems::iterator it = m_items.begin();
1096 it != m_items.end();
1097 ++it )
1098 {
1099 delete *it;
1100 }
1101 }
1102
1103 wxTaskBarJumpListItem*
Append(wxTaskBarJumpListItem * item)1104 wxTaskBarJumpListCategory::Append(wxTaskBarJumpListItem *item)
1105 {
1106 m_items.push_back(item);
1107 item->SetCategory(this);
1108 Update();
1109
1110 return item;
1111 }
1112
Delete(wxTaskBarJumpListItem * item)1113 void wxTaskBarJumpListCategory::Delete(wxTaskBarJumpListItem *item)
1114 {
1115 item = Remove(item);
1116 item->SetCategory(NULL);
1117 Update();
1118
1119 if ( item )
1120 delete item;
1121 }
1122
1123 wxTaskBarJumpListItem*
Remove(wxTaskBarJumpListItem * item)1124 wxTaskBarJumpListCategory::Remove(wxTaskBarJumpListItem *item)
1125 {
1126 for (wxTaskBarJumpListItems::iterator it = m_items.begin();
1127 it != m_items.end();
1128 ++it)
1129 {
1130 if ( *it == item )
1131 {
1132 m_items.erase(it);
1133 item->SetCategory(NULL);
1134 Update();
1135 return item;
1136 }
1137 }
1138
1139 return NULL;
1140 }
1141
1142 wxTaskBarJumpListItem*
FindItemByPosition(size_t pos) const1143 wxTaskBarJumpListCategory::FindItemByPosition(size_t pos) const
1144 {
1145 wxASSERT_MSG( pos < m_items.size(), "invalid pos." );
1146 return m_items[pos];
1147 }
1148
1149 wxTaskBarJumpListItem*
Insert(size_t pos,wxTaskBarJumpListItem * item)1150 wxTaskBarJumpListCategory::Insert(size_t pos, wxTaskBarJumpListItem *item)
1151 {
1152 wxASSERT_MSG( pos <= m_items.size(), "invalid pos." );
1153 m_items.insert(m_items.begin() + pos, item);
1154 item->SetCategory(this);
1155 Update();
1156
1157 return item;
1158 }
1159
1160 wxTaskBarJumpListItem*
Prepend(wxTaskBarJumpListItem * item)1161 wxTaskBarJumpListCategory::Prepend(wxTaskBarJumpListItem *item)
1162 {
1163 return Insert(0, item);
1164 }
1165
SetTitle(const wxString & title)1166 void wxTaskBarJumpListCategory::SetTitle(const wxString& title)
1167 {
1168 m_title = title;
1169 Update();
1170 }
1171
GetTitle() const1172 const wxString& wxTaskBarJumpListCategory::GetTitle() const
1173 {
1174 return m_title;
1175 }
1176
GetItems() const1177 const wxTaskBarJumpListItems& wxTaskBarJumpListCategory::GetItems() const
1178 {
1179 return m_items;
1180 }
1181
Update()1182 void wxTaskBarJumpListCategory::Update()
1183 {
1184 if ( m_parent )
1185 m_parent->Update();
1186 }
1187
1188 // ----------------------------------------------------------------------------
1189 // wxTaskBarJumpList Implementation.
1190 // ----------------------------------------------------------------------------
wxTaskBarJumpList(const wxString & appID)1191 wxTaskBarJumpList::wxTaskBarJumpList(const wxString& appID)
1192 : m_jumpListImpl(new wxTaskBarJumpListImpl(this, appID))
1193 {
1194 }
1195
~wxTaskBarJumpList()1196 wxTaskBarJumpList::~wxTaskBarJumpList()
1197 {
1198 delete m_jumpListImpl;
1199 }
1200
GetTasks() const1201 wxTaskBarJumpListCategory& wxTaskBarJumpList::GetTasks() const
1202 {
1203 return m_jumpListImpl->GetTasks();
1204 }
1205
ShowRecentCategory(bool shown)1206 void wxTaskBarJumpList::ShowRecentCategory(bool shown)
1207 {
1208 m_jumpListImpl->ShowRecentCategory(shown);
1209 }
1210
HideRecentCategory()1211 void wxTaskBarJumpList::HideRecentCategory()
1212 {
1213 m_jumpListImpl->HideRecentCategory();
1214 }
1215
ShowFrequentCategory(bool shown)1216 void wxTaskBarJumpList::ShowFrequentCategory(bool shown)
1217 {
1218 m_jumpListImpl->ShowFrequentCategory(shown);
1219 }
1220
HideFrequentCategory()1221 void wxTaskBarJumpList::HideFrequentCategory()
1222 {
1223 m_jumpListImpl->HideFrequentCategory();
1224 }
1225
GetFrequentCategory() const1226 const wxTaskBarJumpListCategory& wxTaskBarJumpList::GetFrequentCategory() const
1227 {
1228 return m_jumpListImpl->GetFrequentCategory();
1229 }
1230
GetRecentCategory() const1231 const wxTaskBarJumpListCategory& wxTaskBarJumpList::GetRecentCategory() const
1232 {
1233 return m_jumpListImpl->GetRecentCategory();
1234 }
1235
1236 const wxTaskBarJumpListCategories&
GetCustomCategories() const1237 wxTaskBarJumpList::GetCustomCategories() const
1238 {
1239 return m_jumpListImpl->GetCustomCategories();
1240 }
1241
AddCustomCategory(wxTaskBarJumpListCategory * category)1242 void wxTaskBarJumpList::AddCustomCategory(wxTaskBarJumpListCategory* category)
1243 {
1244 m_jumpListImpl->AddCustomCategory(category);
1245 }
1246
RemoveCustomCategory(const wxString & title)1247 wxTaskBarJumpListCategory* wxTaskBarJumpList::RemoveCustomCategory(
1248 const wxString& title)
1249 {
1250 return m_jumpListImpl->RemoveCustomCategory(title);
1251 }
1252
DeleteCustomCategory(const wxString & title)1253 void wxTaskBarJumpList::DeleteCustomCategory(const wxString& title)
1254 {
1255 m_jumpListImpl->DeleteCustomCategory(title);
1256 }
1257
Update()1258 void wxTaskBarJumpList::Update()
1259 {
1260 m_jumpListImpl->Update();
1261 }
1262
1263 // ----------------------------------------------------------------------------
1264 // wxTaskBarJumpListImpl Implementation.
1265 // ----------------------------------------------------------------------------
wxTaskBarJumpListImpl(wxTaskBarJumpList * jumpList,const wxString & appID)1266 wxTaskBarJumpListImpl::wxTaskBarJumpListImpl(wxTaskBarJumpList *jumpList,
1267 const wxString& appID)
1268 : m_jumpList(jumpList),
1269 m_destinationList(NULL)
1270 {
1271 m_appID = appID;
1272 HRESULT hr = CoCreateInstance
1273 (
1274 wxCLSID_DestinationList,
1275 NULL,
1276 CLSCTX_INPROC_SERVER,
1277 wxIID_ICustomDestinationList,
1278 reinterpret_cast<void**> (&(m_destinationList))
1279 );
1280 if ( FAILED(hr) )
1281 {
1282 wxLogApiError(wxT("CoCreateInstance(wxCLSID_DestinationList)"), hr);
1283 return;
1284 }
1285 }
1286
~wxTaskBarJumpListImpl()1287 wxTaskBarJumpListImpl::~wxTaskBarJumpListImpl()
1288 {
1289 for ( wxTaskBarJumpListCategories::iterator it = m_customCategories.begin();
1290 it != m_customCategories.end();
1291 ++it )
1292 {
1293 delete *it;
1294 }
1295 }
1296
Update()1297 void wxTaskBarJumpListImpl::Update()
1298 {
1299 if ( !BeginUpdate() )
1300 return;
1301
1302 AddTasksToDestinationList();
1303 AddCustomCategoriesToDestinationList();
1304 if ( m_recent_visible )
1305 m_destinationList->AppendKnownCategory(KDC_RECENT);
1306 if ( m_frequent_visible )
1307 m_destinationList->AppendKnownCategory(KDC_FREQUENT);
1308 CommitUpdate();
1309 }
1310
GetTasks()1311 wxTaskBarJumpListCategory& wxTaskBarJumpListImpl::GetTasks()
1312 {
1313 if ( m_tasks.get() == NULL )
1314 m_tasks.reset(new wxTaskBarJumpListCategory(m_jumpList, wxT("Tasks")));
1315
1316 return *(m_tasks.get());
1317 }
1318
ShowRecentCategory(bool shown)1319 void wxTaskBarJumpListImpl::ShowRecentCategory(bool shown)
1320 {
1321 m_recent_visible = shown;
1322 }
1323
HideRecentCategory()1324 void wxTaskBarJumpListImpl::HideRecentCategory()
1325 {
1326 ShowRecentCategory(false);
1327 }
1328
ShowFrequentCategory(bool shown)1329 void wxTaskBarJumpListImpl::ShowFrequentCategory(bool shown)
1330 {
1331 m_frequent_visible = shown;
1332 }
1333
HideFrequentCategory()1334 void wxTaskBarJumpListImpl::HideFrequentCategory()
1335 {
1336 ShowFrequentCategory(false);
1337 }
1338
GetFrequentCategory()1339 const wxTaskBarJumpListCategory& wxTaskBarJumpListImpl::GetFrequentCategory()
1340 {
1341 wxString title = wxT("Frequent");
1342 if ( m_frequent.get() == NULL )
1343 m_frequent.reset(new wxTaskBarJumpListCategory(m_jumpList, title));
1344 LoadKnownCategory(title);
1345
1346 return *m_frequent.get();
1347 }
1348
GetRecentCategory()1349 const wxTaskBarJumpListCategory& wxTaskBarJumpListImpl::GetRecentCategory()
1350 {
1351 wxString title = wxT("Recent");
1352 if ( m_recent.get() == NULL )
1353 m_recent.reset(new wxTaskBarJumpListCategory(m_jumpList, title));
1354 LoadKnownCategory(title);
1355
1356 return *m_recent.get();
1357 }
1358
1359 const wxTaskBarJumpListCategories&
GetCustomCategories() const1360 wxTaskBarJumpListImpl::GetCustomCategories() const
1361 {
1362 return m_customCategories;
1363 }
1364
1365 void
AddCustomCategory(wxTaskBarJumpListCategory * category)1366 wxTaskBarJumpListImpl::AddCustomCategory(wxTaskBarJumpListCategory *category)
1367 {
1368 wxASSERT_MSG( category != NULL, "Invalid category." );
1369 m_customCategories.push_back(category);
1370 }
1371
1372 wxTaskBarJumpListCategory*
RemoveCustomCategory(const wxString & title)1373 wxTaskBarJumpListImpl::RemoveCustomCategory(const wxString& title)
1374 {
1375 for ( wxTaskBarJumpListCategories::iterator it = m_customCategories.begin();
1376 it != m_customCategories.end();
1377 ++it )
1378 {
1379 wxTaskBarJumpListCategory* tbJlCat = *it;
1380 if ( tbJlCat->GetTitle() == title )
1381 {
1382 m_customCategories.erase(it);
1383 return tbJlCat;
1384 }
1385 }
1386
1387 return NULL;
1388 }
1389
DeleteCustomCategory(const wxString & title)1390 void wxTaskBarJumpListImpl::DeleteCustomCategory(const wxString& title)
1391 {
1392 wxTaskBarJumpListCategory* category = RemoveCustomCategory(title);
1393 if ( category )
1394 delete category;
1395 }
1396
BeginUpdate()1397 bool wxTaskBarJumpListImpl::BeginUpdate()
1398 {
1399 if ( m_destinationList == NULL )
1400 return false;
1401
1402 unsigned int max_count = 0;
1403 m_objectArray = NULL;
1404 HRESULT hr = m_destinationList->BeginList(&max_count,
1405 wxIID_IObjectArray, reinterpret_cast<void**>(&m_objectArray));
1406 if ( !m_appID.empty() )
1407 m_destinationList->SetAppID(m_appID.wc_str());
1408
1409 return SUCCEEDED(hr);
1410 }
1411
CommitUpdate()1412 bool wxTaskBarJumpListImpl::CommitUpdate()
1413 {
1414 return SUCCEEDED(m_destinationList->CommitList());
1415 }
1416
AddTasksToDestinationList()1417 void wxTaskBarJumpListImpl::AddTasksToDestinationList()
1418 {
1419 if ( !m_tasks.get() )
1420 return;
1421
1422 wxCOMPtr<IObjectCollection> collection(CreateObjectCollection());
1423 if ( !collection )
1424 return;
1425
1426 const wxTaskBarJumpListItems& tasks = m_tasks->GetItems();
1427 for ( wxTaskBarJumpListItems::const_iterator it = tasks.begin();
1428 it != tasks.end();
1429 ++it )
1430 {
1431 wxASSERT_MSG( ((*it)->GetType() == wxTASKBAR_JUMP_LIST_TASK ||
1432 (*it)->GetType() == wxTASKBAR_JUMP_LIST_SEPARATOR),
1433 "Invalid task Item." );
1434 AddShellLink(collection, *(*it));
1435 }
1436 m_destinationList->AddUserTasks(collection);
1437 }
1438
AddCustomCategoriesToDestinationList()1439 void wxTaskBarJumpListImpl::AddCustomCategoriesToDestinationList()
1440 {
1441 for ( wxTaskBarJumpListCategories::iterator it = m_customCategories.begin();
1442 it != m_customCategories.end();
1443 ++it )
1444 {
1445 wxCOMPtr<IObjectCollection> collection(CreateObjectCollection());
1446 if ( !collection )
1447 continue;
1448
1449 const wxTaskBarJumpListItems& tasks = (*it)->GetItems();
1450 for ( wxTaskBarJumpListItems::const_iterator iter = tasks.begin();
1451 iter != tasks.end();
1452 ++iter )
1453 {
1454 wxASSERT_MSG(
1455 (*iter)->GetType() == wxTASKBAR_JUMP_LIST_DESTINATION,
1456 "Invalid category item." );
1457 AddShellLink(collection, *(*iter));
1458 }
1459 m_destinationList->AppendCategory((*it)->GetTitle().wc_str(),
1460 collection);
1461 }
1462 }
1463
LoadKnownCategory(const wxString & title)1464 void wxTaskBarJumpListImpl::LoadKnownCategory(const wxString& title)
1465 {
1466 wxCOMPtr<IApplicationDocumentLists> docList;
1467 HRESULT hr = CoCreateInstance
1468 (
1469 wxCLSID_ApplicationDocumentLists,
1470 NULL,
1471 CLSCTX_INPROC_SERVER,
1472 wxIID_IApplicationDocumentLists,
1473 reinterpret_cast<void **>(&docList)
1474 );
1475 if ( FAILED(hr) )
1476 {
1477 wxLogApiError("CoCreateInstance(wxCLSID_ApplicationDocumentLists)", hr);
1478 return;
1479 }
1480 if ( !m_appID.empty() )
1481 docList->SetAppID(m_appID.wc_str());
1482
1483 wxCOMPtr<IObjectArray> array;
1484 wxASSERT_MSG( title == "Recent" || title == "Frequent", "Invalid title." );
1485 hr = docList->GetList
1486 (
1487 title == "Recent" ? ADLT_RECENT : ADLT_FREQUENT,
1488 0,
1489 wxIID_IObjectArray,
1490 reinterpret_cast<void **>(&array)
1491 );
1492 if ( FAILED(hr) )
1493 {
1494 wxLogApiError("IApplicationDocumentLists::GetList", hr);
1495 return;
1496 }
1497
1498 UINT count = 0;
1499 array->GetCount(&count);
1500 for (UINT i = 0; i < count; ++i)
1501 {
1502 wxCOMPtr<IUnknown> collectionItem;
1503 hr = array->GetAt(i, wxIID_IUnknown,
1504 reinterpret_cast<void **>(&collectionItem));
1505 if ( FAILED(hr) )
1506 {
1507 wxLogApiError("IObjectArray::GetAt", hr);
1508 continue;
1509 }
1510
1511 wxCOMPtr<IShellLink> shellLink;
1512 wxCOMPtr<IShellItem> shellItem;
1513 wxTaskBarJumpListItem* item = NULL;
1514
1515 if ( SUCCEEDED(collectionItem->QueryInterface(
1516 wxIID_IShellLink, reinterpret_cast<void**>(&shellLink))) )
1517 {
1518 item = GetItemFromIShellLink(shellLink);
1519 }
1520 else if ( SUCCEEDED(collectionItem->QueryInterface(
1521 wxIID_IShellItem, reinterpret_cast<void**>(&shellItem))) )
1522 {
1523 item = GetItemFromIShellItem(shellItem);
1524 }
1525 else
1526 {
1527 wxLogError("Can not query interfaces: IShellLink or IShellItem.");
1528 }
1529
1530 if ( item )
1531 {
1532 if ( title == wxT("Frequent") )
1533 m_frequent->Append(item);
1534 else
1535 m_recent->Append(item);
1536 }
1537 }
1538 }
1539
1540 #endif // wxUSE_TASKBARBUTTON
1541