Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add profiles to the Jumplist #7515

Merged
9 commits merged into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/spell-check/dictionary/microsoft.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pgo
pgosweep
powerrename
powershell
propkey
pscustomobject
robocopy
SACLs
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,8 @@ namespace winrt::TerminalApp::implementation

// Register for directory change notification.
_RegisterSettingsChange();

jumplist.UpdateJumplist(_settings);
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
}

// Method Description:
Expand Down Expand Up @@ -851,6 +853,8 @@ namespace winrt::TerminalApp::implementation

_RefreshThemeRoutine();
_ApplyStartupTaskStateChange();

jumplist.UpdateJumplist(_settings);
}

// Method Description:
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "Tab.h"
#include "CascadiaSettings.h"
#include "TerminalPage.h"
#include "Jumplist.h"
#include "../../cascadia/inc/cppwinrt_utils.h"

namespace winrt::TerminalApp::implementation
Expand Down Expand Up @@ -79,6 +80,8 @@ namespace winrt::TerminalApp::implementation

std::shared_mutex _dialogLock;

Jumplist jumplist;

std::atomic<bool> _settingsReloadQueued{ false };

::TerminalApp::AppCommandlineArgs _appArgs;
Expand Down
142 changes: 142 additions & 0 deletions src/cascadia/TerminalApp/Jumplist.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include "Jumplist.h"

#include <Propkey.h>

using namespace winrt::TerminalApp;

// This property key isn't already defined in Propkey.h, but is used by UWP Jumplist to determine the icon of the jumplist item.
// IShellLink's SetIconLocation isn't going to read "ms-appx://" icon paths, so we'll need to use this to set the icon.
DEFINE_PROPERTYKEY(PKEY_AppUserModel_DestListLogoUri, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 29);
#define INIT_PKEY_AppUserModel_DestListLogoUri \
{ \
{ 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 }, 29 \
}

// Method Description:
// - Updates the items of the Jumplist based on the given settings.
// Arguments:
// - settings - The settings object to update the jumplist with.
// Return Value:
// - <none>
void Jumplist::UpdateJumplist(std::shared_ptr<::TerminalApp::CascadiaSettings> settings)
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
winrt::com_ptr<ICustomDestinationList> jumplistInstance;
if (FAILED(CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&jumplistInstance))))
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
return;
}
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved

// Start the Jumplist edit transaction
uint32_t slots;
winrt::com_ptr<IObjectCollection> jumplistItems;
if (FAILED(jumplistInstance->BeginList(&slots, IID_PPV_ARGS(&jumplistItems))))
{
return;
}

leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
// It's easier to clear the list and re-add everything. The settings aren't
// updated often, and there likely isn't a huge amount of items to add.
jumplistItems->Clear();

// Update the list of profiles.
if (FAILED(_updateProfiles(jumplistItems, settings->GetProfiles())))
{
return;
}

// TODO: Add items from the future customizable new tab dropdown as well.
// This could either replace the default profiles, or be added alongside them.
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved

// Add the items to the jumplist Task section.
// The Tasks section is immutable by the user, unlike the destinations
// section that can have its items pinned and removed.
jumplistInstance->AddUserTasks(jumplistItems.get());

if (FAILED(jumplistInstance->CommitList()))
{
return;
}
}

// Method Description:
// - Creates and adds a ShellLink object to the Jumplist for each profile.
// Arguments:
// - jumplistItems - The jumplist item list
// - profiles - The profiles to add to the jumplist
// Return Value:
// - S_OK or HRESULT failure code.
HRESULT Jumplist::_updateProfiles(winrt::com_ptr<IObjectCollection>& jumplistItems, const gsl::span<const Profile>& profiles)
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
HRESULT result = S_OK;
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved

for (const auto& profile : profiles)
{
// Craft the arguments following "wt.exe"
auto profileName = profile.Name();
auto args = fmt::format(L"-p \"{}\"", profileName);
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved

// Create the shell link object for the profile
winrt::com_ptr<IShellLink> shLink;
auto result = _createShellLink(profileName, profile.GetExpandedIconPath(), args, shLink);
if (FAILED(result))
{
return result;
}

jumplistItems->AddObject(shLink.get());
}

return result;
}

// Method Description:
// - Creates a ShellLink object. Each item in a jumplist is a ShellLink, which is sort of
// like a shortcut. It requires the path to the application (wt.exe), the arguments to pass,
// and the path to the icon for the jumplist item. The path to the application isn't passed
// into this function, as we'll determine it with GetModuleFileName.
// Arguments:
// - name: The name of the item displayed in the jumplist.
// - path: The path to the icon for the jumplist item.
// - args: The arguments to pass along with wt.exe
// Return Value:
// - S_OK or HRESULT failure code.
HRESULT Jumplist::_createShellLink(const std::wstring_view& name,
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
const std::wstring_view& path,
const std::wstring_view& args,
winrt::com_ptr<IShellLink>& shLink)
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
// Create a shell link object
auto result = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&shLink));
if (FAILED(result))
{
return result;
}
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved

std::filesystem::path module{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
shLink->SetPath(module.c_str());
shLink->SetArguments(args.data());

PROPVARIANT titleProp;
titleProp.vt = VT_LPWSTR;
titleProp.pwszVal = const_cast<wchar_t*>(name.data());
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved

PROPVARIANT iconProp;
iconProp.vt = VT_LPWSTR;
iconProp.pwszVal = const_cast<wchar_t*>(path.data());

winrt::com_ptr<IPropertyStore> propStore = shLink.as<IPropertyStore>();
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
propStore->SetValue(PKEY_Title, titleProp);
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved
propStore->SetValue(PKEY_AppUserModel_DestListLogoUri, iconProp);

result = propStore->Commit();
if (FAILED(result))
{
return result;
}

return result;
}
28 changes: 28 additions & 0 deletions src/cascadia/TerminalApp/Jumplist.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
// Module Name:
// - Jumplist.h
//
// Abstract:
// - The Jumplist is the menu that pops up when right clicking a pinned
// item in the taskbar. This class handles updating the Terminal's jumplist
// using the Terminal's settings.
//

#pragma once

#include "CascadiaSettings.h"
#include "Profile.h"

#include <ShObjIdl.h>
leonMSFT marked this conversation as resolved.
Show resolved Hide resolved

class Jumplist
{
public:
Jumplist() = default;
void UpdateJumplist(std::shared_ptr<::TerminalApp::CascadiaSettings> settings);
private:
HRESULT _updateProfiles(winrt::com_ptr<IObjectCollection>& jumplistItems, const gsl::span<const winrt::TerminalApp::Profile>& profiles);
HRESULT _createShellLink(const std::wstring_view& name, const std::wstring_view& path, const std::wstring_view& args, winrt::com_ptr<IShellLink>& shLink);
};
2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/TerminalAppLib.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<ClInclude Include="App.base.h" />
<ClInclude Include="AppCommandlineArgs.h" />
<ClInclude Include="Commandline.h" />
<ClInclude Include="Jumplist.h" />
<ClInclude Include="MinMaxCloseControl.h">
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
</ClInclude>
Expand Down Expand Up @@ -155,6 +156,7 @@
<ClCompile Include="init.cpp" />
<ClCompile Include="AppCommandlineArgs.cpp" />
<ClCompile Include="Commandline.cpp" />
<ClCompile Include="Jumplist.cpp" />
<ClCompile Include="MinMaxCloseControl.cpp">
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
</ClCompile>
Expand Down