Bug 1893458 - attempt to fix tab pinning not working sometimes on the first time r=nalexander,nrishel

Differential Revision: https://phabricator.services.mozilla.com/D208669
This commit is contained in:
Michael Hughes
2024-05-01 17:11:53 +00:00
parent 85a4294091
commit e8f6c31e3d
3 changed files with 225 additions and 180 deletions

View File

@@ -100,6 +100,18 @@ static Result<ComPtr<ITaskbarManager>, HRESULT> InitializeTaskbar() {
return taskbarManager; return taskbarManager;
} }
static bool IsStatusToRetry(Win11PinToTaskBarResultStatus status) {
switch (status) {
case Win11PinToTaskBarResultStatus::NotCurrentlyAllowed:
case Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked:
case Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures:
return true;
default:
return false;
}
}
Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11( Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
bool aCheckOnly, const nsAString& aAppUserModelId, bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath) { nsAutoString aShortcutPath) {
@@ -108,42 +120,53 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
"thread only. It blocks, waiting on things to execute " "thread only. It blocks, waiting on things to execute "
"asynchronously on the main thread."); "asynchronously on the main thread.");
{
RefPtr<Win11LimitedAccessFeaturesInterface> limitedAccessFeatures =
CreateWin11LimitedAccessFeaturesInterface();
auto result =
limitedAccessFeatures->Unlock(Win11LimitedAccessFeatureType::Taskbar);
if (result.isErr()) {
auto hr = result.unwrapErr();
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar unlock: Error. HRESULT = 0x%lx", hr);
return {hr, Win11PinToTaskBarResultStatus::NotSupported};
}
if (result.unwrap() == false) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar unlock: failed. Not supported on this version of Windows.");
return {S_OK, Win11PinToTaskBarResultStatus::NotSupported};
}
}
HRESULT hr; HRESULT hr;
Win11PinToTaskBarResultStatus resultStatus = Win11PinToTaskBarResultStatus resultStatus =
Win11PinToTaskBarResultStatus::NotSupported; Win11PinToTaskBarResultStatus::NotSupported;
// Pinning with the Win 11 APIs sometimes reports that pinning is not
// available. There is no documentation on what causes it to not be available
// or why. One way to work around that is to try again. We try 3 times if it's
// not currently available.
const int maxNumberOfRetryAttempts = 3;
int delayInMilliseconds = 200;
int count = 0;
do {
EventWrapper event; EventWrapper event;
// Everything related to the taskbar and pinning must be done on the main / // Everything related to the taskbar and pinning must be done on the main /
// user interface thread or Windows will cause them to fail. // user interface thread or Windows will cause them to fail.
NS_DispatchToMainThread(NS_NewRunnableFunction( NS_DispatchToMainThread(NS_NewRunnableFunction(
"PinCurrentAppToTaskbarWin11", [&event, &hr, &resultStatus, aCheckOnly] { "PinCurrentAppToTaskbarWin11",
[&event, &count, &hr, &resultStatus, aCheckOnly] {
auto CompletedOperations = auto CompletedOperations =
[&event, &resultStatus](Win11PinToTaskBarResultStatus status) { [&event, &resultStatus](Win11PinToTaskBarResultStatus status) {
resultStatus = status; resultStatus = status;
event.Set(); event.Set();
}; };
{
RefPtr<Win11LimitedAccessFeaturesInterface> limitedAccessFeatures =
CreateWin11LimitedAccessFeaturesInterface();
auto result = limitedAccessFeatures->Unlock(
Win11LimitedAccessFeatureType::Taskbar);
if (result.isErr()) {
hr = result.unwrapErr();
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar unlock: Error. HRESULT = 0x%lx", hr);
return CompletedOperations(
Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures);
}
if (result.unwrap() == false) {
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar unlock: failed. Not supported on "
"this version of Windows.");
return CompletedOperations(
Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked);
}
}
auto result = InitializeTaskbar(); auto result = InitializeTaskbar();
if (result.isErr()) { if (result.isErr()) {
hr = result.unwrapErr(); hr = result.unwrapErr();
@@ -183,7 +206,8 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
} else { } else {
TASKBAR_PINNING_LOG( TASKBAR_PINNING_LOG(
LogLevel::Debug, LogLevel::Debug,
"Taskbar: is pinning allowed error or isn't allowed right now. " "Taskbar: is pinning allowed error or isn't allowed right "
"now. "
"It's not clear when it will be allowed. Possibly after a " "It's not clear when it will be allowed. Possibly after a "
"reboot."); "reboot.");
} }
@@ -213,8 +237,8 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
IAsyncOperation<bool>* asyncInfo, IAsyncOperation<bool>* asyncInfo,
AsyncStatus status) mutable -> HRESULT { AsyncStatus status) mutable -> HRESULT {
auto CompletedOperations = auto CompletedOperations =
[&event, [&event, &resultStatus](
&resultStatus](Win11PinToTaskBarResultStatus status) -> HRESULT { Win11PinToTaskBarResultStatus status) -> HRESULT {
resultStatus = status; resultStatus = status;
event.Set(); event.Set();
return S_OK; return S_OK;
@@ -231,9 +255,9 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
unsigned char isCurrentAppPinned = false; unsigned char isCurrentAppPinned = false;
hr = asyncInfo->GetResults(&isCurrentAppPinned); hr = asyncInfo->GetResults(&isCurrentAppPinned);
if (FAILED(hr)) { if (FAILED(hr)) {
TASKBAR_PINNING_LOG( TASKBAR_PINNING_LOG(LogLevel::Debug,
LogLevel::Debug, "Taskbar: is current app pinned check "
"Taskbar: is current app pinned check failed. HRESULT = 0x%lx", "failed. HRESULT = 0x%lx",
hr); hr);
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed); return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
} }
@@ -256,9 +280,9 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed); return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
} }
auto pinAppCallback = Callback<IAsyncOperationCompletedHandler< auto pinAppCallback = Callback<
bool>>([CompletedOperations, &hr]( IAsyncOperationCompletedHandler<bool>>(
IAsyncOperation<bool>* asyncInfo, [CompletedOperations, &hr](IAsyncOperation<bool>* asyncInfo,
AsyncStatus status) -> HRESULT { AsyncStatus status) -> HRESULT {
bool asyncOpSucceeded = status == AsyncStatus::Completed; bool asyncOpSucceeded = status == AsyncStatus::Completed;
if (!asyncOpSucceeded) { if (!asyncOpSucceeded) {
@@ -266,38 +290,41 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
LogLevel::Debug, LogLevel::Debug,
"Taskbar: request pin current app operation did not " "Taskbar: request pin current app operation did not "
"complete."); "complete.");
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed); return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
} }
unsigned char successfullyPinned = 0; unsigned char successfullyPinned = 0;
hr = asyncInfo->GetResults(&successfullyPinned); hr = asyncInfo->GetResults(&successfullyPinned);
if (FAILED(hr) || !successfullyPinned) { if (FAILED(hr) || !successfullyPinned) {
if (FAILED(hr)) { if (FAILED(hr)) {
TASKBAR_PINNING_LOG( TASKBAR_PINNING_LOG(LogLevel::Debug,
LogLevel::Debug, "Taskbar: request pin current app "
"Taskbar: request pin current app operation failed to pin " "operation failed to pin "
"due to error. HRESULT = 0x%lx", "due to error. HRESULT = 0x%lx",
hr); hr);
} else { } else {
TASKBAR_PINNING_LOG( TASKBAR_PINNING_LOG(LogLevel::Debug,
LogLevel::Debug, "Taskbar: request pin current app "
"Taskbar: request pin current app operation failed to pin"); "operation failed to pin");
} }
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed); return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
} }
TASKBAR_PINNING_LOG( TASKBAR_PINNING_LOG(
LogLevel::Debug, LogLevel::Debug,
"Taskbar: request pin current app operation succeeded"); "Taskbar: request pin current app operation succeeded");
return CompletedOperations(Win11PinToTaskBarResultStatus::Success); return CompletedOperations(
Win11PinToTaskBarResultStatus::Success);
}); });
HRESULT pinOperationHR = HRESULT pinOperationHR =
requestPinOperation->put_Completed(pinAppCallback.Get()); requestPinOperation->put_Completed(pinAppCallback.Get());
if (FAILED(pinOperationHR)) { if (FAILED(pinOperationHR)) {
TASKBAR_PINNING_LOG( TASKBAR_PINNING_LOG(LogLevel::Debug,
LogLevel::Debug, "Taskbar: request pin operation failed when "
"Taskbar: request pin operation failed when setting completion " "setting completion "
"callback. HRESULT = 0x%lx", "callback. HRESULT = 0x%lx",
hr); hr);
hr = pinOperationHR; hr = pinOperationHR;
@@ -323,14 +350,27 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
} }
// DO NOT SET event HERE. It will be set in the is pin operation // DO NOT SET event HERE. It will be set in the is pin operation
// callback As in, operations are not completed, so don't call // callback. As in, operations are not completed, so don't call
// CompletedOperations // CompletedOperations
})); }));
// block until the pinning is completed on the main thread // block until the pinning is completed on the main thread
event.Wait(); event.Wait();
return {hr, resultStatus}; count++;
if (!IsStatusToRetry(resultStatus) || (count >= maxNumberOfRetryAttempts)) {
break;
}
// If retrying, put in a delay. Make it short the first time and slightly
// longer the second time. This is not on the main thread so shouldn't
// forcefully block the user. If called from Javascript with an await it
// will still block, but that's a decision on the Javascript side
Sleep(delayInMilliseconds);
delayInMilliseconds *= 2;
} while (count < maxNumberOfRetryAttempts);
return {hr, resultStatus, count};
} }
#else // MINGW32 implementation below #else // MINGW32 implementation below

View File

@@ -21,11 +21,14 @@ enum class Win11PinToTaskBarResultStatus {
AlreadyPinned, AlreadyPinned,
Success, Success,
NotSupported, NotSupported,
ErrorLimitedAccessFeatures,
LimitedAccessFeaturesLocked,
}; };
struct Win11PinToTaskBarResult { struct Win11PinToTaskBarResult {
HRESULT errorCode; HRESULT errorCode;
Win11PinToTaskBarResultStatus result; Win11PinToTaskBarResultStatus result;
int numAttempts;
}; };
Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11( Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(

View File

@@ -1707,6 +1707,8 @@ static nsresult PinCurrentAppToTaskbarImpl(
case Win11PinToTaskBarResultStatus::AlreadyPinned: case Win11PinToTaskBarResultStatus::AlreadyPinned:
return NS_OK; return NS_OK;
case Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures:
case Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked:
case Win11PinToTaskBarResultStatus::NotCurrentlyAllowed: case Win11PinToTaskBarResultStatus::NotCurrentlyAllowed:
case Win11PinToTaskBarResultStatus::Failed: case Win11PinToTaskBarResultStatus::Failed:
// return NS_ERROR_FAILURE; // return NS_ERROR_FAILURE;