diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 07e584c6b..319e0bae7 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -1401,7 +1401,8 @@ "properties": { "acrylicOpacity": { "default": 0.5, - "description": "When useAcrylic is set to true, it sets the transparency of the window for the profile. Accepts floating point values from 0-1 (default 0.5).", + "description": "[deprecated] Please use `opacity` instead.", + "deprecated": true, "maximum": 1, "minimum": 0, "type": "number" @@ -1614,6 +1615,13 @@ "minLength": 1, "type": "string" }, + "opacity": { + "default": 100, + "description": "Sets the opacity of the window for the profile. Accepts values from 0-100. Defaults to 50 when useAcrylic is set to true.", + "maximum": 100, + "minimum": 0, + "type": "number" + }, "padding": { "default": "8, 8, 8, 8", "description": "Sets the padding around the text within the window. Can have three different formats:\n -\"#\" sets the same padding for all sides \n -\"#, #\" sets the same padding for left-right and top-bottom\n -\"#, #, #, #\" sets the padding individually for left, top, right, and bottom.", diff --git a/scratch/ScratchIslandApp/Package/Package.wapproj b/scratch/ScratchIslandApp/Package/Package.wapproj index 262719541..f7458a902 100644 --- a/scratch/ScratchIslandApp/Package/Package.wapproj +++ b/scratch/ScratchIslandApp/Package/Package.wapproj @@ -140,12 +140,12 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/scratch/ScratchIslandApp/SampleApp/MySettings.h b/scratch/ScratchIslandApp/SampleApp/MySettings.h index 34643f7fe..4d34b8624 100644 --- a/scratch/ScratchIslandApp/SampleApp/MySettings.h +++ b/scratch/ScratchIslandApp/SampleApp/MySettings.h @@ -45,7 +45,7 @@ namespace winrt::SampleApp::implementation WINRT_PROPERTY(winrt::hstring, ProfileName); WINRT_PROPERTY(bool, UseAcrylic, false); - WINRT_PROPERTY(double, TintOpacity, 0.5); + WINRT_PROPERTY(double, Opacity, .5); WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING); WINRT_PROPERTY(winrt::hstring, FontFace, L"Consolas"); WINRT_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE); diff --git a/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj b/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj index 54a6c5706..04b9b0824 100644 --- a/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj +++ b/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj @@ -147,13 +147,13 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj b/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj index 23b157e9d..59d500ccc 100644 --- a/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj +++ b/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj @@ -80,13 +80,13 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/scratch/ScratchIslandApp/SampleApp/packages.config b/scratch/ScratchIslandApp/SampleApp/packages.config index 9de6f1b8d..78467467c 100644 --- a/scratch/ScratchIslandApp/SampleApp/packages.config +++ b/scratch/ScratchIslandApp/SampleApp/packages.config @@ -1,6 +1,6 @@  - + diff --git a/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj b/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj index e8cb725b7..4332ae5d0 100644 --- a/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj +++ b/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj @@ -120,14 +120,14 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/scratch/ScratchIslandApp/WindowExe/packages.config b/scratch/ScratchIslandApp/WindowExe/packages.config index 3d9e08c4b..d55a833a5 100644 --- a/scratch/ScratchIslandApp/WindowExe/packages.config +++ b/scratch/ScratchIslandApp/WindowExe/packages.config @@ -2,6 +2,6 @@ - + diff --git a/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj b/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj index b18c6d57a..ba722f246 100644 --- a/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj +++ b/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj @@ -146,12 +146,12 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj b/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj index ac1af0396..576c89e7d 100644 --- a/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj +++ b/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj @@ -98,10 +98,10 @@ x86 $(Platform) - <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\" + <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\runtimes\win10-$(Native-Platform)\native\" - + diff --git a/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj b/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj index a6340764b..95d8ea17f 100644 --- a/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj +++ b/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj @@ -92,11 +92,11 @@ x86 $(Platform) - <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\" + <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\runtimes\win10-$(Native-Platform)\native\" - + diff --git a/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj b/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj index cef96d52f..722ce9f5d 100644 --- a/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj +++ b/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj @@ -123,7 +123,7 @@ - + diff --git a/src/cascadia/Remoting/Monarch.cpp b/src/cascadia/Remoting/Monarch.cpp index 9bf60fc8b..c16eb52e9 100644 --- a/src/cascadia/Remoting/Monarch.cpp +++ b/src/cascadia/Remoting/Monarch.cpp @@ -50,6 +50,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // - Add the given peasant to the list of peasants we're tracking. This // Peasant may have already been assigned an ID. If it hasn't, then give // it an ID. + // - NB: this takes a unique_lock on _peasantsMutex. // Arguments: // - peasant: the new Peasant to track. // Return Value: @@ -71,10 +72,24 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation { // Peasant already had an ID (from an older monarch). Leave that one // be. Make sure that the next peasant's ID is higher than it. - _nextPeasantID = providedID >= _nextPeasantID ? providedID + 1 : _nextPeasantID; + // If multiple peasants are added concurrently we keep trying to update + // until we get to set the new id. + uint64_t current; + do + { + current = _nextPeasantID.load(std::memory_order_relaxed); + } while (current <= providedID && !_nextPeasantID.compare_exchange_weak(current, providedID + 1, std::memory_order_relaxed)); } auto newPeasantsId = peasant.GetID(); + + // Keep track of which peasant we are + // SAFETY: this is only true for one peasant, and each peasant + // is only added to a monarch once, so we do not need synchronization here. + if (peasant.GetPID() == _ourPID) + { + _ourPeasantId = newPeasantsId; + } // Add an event listener to the peasant's WindowActivated event. peasant.WindowActivated({ this, &Monarch::_peasantWindowActivated }); peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows }); @@ -84,7 +99,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation peasant.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); }); peasant.QuitAllRequested({ this, &Monarch::_handleQuitAll }); - _peasants[newPeasantsId] = peasant; + { + std::unique_lock lock{ _peasantsMutex }; + _peasants[newPeasantsId] = peasant; + } TraceLoggingWrite(g_hRemotingProvider, "Monarch_AddPeasant", @@ -124,9 +142,15 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // closing all windows. _QuitAllRequestedHandlers(*this, nullptr); + _quitting.store(true); // Tell all peasants to exit. - const auto callback = [&](const auto& /*id*/, const auto& p) { - p.Quit(); + const auto callback = [&](const auto& id, const auto& p) { + // We want to tell our peasant to quit last, so that we don't try + // to perform a bunch of elections on quit. + if (id != _ourPeasantId) + { + p.Quit(); + } }; const auto onError = [&](const auto& id) { TraceLoggingWrite(g_hRemotingProvider, @@ -137,18 +161,46 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation }; _forEachPeasant(callback, onError); + + { + std::shared_lock lock{ _peasantsMutex }; + const auto peasantSearch = _peasants.find(_ourPeasantId); + if (peasantSearch != _peasants.end()) + { + peasantSearch->second.Quit(); + } + else + { + // Somehow we don't have our own peasant, this should never happen. + // We are trying to quit anyways so just fail here. + assert(peasantSearch != _peasants.end()); + } + } } // Method Description: // - Tells the monarch that a peasant is being closed. + // - NB: this (separately) takes unique locks on _peasantsMutex and + // _mruPeasantsMutex. // Arguments: // - peasantId: the id of the peasant // Return Value: // - void Monarch::SignalClose(const uint64_t peasantId) { - _clearOldMruEntries(peasantId); - _peasants.erase(peasantId); + // If we are quitting we don't care about maintaining our list of + // peasants anymore, and don't need to notify the host that something + // changed. + if (_quitting.load(std::memory_order_acquire)) + { + return; + } + + _clearOldMruEntries({ peasantId }); + { + std::unique_lock lock{ _peasantsMutex }; + _peasants.erase(peasantId); + } _WindowClosedHandlers(nullptr, nullptr); } @@ -160,23 +212,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // - the number of active peasants. uint64_t Monarch::GetNumberOfPeasants() { - auto num = 0; - auto callback = [&](const auto& /*id*/, const auto& p) { - // Check that the peasant is alive, and if so increment the count - p.GetID(); - num += 1; - }; - auto onError = [](const auto& id) { - TraceLoggingWrite(g_hRemotingProvider, - "Monarch_GetNumberOfPeasants_Failed", - TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not enumerate"), - TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), - TraceLoggingKeyword(TIL_KEYWORD_TRACE)); - }; - - _forEachPeasant(callback, onError); - - return num; + std::shared_lock lock{ _peasantsMutex }; + return _peasants.size(); } // Method Description: @@ -197,16 +234,25 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // Method Description: // - Lookup a peasant by its ID. If the peasant has died, this will also // remove the peasant from our list of peasants. + // - NB: this (separately) takes unique locks on _peasantsMutex and + // _mruPeasantsMutex. // Arguments: // - peasantID: The ID Of the peasant to find + // - clearMruPeasantOnFailure: When true this function will handle clearing + // from _mruPeasants if a peasant was not found, otherwise the caller is + // expected to handle that cleanup themselves. // Return Value: // - the peasant if it exists in our map, otherwise null - Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID) + Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID, bool clearMruPeasantOnFailure) { try { - const auto peasantSearch = _peasants.find(peasantID); - auto maybeThePeasant = peasantSearch == _peasants.end() ? nullptr : peasantSearch->second; + IPeasant maybeThePeasant = nullptr; + { + std::shared_lock lock{ _peasantsMutex }; + const auto peasantSearch = _peasants.find(peasantID); + maybeThePeasant = peasantSearch == _peasants.end() ? nullptr : peasantSearch->second; + } // Ask the peasant for their PID. This will validate that they're // actually still alive. if (maybeThePeasant) @@ -218,12 +264,19 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation catch (...) { LOG_CAUGHT_EXCEPTION(); - // Remove the peasant from the list of peasants - _peasants.erase(peasantID); - // Remove the peasant from the list of MRU windows. They're dead. - // They can't be the MRU anymore. - _clearOldMruEntries(peasantID); + // Remove the peasant from the list of peasants + { + std::unique_lock lock{ _peasantsMutex }; + _peasants.erase(peasantID); + } + + if (clearMruPeasantOnFailure) + { + // Remove the peasant from the list of MRU windows. They're dead. + // They can't be the MRU anymore. + _clearOldMruEntries({ peasantID }); + } return nullptr; } } @@ -244,39 +297,27 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation return 0; } - std::vector peasantsToErase{}; uint64_t result = 0; - for (const auto& [id, p] : _peasants) - { - try - { - auto otherName = p.WindowName(); - if (otherName == name) - { - result = id; - break; - } - } - catch (...) - { - LOG_CAUGHT_EXCEPTION(); - // Normally, we'd just erase the peasant here. However, we can't - // erase from the map while we're iterating over it like this. - // Instead, pull a good ole Java and collect this id for removal - // later. - peasantsToErase.push_back(id); - } - } - // Remove the dead peasants we came across while iterating. - for (const auto& id : peasantsToErase) - { - // Remove the peasant from the list of peasants - _peasants.erase(id); - // Remove the peasant from the list of MRU windows. They're dead. - // They can't be the MRU anymore. - _clearOldMruEntries(id); - } + const auto callback = [&](const auto& id, const auto& p) { + auto otherName = p.WindowName(); + if (otherName == name) + { + result = id; + return false; + } + return true; + }; + + const auto onError = [&](const auto& id) { + TraceLoggingWrite(g_hRemotingProvider, + "Monarch_lookupPeasantIdForName_Failed", + TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not get the name of"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingKeyword(TIL_KEYWORD_TRACE)); + }; + + _forEachPeasant(callback, onError); TraceLoggingWrite(g_hRemotingProvider, "Monarch_lookupPeasantIdForName", @@ -328,33 +369,42 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // - Helper for removing a peasant from the list of MRU peasants. We want to // do this both when the peasant dies, and also when the peasant is newly // activated (so that we don't leave an old entry for it in the list). + // - NB: This takes a unique lock on _mruPeasantsMutex. // Arguments: - // - peasantID: The ID of the peasant to remove from the MRU list + // - peasantIds: The list of peasant IDs to remove from the MRU list // Return Value: // - - void Monarch::_clearOldMruEntries(const uint64_t peasantID) + void Monarch::_clearOldMruEntries(const std::unordered_set& peasantIds) { - auto result = std::find_if(_mruPeasants.begin(), - _mruPeasants.end(), - [peasantID](auto&& other) { - return peasantID == other.PeasantID(); - }); - - if (result != std::end(_mruPeasants)) + if (peasantIds.size() == 0) { - TraceLoggingWrite(g_hRemotingProvider, - "Monarch_RemovedPeasantFromDesktop", - TraceLoggingUInt64(peasantID, "peasantID", "The ID of the peasant"), - TraceLoggingGuid(result->DesktopID(), "desktopGuid", "The GUID of the previous desktop the window was on"), - TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), - TraceLoggingKeyword(TIL_KEYWORD_TRACE)); - - _mruPeasants.erase(result); + return; } + + std::unique_lock lock{ _mruPeasantsMutex }; + auto partition = std::remove_if(_mruPeasants.begin(), _mruPeasants.end(), [&](const auto& p) { + const auto id = p.PeasantID(); + // remove the element if it was found in the list to erase. + if (peasantIds.count(id) == 1) + { + TraceLoggingWrite(g_hRemotingProvider, + "Monarch_RemovedPeasantFromDesktop", + TraceLoggingUInt64(id, "peasantID", "The ID of the peasant"), + TraceLoggingGuid(p.DesktopID(), "desktopGuid", "The GUID of the previous desktop the window was on"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingKeyword(TIL_KEYWORD_TRACE)); + return true; + } + return false; + }); + + // Remove everything that was in the list + _mruPeasants.erase(partition, _mruPeasants.end()); } // Method Description: // - Actually handle inserting the WindowActivatedArgs into our list of MRU windows. + // - NB: this takes a unique_lock on _mruPeasantsMutex. // Arguments: // - localArgs: an in-proc WindowActivatedArgs that we should add to our list of MRU windows. // Return Value: @@ -365,19 +415,22 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // * Check all the current lists to look for this peasant. // remove it from any where it exists. - _clearOldMruEntries(localArgs->PeasantID()); + _clearOldMruEntries({ localArgs->PeasantID() }); // * If the current desktop doesn't have a vector, add one. const auto desktopGuid{ localArgs->DesktopID() }; - // * Add this args list. By using lower_bound with insert, we can get it - // into exactly the right spot, without having to re-sort the whole - // array. - _mruPeasants.insert(std::lower_bound(_mruPeasants.begin(), - _mruPeasants.end(), - *localArgs, - [](const auto& first, const auto& second) { return first.ActivatedTime() > second.ActivatedTime(); }), - *localArgs); + { + std::unique_lock lock{ _mruPeasantsMutex }; + // * Add this args list. By using lower_bound with insert, we can get it + // into exactly the right spot, without having to re-sort the whole + // array. + _mruPeasants.insert(std::lower_bound(_mruPeasants.begin(), + _mruPeasants.end(), + *localArgs, + [](const auto& first, const auto& second) { return first.ActivatedTime() > second.ActivatedTime(); }), + *localArgs); + } TraceLoggingWrite(g_hRemotingProvider, "Monarch_SetMostRecentPeasant", @@ -391,6 +444,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // Method Description: // - Retrieves the ID of the MRU peasant window. If requested, will limit // the search to windows that are on the current desktop. + // - NB: This method will hold a shared lock on _mruPeasantsMutex and + // potentially a unique_lock on _peasantsMutex at the same time. + // Separately it might hold a unique_lock on _mruPeasantsMutex. // Arguments: // - limitToCurrentDesktop: if true, only return the MRU peasant that's // actually on the current desktop. @@ -403,8 +459,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // - the ID of the most recent peasant, otherwise 0 if we could not find one. uint64_t Monarch::_getMostRecentPeasantID(const bool limitToCurrentDesktop, const bool ignoreQuakeWindow) { + std::shared_lock lock{ _mruPeasantsMutex }; if (_mruPeasants.empty()) { + // unlock the mruPeasants mutex to make sure we can't deadlock here. + lock.unlock(); + // Only need a shared lock for read + std::shared_lock peasantsLock{ _peasantsMutex }; // We haven't yet been told the MRU peasant. Just use the first one. // This is just gonna be a random one, but really shouldn't happen // in practice. The WindowManager should set the MRU peasant @@ -445,15 +506,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // - If it isn't on the current desktop, we'll loop again, on the // following peasant. // * If we don't care, then we'll just return that one. - // - // We're not just using an iterator because the contents of the list - // might change while we're iterating here (if the peasant is dead we'll - // remove it from the list). - int positionInList = 0; - while (_mruPeasants.cbegin() + positionInList < _mruPeasants.cend()) + uint64_t result = 0; + std::unordered_set peasantsToErase{}; + for (const auto& mruWindowArgs : _mruPeasants) { - const auto mruWindowArgs{ *(_mruPeasants.begin() + positionInList) }; - const auto peasant{ _getPeasant(mruWindowArgs.PeasantID()) }; + // Try to get the peasant, but do not have _getPeasant clean up old + // _mruPeasants because we are iterating here. + // SAFETY: _getPeasant can take a unique_lock on _peasantsMutex if + // it detects a peasant is dead. Currently _getMostRecentPeasantId + // is the only method that holds a lock on both _mruPeasantsMutex and + // _peasantsMutex at the same time so there cannot be a deadlock here. + const auto peasant{ _getPeasant(mruWindowArgs.PeasantID(), false) }; if (!peasant) { TraceLoggingWrite(g_hRemotingProvider, @@ -467,6 +530,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // We'll go through the loop again. We removed the current one // at positionInList, so the next one in positionInList will be // a new, different peasant. + peasantsToErase.emplace(mruWindowArgs.PeasantID()); continue; } @@ -504,7 +568,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation "true if this window was in fact on the current desktop"), TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), TraceLoggingKeyword(TIL_KEYWORD_TRACE)); - return mruWindowArgs.PeasantID(); + result = mruWindowArgs.PeasantID(); + break; } // If this window wasn't on the current desktop, another one // might be. We'll increment positionInList below, and try @@ -518,20 +583,30 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), TraceLoggingKeyword(TIL_KEYWORD_TRACE)); - return mruWindowArgs.PeasantID(); + result = mruWindowArgs.PeasantID(); + break; } - positionInList++; } - // Here, we've checked all the windows, and none of them was both alive - // and the most recent (on this desktop). Just return 0 - the caller - // will use this to create a new window. - TraceLoggingWrite(g_hRemotingProvider, - "Monarch_getMostRecentPeasantID_NotFound", - TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), - TraceLoggingKeyword(TIL_KEYWORD_TRACE)); + lock.unlock(); - return 0; + if (peasantsToErase.size() > 0) + { + _clearOldMruEntries(peasantsToErase); + } + + if (result == 0) + { + // Here, we've checked all the windows, and none of them was both alive + // and the most recent (on this desktop). Just return 0 - the caller + // will use this to create a new window. + TraceLoggingWrite(g_hRemotingProvider, + "Monarch_getMostRecentPeasantID_NotFound", + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingKeyword(TIL_KEYWORD_TRACE)); + } + + return result; } // Method Description: @@ -855,7 +930,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation Windows::Foundation::Collections::IVectorView Monarch::GetPeasantInfos() { std::vector names; - names.reserve(_peasants.size()); + { + std::shared_lock lock{ _peasantsMutex }; + names.reserve(_peasants.size()); + } const auto func = [&](const auto& id, const auto& p) -> void { names.push_back({ id, p.WindowName(), p.ActiveTabTitle() }); diff --git a/src/cascadia/Remoting/Monarch.h b/src/cascadia/Remoting/Monarch.h index 2e8e40aa1..7ec904499 100644 --- a/src/cascadia/Remoting/Monarch.h +++ b/src/cascadia/Remoting/Monarch.h @@ -7,6 +7,7 @@ #include "Peasant.h" #include "../cascadia/inc/cppwinrt_utils.h" #include "WindowActivatedArgs.h" +#include // We sure different GUIDs here depending on whether we're running a Release, // Preview, or Dev build. This ensures that different installs don't @@ -69,23 +70,29 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation private: uint64_t _ourPID; - uint64_t _nextPeasantID{ 1 }; - uint64_t _thisPeasantID{ 0 }; + std::atomic _nextPeasantID{ 1 }; + uint64_t _ourPeasantId{ 0 }; + + // When we're quitting we do not care as much about handling some events that we know will be triggered + std::atomic _quitting{ false }; winrt::com_ptr _desktopManager{ nullptr }; std::unordered_map _peasants; - std::vector _mruPeasants; + // These should not be locked at the same time to prevent deadlocks + // unless they are both shared_locks. + std::shared_mutex _peasantsMutex{}; + std::shared_mutex _mruPeasantsMutex{}; - winrt::Microsoft::Terminal::Remoting::IPeasant _getPeasant(uint64_t peasantID); + winrt::Microsoft::Terminal::Remoting::IPeasant _getPeasant(uint64_t peasantID, bool clearMruPeasantOnFailure = true); uint64_t _getMostRecentPeasantID(bool limitToCurrentDesktop, const bool ignoreQuakeWindow); uint64_t _lookupPeasantIdForName(std::wstring_view name); void _peasantWindowActivated(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args); void _doHandleActivatePeasant(const winrt::com_ptr& args); - void _clearOldMruEntries(const uint64_t peasantID); + void _clearOldMruEntries(const std::unordered_set& peasantIds); void _forAllPeasantsIgnoringTheDead(std::function callback, std::function errorCallback); @@ -107,6 +114,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // returns false. // - If any single peasant is dead, then we'll call onError and then add it to a // list of peasants to clean up once the loop ends. + // - NB: this (separately) takes unique locks on _peasantsMutex and + // _mruPeasantsMutex. // Arguments: // - func: The function to call on each peasant // - onError: The function to call if a peasant is dead. @@ -119,44 +128,55 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation using R = std::invoke_result_t; static constexpr auto IsVoid = std::is_void_v; - std::vector peasantsToErase; - - for (const auto& [id, p] : _peasants) + std::unordered_set peasantsToErase; { - try + std::shared_lock lock{ _peasantsMutex }; + + for (const auto& [id, p] : _peasants) { - if constexpr (IsVoid) + try { - func(id, p); - } - else - { - if (!func(id, p)) + if constexpr (IsVoid) { - break; + func(id, p); + } + else + { + if (!func(id, p)) + { + break; + } } } - } - catch (const winrt::hresult_error& exception) - { - onError(id); + catch (const winrt::hresult_error& exception) + { + onError(id); - if (exception.code() == 0x800706ba) // The RPC server is unavailable. - { - peasantsToErase.emplace_back(id); - } - else - { - LOG_CAUGHT_EXCEPTION(); - throw; + if (exception.code() == 0x800706ba) // The RPC server is unavailable. + { + peasantsToErase.emplace(id); + } + else + { + LOG_CAUGHT_EXCEPTION(); + throw; + } } } } - for (const auto& id : peasantsToErase) + if (peasantsToErase.size() > 0) { - _peasants.erase(id); - _clearOldMruEntries(id); + // Don't hold a lock on _peasants and _mruPeasants at the same + // time to avoid deadlocks. + { + std::unique_lock lock{ _peasantsMutex }; + for (const auto& id : peasantsToErase) + { + _peasants.erase(id); + } + } + _clearOldMruEntries(peasantsToErase); } } diff --git a/src/cascadia/Remoting/WindowManager.cpp b/src/cascadia/Remoting/WindowManager.cpp index e3b85e0a2..9a71fcef0 100644 --- a/src/cascadia/Remoting/WindowManager.cpp +++ b/src/cascadia/Remoting/WindowManager.cpp @@ -324,6 +324,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), TraceLoggingKeyword(TIL_KEYWORD_TRACE)); + // If the peasant asks us to quit we should not try to act in future elections. + _peasant.QuitRequested([weakThis{ get_weak() }](auto&&, auto&&) { + if (auto wm = weakThis.get()) + { + wm->_monarchWaitInterrupt.SetEvent(); + } + }); + return _peasant; } diff --git a/src/cascadia/TerminalApp/App.xaml b/src/cascadia/TerminalApp/App.xaml index bc77872e3..251028dee 100644 --- a/src/cascadia/TerminalApp/App.xaml +++ b/src/cascadia/TerminalApp/App.xaml @@ -20,7 +20,8 @@ - + - + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/src/cascadia/TerminalApp/TerminalPage.xaml b/src/cascadia/TerminalApp/TerminalPage.xaml index eea2039f6..b6a4676dd 100644 --- a/src/cascadia/TerminalApp/TerminalPage.xaml +++ b/src/cascadia/TerminalApp/TerminalPage.xaml @@ -9,10 +9,11 @@ xmlns:local="using:TerminalApp" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mux="using:Microsoft.UI.Xaml.Controls" + Background="Transparent" mc:Ignorable="d"> + Background="Transparent"> diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index f5e2ca206..53c75eb6f 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1400,11 +1400,22 @@ namespace winrt::TerminalApp::implementation deselectedTabBrush.Color(deselectedTabColor); // currently if a tab has a custom color, a deselected state is - // signified by using the same color with a bit ot transparency + // signified by using the same color with a bit of transparency + // + // Prior to MUX 2.7, we set TabViewItemHeaderBackground, but now we can + // use TabViewItem().Background() for that. HOWEVER, + // TabViewItem().Background() only sets the color of the tab background + // when the TabViewItem is unselected. So we still need to set the other + // properties ourselves. + TabViewItem().Background(deselectedTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush); - TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackground"), deselectedTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), hoverTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPressed"), selectedTabBrush); + + // TabViewItem().Foreground() unfortunately does not work for us. It + // sets the color for the text when the TabViewItem isn't selected, but + // not when it is hovered, pressed, dragged, or selected, so we'll need + // to just set them all anyways. TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForeground"), fontBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundSelected"), fontBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundPointerOver"), fontBrush); @@ -1442,7 +1453,6 @@ namespace winrt::TerminalApp::implementation void TerminalTab::_ClearTabBackgroundColor() { winrt::hstring keys[] = { - L"TabViewItemHeaderBackground", L"TabViewItemHeaderBackgroundSelected", L"TabViewItemHeaderBackgroundPointerOver", L"TabViewItemHeaderForeground", @@ -1463,6 +1473,9 @@ namespace winrt::TerminalApp::implementation } } + // Clear out the Background. + TabViewItem().Background(nullptr); + _RefreshVisualState(); _colorCleared(); } @@ -1487,7 +1500,7 @@ namespace winrt::TerminalApp::implementation // - void TerminalTab::_RefreshVisualState() { - if (_focusState != FocusState::Unfocused) + if (TabViewItem().IsSelected()) { VisualStateManager::GoToState(TabViewItem(), L"Normal", true); VisualStateManager::GoToState(TabViewItem(), L"Selected", true); diff --git a/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj b/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj index 5f9d3f7c7..a5d865776 100644 --- a/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj +++ b/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj @@ -89,13 +89,13 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/src/cascadia/TerminalApp/packages.config b/src/cascadia/TerminalApp/packages.config index 9de6f1b8d..78467467c 100644 --- a/src/cascadia/TerminalApp/packages.config +++ b/src/cascadia/TerminalApp/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/cascadia/TerminalConnection/ConptyConnection.cpp b/src/cascadia/TerminalConnection/ConptyConnection.cpp index 5c2373fd2..b6ad2ce7f 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.cpp +++ b/src/cascadia/TerminalConnection/ConptyConnection.cpp @@ -16,6 +16,10 @@ #include "LibraryResources.h" using namespace ::Microsoft::Console; +using namespace std::string_view_literals; + +// Format is: "DecimalResult (HexadecimalForm)" +static constexpr auto _errorFormat = L"{0} ({0:#010x})"sv; // Notes: // There is a number of ways that the Conpty connection can be terminated (voluntarily or not): @@ -417,7 +421,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation const auto hr = wil::ResultFromCaughtException(); winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") }, - gsl::narrow_cast(hr), + fmt::format(_errorFormat, hr), _commandline) }; _TerminalOutputHandlers(failureText); @@ -444,7 +448,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation { try { - winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, status) }; + winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, fmt::format(_errorFormat, status)) }; _TerminalOutputHandlers(L"\r\n"); _TerminalOutputHandlers(exitText); } diff --git a/src/cascadia/TerminalConnection/Resources/en-US/Resources.resw b/src/cascadia/TerminalConnection/Resources/en-US/Resources.resw index d32f59269..7af3cf590 100644 --- a/src/cascadia/TerminalConnection/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalConnection/Resources/en-US/Resources.resw @@ -205,15 +205,15 @@ [process exited with code {0}] - The first argument {0} is the (positive) error code of the process. When there is no error, the number ZERO will be displayed. + The first argument {0} is the error code of the process. When there is no error, the number ZERO will be displayed. - [error {0:#08x} when launching `{1}'] - The first argument {0...} is the hexadecimal error code. The second argument {1} is the user-specified path to a program. + [error {0} when launching `{1}'] + The first argument {0} is the error code. The second argument {1} is the user-specified path to a program. If this string is broken to multiple lines, it will not be displayed properly. Could not access starting directory "{0}" The first argument {0} is a path to a directory on the filesystem, as provided by the user. - \ No newline at end of file + diff --git a/src/cascadia/TerminalConnection/TerminalConnection.vcxproj b/src/cascadia/TerminalConnection/TerminalConnection.vcxproj index 5cfd57c40..f594bc46f 100644 --- a/src/cascadia/TerminalConnection/TerminalConnection.vcxproj +++ b/src/cascadia/TerminalConnection/TerminalConnection.vcxproj @@ -56,7 +56,9 @@ - + + Designer + @@ -88,11 +90,11 @@ - $(IntDir)..\OpenConsoleProxy;%(AdditionalIncludeDirectories) + $(IntDir)..\OpenConsoleProxy;%(AdditionalIncludeDirectories) $(OpenConsoleCommonOutDir)\conptylib.lib;%(AdditionalDependencies) - + \ No newline at end of file diff --git a/src/cascadia/TerminalConnection/TerminalConnection.vcxproj.filters b/src/cascadia/TerminalConnection/TerminalConnection.vcxproj.filters index 12a9cc6c4..a7d2f9092 100644 --- a/src/cascadia/TerminalConnection/TerminalConnection.vcxproj.filters +++ b/src/cascadia/TerminalConnection/TerminalConnection.vcxproj.filters @@ -32,6 +32,7 @@ + diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index eac350c2a..e09eb93ae 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -276,7 +276,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // GH#5098: Inform the engine of the opacity of the default text background. if (_settings.UseAcrylic()) { - _renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast(_settings.TintOpacity())); + _renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast(_settings.Opacity())); } THROW_IF_FAILED(_renderEngine->Enable()); @@ -425,41 +425,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation return; } - auto newOpacity = std::clamp(_settings.TintOpacity() + adjustment, + auto newOpacity = std::clamp(_settings.Opacity() + adjustment, 0.0, 1.0); - if (_settings.UseAcrylic()) - { - try - { - _settings.TintOpacity(newOpacity); - if (newOpacity >= 1.0) - { - _settings.UseAcrylic(false); - } - else - { - // GH#5098: Inform the engine of the new opacity of the default text background. - SetBackgroundOpacity(::base::saturated_cast(newOpacity)); - } + // GH#5098: Inform the engine of the new opacity of the default text background. + SetBackgroundOpacity(::base::saturated_cast(newOpacity)); - auto eventArgs = winrt::make_self(newOpacity); - _TransparencyChangedHandlers(*this, *eventArgs); - } - CATCH_LOG(); - } - else if (adjustment < 0) - { - _settings.UseAcrylic(true); + _settings.Opacity(newOpacity); - //Setting initial opacity set to 1 to ensure smooth transition to acrylic during mouse scroll - newOpacity = std::clamp(1.0 + adjustment, 0.0, 1.0); - _settings.TintOpacity(newOpacity); - - auto eventArgs = winrt::make_self(newOpacity); - _TransparencyChangedHandlers(*this, *eventArgs); - } + auto eventArgs = winrt::make_self(newOpacity); + _TransparencyChangedHandlers(*this, *eventArgs); } void ControlCore::ToggleShaderEffects() @@ -1003,6 +979,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation { _terminal->WritePastedText(hstr); _terminal->ClearSelection(); + _renderer->TriggerSelection(); _terminal->TrySnapOnInput(); } diff --git a/src/cascadia/TerminalControl/IControlAppearance.idl b/src/cascadia/TerminalControl/IControlAppearance.idl index a0fa0a0ad..fd06bc853 100644 --- a/src/cascadia/TerminalControl/IControlAppearance.idl +++ b/src/cascadia/TerminalControl/IControlAppearance.idl @@ -13,6 +13,7 @@ namespace Microsoft.Terminal.Control Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment; Boolean IntenseIsBold; // IntenseIsBright is in Core Appearance + Double Opacity; // Experimental settings Boolean RetroTerminalEffect; diff --git a/src/cascadia/TerminalControl/IControlSettings.idl b/src/cascadia/TerminalControl/IControlSettings.idl index 56aab7395..1b67df91f 100644 --- a/src/cascadia/TerminalControl/IControlSettings.idl +++ b/src/cascadia/TerminalControl/IControlSettings.idl @@ -29,7 +29,6 @@ namespace Microsoft.Terminal.Control String ProfileName; Boolean UseAcrylic; - Double TintOpacity; ScrollbarState ScrollState; String FontFace; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 115f9afc5..fc74dd0a9 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -428,6 +428,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - void TermControl::_InitializeBackgroundBrush() { + auto appearance = _settings.try_as(); if (_settings.UseAcrylic()) { // See if we've already got an acrylic background brush @@ -449,7 +450,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation acrylic.TintColor(bgColor); // Apply brush settings - acrylic.TintOpacity(_settings.TintOpacity()); + acrylic.TintOpacity(appearance.Opacity()); // Apply brush to control if it's not already there if (RootGrid().Background() != acrylic) @@ -458,15 +459,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation } // GH#5098: Inform the engine of the new opacity of the default text background. - _core.SetBackgroundOpacity(::base::saturated_cast(_settings.TintOpacity())); + _core.SetBackgroundOpacity(::base::saturated_cast(appearance.Opacity())); } else { Media::SolidColorBrush solidColor{}; + solidColor.Opacity(_settings.Opacity()); RootGrid().Background(solidColor); // GH#5098: Inform the engine of the new opacity of the default text background. - _core.SetBackgroundOpacity(1.0f); + _core.SetBackgroundOpacity(appearance.Opacity()); } } @@ -497,7 +499,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation } else if (auto solidColor = RootGrid().Background().try_as()) { + const auto originalOpacity = solidColor.Opacity(); solidColor.Color(bg); + solidColor.Opacity(originalOpacity); } } } diff --git a/src/cascadia/TerminalControl/TermControl.xaml b/src/cascadia/TerminalControl/TermControl.xaml index 94aa92c5f..663ccf7ce 100644 --- a/src/cascadia/TerminalControl/TermControl.xaml +++ b/src/cascadia/TerminalControl/TermControl.xaml @@ -14,6 +14,7 @@ d:DesignWidth="1024" AllowDrop="True" AllowFocusOnInteraction="True" + Background="Transparent" CharacterReceived="_CharacterHandler" DragOver="_DragOverHandler" Drop="_DragDropHandler" diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.xaml b/src/cascadia/TerminalSettingsEditor/MainPage.xaml index 9576102a1..9d24ac109 100644 --- a/src/cascadia/TerminalSettingsEditor/MainPage.xaml +++ b/src/cascadia/TerminalSettingsEditor/MainPage.xaml @@ -8,6 +8,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:muxc="using:Microsoft.UI.Xaml.Controls" + Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" mc:Ignorable="d"> diff --git a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj index e60fccb32..e4335126c 100644 --- a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj +++ b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj @@ -312,12 +312,12 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.h b/src/cascadia/TerminalSettingsEditor/Profiles.h index e1ceba5d0..54d7d4108 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.h +++ b/src/cascadia/TerminalSettingsEditor/Profiles.h @@ -22,7 +22,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void SetAcrylicOpacityPercentageValue(double value) { - AcrylicOpacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value)); + _profile.DefaultAppearance().Opacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value)); }; void SetPadding(double value) @@ -66,7 +66,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation OBSERVABLE_PROJECTED_SETTING(_profile, TabColor); OBSERVABLE_PROJECTED_SETTING(_profile, SuppressApplicationTitle); OBSERVABLE_PROJECTED_SETTING(_profile, UseAcrylic); - OBSERVABLE_PROJECTED_SETTING(_profile, AcrylicOpacity); OBSERVABLE_PROJECTED_SETTING(_profile, ScrollState); OBSERVABLE_PROJECTED_SETTING(_profile, Padding); OBSERVABLE_PROJECTED_SETTING(_profile, Commandline); @@ -78,6 +77,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), CursorColor); + OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Opacity); OBSERVABLE_PROJECTED_SETTING(_profile, HistorySize); OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput); OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing); diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.idl b/src/cascadia/TerminalSettingsEditor/Profiles.idl index 4ecc48899..482a19671 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.idl +++ b/src/cascadia/TerminalSettingsEditor/Profiles.idl @@ -47,7 +47,7 @@ namespace Microsoft.Terminal.Settings.Editor OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference, TabColor); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SuppressApplicationTitle); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAcrylic); - OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, AcrylicOpacity); + OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, Opacity); OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState); OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Padding); OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline); @@ -109,6 +109,6 @@ namespace Microsoft.Terminal.Settings.Editor IInspectable CurrentScrollState; Windows.Foundation.Collections.IObservableVector ScrollStateList { get; }; - Windows.UI.Xaml.Controls.Slider AcrylicOpacitySlider { get; }; + Windows.UI.Xaml.Controls.Slider OpacitySlider { get; }; } } diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.xaml b/src/cascadia/TerminalSettingsEditor/Profiles.xaml index 5e11e2450..24e6a7fe1 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.xaml +++ b/src/cascadia/TerminalSettingsEditor/Profiles.xaml @@ -238,11 +238,33 @@ - + - + + + + + + + + + + + + + + - - - - - - - - - - - - - diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw index 4c39ba4d1..a21ae08e3 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw @@ -495,6 +495,14 @@ Sets the transparency of the window. A description for what the "acrylic opacity" setting does. Presented near "Profile_AcrylicOpacity.Header". + + Background Opacity + Header for a control to determine the level of opacity for the background of the control. The user can choose to make the background of the app more or less opaque. + + + Sets the transparency of the window. + A description for what the "opacity" setting does. Presented near "Profile_Opacity.Header". + Advanced Header for a sub-page of profile settings focused on more advanced scenarios. @@ -986,6 +994,10 @@ Acrylic Header for a group of settings related to the acrylic texture rendering on the background of the app. + + Transparency + Header for a group of settings related to transparency, including the acrylic texture rendering on the background of the app. + Background image Header for a group of settings that control the image presented on the background of the app. Presented near "Profile_BackgroundImage" and other keys starting with "Profile_BackgroundImage". diff --git a/src/cascadia/TerminalSettingsEditor/packages.config b/src/cascadia/TerminalSettingsEditor/packages.config index ecf244764..bd1e02e27 100644 --- a/src/cascadia/TerminalSettingsEditor/packages.config +++ b/src/cascadia/TerminalSettingsEditor/packages.config @@ -1,5 +1,5 @@  - + diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp index 67eb279ea..1f8c88758 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp @@ -26,6 +26,8 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" }; static constexpr std::string_view PixelShaderPathKey{ "experimental.pixelShaderPath" }; static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" }; +static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" }; +static constexpr std::string_view OpacityKey{ "opacity" }; winrt::Microsoft::Terminal::Settings::Model::implementation::AppearanceConfig::AppearanceConfig(const winrt::weak_ref sourceProfile) : _sourceProfile(sourceProfile) @@ -50,6 +52,7 @@ winrt::com_ptr AppearanceConfig::CopyAppearance(const winrt::c appearance->_RetroTerminalEffect = sourceAppearance->_RetroTerminalEffect; appearance->_PixelShaderPath = sourceAppearance->_PixelShaderPath; appearance->_IntenseTextStyle = sourceAppearance->_IntenseTextStyle; + appearance->_Opacity = sourceAppearance->_Opacity; return appearance; } @@ -71,6 +74,7 @@ Json::Value AppearanceConfig::ToJson() const JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::SetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::SetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); + JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); return json; } @@ -102,6 +106,8 @@ void AppearanceConfig::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::GetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::GetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); + JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity); + JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); } winrt::Microsoft::Terminal::Settings::Model::Profile AppearanceConfig::SourceProfile() diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h index 7a0c47985..d28b9a92c 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h @@ -53,6 +53,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::IAppearanceConfig, bool, RetroTerminalEffect, false); INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, PixelShaderPath, L""); INHERITABLE_SETTING(Model::IAppearanceConfig, Model::IntenseStyle, IntenseTextStyle, Model::IntenseStyle::Bright); + INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0); private: winrt::weak_ref _sourceProfile; diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index e98592ce4..c2b2fceb2 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -307,7 +307,6 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::Duplicate DUPLICATE_SETTING_MACRO(TabColor); DUPLICATE_SETTING_MACRO(SuppressApplicationTitle); DUPLICATE_SETTING_MACRO(UseAcrylic); - DUPLICATE_SETTING_MACRO(AcrylicOpacity); DUPLICATE_SETTING_MACRO(ScrollState); DUPLICATE_SETTING_MACRO(Padding); DUPLICATE_SETTING_MACRO(Commandline); @@ -347,6 +346,7 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::Duplicate DUPLICATE_SETTING_MACRO_SUB(appearance, target, RetroTerminalEffect); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorShape); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorHeight); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, Opacity); } // UnfocusedAppearance is treated as a single setting, diff --git a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl index b33cf23e7..af89f55e8 100644 --- a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl +++ b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl @@ -51,5 +51,6 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_APPEARANCE_SETTING(Boolean, RetroTerminalEffect); INHERITABLE_APPEARANCE_SETTING(String, PixelShaderPath); INHERITABLE_APPEARANCE_SETTING(IntenseStyle, IntenseTextStyle); + INHERITABLE_APPEARANCE_SETTING(Double, Opacity); }; } diff --git a/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj index 971096375..3c56c6620 100644 --- a/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj +++ b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj @@ -241,12 +241,13 @@ - + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + - - \ No newline at end of file + + diff --git a/src/cascadia/WindowsTerminal/packages.config b/src/cascadia/WindowsTerminal/packages.config index f2f5c3f58..2b5489325 100644 --- a/src/cascadia/WindowsTerminal/packages.config +++ b/src/cascadia/WindowsTerminal/packages.config @@ -2,7 +2,7 @@ - - - + + + diff --git a/src/cascadia/WindowsTerminal/pch.h b/src/cascadia/WindowsTerminal/pch.h index 01d2f04a7..59f24e949 100644 --- a/src/cascadia/WindowsTerminal/pch.h +++ b/src/cascadia/WindowsTerminal/pch.h @@ -67,6 +67,7 @@ Abstract: #include #include #include +#include #include #include diff --git a/src/cascadia/WindowsTerminalUniversal/WindowsTerminalUniversal.vcxproj b/src/cascadia/WindowsTerminalUniversal/WindowsTerminalUniversal.vcxproj index ab1d88cdb..6a0cf3d03 100644 --- a/src/cascadia/WindowsTerminalUniversal/WindowsTerminalUniversal.vcxproj +++ b/src/cascadia/WindowsTerminalUniversal/WindowsTerminalUniversal.vcxproj @@ -87,14 +87,14 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/src/cascadia/ut_app/TerminalApp.UnitTests.vcxproj b/src/cascadia/ut_app/TerminalApp.UnitTests.vcxproj index 6925f252e..32bafde87 100644 --- a/src/cascadia/ut_app/TerminalApp.UnitTests.vcxproj +++ b/src/cascadia/ut_app/TerminalApp.UnitTests.vcxproj @@ -92,7 +92,7 @@ x86 $(Platform) - <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\" + <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\runtimes\win10-$(Native-Platform)\native\"