Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / widget / windows / WinTaskbar.cpp
blob3f368e8f62ec21c4e4095a78fd126d327192dd07
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 "nsIWinTaskbar.h"
9 #include "WinTaskbar.h"
10 #include "TaskbarPreview.h"
11 #include <nsITaskbarPreviewController.h>
13 #include "mozilla/RefPtr.h"
14 #include <nsError.h>
15 #include <nsCOMPtr.h>
16 #include <nsIWidget.h>
17 #include <nsIBaseWindow.h>
18 #include <nsServiceManagerUtils.h>
19 #include "nsIXULAppInfo.h"
20 #include "nsIJumpListBuilder.h"
21 #include "nsUXThemeData.h"
22 #include "nsWindow.h"
23 #include "WinUtils.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 "nsAppRunner.h"
32 #include "nsXREDirProvider.h"
33 #include <io.h>
34 #include <propvarutil.h>
35 #include <propkey.h>
36 #include <shellapi.h>
38 static NS_DEFINE_CID(kJumpListBuilderCID, NS_WIN_JUMPLISTBUILDER_CID);
40 namespace {
42 HWND GetHWNDFromDocShell(nsIDocShell* aShell) {
43 nsCOMPtr<nsIBaseWindow> baseWindow(
44 do_QueryInterface(reinterpret_cast<nsISupports*>(aShell)));
46 if (!baseWindow) return nullptr;
48 nsCOMPtr<nsIWidget> widget;
49 baseWindow->GetMainWidget(getter_AddRefs(widget));
51 return widget ? (HWND)widget->GetNativeData(NS_NATIVE_WINDOW) : nullptr;
54 HWND GetHWNDFromDOMWindow(mozIDOMWindow* dw) {
55 nsCOMPtr<nsIWidget> widget;
57 if (!dw) return nullptr;
59 nsCOMPtr<nsPIDOMWindowInner> window = nsPIDOMWindowInner::From(dw);
60 return GetHWNDFromDocShell(window->GetDocShell());
63 nsresult SetWindowAppUserModelProp(mozIDOMWindow* aParent,
64 const nsString& aIdentifier) {
65 NS_ENSURE_ARG_POINTER(aParent);
67 if (aIdentifier.IsEmpty()) return NS_ERROR_INVALID_ARG;
69 HWND toplevelHWND = ::GetAncestor(GetHWNDFromDOMWindow(aParent), GA_ROOT);
71 if (!toplevelHWND) return NS_ERROR_INVALID_ARG;
73 RefPtr<IPropertyStore> pPropStore;
74 if (FAILED(SHGetPropertyStoreForWindow(toplevelHWND, IID_IPropertyStore,
75 getter_AddRefs(pPropStore)))) {
76 return NS_ERROR_INVALID_ARG;
79 PROPVARIANT pv;
80 if (FAILED(InitPropVariantFromString(aIdentifier.get(), &pv))) {
81 return NS_ERROR_UNEXPECTED;
84 nsresult rv = NS_OK;
85 if (FAILED(pPropStore->SetValue(PKEY_AppUserModel_ID, pv)) ||
86 FAILED(pPropStore->Commit())) {
87 rv = NS_ERROR_FAILURE;
90 PropVariantClear(&pv);
92 return rv;
95 ///////////////////////////////////////////////////////////////////////////////
96 // default nsITaskbarPreviewController
98 class DefaultController final : public nsITaskbarPreviewController {
99 ~DefaultController() {}
100 HWND mWnd;
102 public:
103 explicit DefaultController(HWND hWnd) : mWnd(hWnd) {}
105 NS_DECL_ISUPPORTS
106 NS_DECL_NSITASKBARPREVIEWCONTROLLER
109 NS_IMETHODIMP
110 DefaultController::GetWidth(uint32_t* aWidth) {
111 RECT r;
112 ::GetClientRect(mWnd, &r);
113 *aWidth = r.right;
114 return NS_OK;
117 NS_IMETHODIMP
118 DefaultController::GetHeight(uint32_t* aHeight) {
119 RECT r;
120 ::GetClientRect(mWnd, &r);
121 *aHeight = r.bottom;
122 return NS_OK;
125 NS_IMETHODIMP
126 DefaultController::GetThumbnailAspectRatio(float* aThumbnailAspectRatio) {
127 uint32_t width, height;
128 GetWidth(&width);
129 GetHeight(&height);
130 if (!height) height = 1;
132 *aThumbnailAspectRatio = width / float(height);
133 return NS_OK;
136 NS_IMETHODIMP
137 DefaultController::RequestThumbnail(nsITaskbarPreviewCallback* aCallback,
138 uint32_t width, uint32_t height) {
139 return NS_OK;
142 NS_IMETHODIMP
143 DefaultController::RequestPreview(nsITaskbarPreviewCallback* aCallback) {
144 return NS_OK;
147 NS_IMETHODIMP
148 DefaultController::OnClose(void) {
149 MOZ_ASSERT_UNREACHABLE(
150 "OnClose should not be called for "
151 "TaskbarWindowPreviews");
152 return NS_OK;
155 NS_IMETHODIMP
156 DefaultController::OnActivate(bool* rAcceptActivation) {
157 *rAcceptActivation = true;
158 MOZ_ASSERT_UNREACHABLE(
159 "OnActivate should not be called for "
160 "TaskbarWindowPreviews");
161 return NS_OK;
164 NS_IMETHODIMP
165 DefaultController::OnClick(nsITaskbarPreviewButton* button) { return NS_OK; }
167 NS_IMPL_ISUPPORTS(DefaultController, nsITaskbarPreviewController)
168 } // namespace
170 namespace mozilla {
171 namespace widget {
173 ///////////////////////////////////////////////////////////////////////////////
174 // nsIWinTaskbar
176 NS_IMPL_ISUPPORTS(WinTaskbar, nsIWinTaskbar)
178 bool WinTaskbar::Initialize() {
179 if (mTaskbar) return true;
181 ::CoInitialize(nullptr);
182 HRESULT hr =
183 ::CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER,
184 IID_ITaskbarList4, (void**)&mTaskbar);
185 if (FAILED(hr)) return false;
187 hr = mTaskbar->HrInit();
188 if (FAILED(hr)) {
189 // This may fail with shell extensions like blackbox installed.
190 NS_WARNING("Unable to initialize taskbar");
191 NS_RELEASE(mTaskbar);
192 return false;
194 return true;
197 WinTaskbar::WinTaskbar() : mTaskbar(nullptr) {}
199 WinTaskbar::~WinTaskbar() {
200 if (mTaskbar) { // match successful Initialize() call
201 NS_RELEASE(mTaskbar);
202 ::CoUninitialize();
206 // static
207 bool WinTaskbar::GenerateAppUserModelID(nsAString& aAppUserModelId,
208 bool aPrivateBrowsing) {
209 // If marked as such in prefs, use a hash of the profile path for the id
210 // instead of the install path hash setup by the installer.
211 bool useProfile = Preferences::GetBool("taskbar.grouping.useprofile", false);
212 if (useProfile) {
213 nsCOMPtr<nsIFile> profileDir;
214 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
215 getter_AddRefs(profileDir));
216 bool exists = false;
217 if (profileDir && NS_SUCCEEDED(profileDir->Exists(&exists)) && exists) {
218 nsAutoCString path;
219 if (NS_SUCCEEDED(profileDir->GetPersistentDescriptor(path))) {
220 nsAutoString id;
221 id.AppendInt(HashString(path));
222 if (!id.IsEmpty()) {
223 aAppUserModelId.Assign(id);
224 return true;
230 // The default value is set by the installer and is stored in the registry
231 // under (HKLM||HKCU)/Software/Mozilla/Firefox/TaskBarIDs. If for any reason
232 // hash generation operation fails, the installer will not store a value in
233 // the registry or set ids on shortcuts. A lack of an id can also occur for
234 // zipped builds.
235 nsCOMPtr<nsIXULAppInfo> appInfo =
236 do_GetService("@mozilla.org/xre/app-info;1");
237 nsCString appName;
238 if (appInfo && NS_SUCCEEDED(appInfo->GetName(appName))) {
239 nsAutoString regKey;
240 regKey.AssignLiteral("Software\\Mozilla\\");
241 AppendASCIItoUTF16(appName, regKey);
242 regKey.AppendLiteral("\\TaskBarIDs");
244 WCHAR path[MAX_PATH];
245 if (GetModuleFileNameW(nullptr, path, MAX_PATH)) {
246 wchar_t* slash = wcsrchr(path, '\\');
247 if (!slash) return false;
248 *slash = '\0'; // no trailing slash
250 // The hash is short, but users may customize this, so use a respectable
251 // string buffer.
252 wchar_t buf[256];
253 if (WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE, regKey.get(), path, buf,
254 sizeof buf)) {
255 aAppUserModelId.Assign(buf);
256 } else if (WinUtils::GetRegistryKey(HKEY_CURRENT_USER, regKey.get(), path,
257 buf, sizeof buf)) {
258 aAppUserModelId.Assign(buf);
263 // If we haven't found an ID yet then use the install hash. In xpcshell tests
264 // the directory provider may not have been initialized so bypass in this
265 // case.
266 if (aAppUserModelId.IsEmpty() && gDirServiceProvider) {
267 gDirServiceProvider->GetInstallHash(aAppUserModelId);
270 if (aPrivateBrowsing) {
271 aAppUserModelId.AppendLiteral(";PrivateBrowsingAUMID");
274 return !aAppUserModelId.IsEmpty();
277 // static
278 bool WinTaskbar::GetAppUserModelID(nsAString& aAppUserModelId,
279 bool aPrivateBrowsing) {
280 // If an ID has already been set then use that.
281 PWSTR id;
282 if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&id))) {
283 aAppUserModelId.Assign(id);
284 CoTaskMemFree(id);
287 return GenerateAppUserModelID(aAppUserModelId, aPrivateBrowsing);
290 NS_IMETHODIMP
291 WinTaskbar::GetDefaultGroupId(nsAString& aDefaultGroupId) {
292 if (!GetAppUserModelID(aDefaultGroupId)) return NS_ERROR_UNEXPECTED;
294 return NS_OK;
297 NS_IMETHODIMP
298 WinTaskbar::GetDefaultPrivateGroupId(nsAString& aDefaultPrivateGroupId) {
299 if (!GetAppUserModelID(aDefaultPrivateGroupId, true))
300 return NS_ERROR_UNEXPECTED;
302 return NS_OK;
305 // (static) Called from AppShell
306 bool WinTaskbar::RegisterAppUserModelID() {
307 nsAutoString uid;
308 if (!GetAppUserModelID(uid)) return false;
310 return SUCCEEDED(SetCurrentProcessExplicitAppUserModelID(uid.get()));
313 NS_IMETHODIMP
314 WinTaskbar::GetAvailable(bool* aAvailable) {
315 // ITaskbarList4::HrInit() may fail with shell extensions like blackbox
316 // installed. Initialize early to return available=false in those cases.
317 *aAvailable = Initialize();
319 return NS_OK;
322 NS_IMETHODIMP
323 WinTaskbar::CreateTaskbarTabPreview(nsIDocShell* shell,
324 nsITaskbarPreviewController* controller,
325 nsITaskbarTabPreview** _retval) {
326 if (!Initialize()) return NS_ERROR_NOT_AVAILABLE;
328 NS_ENSURE_ARG_POINTER(shell);
329 NS_ENSURE_ARG_POINTER(controller);
331 HWND toplevelHWND = ::GetAncestor(GetHWNDFromDocShell(shell), GA_ROOT);
333 if (!toplevelHWND) return NS_ERROR_INVALID_ARG;
335 RefPtr<TaskbarTabPreview> preview(
336 new TaskbarTabPreview(mTaskbar, controller, toplevelHWND, shell));
337 if (!preview) return NS_ERROR_OUT_OF_MEMORY;
339 nsresult rv = preview->Init();
340 if (NS_FAILED(rv)) {
341 return rv;
344 preview.forget(_retval);
346 return NS_OK;
349 NS_IMETHODIMP
350 WinTaskbar::GetTaskbarWindowPreview(nsIDocShell* shell,
351 nsITaskbarWindowPreview** _retval) {
352 if (!Initialize()) return NS_ERROR_NOT_AVAILABLE;
354 NS_ENSURE_ARG_POINTER(shell);
356 HWND toplevelHWND = ::GetAncestor(GetHWNDFromDocShell(shell), GA_ROOT);
358 if (!toplevelHWND) return NS_ERROR_INVALID_ARG;
360 nsWindow* window = WinUtils::GetNSWindowPtr(toplevelHWND);
362 if (!window) return NS_ERROR_FAILURE;
364 nsCOMPtr<nsITaskbarWindowPreview> preview = window->GetTaskbarPreview();
365 if (!preview) {
366 RefPtr<DefaultController> defaultController =
367 new DefaultController(toplevelHWND);
369 TaskbarWindowPreview* previewRaw = new TaskbarWindowPreview(
370 mTaskbar, defaultController, toplevelHWND, shell);
371 if (!previewRaw) {
372 return NS_ERROR_OUT_OF_MEMORY;
375 preview = previewRaw;
377 nsresult rv = previewRaw->Init();
378 if (NS_FAILED(rv)) {
379 return rv;
381 window->SetTaskbarPreview(preview);
384 preview.forget(_retval);
386 return NS_OK;
389 NS_IMETHODIMP
390 WinTaskbar::GetTaskbarProgress(nsIDocShell* shell,
391 nsITaskbarProgress** _retval) {
392 nsCOMPtr<nsITaskbarWindowPreview> preview;
393 nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
394 NS_ENSURE_SUCCESS(rv, rv);
396 return CallQueryInterface(preview, _retval);
399 NS_IMETHODIMP
400 WinTaskbar::GetOverlayIconController(
401 nsIDocShell* shell, nsITaskbarOverlayIconController** _retval) {
402 nsCOMPtr<nsITaskbarWindowPreview> preview;
403 nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
404 NS_ENSURE_SUCCESS(rv, rv);
406 return CallQueryInterface(preview, _retval);
409 NS_IMETHODIMP
410 WinTaskbar::CreateJumpListBuilder(bool aPrivateBrowsing,
411 nsIJumpListBuilder** aJumpListBuilder) {
412 nsresult rv;
414 if (JumpListBuilder::sBuildingList) return NS_ERROR_ALREADY_INITIALIZED;
416 nsCOMPtr<nsIJumpListBuilder> builder =
417 do_CreateInstance(kJumpListBuilderCID, &rv);
418 if (NS_FAILED(rv)) return NS_ERROR_UNEXPECTED;
420 NS_IF_ADDREF(*aJumpListBuilder = builder);
422 nsAutoString aumid;
423 GenerateAppUserModelID(aumid, aPrivateBrowsing);
424 builder->SetAppUserModelID(aumid);
426 return NS_OK;
429 NS_IMETHODIMP
430 WinTaskbar::SetGroupIdForWindow(mozIDOMWindow* aParent,
431 const nsAString& aIdentifier) {
432 return SetWindowAppUserModelProp(aParent, nsString(aIdentifier));
435 NS_IMETHODIMP
436 WinTaskbar::PrepareFullScreen(void* aHWND, bool aFullScreen) {
437 if (!Initialize()) return NS_ERROR_NOT_AVAILABLE;
439 NS_ENSURE_ARG_POINTER(aHWND);
441 if (!::IsWindow((HWND)aHWND)) return NS_ERROR_INVALID_ARG;
443 HRESULT hr = mTaskbar->MarkFullscreenWindow((HWND)aHWND, aFullScreen);
444 if (FAILED(hr)) {
445 return NS_ERROR_UNEXPECTED;
448 return NS_OK;
451 } // namespace widget
452 } // namespace mozilla