Skip to content

Commit 41645fc

Browse files
committed
Bug 1863636 - Part 2: Added native code changes for taskbar tabs r=win-reviewers,mhughes,gstoll
Differential Revision: https://phabricator.services.mozilla.com/D197342
1 parent 1b61a2b commit 41645fc

File tree

4 files changed

+222
-10
lines changed

4 files changed

+222
-10
lines changed

browser/components/shell/nsIWindowsShellService.idl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,44 @@ interface nsIWindowsShellService : nsISupports
189189
*/
190190
void unpinShortcutFromTaskbar(in AString aShortcutPath);
191191

192+
193+
/**
194+
* Gets the full path of a taskbar tab shortcut.
195+
*
196+
* @param aShortcutName
197+
* The name of the taskbar tab shortcut, excluding the file extension.
198+
* @throws NS_ERROR_FAILURE
199+
* If the user token cannot be found.
200+
* @throws NS_ERROR_ABORT
201+
* If converting the sid to a string fails.
202+
*
203+
* @return The full path of the taskbar tab shortcut
204+
*/
205+
AString getTaskbarTabShortcutPath(in AString aShortcutName);
206+
207+
/*
208+
* Searches the %USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start
209+
* Menu\Programs folder and returns an array with the path of all
210+
* shortcuts with a target matching the current Firefox install location
211+
* and the -taskbar-tab argument.
212+
*
213+
* It is possible to return an empty array if no shortcuts are found.
214+
*
215+
* @return An array of paths for all taskbar tab shortcuts.
216+
*
217+
* @throws NS_ERROR_NOT_IMPLEMENTED
218+
* if run on a MinGW compilation
219+
* @throws NS_ERROR_ABORT
220+
* if instance cannot be created.
221+
* @throws NS_ERROR_FILE_NOT_FOUND
222+
* if %USERPROFILE%\AppData\Roaming\ cannot be opened.
223+
* @throws NS_ERROR_FAILURE
224+
* if the executable file cannot be found.
225+
* @throws NS_ERROR_FILE_UNRECOGNIZED_PATH
226+
* if the executable file cannot be converted into a string.
227+
*/
228+
Array<AString> getTaskbarTabPins();
229+
192230
/*
193231
* Determine where a given shortcut likely appears in the shell.
194232
*

browser/components/shell/nsWindowsShellService.cpp

Lines changed: 143 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,23 +1418,15 @@ static nsresult ManageShortcutTaskbarPins(bool aCheckOnly, bool aPinType,
14181418
}
14191419
};
14201420

1421-
HRESULT hr = CoInitialize(nullptr);
1422-
if (FAILED(hr)) {
1423-
return NS_ERROR_FAILURE;
1424-
}
1425-
const struct ComUninitializer {
1426-
~ComUninitializer() { CoUninitialize(); }
1427-
} kCUi;
1428-
14291421
mozilla::UniquePtr<__unaligned ITEMIDLIST, ILFreeDeleter> path(
14301422
ILCreateFromPathW(nsString(aShortcutPath).get()));
14311423
if (NS_WARN_IF(!path)) {
14321424
return NS_ERROR_FILE_NOT_FOUND;
14331425
}
14341426

14351427
IPinnedList3* pinnedList = nullptr;
1436-
hr = CoCreateInstance(CLSID_TaskbandPin, NULL, CLSCTX_INPROC_SERVER,
1437-
IID_IPinnedList3, (void**)&pinnedList);
1428+
HRESULT hr = CoCreateInstance(CLSID_TaskbandPin, NULL, CLSCTX_INPROC_SERVER,
1429+
IID_IPinnedList3, (void**)&pinnedList);
14381430
if (FAILED(hr) || !pinnedList) {
14391431
return NS_ERROR_NOT_AVAILABLE;
14401432
}
@@ -1467,6 +1459,147 @@ nsWindowsShellService::UnpinShortcutFromTaskbar(
14671459
return ManageShortcutTaskbarPins(runInTestMode, pinType, aShortcutPath);
14681460
}
14691461

1462+
NS_IMETHODIMP
1463+
nsWindowsShellService::GetTaskbarTabShortcutPath(const nsAString& aShortcutName,
1464+
nsAString& aRetPath) {
1465+
// The taskbar tab shortcut will always be in
1466+
// %APPDATA%\Microsoft\Windows\Start Menu\Programs
1467+
RefPtr<IKnownFolderManager> fManager;
1468+
RefPtr<IKnownFolder> progFolder;
1469+
LPWSTR progFolderW;
1470+
nsString progFolderNS;
1471+
HRESULT hr =
1472+
CoCreateInstance(CLSID_KnownFolderManager, nullptr, CLSCTX_INPROC_SERVER,
1473+
IID_IKnownFolderManager, getter_AddRefs(fManager));
1474+
if (NS_WARN_IF(FAILED(hr))) {
1475+
return NS_ERROR_ABORT;
1476+
}
1477+
fManager->GetFolder(FOLDERID_Programs, progFolder.StartAssignment());
1478+
hr = progFolder->GetPath(0, &progFolderW);
1479+
if (FAILED(hr)) {
1480+
return NS_ERROR_FILE_NOT_FOUND;
1481+
}
1482+
progFolderNS.Assign(progFolderW);
1483+
aRetPath = progFolderNS + u"\\"_ns + aShortcutName + u".lnk"_ns;
1484+
return NS_OK;
1485+
}
1486+
1487+
NS_IMETHODIMP
1488+
nsWindowsShellService::GetTaskbarTabPins(nsTArray<nsString>& aShortcutPaths) {
1489+
#ifdef __MINGW32__
1490+
return NS_ERROR_NOT_IMPLEMENTED;
1491+
#else
1492+
aShortcutPaths.Clear();
1493+
1494+
// Get AppData\\Roaming folder using a known folder ID
1495+
RefPtr<IKnownFolderManager> fManager;
1496+
RefPtr<IKnownFolder> roamingAppData;
1497+
LPWSTR roamingAppDataW;
1498+
nsString roamingAppDataNS;
1499+
HRESULT hr =
1500+
CoCreateInstance(CLSID_KnownFolderManager, nullptr, CLSCTX_INPROC_SERVER,
1501+
IID_IKnownFolderManager, getter_AddRefs(fManager));
1502+
if (NS_WARN_IF(FAILED(hr))) {
1503+
return NS_ERROR_ABORT;
1504+
}
1505+
fManager->GetFolder(FOLDERID_RoamingAppData,
1506+
roamingAppData.StartAssignment());
1507+
hr = roamingAppData->GetPath(0, &roamingAppDataW);
1508+
if (FAILED(hr)) {
1509+
return NS_ERROR_FILE_NOT_FOUND;
1510+
}
1511+
1512+
// Append taskbar pins folder to AppData\\Roaming
1513+
roamingAppDataNS.Assign(roamingAppDataW);
1514+
CoTaskMemFree(roamingAppDataW);
1515+
nsString taskbarFolder =
1516+
roamingAppDataNS + u"\\Microsoft\\Windows\\Start Menu\\Programs"_ns;
1517+
nsString taskbarFolderWildcard = taskbarFolder + u"\\*.lnk"_ns;
1518+
1519+
// Get known path for binary file for later comparison with shortcuts.
1520+
// Returns lowercase file path which should be fine for Windows as all
1521+
// directories and files are case-insensitive by default.
1522+
RefPtr<nsIFile> binFile;
1523+
nsString binPath;
1524+
nsresult rv = XRE_GetBinaryPath(binFile.StartAssignment());
1525+
if (NS_WARN_IF(FAILED(rv))) {
1526+
return NS_ERROR_FAILURE;
1527+
}
1528+
rv = binFile->GetPath(binPath);
1529+
if (NS_WARN_IF(FAILED(rv))) {
1530+
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
1531+
}
1532+
1533+
// Check for if first file exists with a shortcut extension (.lnk)
1534+
WIN32_FIND_DATAW ffd;
1535+
HANDLE fileHandle = INVALID_HANDLE_VALUE;
1536+
fileHandle = FindFirstFileW(taskbarFolderWildcard.get(), &ffd);
1537+
if (fileHandle == INVALID_HANDLE_VALUE) {
1538+
// This means that no files were found in the folder which
1539+
// doesn't imply an error.
1540+
return NS_OK;
1541+
}
1542+
1543+
do {
1544+
// Extract shortcut target path from every
1545+
// shortcut in the taskbar pins folder.
1546+
nsString fileName(ffd.cFileName);
1547+
RefPtr<IShellLinkW> link;
1548+
RefPtr<IPropertyStore> pps;
1549+
nsString target;
1550+
target.SetLength(MAX_PATH);
1551+
hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
1552+
IID_IShellLinkW, getter_AddRefs(link));
1553+
if (NS_WARN_IF(FAILED(hr))) {
1554+
continue;
1555+
}
1556+
nsString filePath = taskbarFolder + u"\\"_ns + fileName;
1557+
if (NS_WARN_IF(FAILED(hr))) {
1558+
continue;
1559+
}
1560+
1561+
// After loading shortcut, search through arguments to find if
1562+
// it is a taskbar tab shortcut.
1563+
hr = SHGetPropertyStoreFromParsingName(filePath.get(), nullptr,
1564+
GPS_READWRITE, IID_IPropertyStore,
1565+
getter_AddRefs(pps));
1566+
if (NS_WARN_IF(FAILED(hr)) || pps == nullptr) {
1567+
continue;
1568+
}
1569+
PROPVARIANT propVar;
1570+
PropVariantInit(&propVar);
1571+
auto cleanupPropVariant =
1572+
MakeScopeExit([&] { PropVariantClear(&propVar); });
1573+
// Get the PKEY_Link_Arguments property
1574+
hr = pps->GetValue(PKEY_Link_Arguments, &propVar);
1575+
if (NS_WARN_IF(FAILED(hr))) {
1576+
continue;
1577+
}
1578+
// Check if the argument matches
1579+
if (!(propVar.vt == VT_LPWSTR && propVar.pwszVal != nullptr &&
1580+
wcsstr(propVar.pwszVal, L"-taskbar-tab") != nullptr)) {
1581+
continue;
1582+
}
1583+
1584+
hr = link->GetPath(target.get(), MAX_PATH, nullptr, 0);
1585+
if (NS_WARN_IF(FAILED(hr))) {
1586+
continue;
1587+
}
1588+
1589+
// If shortcut target matches known binary file value
1590+
// then add the path to the shortcut as a valid
1591+
// shortcut. This has to be a substring search as
1592+
// the user could have added unknown command line arguments
1593+
// to the shortcut.
1594+
if (_wcsnicmp(target.get(), binPath.get(), binPath.Length()) == 0) {
1595+
aShortcutPaths.AppendElement(filePath);
1596+
}
1597+
} while (FindNextFile(fileHandle, &ffd) != 0);
1598+
FindClose(fileHandle);
1599+
return NS_OK;
1600+
#endif
1601+
}
1602+
14701603
static nsresult PinCurrentAppToTaskbarWin10(bool aCheckOnly,
14711604
const nsAString& aAppUserModelId,
14721605
nsAutoString aShortcutPath) {

widget/nsIWinTaskbar.idl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,20 @@ interface nsIWinTaskbar : nsISupports
145145
* Application window taskbar group settings
146146
*/
147147

148+
/**
149+
* Get the grouping id for a window.
150+
*
151+
* The runtime sets a default, global grouping id for all windows on startup.
152+
* getGroupIdForWindow allows finding the grouping of individual windows
153+
* on the taskbar.
154+
*
155+
* @throw NS_ERROR_INVALID_ARG if the window is not a valid top level window
156+
* associated with a widget.
157+
* @throw NS_ERROR_FAILURE if the property on the window could not be set.
158+
* @throw NS_ERROR_UNEXPECTED for general failures.
159+
*/
160+
AString getGroupIdForWindow(in mozIDOMWindow aParent);
161+
148162
/**
149163
* Set the grouping id for a window.
150164
*

widget/windows/WinTaskbar.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,33 @@ WinTaskbar::CreateJumpListBuilder(bool aPrivateBrowsing,
440440
return NS_OK;
441441
}
442442

443+
NS_IMETHODIMP
444+
WinTaskbar::GetGroupIdForWindow(mozIDOMWindow* aParent,
445+
nsAString& aIdentifier) {
446+
NS_ENSURE_ARG_POINTER(aParent);
447+
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDOMWindow(aParent), GA_ROOT);
448+
if (!toplevelHWND) return NS_ERROR_INVALID_ARG;
449+
RefPtr<IPropertyStore> pPropStore;
450+
if (FAILED(SHGetPropertyStoreForWindow(toplevelHWND, IID_IPropertyStore,
451+
getter_AddRefs(pPropStore)))) {
452+
return NS_ERROR_INVALID_ARG;
453+
}
454+
PROPVARIANT pv;
455+
PropVariantInit(&pv);
456+
auto cleanupPropVariant = MakeScopeExit([&] { PropVariantClear(&pv); });
457+
if (FAILED(pPropStore->GetValue(PKEY_AppUserModel_ID, &pv))) {
458+
return NS_ERROR_FAILURE;
459+
}
460+
if (pv.vt != VT_LPWSTR) {
461+
// This can happen when there is no window specific group ID set
462+
// It's not an error case so we have to check for empty strings
463+
// returned from the function.
464+
return NS_OK;
465+
}
466+
aIdentifier.Assign(char16ptr_t(pv.pwszVal));
467+
return NS_OK;
468+
}
469+
443470
NS_IMETHODIMP
444471
WinTaskbar::SetGroupIdForWindow(mozIDOMWindow* aParent,
445472
const nsAString& aIdentifier) {

0 commit comments

Comments
 (0)