1 /* vim: se cin sw=2 ts=2 et : */
2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "WinTaskbar.h"
9 #include "TaskbarPreview.h"
10 #include <nsITaskbarPreviewController.h>
14 #include <nsIWidget.h>
15 #include <nsIBaseWindow.h>
16 #include <nsIObserverService.h>
17 #include <nsServiceManagerUtils.h>
18 #include <nsAutoPtr.h>
19 #include "nsIXULAppInfo.h"
20 #include "nsIJumpListBuilder.h"
21 #include "nsUXThemeData.h"
24 #include "TaskbarTabPreview.h"
25 #include "TaskbarWindowPreview.h"
26 #include "JumpListBuilder.h"
27 #include "nsWidgetsCID.h"
28 #include "nsPIDOMWindow.h"
29 #include "nsAppDirectoryServiceDefs.h"
30 #include "mozilla/Preferences.h"
31 #include "mozilla/WindowsVersion.h"
33 #include <propvarutil.h>
37 const wchar_t kShellLibraryName
[] = L
"shell32.dll";
39 static NS_DEFINE_CID(kJumpListBuilderCID
, NS_WIN_JUMPLISTBUILDER_CID
);
44 GetHWNDFromDocShell(nsIDocShell
*aShell
) {
45 nsCOMPtr
<nsIBaseWindow
> baseWindow(do_QueryInterface(reinterpret_cast<nsISupports
*>(aShell
)));
50 nsCOMPtr
<nsIWidget
> widget
;
51 baseWindow
->GetMainWidget(getter_AddRefs(widget
));
53 return widget
? (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
) : nullptr;
57 GetHWNDFromDOMWindow(nsIDOMWindow
*dw
) {
58 nsCOMPtr
<nsIWidget
> widget
;
60 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(dw
);
64 return GetHWNDFromDocShell(window
->GetDocShell());
68 SetWindowAppUserModelProp(nsIDOMWindow
*aParent
,
69 const nsString
& aIdentifier
) {
70 NS_ENSURE_ARG_POINTER(aParent
);
72 if (aIdentifier
.IsEmpty())
73 return NS_ERROR_INVALID_ARG
;
75 HWND toplevelHWND
= ::GetAncestor(GetHWNDFromDOMWindow(aParent
), GA_ROOT
);
78 return NS_ERROR_INVALID_ARG
;
80 typedef HRESULT (WINAPI
* SHGetPropertyStoreForWindowPtr
)
81 (HWND hwnd
, REFIID riid
, void** ppv
);
82 SHGetPropertyStoreForWindowPtr funcGetProStore
= nullptr;
84 HMODULE hDLL
= ::LoadLibraryW(kShellLibraryName
);
85 funcGetProStore
= (SHGetPropertyStoreForWindowPtr
)
86 GetProcAddress(hDLL
, "SHGetPropertyStoreForWindow");
88 if (!funcGetProStore
) {
90 return NS_ERROR_NO_INTERFACE
;
93 IPropertyStore
* pPropStore
;
94 if (FAILED(funcGetProStore(toplevelHWND
,
95 IID_PPV_ARGS(&pPropStore
)))) {
97 return NS_ERROR_INVALID_ARG
;
101 if (FAILED(InitPropVariantFromString(aIdentifier
.get(), &pv
))) {
102 pPropStore
->Release();
104 return NS_ERROR_UNEXPECTED
;
108 if (FAILED(pPropStore
->SetValue(PKEY_AppUserModel_ID
, pv
)) ||
109 FAILED(pPropStore
->Commit())) {
110 rv
= NS_ERROR_FAILURE
;
113 PropVariantClear(&pv
);
114 pPropStore
->Release();
120 ///////////////////////////////////////////////////////////////////////////////
121 // default nsITaskbarPreviewController
123 class DefaultController MOZ_FINAL
: public nsITaskbarPreviewController
125 ~DefaultController() {}
128 DefaultController(HWND hWnd
)
134 NS_DECL_NSITASKBARPREVIEWCONTROLLER
138 DefaultController::GetWidth(uint32_t *aWidth
)
141 ::GetClientRect(mWnd
, &r
);
147 DefaultController::GetHeight(uint32_t *aHeight
)
150 ::GetClientRect(mWnd
, &r
);
156 DefaultController::GetThumbnailAspectRatio(float *aThumbnailAspectRatio
) {
157 uint32_t width
, height
;
163 *aThumbnailAspectRatio
= width
/float(height
);
168 DefaultController::DrawPreview(nsISupports
*ctx
, bool *rDrawFrame
) {
174 DefaultController::DrawThumbnail(nsISupports
*ctx
, uint32_t width
, uint32_t height
, bool *rDrawFrame
) {
180 DefaultController::OnClose(void) {
181 NS_NOTREACHED("OnClose should not be called for TaskbarWindowPreviews");
186 DefaultController::OnActivate(bool *rAcceptActivation
) {
187 *rAcceptActivation
= true;
188 NS_NOTREACHED("OnActivate should not be called for TaskbarWindowPreviews");
193 DefaultController::OnClick(nsITaskbarPreviewButton
*button
) {
197 NS_IMPL_ISUPPORTS(DefaultController
, nsITaskbarPreviewController
)
203 ///////////////////////////////////////////////////////////////////////////////
206 NS_IMPL_ISUPPORTS(WinTaskbar
, nsIWinTaskbar
)
209 WinTaskbar::Initialize() {
213 ::CoInitialize(nullptr);
214 HRESULT hr
= ::CoCreateInstance(CLSID_TaskbarList
,
216 CLSCTX_INPROC_SERVER
,
222 hr
= mTaskbar
->HrInit();
224 // This may fail with shell extensions like blackbox installed.
225 NS_WARNING("Unable to initialize taskbar");
226 NS_RELEASE(mTaskbar
);
232 WinTaskbar::WinTaskbar()
233 : mTaskbar(nullptr) {
236 WinTaskbar::~WinTaskbar() {
237 if (mTaskbar
) { // match successful Initialize() call
238 NS_RELEASE(mTaskbar
);
245 WinTaskbar::GetAppUserModelID(nsAString
& aDefaultGroupId
) {
246 // For win8 metro builds, we can't set this. The value is static
248 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro
) {
251 // If marked as such in prefs, use a hash of the profile path for the id
252 // instead of the install path hash setup by the installer.
254 Preferences::GetBool("taskbar.grouping.useprofile", false);
256 nsCOMPtr
<nsIFile
> profileDir
;
257 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
258 getter_AddRefs(profileDir
));
260 if (profileDir
&& NS_SUCCEEDED(profileDir
->Exists(&exists
)) && exists
) {
262 if (NS_SUCCEEDED(profileDir
->GetNativePath(path
))) {
264 id
.AppendInt(HashString(path
));
266 aDefaultGroupId
.Assign(id
);
273 // The default value is set by the installer and is stored in the registry
274 // under (HKLM||HKCU)/Software/Mozilla/Firefox/TaskBarIDs. If for any reason
275 // hash generation operation fails, the installer will not store a value in
276 // the registry or set ids on shortcuts. A lack of an id can also occur for
277 // zipped builds. We skip setting the global id in this case as well.
278 nsCOMPtr
<nsIXULAppInfo
> appInfo
=
279 do_GetService("@mozilla.org/xre/app-info;1");
284 if (NS_FAILED(appInfo
->GetName(appName
))) {
285 // We just won't register then, let Windows handle it.
290 regKey
.AssignLiteral("Software\\Mozilla\\");
291 AppendASCIItoUTF16(appName
, regKey
);
292 regKey
.AppendLiteral("\\TaskBarIDs");
294 WCHAR path
[MAX_PATH
];
295 if (GetModuleFileNameW(nullptr, path
, MAX_PATH
)) {
296 wchar_t* slash
= wcsrchr(path
, '\\');
299 *slash
= '\0'; // no trailing slash
301 // The hash is short, but users may customize this, so use a respectable
304 if (WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE
,
309 aDefaultGroupId
.Assign(buf
);
310 } else if (WinUtils::GetRegistryKey(HKEY_CURRENT_USER
,
315 aDefaultGroupId
.Assign(buf
);
319 return !aDefaultGroupId
.IsEmpty();
324 /* readonly attribute AString defaultGroupId; */
326 WinTaskbar::GetDefaultGroupId(nsAString
& aDefaultGroupId
) {
327 if (!GetAppUserModelID(aDefaultGroupId
))
328 return NS_ERROR_UNEXPECTED
;
333 // (static) Called from AppShell
335 WinTaskbar::RegisterAppUserModelID() {
336 if (!IsWin7OrLater())
339 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro
) {
343 SetCurrentProcessExplicitAppUserModelIDPtr funcAppUserModelID
= nullptr;
347 if (!GetAppUserModelID(uid
))
350 HMODULE hDLL
= ::LoadLibraryW(kShellLibraryName
);
352 funcAppUserModelID
= (SetCurrentProcessExplicitAppUserModelIDPtr
)
353 GetProcAddress(hDLL
, "SetCurrentProcessExplicitAppUserModelID");
355 if (!funcAppUserModelID
) {
360 if (SUCCEEDED(funcAppUserModelID(uid
.get())))
370 WinTaskbar::GetAvailable(bool *aAvailable
) {
371 // ITaskbarList4::HrInit() may fail with shell extensions like blackbox
372 // installed. Initialize early to return available=false in those cases.
373 *aAvailable
= IsWin7OrLater() && Initialize();
379 WinTaskbar::CreateTaskbarTabPreview(nsIDocShell
*shell
, nsITaskbarPreviewController
*controller
, nsITaskbarTabPreview
**_retval
) {
381 return NS_ERROR_NOT_AVAILABLE
;
383 NS_ENSURE_ARG_POINTER(shell
);
384 NS_ENSURE_ARG_POINTER(controller
);
386 HWND toplevelHWND
= ::GetAncestor(GetHWNDFromDocShell(shell
), GA_ROOT
);
389 return NS_ERROR_INVALID_ARG
;
391 nsRefPtr
<TaskbarTabPreview
> preview(new TaskbarTabPreview(mTaskbar
, controller
, toplevelHWND
, shell
));
393 return NS_ERROR_OUT_OF_MEMORY
;
395 preview
.forget(_retval
);
401 WinTaskbar::GetTaskbarWindowPreview(nsIDocShell
*shell
, nsITaskbarWindowPreview
**_retval
) {
403 return NS_ERROR_NOT_AVAILABLE
;
405 NS_ENSURE_ARG_POINTER(shell
);
407 HWND toplevelHWND
= ::GetAncestor(GetHWNDFromDocShell(shell
), GA_ROOT
);
410 return NS_ERROR_INVALID_ARG
;
412 nsWindow
*window
= WinUtils::GetNSWindowPtr(toplevelHWND
);
415 return NS_ERROR_FAILURE
;
417 nsCOMPtr
<nsITaskbarWindowPreview
> preview
= window
->GetTaskbarPreview();
419 nsRefPtr
<DefaultController
> defaultController
= new DefaultController(toplevelHWND
);
420 preview
= new TaskbarWindowPreview(mTaskbar
, defaultController
, toplevelHWND
, shell
);
422 return NS_ERROR_OUT_OF_MEMORY
;
423 window
->SetTaskbarPreview(preview
);
426 preview
.forget(_retval
);
432 WinTaskbar::GetTaskbarProgress(nsIDocShell
*shell
, nsITaskbarProgress
**_retval
) {
433 nsCOMPtr
<nsITaskbarWindowPreview
> preview
;
434 nsresult rv
= GetTaskbarWindowPreview(shell
, getter_AddRefs(preview
));
435 NS_ENSURE_SUCCESS(rv
, rv
);
437 return CallQueryInterface(preview
, _retval
);
441 WinTaskbar::GetOverlayIconController(nsIDocShell
*shell
,
442 nsITaskbarOverlayIconController
**_retval
) {
443 nsCOMPtr
<nsITaskbarWindowPreview
> preview
;
444 nsresult rv
= GetTaskbarWindowPreview(shell
, getter_AddRefs(preview
));
445 NS_ENSURE_SUCCESS(rv
, rv
);
447 return CallQueryInterface(preview
, _retval
);
450 /* nsIJumpListBuilder createJumpListBuilder(); */
452 WinTaskbar::CreateJumpListBuilder(nsIJumpListBuilder
* *aJumpListBuilder
) {
455 if (JumpListBuilder::sBuildingList
)
456 return NS_ERROR_ALREADY_INITIALIZED
;
458 nsCOMPtr
<nsIJumpListBuilder
> builder
=
459 do_CreateInstance(kJumpListBuilderCID
, &rv
);
461 return NS_ERROR_UNEXPECTED
;
463 NS_IF_ADDREF(*aJumpListBuilder
= builder
);
468 /* void setGroupIdForWindow (in nsIDOMWindow aParent, in AString aIdentifier); */
470 WinTaskbar::SetGroupIdForWindow(nsIDOMWindow
*aParent
,
471 const nsAString
& aIdentifier
) {
472 return SetWindowAppUserModelProp(aParent
, nsString(aIdentifier
));
475 /* void prepareFullScreen(in nsIDOMWindow aWindow, in boolean aFullScreen); */
477 WinTaskbar::PrepareFullScreen(nsIDOMWindow
*aWindow
, bool aFullScreen
) {
478 NS_ENSURE_ARG_POINTER(aWindow
);
480 HWND toplevelHWND
= ::GetAncestor(GetHWNDFromDOMWindow(aWindow
), GA_ROOT
);
482 return NS_ERROR_INVALID_ARG
;
484 return PrepareFullScreenHWND(toplevelHWND
, aFullScreen
);
487 /* void prepareFullScreen(in voidPtr aWindow, in boolean aFullScreen); */
489 WinTaskbar::PrepareFullScreenHWND(void *aHWND
, bool aFullScreen
) {
491 return NS_ERROR_NOT_AVAILABLE
;
493 NS_ENSURE_ARG_POINTER(aHWND
);
495 if (!::IsWindow((HWND
)aHWND
))
496 return NS_ERROR_INVALID_ARG
;
498 HRESULT hr
= mTaskbar
->MarkFullscreenWindow((HWND
)aHWND
, aFullScreen
);
500 return NS_ERROR_UNEXPECTED
;
506 } // namespace widget
507 } // namespace mozilla