mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1863636 - Part 2: Added native code changes for taskbar tabs r=win-reviewers,mhughes,gstoll
Differential Revision: https://phabricator.services.mozilla.com/D197342
This commit is contained in:
parent
1b61a2bdab
commit
41645fcb5c
@ -189,6 +189,44 @@ interface nsIWindowsShellService : nsISupports
|
||||
*/
|
||||
void unpinShortcutFromTaskbar(in AString aShortcutPath);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the full path of a taskbar tab shortcut.
|
||||
*
|
||||
* @param aShortcutName
|
||||
* The name of the taskbar tab shortcut, excluding the file extension.
|
||||
* @throws NS_ERROR_FAILURE
|
||||
* If the user token cannot be found.
|
||||
* @throws NS_ERROR_ABORT
|
||||
* If converting the sid to a string fails.
|
||||
*
|
||||
* @return The full path of the taskbar tab shortcut
|
||||
*/
|
||||
AString getTaskbarTabShortcutPath(in AString aShortcutName);
|
||||
|
||||
/*
|
||||
* Searches the %USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start
|
||||
* Menu\Programs folder and returns an array with the path of all
|
||||
* shortcuts with a target matching the current Firefox install location
|
||||
* and the -taskbar-tab argument.
|
||||
*
|
||||
* It is possible to return an empty array if no shortcuts are found.
|
||||
*
|
||||
* @return An array of paths for all taskbar tab shortcuts.
|
||||
*
|
||||
* @throws NS_ERROR_NOT_IMPLEMENTED
|
||||
* if run on a MinGW compilation
|
||||
* @throws NS_ERROR_ABORT
|
||||
* if instance cannot be created.
|
||||
* @throws NS_ERROR_FILE_NOT_FOUND
|
||||
* if %USERPROFILE%\AppData\Roaming\ cannot be opened.
|
||||
* @throws NS_ERROR_FAILURE
|
||||
* if the executable file cannot be found.
|
||||
* @throws NS_ERROR_FILE_UNRECOGNIZED_PATH
|
||||
* if the executable file cannot be converted into a string.
|
||||
*/
|
||||
Array<AString> getTaskbarTabPins();
|
||||
|
||||
/*
|
||||
* Determine where a given shortcut likely appears in the shell.
|
||||
*
|
||||
|
@ -1418,14 +1418,6 @@ static nsresult ManageShortcutTaskbarPins(bool aCheckOnly, bool aPinType,
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT hr = CoInitialize(nullptr);
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
const struct ComUninitializer {
|
||||
~ComUninitializer() { CoUninitialize(); }
|
||||
} kCUi;
|
||||
|
||||
mozilla::UniquePtr<__unaligned ITEMIDLIST, ILFreeDeleter> path(
|
||||
ILCreateFromPathW(nsString(aShortcutPath).get()));
|
||||
if (NS_WARN_IF(!path)) {
|
||||
@ -1433,8 +1425,8 @@ static nsresult ManageShortcutTaskbarPins(bool aCheckOnly, bool aPinType,
|
||||
}
|
||||
|
||||
IPinnedList3* pinnedList = nullptr;
|
||||
hr = CoCreateInstance(CLSID_TaskbandPin, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IPinnedList3, (void**)&pinnedList);
|
||||
HRESULT hr = CoCreateInstance(CLSID_TaskbandPin, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IPinnedList3, (void**)&pinnedList);
|
||||
if (FAILED(hr) || !pinnedList) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
@ -1467,6 +1459,147 @@ nsWindowsShellService::UnpinShortcutFromTaskbar(
|
||||
return ManageShortcutTaskbarPins(runInTestMode, pinType, aShortcutPath);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::GetTaskbarTabShortcutPath(const nsAString& aShortcutName,
|
||||
nsAString& aRetPath) {
|
||||
// The taskbar tab shortcut will always be in
|
||||
// %APPDATA%\Microsoft\Windows\Start Menu\Programs
|
||||
RefPtr<IKnownFolderManager> fManager;
|
||||
RefPtr<IKnownFolder> progFolder;
|
||||
LPWSTR progFolderW;
|
||||
nsString progFolderNS;
|
||||
HRESULT hr =
|
||||
CoCreateInstance(CLSID_KnownFolderManager, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_IKnownFolderManager, getter_AddRefs(fManager));
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
fManager->GetFolder(FOLDERID_Programs, progFolder.StartAssignment());
|
||||
hr = progFolder->GetPath(0, &progFolderW);
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
progFolderNS.Assign(progFolderW);
|
||||
aRetPath = progFolderNS + u"\\"_ns + aShortcutName + u".lnk"_ns;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::GetTaskbarTabPins(nsTArray<nsString>& aShortcutPaths) {
|
||||
#ifdef __MINGW32__
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
aShortcutPaths.Clear();
|
||||
|
||||
// Get AppData\\Roaming folder using a known folder ID
|
||||
RefPtr<IKnownFolderManager> fManager;
|
||||
RefPtr<IKnownFolder> roamingAppData;
|
||||
LPWSTR roamingAppDataW;
|
||||
nsString roamingAppDataNS;
|
||||
HRESULT hr =
|
||||
CoCreateInstance(CLSID_KnownFolderManager, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_IKnownFolderManager, getter_AddRefs(fManager));
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
fManager->GetFolder(FOLDERID_RoamingAppData,
|
||||
roamingAppData.StartAssignment());
|
||||
hr = roamingAppData->GetPath(0, &roamingAppDataW);
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Append taskbar pins folder to AppData\\Roaming
|
||||
roamingAppDataNS.Assign(roamingAppDataW);
|
||||
CoTaskMemFree(roamingAppDataW);
|
||||
nsString taskbarFolder =
|
||||
roamingAppDataNS + u"\\Microsoft\\Windows\\Start Menu\\Programs"_ns;
|
||||
nsString taskbarFolderWildcard = taskbarFolder + u"\\*.lnk"_ns;
|
||||
|
||||
// Get known path for binary file for later comparison with shortcuts.
|
||||
// Returns lowercase file path which should be fine for Windows as all
|
||||
// directories and files are case-insensitive by default.
|
||||
RefPtr<nsIFile> binFile;
|
||||
nsString binPath;
|
||||
nsresult rv = XRE_GetBinaryPath(binFile.StartAssignment());
|
||||
if (NS_WARN_IF(FAILED(rv))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = binFile->GetPath(binPath);
|
||||
if (NS_WARN_IF(FAILED(rv))) {
|
||||
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
||||
}
|
||||
|
||||
// Check for if first file exists with a shortcut extension (.lnk)
|
||||
WIN32_FIND_DATAW ffd;
|
||||
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
||||
fileHandle = FindFirstFileW(taskbarFolderWildcard.get(), &ffd);
|
||||
if (fileHandle == INVALID_HANDLE_VALUE) {
|
||||
// This means that no files were found in the folder which
|
||||
// doesn't imply an error.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
do {
|
||||
// Extract shortcut target path from every
|
||||
// shortcut in the taskbar pins folder.
|
||||
nsString fileName(ffd.cFileName);
|
||||
RefPtr<IShellLinkW> link;
|
||||
RefPtr<IPropertyStore> pps;
|
||||
nsString target;
|
||||
target.SetLength(MAX_PATH);
|
||||
hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_IShellLinkW, getter_AddRefs(link));
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
continue;
|
||||
}
|
||||
nsString filePath = taskbarFolder + u"\\"_ns + fileName;
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// After loading shortcut, search through arguments to find if
|
||||
// it is a taskbar tab shortcut.
|
||||
hr = SHGetPropertyStoreFromParsingName(filePath.get(), nullptr,
|
||||
GPS_READWRITE, IID_IPropertyStore,
|
||||
getter_AddRefs(pps));
|
||||
if (NS_WARN_IF(FAILED(hr)) || pps == nullptr) {
|
||||
continue;
|
||||
}
|
||||
PROPVARIANT propVar;
|
||||
PropVariantInit(&propVar);
|
||||
auto cleanupPropVariant =
|
||||
MakeScopeExit([&] { PropVariantClear(&propVar); });
|
||||
// Get the PKEY_Link_Arguments property
|
||||
hr = pps->GetValue(PKEY_Link_Arguments, &propVar);
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
continue;
|
||||
}
|
||||
// Check if the argument matches
|
||||
if (!(propVar.vt == VT_LPWSTR && propVar.pwszVal != nullptr &&
|
||||
wcsstr(propVar.pwszVal, L"-taskbar-tab") != nullptr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = link->GetPath(target.get(), MAX_PATH, nullptr, 0);
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If shortcut target matches known binary file value
|
||||
// then add the path to the shortcut as a valid
|
||||
// shortcut. This has to be a substring search as
|
||||
// the user could have added unknown command line arguments
|
||||
// to the shortcut.
|
||||
if (_wcsnicmp(target.get(), binPath.get(), binPath.Length()) == 0) {
|
||||
aShortcutPaths.AppendElement(filePath);
|
||||
}
|
||||
} while (FindNextFile(fileHandle, &ffd) != 0);
|
||||
FindClose(fileHandle);
|
||||
return NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
static nsresult PinCurrentAppToTaskbarWin10(bool aCheckOnly,
|
||||
const nsAString& aAppUserModelId,
|
||||
nsAutoString aShortcutPath) {
|
||||
|
@ -145,6 +145,20 @@ interface nsIWinTaskbar : nsISupports
|
||||
* Application window taskbar group settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the grouping id for a window.
|
||||
*
|
||||
* The runtime sets a default, global grouping id for all windows on startup.
|
||||
* getGroupIdForWindow allows finding the grouping of individual windows
|
||||
* on the taskbar.
|
||||
*
|
||||
* @throw NS_ERROR_INVALID_ARG if the window is not a valid top level window
|
||||
* associated with a widget.
|
||||
* @throw NS_ERROR_FAILURE if the property on the window could not be set.
|
||||
* @throw NS_ERROR_UNEXPECTED for general failures.
|
||||
*/
|
||||
AString getGroupIdForWindow(in mozIDOMWindow aParent);
|
||||
|
||||
/**
|
||||
* Set the grouping id for a window.
|
||||
*
|
||||
|
@ -440,6 +440,33 @@ WinTaskbar::CreateJumpListBuilder(bool aPrivateBrowsing,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::GetGroupIdForWindow(mozIDOMWindow* aParent,
|
||||
nsAString& aIdentifier) {
|
||||
NS_ENSURE_ARG_POINTER(aParent);
|
||||
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDOMWindow(aParent), GA_ROOT);
|
||||
if (!toplevelHWND) return NS_ERROR_INVALID_ARG;
|
||||
RefPtr<IPropertyStore> pPropStore;
|
||||
if (FAILED(SHGetPropertyStoreForWindow(toplevelHWND, IID_IPropertyStore,
|
||||
getter_AddRefs(pPropStore)))) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
PROPVARIANT pv;
|
||||
PropVariantInit(&pv);
|
||||
auto cleanupPropVariant = MakeScopeExit([&] { PropVariantClear(&pv); });
|
||||
if (FAILED(pPropStore->GetValue(PKEY_AppUserModel_ID, &pv))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (pv.vt != VT_LPWSTR) {
|
||||
// This can happen when there is no window specific group ID set
|
||||
// It's not an error case so we have to check for empty strings
|
||||
// returned from the function.
|
||||
return NS_OK;
|
||||
}
|
||||
aIdentifier.Assign(char16ptr_t(pv.pwszVal));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::SetGroupIdForWindow(mozIDOMWindow* aParent,
|
||||
const nsAString& aIdentifier) {
|
||||
|
Loading…
Reference in New Issue
Block a user