mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-06 22:29:43 +00:00
Compare commits
14 Commits
dev/migrie
...
v1.16.2641
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47f1167af2 | ||
|
|
45310d77a8 | ||
|
|
3717fae714 | ||
|
|
9d0346c2b3 | ||
|
|
8876417f87 | ||
|
|
9310db572d | ||
|
|
9ec3e799ed | ||
|
|
73ea629c18 | ||
|
|
8f013d7ae8 | ||
|
|
c2c5f410f9 | ||
|
|
5e9147e994 | ||
|
|
b899d49a26 | ||
|
|
b73e39ce17 | ||
|
|
bccd97257e |
@@ -4,7 +4,7 @@
|
||||
"collection": "microsoft",
|
||||
"project": "OS",
|
||||
"repo": "os.2020",
|
||||
"name": "official/rs_wdx_dxp_windev",
|
||||
"name": "official/rs_we_adept_e4d2",
|
||||
"workitem": "38106206",
|
||||
"CheckinFiles": [
|
||||
{
|
||||
@@ -21,4 +21,4 @@
|
||||
"sendOnErrorOnly": "False"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
|
||||
<PGOBranch>main</PGOBranch>
|
||||
<PGOBranch>release-1.16</PGOBranch>
|
||||
|
||||
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
|
||||
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>
|
||||
|
||||
@@ -708,6 +708,7 @@ jobs:
|
||||
description: VPack for the Windows Terminal Application
|
||||
pushPkgName: WindowsTerminal.app
|
||||
owner: conhost
|
||||
githubToken: $(GitHubTokenForVpackProvenance)
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Copy VPack Manifest to Drop'
|
||||
inputs:
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
"default": 12,
|
||||
"description": "Size of the font in points.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
"type": "number"
|
||||
},
|
||||
"weight": {
|
||||
"default": "normal",
|
||||
@@ -2252,7 +2252,7 @@
|
||||
"default": 12,
|
||||
"description": "[deprecated] Define 'size' within the 'font' object instead.",
|
||||
"minimum": 1,
|
||||
"type": "integer",
|
||||
"type": "number",
|
||||
"deprecated": true
|
||||
},
|
||||
"fontWeight": {
|
||||
|
||||
@@ -169,7 +169,7 @@ static bool RegisterTermClass(HINSTANCE hInstance) noexcept
|
||||
}
|
||||
|
||||
HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8 },
|
||||
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, 14, CP_UTF8 },
|
||||
_actualFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8, false },
|
||||
_uiaProvider{ nullptr },
|
||||
_currentDpi{ USER_DEFAULT_SCREEN_DPI },
|
||||
@@ -799,7 +799,7 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
|
||||
|
||||
publicTerminal->_terminal->SetCursorStyle(static_cast<DispatchTypes::CursorStyle>(theme.CursorStyle));
|
||||
|
||||
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, { 0, fontSize }, CP_UTF8 };
|
||||
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, static_cast<float>(fontSize), CP_UTF8 };
|
||||
publicTerminal->_UpdateFont(newDpi);
|
||||
|
||||
// When the font changes the terminal dimensions need to be recalculated since the available row and column
|
||||
|
||||
@@ -25,37 +25,25 @@ static constexpr std::wstring_view VerbName{ L"WindowsTerminalOpenHere" };
|
||||
// failure from an earlier HRESULT.
|
||||
HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
||||
IBindCtx* /*pBindContext*/)
|
||||
try
|
||||
{
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
RETURN_IF_FAILED(GetBestLocationFromSelectionOrSite(psiItemArray, psi.put()));
|
||||
if (!psi)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
wil::unique_cotaskmem_string pszName;
|
||||
|
||||
if (psiItemArray == nullptr)
|
||||
{
|
||||
// get the current path from explorer.exe
|
||||
const auto path = this->_GetPathFromExplorer();
|
||||
|
||||
// no go, unable to get a reasonable path
|
||||
if (path.empty())
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
pszName = wil::make_cotaskmem_string(path.c_str(), path.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD count;
|
||||
psiItemArray->GetCount(&count);
|
||||
|
||||
winrt::com_ptr<IShellItem> psi;
|
||||
RETURN_IF_FAILED(psiItemArray->GetItemAt(0, psi.put()));
|
||||
RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName));
|
||||
}
|
||||
RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName));
|
||||
|
||||
{
|
||||
wil::unique_process_information _piClient;
|
||||
STARTUPINFOEX siEx{ 0 };
|
||||
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
||||
|
||||
auto cmdline{ wil::str_printf<std::wstring>(LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()) };
|
||||
std::wstring cmdline;
|
||||
RETURN_IF_FAILED(wil::str_printf_nothrow(cmdline, LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()));
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
nullptr, // lpApplicationName
|
||||
cmdline.data(),
|
||||
@@ -72,6 +60,7 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
HRESULT OpenTerminalHere::GetToolTip(IShellItemArray* /*psiItemArray*/,
|
||||
LPWSTR* ppszInfoTip)
|
||||
@@ -109,21 +98,14 @@ HRESULT OpenTerminalHere::GetState(IShellItemArray* psiItemArray,
|
||||
// We however don't need to bother with any of that.
|
||||
|
||||
// If no item was selected when the context menu was opened and Explorer
|
||||
// is not at a valid path (e.g. This PC or Quick Access), we should hide
|
||||
// is not at a valid location (e.g. This PC or Quick Access), we should hide
|
||||
// the verb from the context menu.
|
||||
if (psiItemArray == nullptr)
|
||||
{
|
||||
const auto path = this->_GetPathFromExplorer();
|
||||
*pCmdState = path.empty() ? ECS_HIDDEN : ECS_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
winrt::com_ptr<IShellItem> psi;
|
||||
psiItemArray->GetItemAt(0, psi.put());
|
||||
SFGAOF attributes;
|
||||
const bool isFileSystemItem = (psi->GetAttributes(SFGAO_FILESYSTEM, &attributes) == S_OK);
|
||||
*pCmdState = isFileSystemItem ? ECS_ENABLED : ECS_HIDDEN;
|
||||
}
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
RETURN_IF_FAILED(GetBestLocationFromSelectionOrSite(psiItemArray, psi.put()));
|
||||
|
||||
SFGAOF attributes;
|
||||
const bool isFileSystemItem = psi && (psi->GetAttributes(SFGAO_FILESYSTEM, &attributes) == S_OK);
|
||||
*pCmdState = isFileSystemItem ? ECS_ENABLED : ECS_HIDDEN;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -160,102 +142,47 @@ HRESULT OpenTerminalHere::EnumSubCommands(IEnumExplorerCommand** ppEnum)
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
std::wstring OpenTerminalHere::_GetPathFromExplorer() const
|
||||
IFACEMETHODIMP OpenTerminalHere::SetSite(IUnknown* site) noexcept
|
||||
{
|
||||
using namespace std;
|
||||
using namespace winrt;
|
||||
|
||||
wstring path;
|
||||
HRESULT hr = NOERROR;
|
||||
|
||||
auto hwnd = ::GetForegroundWindow();
|
||||
if (hwnd == nullptr)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
TCHAR szName[MAX_PATH] = { 0 };
|
||||
::GetClassName(hwnd, szName, MAX_PATH);
|
||||
if (0 == StrCmp(szName, L"WorkerW") ||
|
||||
0 == StrCmp(szName, L"Progman"))
|
||||
{
|
||||
//special folder: desktop
|
||||
hr = ::SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, szName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
path = szName;
|
||||
return path;
|
||||
}
|
||||
|
||||
if (0 != StrCmp(szName, L"CabinetWClass"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
com_ptr<IShellWindows> shell;
|
||||
try
|
||||
{
|
||||
shell = create_instance<IShellWindows>(CLSID_ShellWindows, CLSCTX_ALL);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
//look like try_create_instance is not available no more
|
||||
}
|
||||
|
||||
if (shell == nullptr)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
com_ptr<IDispatch> disp;
|
||||
wil::unique_variant variant;
|
||||
variant.vt = VT_I4;
|
||||
|
||||
com_ptr<IWebBrowserApp> browser;
|
||||
// look for correct explorer window
|
||||
for (variant.intVal = 0;
|
||||
shell->Item(variant, disp.put()) == S_OK;
|
||||
variant.intVal++)
|
||||
{
|
||||
com_ptr<IWebBrowserApp> tmp;
|
||||
if (FAILED(disp->QueryInterface(tmp.put())))
|
||||
{
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
continue;
|
||||
}
|
||||
|
||||
HWND tmpHWND = NULL;
|
||||
hr = tmp->get_HWND(reinterpret_cast<SHANDLE_PTR*>(&tmpHWND));
|
||||
if (hwnd == tmpHWND)
|
||||
{
|
||||
browser = tmp;
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
break; //found
|
||||
}
|
||||
|
||||
disp = nullptr; // get rid of DEBUG non-nullptr warning
|
||||
}
|
||||
|
||||
if (browser != nullptr)
|
||||
{
|
||||
wil::unique_bstr url;
|
||||
hr = browser->get_LocationURL(&url);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
wstring sUrl(url.get(), SysStringLen(url.get()));
|
||||
DWORD size = MAX_PATH;
|
||||
hr = ::PathCreateFromUrl(sUrl.c_str(), szName, &size, NULL);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
path = szName;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
site_ = site;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OpenTerminalHere::GetSite(REFIID riid, void** site) noexcept
|
||||
{
|
||||
RETURN_IF_FAILED(site_.query_to(riid, site));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OpenTerminalHere::GetLocationFromSite(IShellItem** location) const noexcept
|
||||
{
|
||||
wil::com_ptr_nothrow<IServiceProvider> serviceProvider;
|
||||
RETURN_IF_FAILED(site_.query_to(serviceProvider.put()));
|
||||
wil::com_ptr_nothrow<IFolderView> folderView;
|
||||
RETURN_IF_FAILED(serviceProvider->QueryService(SID_SFolderView, IID_PPV_ARGS(folderView.put())));
|
||||
RETURN_IF_FAILED(folderView->GetFolder(IID_PPV_ARGS(location)));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OpenTerminalHere::GetBestLocationFromSelectionOrSite(IShellItemArray* psiArray, IShellItem** location) const noexcept
|
||||
{
|
||||
wil::com_ptr_nothrow<IShellItem> psi;
|
||||
if (psiArray)
|
||||
{
|
||||
DWORD count{};
|
||||
RETURN_IF_FAILED(psiArray->GetCount(&count));
|
||||
if (count) // Sometimes we get an array with a count of 0. Fall back to the site chain.
|
||||
{
|
||||
RETURN_IF_FAILED(psiArray->GetItemAt(0, psi.put()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!psi)
|
||||
{
|
||||
RETURN_IF_FAILED(GetLocationFromSite(psi.put()));
|
||||
}
|
||||
|
||||
RETURN_HR_IF(S_FALSE, !psi);
|
||||
RETURN_IF_FAILED(psi.copy_to(location));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ Author(s):
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include <conattrs.hpp>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
struct
|
||||
@@ -34,7 +32,7 @@ struct
|
||||
#else // DEV
|
||||
__declspec(uuid("52065414-e077-47ec-a3ac-1cc5455e1b54"))
|
||||
#endif
|
||||
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand>
|
||||
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand, IObjectWithSite>
|
||||
{
|
||||
#pragma region IExplorerCommand
|
||||
STDMETHODIMP Invoke(IShellItemArray* psiItemArray,
|
||||
@@ -52,9 +50,16 @@ struct
|
||||
STDMETHODIMP GetCanonicalName(GUID* pguidCommandName);
|
||||
STDMETHODIMP EnumSubCommands(IEnumExplorerCommand** ppEnum);
|
||||
#pragma endregion
|
||||
#pragma region IObjectWithSite
|
||||
IFACEMETHODIMP SetSite(IUnknown* site) noexcept;
|
||||
IFACEMETHODIMP GetSite(REFIID riid, void** site) noexcept;
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
std::wstring _GetPathFromExplorer() const;
|
||||
HRESULT GetLocationFromSite(IShellItem** location) const noexcept;
|
||||
HRESULT GetBestLocationFromSelectionOrSite(IShellItemArray* psiArray, IShellItem** location) const noexcept;
|
||||
|
||||
wil::com_ptr_nothrow<IUnknown> site_;
|
||||
};
|
||||
|
||||
CoCreatableClass(OpenTerminalHere);
|
||||
|
||||
@@ -554,6 +554,15 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
_hPC.reset(); // tear down the pseudoconsole (this is like clicking X on a console window)
|
||||
|
||||
// CloseHandle() on pipes blocks until any current WriteFile()/ReadFile() has returned.
|
||||
// CancelSynchronousIo prevents us from deadlocking ourselves.
|
||||
// At this point in Close(), _inPipe won't be used anymore since the UI parts are torn down.
|
||||
// _outPipe is probably still stuck in ReadFile() and might currently be written to.
|
||||
if (_hOutputThread)
|
||||
{
|
||||
CancelSynchronousIo(_hOutputThread.get());
|
||||
}
|
||||
|
||||
_inPipe.reset(); // break the pipes
|
||||
_outPipe.reset();
|
||||
|
||||
@@ -615,10 +624,17 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
DWORD read{};
|
||||
|
||||
const auto readFail{ !ReadFile(_outPipe.get(), _buffer.data(), gsl::narrow_cast<DWORD>(_buffer.size()), &read, nullptr) };
|
||||
|
||||
// When we call CancelSynchronousIo() in Close() this is the branch that's taken and gets us out of here.
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (readFail) // reading failed (we must check this first, because read will also be 0.)
|
||||
{
|
||||
const auto lastError = GetLastError();
|
||||
if (lastError != ERROR_BROKEN_PIPE && !_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
if (lastError != ERROR_BROKEN_PIPE)
|
||||
{
|
||||
// EXIT POINT
|
||||
_indicateExitWithStatus(HRESULT_FROM_WIN32(lastError)); // print a message
|
||||
@@ -631,12 +647,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const auto result{ til::u8u16(std::string_view{ _buffer.data(), read }, _u16Str, _u8State) };
|
||||
if (FAILED(result))
|
||||
{
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
// This termination was expected.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXIT POINT
|
||||
_indicateExitWithStatus(result); // print a message
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
namespace wil
|
||||
{
|
||||
// These belong in WIL upstream, so when we reingest the change that has them we'll get rid of ours.
|
||||
using unique_static_pseudoconsole_handle = wil::unique_any<HPCON, decltype(&::ConptyClosePseudoConsole), ::ConptyClosePseudoConsole>;
|
||||
using unique_static_pseudoconsole_handle = wil::unique_any<HPCON, decltype(&::ConptyClosePseudoConsole), ::ConptyClosePseudoConsoleNoWait>;
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Control::IControlAppearance unfocusedAppearance,
|
||||
TerminalConnection::ITerminalConnection connection) :
|
||||
_connection{ connection },
|
||||
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8 },
|
||||
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, DEFAULT_FONT_SIZE, CP_UTF8 },
|
||||
_actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false }
|
||||
{
|
||||
_EnsureStaticInitialization();
|
||||
@@ -859,15 +859,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - fontSize: The size of the font.
|
||||
// Return Value:
|
||||
// - Returns true if you need to call _refreshSizeUnderLock().
|
||||
bool ControlCore::_setFontSizeUnderLock(int fontSize)
|
||||
bool ControlCore::_setFontSizeUnderLock(float fontSize)
|
||||
{
|
||||
// Make sure we have a non-zero font size
|
||||
const auto newSize = std::max(fontSize, 1);
|
||||
const auto newSize = std::max(fontSize, 1.0f);
|
||||
const auto fontFace = _settings->FontFace();
|
||||
const auto fontWeight = _settings->FontWeight();
|
||||
_actualFont = { fontFace, 0, fontWeight.Weight, { 0, newSize }, CP_UTF8, false };
|
||||
_desiredFont = { fontFace, 0, fontWeight.Weight, newSize, CP_UTF8 };
|
||||
_actualFont = { fontFace, 0, fontWeight.Weight, _desiredFont.GetEngineSize(), CP_UTF8, false };
|
||||
_actualFontFaceName = { fontFace };
|
||||
_desiredFont = { _actualFont };
|
||||
|
||||
const auto before = _actualFont.GetSize();
|
||||
_updateFont();
|
||||
@@ -893,11 +893,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - Adjust the font size of the terminal control.
|
||||
// Arguments:
|
||||
// - fontSizeDelta: The amount to increase or decrease the font size by.
|
||||
void ControlCore::AdjustFontSize(int fontSizeDelta)
|
||||
void ControlCore::AdjustFontSize(float fontSizeDelta)
|
||||
{
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
|
||||
if (_setFontSizeUnderLock(_desiredFont.GetEngineSize().Y + fontSizeDelta))
|
||||
if (_setFontSizeUnderLock(_desiredFont.GetFontSize() + fontSizeDelta))
|
||||
{
|
||||
_refreshSizeUnderLock();
|
||||
}
|
||||
@@ -1211,10 +1211,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return static_cast<uint16_t>(_actualFont.GetWeight());
|
||||
}
|
||||
|
||||
til::size ControlCore::FontSizeInDips() const
|
||||
winrt::Windows::Foundation::Size ControlCore::FontSizeInDips() const
|
||||
{
|
||||
const til::size fontSize{ _actualFont.GetSize() };
|
||||
return fontSize.scale(til::math::rounding, 1.0f / ::base::saturated_cast<float>(_compositionScale));
|
||||
const auto fontSize = _actualFont.GetSize();
|
||||
const auto scale = 1.0f / static_cast<float>(_compositionScale);
|
||||
return {
|
||||
fontSize.width * scale,
|
||||
fontSize.height * scale,
|
||||
};
|
||||
}
|
||||
|
||||
TerminalConnection::ConnectionState ControlCore::ConnectionState() const
|
||||
|
||||
@@ -76,10 +76,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void SizeChanged(const double width, const double height);
|
||||
void ScaleChanged(const double scale);
|
||||
|
||||
void AdjustFontSize(int fontSizeDelta);
|
||||
void AdjustFontSize(float fontSizeDelta);
|
||||
void ResetFontSize();
|
||||
FontInfo GetFont() const;
|
||||
til::size FontSizeInDips() const;
|
||||
winrt::Windows::Foundation::Size FontSizeInDips() const;
|
||||
|
||||
winrt::Windows::Foundation::Size FontSize() const noexcept;
|
||||
winrt::hstring FontFaceName() const noexcept;
|
||||
@@ -282,7 +282,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
|
||||
|
||||
bool _setFontSizeUnderLock(int fontSize);
|
||||
bool _setFontSizeUnderLock(float fontSize);
|
||||
void _updateFont(const bool initialUpdate = false);
|
||||
void _refreshSizeUnderLock();
|
||||
void _updateSelectionUI();
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Microsoft.Terminal.Control
|
||||
void ClearHoveredCell();
|
||||
|
||||
void ResetFontSize();
|
||||
void AdjustFontSize(Int32 fontSizeDelta);
|
||||
void AdjustFontSize(Single fontSizeDelta);
|
||||
void SizeChanged(Double width, Double height);
|
||||
void ScaleChanged(Double scale);
|
||||
|
||||
|
||||
@@ -301,7 +301,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto touchdownPoint = *_singleClickTouchdownPos;
|
||||
const auto dx = pixelPosition.X - touchdownPoint.X;
|
||||
const auto dy = pixelPosition.Y - touchdownPoint.Y;
|
||||
const auto w = fontSizeInDips.width;
|
||||
const auto w = fontSizeInDips.Width;
|
||||
const auto distanceSquared = dx * dx + dy * dy;
|
||||
const auto maxDistanceSquared = w * w / 16; // (w / 4)^2
|
||||
|
||||
@@ -337,16 +337,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto fontSizeInDips{ _core->FontSizeInDips() };
|
||||
|
||||
// Get the difference between the point we've dragged to and the start of the touch.
|
||||
const auto dy = static_cast<double>(newTouchPoint.Y - anchor.Y);
|
||||
const auto dy = static_cast<float>(newTouchPoint.Y - anchor.Y);
|
||||
|
||||
// Start viewport scroll after we've moved more than a half row of text
|
||||
if (std::abs(dy) > (fontSizeInDips.height / 2.0))
|
||||
if (std::abs(dy) > (fontSizeInDips.Height / 2.0f))
|
||||
{
|
||||
// Multiply by -1, because moving the touch point down will
|
||||
// create a positive delta, but we want the viewport to move up,
|
||||
// so we'll need a negative scroll amount (and the inverse for
|
||||
// panning down)
|
||||
const auto numRows = dy / -fontSizeInDips.height;
|
||||
const auto numRows = dy / -fontSizeInDips.Height;
|
||||
|
||||
const auto currentOffset = _core->ScrollOffset();
|
||||
const auto newValue = numRows + currentOffset;
|
||||
@@ -459,7 +459,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// scrolling event.
|
||||
// Arguments:
|
||||
// - mouseDelta: the mouse wheel delta that triggered this event.
|
||||
void ControlInteractivity::_mouseTransparencyHandler(const double mouseDelta)
|
||||
void ControlInteractivity::_mouseTransparencyHandler(const int32_t mouseDelta) const
|
||||
{
|
||||
// Transparency is on a scale of [0.0,1.0], so only increment by .01.
|
||||
const auto effectiveDelta = mouseDelta < 0 ? -.01 : .01;
|
||||
@@ -471,9 +471,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// event.
|
||||
// Arguments:
|
||||
// - mouseDelta: the mouse wheel delta that triggered this event.
|
||||
void ControlInteractivity::_mouseZoomHandler(const double mouseDelta)
|
||||
void ControlInteractivity::_mouseZoomHandler(const int32_t mouseDelta) const
|
||||
{
|
||||
const auto fontDelta = mouseDelta < 0 ? -1 : 1;
|
||||
const auto fontDelta = mouseDelta < 0 ? -1.0f : 1.0f;
|
||||
_core->AdjustFontSize(fontDelta);
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - mouseDelta: the mouse wheel delta that triggered this event.
|
||||
// - pixelPosition: the location of the mouse during this event
|
||||
// - isLeftButtonPressed: true iff the left mouse button was pressed during this event.
|
||||
void ControlInteractivity::_mouseScrollHandler(const double mouseDelta,
|
||||
void ControlInteractivity::_mouseScrollHandler(const int32_t mouseDelta,
|
||||
const Core::Point pixelPosition,
|
||||
const bool isLeftButtonPressed)
|
||||
{
|
||||
|
||||
@@ -132,9 +132,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
unsigned int _numberOfClicks(Core::Point clickPos, Timestamp clickTime);
|
||||
void _updateSystemParameterSettings() noexcept;
|
||||
|
||||
void _mouseTransparencyHandler(const double mouseDelta);
|
||||
void _mouseZoomHandler(const double mouseDelta);
|
||||
void _mouseScrollHandler(const double mouseDelta,
|
||||
void _mouseTransparencyHandler(const int32_t mouseDelta) const;
|
||||
void _mouseZoomHandler(const int32_t mouseDelta) const;
|
||||
void _mouseScrollHandler(const int32_t mouseDelta,
|
||||
const Core::Point terminalPosition,
|
||||
const bool isLeftButtonPressed);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Microsoft.Terminal.Control
|
||||
Boolean UseAtlasEngine { get; };
|
||||
|
||||
String FontFace { get; };
|
||||
Int32 FontSize { get; };
|
||||
Single FontSize { get; };
|
||||
Windows.UI.Text.FontWeight FontWeight { get; };
|
||||
String Padding { get; };
|
||||
Windows.Foundation.Collections.IMap<String, UInt32> FontFeatures { get; };
|
||||
|
||||
@@ -1517,7 +1517,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - Adjust the font size of the terminal control.
|
||||
// Arguments:
|
||||
// - fontSizeDelta: The amount to increase or decrease the font size by.
|
||||
void TermControl::AdjustFontSize(int fontSizeDelta)
|
||||
void TermControl::AdjustFontSize(float fontSizeDelta)
|
||||
{
|
||||
_core.AdjustFontSize(fontSizeDelta);
|
||||
}
|
||||
@@ -2082,8 +2082,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// The family is only used to determine if the font is truetype or
|
||||
// not, but DX doesn't use that info at all.
|
||||
// The Codepage is additionally not actually used by the DX engine at all.
|
||||
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, fontSize }, CP_UTF8, false };
|
||||
FontInfoDesired desiredFont = { actualFont };
|
||||
FontInfoDesired desiredFont{ fontFace, 0, fontWeight.Weight, fontSize, CP_UTF8 };
|
||||
FontInfo actualFont{ fontFace, 0, fontWeight.Weight, desiredFont.GetEngineSize(), CP_UTF8, false };
|
||||
|
||||
// Create a DX engine and initialize it with our font and DPI. We'll
|
||||
// then use it to measure how much space the requested rows and columns
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ScrollViewport(int viewTop);
|
||||
|
||||
void AdjustFontSize(int fontSizeDelta);
|
||||
void AdjustFontSize(float fontSizeDelta);
|
||||
void ResetFontSize();
|
||||
til::point GetFontSize() const;
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Microsoft.Terminal.Control
|
||||
|
||||
void SearchMatch(Boolean goForward);
|
||||
|
||||
void AdjustFontSize(Int32 fontSizeDelta);
|
||||
void AdjustFontSize(Single fontSizeDelta);
|
||||
void ResetFontSize();
|
||||
|
||||
void ToggleShaderEffects();
|
||||
|
||||
@@ -379,7 +379,7 @@ void Terminal::ExpandSelectionToWord()
|
||||
_selection->pivot = _selection->start;
|
||||
_selection->end = buffer.GetWordEnd(_selection->end, _wordDelimiters);
|
||||
|
||||
// if we're targetting both endpoints, instead just target "end"
|
||||
// if we're targeting both endpoints, instead just target "end"
|
||||
if (WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::Start) && WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::End))
|
||||
{
|
||||
_selectionEndpoint = SelectionEndpoint::End;
|
||||
|
||||
@@ -91,6 +91,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
{
|
||||
using namespace winrt::Windows::Globalization::NumberFormatting;
|
||||
// > .NET rounds to 12 significant digits when displaying doubles, so we will [...]
|
||||
// ...obviously not do that, because this is an UI element for humans. This prevents
|
||||
// issues when displaying 32-bit floats, because WinUI is unaware about their existence.
|
||||
SignificantDigitsNumberRounder rounder;
|
||||
rounder.SignificantDigits(6);
|
||||
// BODGY: Depends on WinUI internals.
|
||||
_fontSizeBox().NumberFormatter().as<DecimalFormatter>().NumberRounder(rounder);
|
||||
}
|
||||
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING(CursorShape, CursorStyle, winrt::Microsoft::Terminal::Core::CursorStyle, L"Profile_CursorShape", L"Content");
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING(AdjustIndistinguishableColors, AdjustIndistinguishableColors, winrt::Microsoft::Terminal::Core::AdjustTextMode, L"Profile_AdjustIndistinguishableColors", L"Content");
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING_REVERSE_ORDER(BackgroundImageStretchMode, BackgroundImageStretchMode, winrt::Windows::UI::Xaml::Media::Stretch, L"Profile_BackgroundImageStretchMode", L"Content");
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
IHostedInWindow WindowRoot; // necessary to send the right HWND into the file picker dialogs.
|
||||
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, FontFace);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Int32, FontSize);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Single, FontSize);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Text.FontWeight, FontWeight);
|
||||
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, ColorSchemeName);
|
||||
|
||||
@@ -93,7 +93,8 @@
|
||||
HasSettingValue="{x:Bind Appearance.HasFontSize, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontSizeOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
|
||||
<muxc:NumberBox x:Uid="Profile_FontSizeBox"
|
||||
<muxc:NumberBox x:Name="_fontSizeBox"
|
||||
x:Uid="Profile_FontSizeBox"
|
||||
AcceptsExpression="False"
|
||||
LargeChange="10"
|
||||
Maximum="128"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Globalization.h>
|
||||
#include <winrt/Windows.Globalization.NumberFormatting.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.UI.h>
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define ADJUST_FONT_SIZE_ARGS(X) \
|
||||
X(int32_t, Delta, "delta", false, 0)
|
||||
X(float, Delta, "delta", false, 0)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SEND_INPUT_ARGS(X) \
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
[default_interface] runtimeclass AdjustFontSizeArgs : IActionArgs
|
||||
{
|
||||
Int32 Delta { get; };
|
||||
Single Delta { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SendInputArgs : IActionArgs
|
||||
|
||||
@@ -1110,8 +1110,9 @@ void CascadiaSettings::WriteSettingsToDisk()
|
||||
|
||||
// write current settings to current settings file
|
||||
Json::StreamWriterBuilder wbuilder;
|
||||
wbuilder.settings_["indentation"] = " ";
|
||||
wbuilder.settings_["enableYAMLCompatibility"] = true; // suppress spaces around colons
|
||||
wbuilder.settings_["indentation"] = " ";
|
||||
wbuilder.settings_["precision"] = 6; // prevent values like 1.1000000000000001
|
||||
|
||||
FILETIME lastWriteTime{};
|
||||
const auto styledString{ Json::writeString(wbuilder, ToJson()) };
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
Microsoft.Terminal.Settings.Model.Profile SourceProfile { get; };
|
||||
|
||||
INHERITABLE_FONT_SETTING(String, FontFace);
|
||||
INHERITABLE_FONT_SETTING(Int32, FontSize);
|
||||
INHERITABLE_FONT_SETTING(Single, FontSize);
|
||||
INHERITABLE_FONT_SETTING(Windows.UI.Text.FontWeight, FontWeight);
|
||||
|
||||
INHERITABLE_FONT_SETTING(Windows.Foundation.Collections.IMap<String COMMA UInt32>, FontFeatures);
|
||||
|
||||
@@ -96,7 +96,7 @@ Author(s):
|
||||
|
||||
#define MTSM_FONT_SETTINGS(X) \
|
||||
X(hstring, FontFace, "face", DEFAULT_FONT_FACE) \
|
||||
X(int32_t, FontSize, "size", DEFAULT_FONT_SIZE) \
|
||||
X(float, FontSize, "size", DEFAULT_FONT_SIZE) \
|
||||
X(winrt::Windows::UI::Text::FontWeight, FontWeight, "weight", DEFAULT_FONT_WEIGHT) \
|
||||
X(IFontAxesMap, FontAxes, "axes") \
|
||||
X(IFontFeatureMap, FontFeatures, "features")
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, hstring, Padding, DEFAULT_PADDING);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, hstring, FontFace, DEFAULT_FONT_FACE);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, int32_t, FontSize, DEFAULT_FONT_SIZE);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, float, FontSize, DEFAULT_FONT_SIZE);
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, winrt::Windows::UI::Text::FontWeight, FontWeight);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, IFontAxesMap, FontAxes);
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
X(bool, UseAcrylic, false) \
|
||||
X(winrt::hstring, Padding, DEFAULT_PADDING) \
|
||||
X(winrt::hstring, FontFace, L"Consolas") \
|
||||
X(int32_t, FontSize, DEFAULT_FONT_SIZE) \
|
||||
X(float, FontSize, DEFAULT_FONT_SIZE) \
|
||||
X(winrt::Windows::UI::Text::FontWeight, FontWeight) \
|
||||
X(IFontFeatureMap, FontFeatures) \
|
||||
X(IFontAxesMap, FontAxes) \
|
||||
|
||||
@@ -41,4 +41,6 @@ CONPTY_EXPORT HRESULT WINAPI ConptyReparentPseudoConsole(HPCON hPC, HWND newPare
|
||||
|
||||
CONPTY_EXPORT VOID WINAPI ConptyClosePseudoConsole(HPCON hPC);
|
||||
|
||||
CONPTY_EXPORT VOID WINAPI ConptyClosePseudoConsoleNoWait(HPCON hPC);
|
||||
|
||||
CONPTY_EXPORT HRESULT WINAPI ConptyPackPseudoConsole(HANDLE hServerProcess, HANDLE hRef, HANDLE hSignal, HPCON* phPC);
|
||||
|
||||
@@ -39,14 +39,31 @@ void ServiceLocator::SetOneCoreTeardownFunction(void (*pfn)()) noexcept
|
||||
s_oneCoreTeardownFunction = pfn;
|
||||
}
|
||||
|
||||
[[noreturn]] void ServiceLocator::RundownAndExit(const HRESULT hr)
|
||||
void ServiceLocator::RundownAndExit(const HRESULT hr)
|
||||
{
|
||||
static thread_local bool preventRecursion = false;
|
||||
static std::atomic<bool> locked;
|
||||
|
||||
// BODGY:
|
||||
// pRender->TriggerTeardown() might cause another VtEngine pass, which then might fail to write to the IO pipe.
|
||||
// If that happens it calls VtIo::CloseOutput(), which in turn calls ServiceLocator::RundownAndExit().
|
||||
// This prevents the unintended recursion and resulting deadlock.
|
||||
if (std::exchange(preventRecursion, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// MSFT:40146639
|
||||
// The premise of this function is that 1 thread enters and 0 threads leave alive.
|
||||
// We need to prevent anyone from calling us until we actually ExitProcess(),
|
||||
// so that we don't TriggerTeardown() twice. LockConsole() can't be used here,
|
||||
// because doing so would prevent the render thread from progressing.
|
||||
AcquireSRWLockExclusive(&s_shutdownLock);
|
||||
if (locked.exchange(true, std::memory_order_relaxed))
|
||||
{
|
||||
// If we reach this point, another thread is already in the process of exiting.
|
||||
// There's a lot of ways to suspend ourselves until we exit, one of which is "sleep forever".
|
||||
Sleep(INFINITE);
|
||||
}
|
||||
|
||||
// MSFT:15506250
|
||||
// In VT I/O Mode, a client application might die before we've rendered
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Microsoft::Console::Interactivity
|
||||
public:
|
||||
static void SetOneCoreTeardownFunction(void (*pfn)()) noexcept;
|
||||
|
||||
[[noreturn]] static void RundownAndExit(const HRESULT hr);
|
||||
static void RundownAndExit(const HRESULT hr);
|
||||
|
||||
// N.B.: Location methods without corresponding creation methods
|
||||
// automatically create the singleton object on demand.
|
||||
@@ -86,7 +86,6 @@ namespace Microsoft::Console::Interactivity
|
||||
|
||||
static HWND LocatePseudoWindow(const HWND owner = nullptr /*HWND_DESKTOP = 0*/);
|
||||
|
||||
protected:
|
||||
ServiceLocator(const ServiceLocator&) = delete;
|
||||
ServiceLocator& operator=(const ServiceLocator&) = delete;
|
||||
|
||||
@@ -112,7 +111,5 @@ namespace Microsoft::Console::Interactivity
|
||||
static Globals s_globals;
|
||||
static bool s_pseudoWindowInitialized;
|
||||
static wil::unique_hwnd s_pseudoWindow;
|
||||
|
||||
static inline SRWLOCK s_shutdownLock = SRWLOCK_INIT;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -561,6 +561,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
|
||||
{
|
||||
const auto requestedFamily = fontInfoDesired.GetFamily();
|
||||
auto requestedWeight = fontInfoDesired.GetWeight();
|
||||
auto fontSize = fontInfoDesired.GetFontSize();
|
||||
auto requestedSize = fontInfoDesired.GetEngineSize();
|
||||
|
||||
if (!requestedFaceName)
|
||||
@@ -573,6 +574,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
|
||||
}
|
||||
if (!requestedSize.Y)
|
||||
{
|
||||
fontSize = 12.0f;
|
||||
requestedSize = { 0, 12 };
|
||||
}
|
||||
if (!requestedWeight)
|
||||
@@ -614,13 +616,12 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
|
||||
// Point sizes are commonly treated at a 72 DPI scale
|
||||
// (including by OpenType), whereas DirectWrite uses 96 DPI.
|
||||
// Since we want the height in px we multiply by the display's DPI.
|
||||
const auto fontSizeInDIP = requestedSize.Y / 72.0f * 96.0f;
|
||||
const auto fontSizeInPx = requestedSize.Y / 72.0f * _api.dpi;
|
||||
const auto fontSizeInDIP = fontSize / 72.0f * 96.0f;
|
||||
const auto fontSizeInPx = fontSize / 72.0f * _api.dpi;
|
||||
|
||||
const auto designUnitsPerPx = fontSizeInPx / static_cast<float>(metrics.designUnitsPerEm);
|
||||
const auto ascent = static_cast<float>(metrics.ascent) * designUnitsPerPx;
|
||||
const auto descent = static_cast<float>(metrics.descent) * designUnitsPerPx;
|
||||
const auto lineGap = static_cast<float>(metrics.lineGap) * designUnitsPerPx;
|
||||
const auto underlinePosition = static_cast<float>(-metrics.underlinePosition) * designUnitsPerPx;
|
||||
const auto underlineThickness = static_cast<float>(metrics.underlineThickness) * designUnitsPerPx;
|
||||
const auto strikethroughPosition = static_cast<float>(-metrics.strikethroughPosition) * designUnitsPerPx;
|
||||
@@ -628,9 +629,13 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
|
||||
|
||||
const auto advanceWidth = static_cast<float>(glyphMetrics.advanceWidth) * designUnitsPerPx;
|
||||
|
||||
const auto halfGap = lineGap / 2.0f;
|
||||
const auto baseline = std::roundf(ascent + halfGap);
|
||||
const auto lineHeight = std::roundf(baseline + descent + halfGap);
|
||||
// NOTE: Line-gaps shouldn't be taken into account for lineHeight calculations.
|
||||
// Terminals don't really have "gaps" between lines and instead the expectation
|
||||
// is that two full block characters above each other don't leave any gaps
|
||||
// between the lines. "Terminus TTF" for instance sets a line-gap of 90 units
|
||||
// even though its font bitmap only covers the ascend/descend height.
|
||||
const auto baseline = std::roundf(ascent);
|
||||
const auto lineHeight = std::roundf(baseline + descent);
|
||||
const auto underlinePos = std::roundf(baseline + underlinePosition);
|
||||
const auto underlineWidth = std::max(1.0f, std::roundf(underlineThickness));
|
||||
const auto strikethroughPos = std::roundf(baseline + strikethroughPosition);
|
||||
@@ -659,7 +664,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
|
||||
// Our cells can't overlap each other so we additionally clamp the bottom line to be inside the cell boundaries.
|
||||
doubleUnderlinePosBottom = std::min(doubleUnderlinePosBottom, lineHeight - thinLineWidth);
|
||||
|
||||
const auto cellWidth = gsl::narrow<u16>(std::roundf(advanceWidth));
|
||||
const auto cellWidth = gsl::narrow<u16>(std::lroundf(advanceWidth));
|
||||
const auto cellHeight = gsl::narrow<u16>(lineHeight);
|
||||
|
||||
{
|
||||
@@ -672,8 +677,7 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
|
||||
// The coordSizeUnscaled parameter to SetFromEngine is used for API functions like GetConsoleFontSize.
|
||||
// Since clients expect that settings the font height to Y yields back a font height of Y,
|
||||
// we're scaling the X relative/proportional to the actual cellWidth/cellHeight ratio.
|
||||
// The code below uses a poor form of integer rounding.
|
||||
requestedSize.X = (requestedSize.Y * cellWidth + cellHeight / 2) / cellHeight;
|
||||
requestedSize.X = gsl::narrow_cast<til::CoordType>(std::lroundf(fontSize / cellHeight * cellWidth));
|
||||
}
|
||||
|
||||
fontInfo.SetFromEngine(requestedFaceName, requestedFamily, requestedWeight, false, coordSize, requestedSize);
|
||||
|
||||
@@ -249,6 +249,13 @@ try
|
||||
_r.dirtyRect = _api.dirtyRect;
|
||||
_r.scrollOffset = _api.scrollOffset;
|
||||
|
||||
// Clear the previous cursor. PaintCursor() is only called if the cursor is on.
|
||||
if (const auto r = _api.invalidatedCursorArea; r.non_empty())
|
||||
{
|
||||
_setCellFlags(r, CellFlags::Cursor, CellFlags::None);
|
||||
_r.dirtyRect |= til::rect{ r.left, r.top, r.right, r.bottom };
|
||||
}
|
||||
|
||||
// This is an important block of code for our TileHashMap.
|
||||
// We only process glyphs within the dirtyRect, but glyphs outside of the
|
||||
// dirtyRect are still in use and shouldn't be discarded. This is critical
|
||||
@@ -437,13 +444,6 @@ try
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the previous cursor
|
||||
if (const auto r = _api.invalidatedCursorArea; r.non_empty())
|
||||
{
|
||||
_setCellFlags(r, CellFlags::Cursor, CellFlags::None);
|
||||
_r.dirtyRect |= til::rect{ r.left, r.top, r.right, r.bottom };
|
||||
}
|
||||
|
||||
if (options.isOn)
|
||||
{
|
||||
const auto point = options.coordCursor;
|
||||
@@ -639,8 +639,6 @@ void AtlasEngine::_createResources()
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
const auto featureLevel = _r.device->GetFeatureLevel();
|
||||
|
||||
{
|
||||
wil::com_ptr<IDXGIAdapter1> dxgiAdapter;
|
||||
THROW_IF_FAILED(_r.device.query<IDXGIObject>()->GetParent(__uuidof(dxgiAdapter), dxgiAdapter.put_void()));
|
||||
@@ -648,7 +646,23 @@ void AtlasEngine::_createResources()
|
||||
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
THROW_IF_FAILED(dxgiAdapter->GetDesc1(&desc));
|
||||
_r.d2dMode = debugForceD2DMode || featureLevel < D3D_FEATURE_LEVEL_10_0 || WI_IsAnyFlagSet(desc.Flags, DXGI_ADAPTER_FLAG_REMOTE | DXGI_ADAPTER_FLAG_SOFTWARE);
|
||||
_r.d2dMode = debugForceD2DMode || WI_IsAnyFlagSet(desc.Flags, DXGI_ADAPTER_FLAG_REMOTE | DXGI_ADAPTER_FLAG_SOFTWARE);
|
||||
}
|
||||
|
||||
const auto featureLevel = _r.device->GetFeatureLevel();
|
||||
|
||||
if (featureLevel < D3D_FEATURE_LEVEL_10_0)
|
||||
{
|
||||
_r.d2dMode = true;
|
||||
}
|
||||
else if (featureLevel < D3D_FEATURE_LEVEL_11_0)
|
||||
{
|
||||
D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS options;
|
||||
THROW_IF_FAILED(_r.device->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &options, sizeof(options)));
|
||||
if (!options.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x)
|
||||
{
|
||||
_r.d2dMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_r.d2dMode)
|
||||
@@ -681,11 +695,18 @@ void AtlasEngine::_createResources()
|
||||
break;
|
||||
}
|
||||
|
||||
static constexpr auto flags = D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR | D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS
|
||||
static constexpr auto flags =
|
||||
D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR
|
||||
#ifdef NDEBUG
|
||||
| D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||
| D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||
#else
|
||||
| D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
// Only enable strictness and warnings in DEBUG mode
|
||||
// as these settings makes it very difficult to develop
|
||||
// shaders as windows terminal is not telling the user
|
||||
// what's wrong, windows terminal just fails.
|
||||
// Keep it in DEBUG mode to catch errors in shaders
|
||||
// shipped with windows terminal
|
||||
| D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS | D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
#endif
|
||||
|
||||
wil::com_ptr<ID3DBlob> error;
|
||||
@@ -935,6 +956,21 @@ void AtlasEngine::_recreateSizeDependentResources()
|
||||
_api.glyphProps = Buffer<DWRITE_SHAPING_GLYPH_PROPERTIES>{ projectedGlyphSize };
|
||||
_api.glyphAdvances = Buffer<f32>{ projectedGlyphSize };
|
||||
_api.glyphOffsets = Buffer<DWRITE_GLYPH_OFFSET>{ projectedGlyphSize };
|
||||
|
||||
// Initialize cellGlyphMapping with valid data (whitespace), so that it can be
|
||||
// safely used by the TileHashMap refresh logic via makeNewest() in StartPaint().
|
||||
{
|
||||
u16x2* coords{};
|
||||
AtlasKey key{ { .cellCount = 1 }, 1, L" " };
|
||||
AtlasValue value{ CellFlags::None, 1, &coords };
|
||||
|
||||
coords[0] = _r.tileAllocator.allocate(_r.glyphs);
|
||||
|
||||
const auto it = _r.glyphs.insert(std::move(key), std::move(value));
|
||||
_r.glyphQueue.emplace_back(it);
|
||||
|
||||
std::fill(_r.cellGlyphMapping.begin(), _r.cellGlyphMapping.end(), it);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_r.d2dMode)
|
||||
@@ -1066,7 +1102,6 @@ void AtlasEngine::_recreateFontDependentResources()
|
||||
auto& textFormat = _r.textFormats[italic][bold];
|
||||
|
||||
THROW_IF_FAILED(_sr.dwriteFactory->CreateTextFormat(_api.fontMetrics.fontName.c_str(), _api.fontMetrics.fontCollection.get(), fontWeight, fontStyle, DWRITE_FONT_STRETCH_NORMAL, _api.fontMetrics.fontSizeInDIP, L"", textFormat.put()));
|
||||
THROW_IF_FAILED(textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
|
||||
THROW_IF_FAILED(textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP));
|
||||
|
||||
// DWRITE_LINE_SPACING_METHOD_UNIFORM:
|
||||
@@ -1075,11 +1110,16 @@ void AtlasEngine::_recreateFontDependentResources()
|
||||
// We want that. Otherwise fallback fonts might be rendered with an incorrect baseline and get cut off vertically.
|
||||
THROW_IF_FAILED(textFormat->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, _r.cellSizeDIP.y, _api.fontMetrics.baselineInDIP));
|
||||
|
||||
if (const auto textFormat3 = textFormat.try_query<IDWriteTextFormat3>())
|
||||
{
|
||||
THROW_IF_FAILED(textFormat3->SetAutomaticFontAxes(DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE));
|
||||
// NOTE: SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER) breaks certain
|
||||
// bitmap fonts which expect glyphs to be laid out left-aligned.
|
||||
|
||||
if (!_api.fontAxisValues.empty())
|
||||
// NOTE: SetAutomaticFontAxes(DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE) breaks certain
|
||||
// fonts making them look fairly unslightly. With no option to easily disable this
|
||||
// feature in Windows Terminal, it's better left disabled by default.
|
||||
|
||||
if (!_api.fontAxisValues.empty())
|
||||
{
|
||||
if (const auto textFormat3 = textFormat.try_query<IDWriteTextFormat3>())
|
||||
{
|
||||
// The wght axis defaults to the font weight.
|
||||
_api.fontAxisValues[0].value = bold || standardAxes[0].value == -1.0f ? static_cast<float>(fontWeight) : standardAxes[0].value;
|
||||
@@ -1176,6 +1216,15 @@ void AtlasEngine::_flushBufferLine()
|
||||
// This would seriously blow us up otherwise.
|
||||
Expects(_api.bufferLineColumn.size() == _api.bufferLine.size() + 1);
|
||||
|
||||
// GH#13962: With the lack of proper LineRendition support, just fill
|
||||
// the remaining columns with whitespace to prevent any weird artifacts.
|
||||
for (auto lastColumn = _api.bufferLineColumn.back(); lastColumn < _api.cellCount.x;)
|
||||
{
|
||||
++lastColumn;
|
||||
_api.bufferLine.emplace_back(L' ');
|
||||
_api.bufferLineColumn.emplace_back(lastColumn);
|
||||
}
|
||||
|
||||
// NOTE:
|
||||
// This entire function is one huge hack to see if it works.
|
||||
|
||||
|
||||
@@ -523,9 +523,9 @@ namespace Microsoft::Console::Render
|
||||
struct CachedGlyphLayout
|
||||
{
|
||||
wil::com_ptr<IDWriteTextLayout> textLayout;
|
||||
f32x2 halfSize;
|
||||
f32x2 offset;
|
||||
f32x2 scale;
|
||||
f32x2 scaleCenter;
|
||||
D2D1_DRAW_TEXT_OPTIONS options = D2D1_DRAW_TEXT_OPTIONS_NONE;
|
||||
bool scalingRequired = false;
|
||||
|
||||
|
||||
@@ -472,10 +472,10 @@ void AtlasEngine::_drawGlyph(const TileHashMap::iterator& it) const
|
||||
AtlasEngine::CachedGlyphLayout AtlasEngine::_getCachedGlyphLayout(const wchar_t* chars, u16 charsLength, u16 cellCount, IDWriteTextFormat* textFormat, bool coloredGlyph) const
|
||||
{
|
||||
const f32x2 layoutBox{ cellCount * _r.cellSizeDIP.x, _r.cellSizeDIP.y };
|
||||
const f32x2 halfSize{ layoutBox.x * 0.5f, layoutBox.y * 0.5f };
|
||||
bool scalingRequired = false;
|
||||
f32x2 offset{ 0, 0 };
|
||||
f32x2 scale{ 1, 1 };
|
||||
f32x2 scaleCenter;
|
||||
|
||||
// See D2DFactory::DrawText
|
||||
wil::com_ptr<IDWriteTextLayout> textLayout;
|
||||
@@ -550,12 +550,18 @@ AtlasEngine::CachedGlyphLayout AtlasEngine::_getCachedGlyphLayout(const wchar_t*
|
||||
static_cast<f32>(glyphMetrics.advanceHeight) / static_cast<f32>(metrics.designUnitsPerEm) * _r.fontMetrics.fontSizeInDIP,
|
||||
};
|
||||
|
||||
// We always want box drawing glyphs to exactly match the size of a terminal cell.
|
||||
// So for safe measure we'll always scale them to the exact size.
|
||||
// But add 1px to the destination size, so that we don't end up with fractional pixels.
|
||||
scalingRequired = true;
|
||||
scale.x = layoutBox.x / boxSize.x;
|
||||
scale.y = layoutBox.y / boxSize.y;
|
||||
// We always want box drawing glyphs to be centered in their cell.
|
||||
offset.x = (layoutBox.x - boxSize.x) * 0.5f;
|
||||
offset.y = (layoutBox.y - boxSize.y) * 0.5f;
|
||||
// We always want box drawing glyphs to exactly match the size of a terminal cell.
|
||||
// But add 1px to the destination size, so that we don't end up with fractional pixels.
|
||||
scale.x = (layoutBox.x + _r.dipPerPixel) / boxSize.x;
|
||||
scale.y = (layoutBox.y + _r.dipPerPixel) / boxSize.y;
|
||||
// Now that the glyph is in the center of the cell thanks
|
||||
// to the offset, the scaleCenter is center of the cell.
|
||||
scaleCenter.x = layoutBox.x * 0.5f;
|
||||
scaleCenter.y = layoutBox.y * 0.5f;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -563,16 +569,7 @@ AtlasEngine::CachedGlyphLayout AtlasEngine::_getCachedGlyphLayout(const wchar_t*
|
||||
DWRITE_OVERHANG_METRICS overhang;
|
||||
THROW_IF_FAILED(textLayout->GetOverhangMetrics(&overhang));
|
||||
|
||||
const DWRITE_OVERHANG_METRICS clampedOverhang{
|
||||
std::max(0.0f, overhang.left),
|
||||
std::max(0.0f, overhang.top),
|
||||
std::max(0.0f, overhang.right),
|
||||
std::max(0.0f, overhang.bottom),
|
||||
};
|
||||
f32x2 actualSize{
|
||||
layoutBox.x + overhang.left + overhang.right,
|
||||
layoutBox.y + overhang.top + overhang.bottom,
|
||||
};
|
||||
auto actualSizeX = layoutBox.x + overhang.left + overhang.right;
|
||||
|
||||
// Long glyphs should be drawn with their proper design size, even if that makes them a bit blurry,
|
||||
// because otherwise we fail to support "pseudo" block characters like the "===" ligature in Cascadia Code.
|
||||
@@ -585,8 +582,7 @@ AtlasEngine::CachedGlyphLayout AtlasEngine::_getCachedGlyphLayout(const wchar_t*
|
||||
const auto advanceScale = _r.fontMetrics.advanceScale;
|
||||
scalingRequired = true;
|
||||
scale = { advanceScale, advanceScale };
|
||||
actualSize.x *= advanceScale;
|
||||
actualSize.y *= advanceScale;
|
||||
actualSizeX *= advanceScale;
|
||||
}
|
||||
|
||||
// We need to offset glyphs that are simply outside of our layout box (layoutBox.x/.y)
|
||||
@@ -627,34 +623,27 @@ AtlasEngine::CachedGlyphLayout AtlasEngine::_getCachedGlyphLayout(const wchar_t*
|
||||
// --> offsetY = 0
|
||||
// --> scale = layoutBox.y / (layoutBox.y + left + right)
|
||||
// = 0.69f
|
||||
offset.x = clampedOverhang.left - clampedOverhang.right;
|
||||
offset.y = clampedOverhang.top - clampedOverhang.bottom;
|
||||
offset.x = std::max(0.0f, overhang.left) - std::max(0.0f, overhang.right);
|
||||
scaleCenter.x = offset.x;
|
||||
scaleCenter.y = _r.fontMetrics.baselineInDIP;
|
||||
|
||||
if ((actualSize.x - layoutBox.x) > _r.dipPerPixel)
|
||||
if ((actualSizeX - layoutBox.x) > _r.dipPerPixel)
|
||||
{
|
||||
scalingRequired = true;
|
||||
offset.x = (overhang.left - overhang.right) * 0.5f;
|
||||
scale.x = layoutBox.x / actualSize.x;
|
||||
scale.x = layoutBox.x / actualSizeX;
|
||||
scale.y = scale.x;
|
||||
scaleCenter.x = layoutBox.x * 0.5f;
|
||||
}
|
||||
if ((actualSize.y - layoutBox.y) > _r.dipPerPixel)
|
||||
if (overhang.top > _r.dipPerPixel || overhang.bottom > _r.dipPerPixel)
|
||||
{
|
||||
const auto descend = _r.cellSizeDIP.y - _r.fontMetrics.baselineInDIP;
|
||||
const auto scaleTop = _r.fontMetrics.baselineInDIP / (_r.fontMetrics.baselineInDIP + overhang.top);
|
||||
const auto scaleBottom = descend / (descend + overhang.bottom);
|
||||
scalingRequired = true;
|
||||
offset.y = (overhang.top - overhang.bottom) * 0.5f;
|
||||
scale.x = std::min(scale.x, layoutBox.y / actualSize.y);
|
||||
scale.x = std::min(scale.x, std::min(scaleTop, scaleBottom));
|
||||
scale.y = scale.x;
|
||||
}
|
||||
|
||||
// As explained below, we use D2D1_DRAW_TEXT_OPTIONS_NO_SNAP to prevent a weird issue with baseline snapping.
|
||||
// But we do want it technically, so this re-implements baseline snapping... I think?
|
||||
// It calculates the new `baseline` height after transformation by `scale.y` relative to the center point `halfSize.y`.
|
||||
//
|
||||
// This works even if `scale.y == 1`, because then `baseline == baselineInDIP + offset.y` and `baselineInDIP`
|
||||
// is always measured in full pixels. So rounding it will be equivalent to just rounding `offset.y` itself.
|
||||
const auto baseline = halfSize.y + (_r.fontMetrics.baselineInDIP + offset.y - halfSize.y) * scale.y;
|
||||
// This rounds to the nearest multiple of _r.dipPerPixel.
|
||||
const auto baselineFixed = roundf(baseline * _r.pixelPerDIP) * _r.dipPerPixel;
|
||||
offset.y += (baselineFixed - baseline) / scale.y;
|
||||
}
|
||||
|
||||
auto options = D2D1_DRAW_TEXT_OPTIONS_NONE;
|
||||
@@ -672,11 +661,19 @@ AtlasEngine::CachedGlyphLayout AtlasEngine::_getCachedGlyphLayout(const wchar_t*
|
||||
// where every single "=" might be blatantly misaligned vertically (same for any box drawings).
|
||||
WI_SetFlagIf(options, D2D1_DRAW_TEXT_OPTIONS_NO_SNAP, scalingRequired);
|
||||
|
||||
// ClearType basically has a 3x higher horizontal resolution. To make our glyphs render the same everywhere,
|
||||
// it's probably for the best to ensure we initially rasterize them on a whole pixel boundary.
|
||||
// (https://en.wikipedia.org/wiki/ClearType#How_ClearType_works)
|
||||
offset.x = roundf(offset.x * _r.pixelPerDIP) * _r.dipPerPixel;
|
||||
// As explained below, we use D2D1_DRAW_TEXT_OPTIONS_NO_SNAP to prevent a weird issue with baseline snapping.
|
||||
// But we do want it technically, so this re-implements baseline snapping... I think?
|
||||
offset.y = roundf(offset.y * _r.pixelPerDIP) * _r.dipPerPixel;
|
||||
|
||||
return CachedGlyphLayout{
|
||||
.textLayout = textLayout,
|
||||
.halfSize = halfSize,
|
||||
.offset = offset,
|
||||
.scale = scale,
|
||||
.scaleCenter = scaleCenter,
|
||||
.options = options,
|
||||
.scalingRequired = scalingRequired,
|
||||
};
|
||||
@@ -790,8 +787,8 @@ void AtlasEngine::CachedGlyphLayout::applyScaling(ID2D1RenderTarget* d2dRenderTa
|
||||
0,
|
||||
0,
|
||||
scale.y,
|
||||
(origin.x + halfSize.x) * (1.0f - scale.x),
|
||||
(origin.y + halfSize.y) * (1.0f - scale.y),
|
||||
(origin.x + scaleCenter.x) * (1.0f - scale.x),
|
||||
(origin.y + scaleCenter.y) * (1.0f - scale.y),
|
||||
};
|
||||
d2dRenderTarget->SetTransform(&transform);
|
||||
}
|
||||
|
||||
@@ -8,23 +8,24 @@
|
||||
FontInfoDesired::FontInfoDesired(const std::wstring_view& faceName,
|
||||
const unsigned char family,
|
||||
const unsigned int weight,
|
||||
const til::size coordSizeDesired,
|
||||
const float fontSize,
|
||||
const unsigned int codePage) noexcept :
|
||||
FontInfoBase(faceName, family, weight, false, codePage),
|
||||
_coordSizeDesired(coordSizeDesired)
|
||||
_coordSizeDesired{ 0, lroundf(fontSize) },
|
||||
_fontSize{ fontSize }
|
||||
{
|
||||
}
|
||||
|
||||
FontInfoDesired::FontInfoDesired(const FontInfo& fiFont) noexcept :
|
||||
FontInfoBase(fiFont),
|
||||
_coordSizeDesired(fiFont.GetUnscaledSize())
|
||||
_coordSizeDesired{ fiFont.GetUnscaledSize() },
|
||||
_fontSize{ static_cast<float>(_coordSizeDesired.height) }
|
||||
{
|
||||
}
|
||||
|
||||
bool FontInfoDesired::operator==(const FontInfoDesired& other) noexcept
|
||||
float FontInfoDesired::GetFontSize() const noexcept
|
||||
{
|
||||
return FontInfoBase::operator==(other) &&
|
||||
_coordSizeDesired == other._coordSizeDesired;
|
||||
return _fontSize;
|
||||
}
|
||||
|
||||
til::size FontInfoDesired::GetEngineSize() const noexcept
|
||||
|
||||
@@ -75,29 +75,30 @@ Renderer::~Renderer()
|
||||
}
|
||||
|
||||
const auto hr = _PaintFrameForEngine(pEngine);
|
||||
if (E_PENDING == hr)
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (--tries == 0)
|
||||
{
|
||||
// Stop trying.
|
||||
_pThread->DisablePainting();
|
||||
if (_pfnRendererEnteredErrorState)
|
||||
{
|
||||
_pfnRendererEnteredErrorState();
|
||||
}
|
||||
// If there's no callback, we still don't want to FAIL_FAST: the renderer going black
|
||||
// isn't near as bad as the entire application aborting. We're a component. We shouldn't
|
||||
// abort applications that host us.
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// Add a bit of backoff.
|
||||
// Sleep 150ms, 300ms, 450ms before failing out and disabling the renderer.
|
||||
Sleep(renderBackoffBaseTimeMilliseconds * (maxRetriesForRenderEngine - tries));
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
LOG_IF_FAILED(hr);
|
||||
break;
|
||||
|
||||
LOG_HR_IF(hr, hr != E_PENDING);
|
||||
|
||||
if (--tries == 0)
|
||||
{
|
||||
// Stop trying.
|
||||
_pThread->DisablePainting();
|
||||
if (_pfnRendererEnteredErrorState)
|
||||
{
|
||||
_pfnRendererEnteredErrorState();
|
||||
}
|
||||
// If there's no callback, we still don't want to FAIL_FAST: the renderer going black
|
||||
// isn't near as bad as the entire application aborting. We're a component. We shouldn't
|
||||
// abort applications that host us.
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// Add a bit of backoff.
|
||||
// Sleep 150ms, 300ms, 450ms before failing out and disabling the renderer.
|
||||
Sleep(renderBackoffBaseTimeMilliseconds * (maxRetriesForRenderEngine - tries));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,15 +27,17 @@ public:
|
||||
FontInfoDesired(const std::wstring_view& faceName,
|
||||
const unsigned char family,
|
||||
const unsigned int weight,
|
||||
const til::size coordSizeDesired,
|
||||
const float fontSize,
|
||||
const unsigned int uiCodePage) noexcept;
|
||||
FontInfoDesired(const FontInfo& fiFont) noexcept;
|
||||
|
||||
bool operator==(const FontInfoDesired& other) noexcept;
|
||||
bool operator==(const FontInfoDesired& other) = delete;
|
||||
|
||||
float GetFontSize() const noexcept;
|
||||
til::size GetEngineSize() const noexcept;
|
||||
bool IsDefaultRasterFont() const noexcept;
|
||||
|
||||
private:
|
||||
til::size _coordSizeDesired;
|
||||
float _fontSize;
|
||||
};
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace
|
||||
}
|
||||
|
||||
// Generated by Generate-CodepointWidthsFromUCD.ps1 -Pack:True -Full:False -NoOverrides:False
|
||||
// on 6/13/2022 8:57:08 PM (UTC) from Unicode 14.0.0.
|
||||
// 321259 (0x4E6EB) codepoints covered.
|
||||
// on 9/14/2022 7:12:26 PM (UTC) from Unicode 15.0.0.
|
||||
// 321281 (0x4E701) codepoints covered.
|
||||
// 240 (0xF0) codepoints overridden.
|
||||
// Override path: .\src\types\unicode_width_overrides.xml
|
||||
static constexpr std::array<UnicodeRange, 300> s_wideAndAmbiguousTable{
|
||||
@@ -263,7 +263,9 @@ namespace
|
||||
UnicodeRange{ 0x1aff5, 0x1affb, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1affd, 0x1affe, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1b000, 0x1b122, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1b132, 0x1b132, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1b150, 0x1b152, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1b155, 0x1b155, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1b164, 0x1b167, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1b170, 0x1b2fb, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f004, 0x1f004, CodepointWidth::Wide },
|
||||
@@ -303,7 +305,7 @@ namespace
|
||||
UnicodeRange{ 0x1f6cc, 0x1f6cc, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f6d0, 0x1f6d2, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f6d5, 0x1f6d7, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f6dd, 0x1f6df, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f6dc, 0x1f6df, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f6eb, 0x1f6ec, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f6f4, 0x1f6fc, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f7e0, 0x1f7eb, CodepointWidth::Wide },
|
||||
@@ -311,15 +313,13 @@ namespace
|
||||
UnicodeRange{ 0x1f90c, 0x1f93a, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f93c, 0x1f945, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1f947, 0x1f9ff, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fa70, 0x1fa74, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fa78, 0x1fa7c, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fa80, 0x1fa86, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fa90, 0x1faac, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fab0, 0x1faba, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fac0, 0x1fac5, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fad0, 0x1fad9, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fae0, 0x1fae7, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1faf0, 0x1faf6, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fa70, 0x1fa7c, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fa80, 0x1fa88, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fa90, 0x1fabd, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fabf, 0x1fac5, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1face, 0x1fadb, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1fae0, 0x1fae8, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x1faf0, 0x1faf8, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x20000, 0x2fffd, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0x30000, 0x3fffd, CodepointWidth::Wide },
|
||||
UnicodeRange{ 0xe0100, 0xe01ef, CodepointWidth::Ambiguous },
|
||||
|
||||
@@ -4,6 +4,7 @@ EXPORTS
|
||||
ConptyCreatePseudoConsoleAsUser
|
||||
ConptyResizePseudoConsole
|
||||
ConptyClosePseudoConsole
|
||||
ConptyClosePseudoConsoleNoWait
|
||||
ConptyClearPseudoConsole
|
||||
ConptyShowHidePseudoConsole
|
||||
ConptyReparentPseudoConsole
|
||||
|
||||
@@ -84,10 +84,10 @@ void ConPtyTests::CreateConPtyNoPipes()
|
||||
VERIFY_FAILED(_CreatePseudoConsole(defaultSize, nullptr, nullptr, 0, &pcon));
|
||||
|
||||
VERIFY_SUCCEEDED(_CreatePseudoConsole(defaultSize, nullptr, goodOut, 0, &pcon));
|
||||
_ClosePseudoConsoleMembers(&pcon);
|
||||
_ClosePseudoConsoleMembers(&pcon, TRUE);
|
||||
|
||||
VERIFY_SUCCEEDED(_CreatePseudoConsole(defaultSize, goodIn, nullptr, 0, &pcon));
|
||||
_ClosePseudoConsoleMembers(&pcon);
|
||||
_ClosePseudoConsoleMembers(&pcon, TRUE);
|
||||
}
|
||||
|
||||
void ConPtyTests::CreateConPtyBadSize()
|
||||
@@ -131,7 +131,7 @@ void ConPtyTests::GoodCreate()
|
||||
&pcon));
|
||||
|
||||
auto closePty = wil::scope_exit([&] {
|
||||
_ClosePseudoConsoleMembers(&pcon);
|
||||
_ClosePseudoConsoleMembers(&pcon, TRUE);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ void ConPtyTests::GoodCreateMultiple()
|
||||
0,
|
||||
&pcon1));
|
||||
auto closePty1 = wil::scope_exit([&] {
|
||||
_ClosePseudoConsoleMembers(&pcon1);
|
||||
_ClosePseudoConsoleMembers(&pcon1, TRUE);
|
||||
});
|
||||
|
||||
VERIFY_SUCCEEDED(
|
||||
@@ -170,7 +170,7 @@ void ConPtyTests::GoodCreateMultiple()
|
||||
0,
|
||||
&pcon2));
|
||||
auto closePty2 = wil::scope_exit([&] {
|
||||
_ClosePseudoConsoleMembers(&pcon2);
|
||||
_ClosePseudoConsoleMembers(&pcon2, TRUE);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ void ConPtyTests::SurvivesOnBreakInput()
|
||||
0,
|
||||
&pty));
|
||||
auto closePty1 = wil::scope_exit([&] {
|
||||
_ClosePseudoConsoleMembers(&pty);
|
||||
_ClosePseudoConsoleMembers(&pty, TRUE);
|
||||
});
|
||||
|
||||
DWORD dwExit;
|
||||
@@ -242,7 +242,7 @@ void ConPtyTests::SurvivesOnBreakOutput()
|
||||
0,
|
||||
&pty));
|
||||
auto closePty1 = wil::scope_exit([&] {
|
||||
_ClosePseudoConsoleMembers(&pty);
|
||||
_ClosePseudoConsoleMembers(&pty, TRUE);
|
||||
});
|
||||
|
||||
DWORD dwExit;
|
||||
@@ -287,7 +287,7 @@ void ConPtyTests::DiesOnBreakBoth()
|
||||
0,
|
||||
&pty));
|
||||
auto closePty1 = wil::scope_exit([&] {
|
||||
_ClosePseudoConsoleMembers(&pty);
|
||||
_ClosePseudoConsoleMembers(&pty, TRUE);
|
||||
});
|
||||
|
||||
DWORD dwExit;
|
||||
@@ -358,7 +358,7 @@ void ConPtyTests::DiesOnClose()
|
||||
0,
|
||||
&pty));
|
||||
auto closePty1 = wil::scope_exit([&] {
|
||||
_ClosePseudoConsoleMembers(&pty);
|
||||
_ClosePseudoConsoleMembers(&pty, TRUE);
|
||||
});
|
||||
|
||||
DWORD dwExit;
|
||||
@@ -382,7 +382,7 @@ void ConPtyTests::DiesOnClose()
|
||||
Log::Comment(NoThrowString().Format(L"Sleep a bit to let the process attach"));
|
||||
Sleep(100);
|
||||
|
||||
_ClosePseudoConsoleMembers(&pty);
|
||||
_ClosePseudoConsoleMembers(&pty, TRUE);
|
||||
|
||||
GetExitCodeProcess(hConPtyProcess.get(), &dwExit);
|
||||
VERIFY_ARE_NOT_EQUAL(dwExit, (DWORD)STILL_ACTIVE);
|
||||
|
||||
@@ -347,9 +347,10 @@ HRESULT _ReparentPseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const
|
||||
// HPCON via the API).
|
||||
// Arguments:
|
||||
// - pPty: A pointer to a PseudoConsole struct.
|
||||
// - wait: If true, waits for conhost/OpenConsole to exit first.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty)
|
||||
void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty, BOOL wait)
|
||||
{
|
||||
if (pPty != nullptr)
|
||||
{
|
||||
@@ -365,19 +366,11 @@ void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty)
|
||||
// has yet to send before we hard kill it.
|
||||
if (_HandleIsValid(pPty->hConPtyProcess))
|
||||
{
|
||||
// If the conhost is already dead, then that's fine. Presumably
|
||||
// it's finished flushing it's output already.
|
||||
DWORD dwExit = 0;
|
||||
// If GetExitCodeProcess failed, it's likely conhost is already dead
|
||||
// If so, skip waiting regardless of whatever error
|
||||
// GetExitCodeProcess returned.
|
||||
// We'll just go straight to killing conhost.
|
||||
if (GetExitCodeProcess(pPty->hConPtyProcess, &dwExit) && dwExit == STILL_ACTIVE)
|
||||
if (wait)
|
||||
{
|
||||
WaitForSingleObject(pPty->hConPtyProcess, INFINITE);
|
||||
}
|
||||
|
||||
TerminateProcess(pPty->hConPtyProcess, 0);
|
||||
CloseHandle(pPty->hConPtyProcess);
|
||||
pPty->hConPtyProcess = nullptr;
|
||||
}
|
||||
@@ -398,13 +391,14 @@ void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty)
|
||||
// PseudoConsoles that were created with CreatePseudoConsole.
|
||||
// Arguments:
|
||||
// - pPty: A pointer to a PseudoConsole struct.
|
||||
// - wait: If true, waits for conhost/OpenConsole to exit first.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
VOID _ClosePseudoConsole(_In_ PseudoConsole* pPty)
|
||||
static void _ClosePseudoConsole(_In_ PseudoConsole* pPty, BOOL wait) noexcept
|
||||
{
|
||||
if (pPty != nullptr)
|
||||
{
|
||||
_ClosePseudoConsoleMembers(pPty);
|
||||
_ClosePseudoConsoleMembers(pPty, wait);
|
||||
HeapFree(GetProcessHeap(), 0, pPty);
|
||||
}
|
||||
}
|
||||
@@ -465,7 +459,7 @@ extern "C" HRESULT ConptyCreatePseudoConsoleAsUser(_In_ HANDLE hToken,
|
||||
auto pPty = (PseudoConsole*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PseudoConsole));
|
||||
RETURN_IF_NULL_ALLOC(pPty);
|
||||
auto cleanupPty = wil::scope_exit([&]() noexcept {
|
||||
_ClosePseudoConsole(pPty);
|
||||
_ClosePseudoConsole(pPty, TRUE);
|
||||
});
|
||||
|
||||
wil::unique_handle duplicatedInput;
|
||||
@@ -544,13 +538,22 @@ extern "C" HRESULT WINAPI ConptyReparentPseudoConsole(_In_ HPCON hPC, HWND newPa
|
||||
// console window they were running in was closed.
|
||||
// This can fail if the conhost hosting the pseudoconsole failed to be
|
||||
// terminated, or if the pseudoconsole was already terminated.
|
||||
// Waits for conhost/OpenConsole to exit first.
|
||||
extern "C" VOID WINAPI ConptyClosePseudoConsole(_In_ HPCON hPC)
|
||||
{
|
||||
const auto pPty = (PseudoConsole*)hPC;
|
||||
if (pPty != nullptr)
|
||||
{
|
||||
_ClosePseudoConsole(pPty);
|
||||
}
|
||||
_ClosePseudoConsole((PseudoConsole*)hPC, TRUE);
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// Closes the conpty and all associated state.
|
||||
// Client applications attached to the conpty will also behave as though the
|
||||
// console window they were running in was closed.
|
||||
// This can fail if the conhost hosting the pseudoconsole failed to be
|
||||
// terminated, or if the pseudoconsole was already terminated.
|
||||
// Doesn't wait for conhost/OpenConsole to exit.
|
||||
extern "C" VOID WINAPI ConptyClosePseudoConsoleNoWait(_In_ HPCON hPC)
|
||||
{
|
||||
_ClosePseudoConsole((PseudoConsole*)hPC, FALSE);
|
||||
}
|
||||
|
||||
// NOTE: This one is not defined in the Windows headers but is
|
||||
|
||||
@@ -41,8 +41,7 @@ HRESULT _ResizePseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const CO
|
||||
HRESULT _ClearPseudoConsole(_In_ const PseudoConsole* const pPty);
|
||||
HRESULT _ShowHidePseudoConsole(_In_ const PseudoConsole* const pPty, const bool show);
|
||||
HRESULT _ReparentPseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const HWND newParent);
|
||||
void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty);
|
||||
VOID _ClosePseudoConsole(_In_ PseudoConsole* pPty);
|
||||
void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty, BOOL wait);
|
||||
|
||||
HRESULT ConptyCreatePseudoConsoleAsUser(_In_ HANDLE hToken,
|
||||
_In_ COORD size,
|
||||
|
||||
Reference in New Issue
Block a user