Skip to content

Commit

Permalink
Good enough to start
Browse files Browse the repository at this point in the history
  • Loading branch information
zadjii-msft committed May 24, 2023
1 parent 7a85d66 commit 242dfe5
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 52 deletions.
86 changes: 64 additions & 22 deletions src/cascadia/WindowsTerminal/WindowEmperor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,25 @@ WindowEmperor::~WindowEmperor()
_app = nullptr;
}

static bool IsWindows11()
{
static const bool isWindows11 = []() {
OSVERSIONINFOEXW osver{};
osver.dwOSVersionInfoSize = sizeof(osver);
osver.dwBuildNumber = 22000;

DWORDLONG dwlConditionMask = 0;
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);

if (VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE)
{
return true;
}
return false;
}();
return isWindows11;
}

void _buildArgsFromCommandline(std::vector<winrt::hstring>& args)
{
if (auto commandline{ GetCommandLineW() })
Expand Down Expand Up @@ -111,7 +130,8 @@ bool WindowEmperor::HandleCommandlineArgs()

const auto result = _manager.ProposeCommandline(eventArgs, isolatedMode);

if (result.ShouldCreateWindow())
const bool makeWindow = result.ShouldCreateWindow();
if (makeWindow)
{
_createNewWindowThread(Remoting::WindowRequestedArgs{ result, eventArgs });

Expand All @@ -127,7 +147,7 @@ bool WindowEmperor::HandleCommandlineArgs()
}
}

return result.ShouldCreateWindow();
return makeWindow;
}

void WindowEmperor::WaitForWindows()
Expand Down Expand Up @@ -185,12 +205,6 @@ void WindowEmperor::_createNewWindowThread(const Remoting::WindowRequestedArgs&
std::thread t([weakThis, window]() {
try
{
auto removeWindow = wil::scope_exit([&]() {
if (auto self{ weakThis.lock() })
{
self->_removeWindow(window->PeasantID());
}
});

window->CreateHost();

Expand All @@ -200,6 +214,23 @@ void WindowEmperor::_createNewWindowThread(const Remoting::WindowRequestedArgs&
}
while (window->KeepWarm())
{
// Now that the window is ready to go, we can add it to our list of windows,
// because we know it will be well behaved.
//
// Be sure to only modify the list of windows under lock.

if (auto self{ weakThis.lock() })
{
auto lockedWindows{ self->_windows.lock() };
lockedWindows->push_back(window);
}
auto removeWindow = wil::scope_exit([&]() {
if (auto self{ weakThis.lock() })
{
self->_removeWindow(window->PeasantID());
}
});

auto decrementWindowCount = wil::scope_exit([&]() {
if (auto self{ weakThis.lock() })
{
Expand All @@ -215,13 +246,24 @@ void WindowEmperor::_createNewWindowThread(const Remoting::WindowRequestedArgs&
// elsewhere).
removeWindow.reset();

window->Refrigerate();
decrementWindowCount.reset();
// On Windows 11, we DONT want to refrigerate the window. There, we can just
// close it like normal.
// TODO!

if (auto self{ weakThis.lock() })
if (IsWindows11())
{
auto fridge{ self->_oldThreads.lock() };
fridge->push_back(window);
decrementWindowCount.reset();
}
else
{
window->Refrigerate();
decrementWindowCount.reset();

if (auto self{ weakThis.lock() })
{
auto fridge{ self->_oldThreads.lock() };
fridge->push_back(window);
}
}
}

Expand Down Expand Up @@ -257,15 +299,6 @@ void WindowEmperor::_windowStartedHandlerPostXAML(const std::shared_ptr<WindowTh
// the Terminal window, making it visible BEFORE the XAML island is actually
// ready to be drawn. We want to wait till the app's Initialized event
// before we make the window visible.

// Now that the window is ready to go, we can add it to our list of windows,
// because we know it will be well behaved.
//
// Be sure to only modify the list of windows under lock.
{
auto lockedWindows{ _windows.lock() };
lockedWindows->push_back(sender);
}
}

void WindowEmperor::_removeWindow(uint64_t senderID)
Expand Down Expand Up @@ -553,6 +586,15 @@ LRESULT WindowEmperor::_messageHandler(UINT const message, WPARAM const wParam,

winrt::fire_and_forget WindowEmperor::_close()
{
{
auto fridge{ _oldThreads.lock() };
for (auto& window : *fridge)
{
window->ThrowAway();
}
fridge->clear();
}

// Important! Switch back to the main thread for the emperor. That way, the
// quit will go to the emperor's message pump.
co_await wil::resume_foreground(_dispatcher);
Expand Down
81 changes: 51 additions & 30 deletions src/cascadia/WindowsTerminal/WindowThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,20 @@ WindowThread::WindowThread(winrt::TerminalApp::AppLogic logic,

void WindowThread::CreateHost()
{
const bool coldStart = _warmWindow == nullptr;
// Calling this while refrigerated won't work.
// * We can't re-initialize our winrt apartment.
// * AppHost::Initialize has to be done on the "UI" thread.
assert(_warmWindow == nullptr);

// Start the AppHost HERE, on the actual thread we want XAML to run on
_host = !coldStart ? std::make_unique<::AppHost>(_appLogic,
_args,
_manager,
_peasant,
std::move(_warmWindow)) :
std::make_unique<::AppHost>(_appLogic,
_args,
_manager,
_peasant);
_host = std::make_unique<::AppHost>(_appLogic,
_args,
_manager,
_peasant);

_UpdateSettingsRequestedToken = _host->UpdateSettingsRequested([this]() { _UpdateSettingsRequestedHandlers(); });

if (coldStart)
{
winrt::init_apartment(winrt::apartment_type::single_threaded);
}
winrt::init_apartment(winrt::apartment_type::single_threaded);

// Initialize the xaml content. This must be called AFTER the
// WindowsXamlManager is initialized.
Expand All @@ -49,10 +46,29 @@ int WindowThread::RunMessagePump()
return exitCode;
}

void WindowThread::_pumpRemainingXamlMessages()
{
MSG msg = {};
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
{
::DispatchMessageW(&msg);
}
}

void WindowThread::RundownForExit()
{
_host->UpdateSettingsRequested(_UpdateSettingsRequestedToken);
_host->Close();
if (_host)
{
_host->UpdateSettingsRequested(_UpdateSettingsRequestedToken);
_host->Close();
}
if (_warmWindow)
{
// If we have a _warmWindow, we're a refrigerated thread without a
// AppHost in control of the window. Manually close the window
// ourselves, to free the DWXS.
_warmWindow->Close();
}

// !! LOAD BEARING !!
//
Expand All @@ -62,13 +78,13 @@ void WindowThread::RundownForExit()
// exiting. So do that now. If you don't, then the last tab to close
// will never actually destruct the last tab / TermControl / ControlCore
// / renderer.
{
MSG msg = {};
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
{
::DispatchMessageW(&msg);
}
}
_pumpRemainingXamlMessages();
}

void WindowThread::ThrowAway()
{
// raise the signal to unblock KeepWarm. We won't have a host, so we'll drop out of the message loop to eventually RundownForExit.
_microwaveBuzzer.notify_one();
}

// Method Description:
Expand Down Expand Up @@ -113,6 +129,12 @@ bool WindowThread::KeepWarm()
}
}

// Method Description:
// - "Refrigerate" this thread for later reuse. This will refrigerate the window
// itself, and tear down our current app host. We'll save our window for
// later. We'll also pump out the existing message from XAML, before
// returning. After we return, the emperor will add us to the list of threads
// that can be re-used.
void WindowThread::Refrigerate()
{
_host->UpdateSettingsRequested(_UpdateSettingsRequestedToken);
Expand All @@ -121,16 +143,15 @@ void WindowThread::Refrigerate()
_warmWindow = std::move(_host->Refrigerate());

// rundown remaining messages before dtoring the app host
{
MSG msg = {};
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
{
::DispatchMessageW(&msg);
}
}
_pumpRemainingXamlMessages();
_host = nullptr;
}

// Method Description:
// - "Reheat" this thread for reuse. We'll build a new AppHost, and pass in the
// existing window to it. We'll then trigger the _microwaveBuzzer, so KeepWarm
// (which is on the UI thread) will get unblocked, and we can initialize this
// window.
void WindowThread::Microwave(
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
winrt::Microsoft::Terminal::Remoting::Peasant peasant)
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/WindowsTerminal/WindowThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class WindowThread : public std::enable_shared_from_this<WindowThread>
void Microwave(
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
winrt::Microsoft::Terminal::Remoting::Peasant peasant);
void ThrowAway();

uint64_t PeasantID();

Expand All @@ -42,4 +43,5 @@ class WindowThread : public std::enable_shared_from_this<WindowThread>
std::condition_variable _microwaveBuzzer;

int _messagePump();
void _pumpRemainingXamlMessages();
};

1 comment on commit 242dfe5

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@check-spelling-bot Report

🔴 Please review

See the 📜action log for details.

Unrecognized words (6)

dtoring
DWXS
INVARAINT
microwaved
NCIW
revokec

Previously acknowledged words that are now absent Hirots NULs spand xwwyzz xxyyzz :arrow_right:
To accept ✔️ these unrecognized words as correct and remove the previously acknowledged and now absent words, run the following commands

... in a clone of the git@github.com:microsoft/terminal.git repository
on the dev/migrie/b/refrigerate-threads-for-later branch (ℹ️ how do I use this?):

curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.21/apply.pl' |
perl - 'https://github.com/microsoft/terminal/actions/runs/5073652539/attempts/1'
Errors (1)

See the 📜action log for details.

❌ Errors Count
❌ forbidden-pattern 1

See ❌ Event descriptions for more information.

✏️ Contributor please read this

By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.

⚠️ The command is written for posix shells. If it doesn't work for you, you can manually add (one word per line) / remove items to expect.txt and the excludes.txt files.

If the listed items are:

  • ... misspelled, then please correct them instead of using the command.
  • ... names, please add them to .github/actions/spelling/allow/names.txt.
  • ... APIs, you can add them to a file in .github/actions/spelling/allow/.
  • ... just things you're using, please add them to an appropriate file in .github/actions/spelling/expect/.
  • ... tokens you only need in one place and shouldn't generally be used, you can add an item in an appropriate file in .github/actions/spelling/patterns/.

See the README.md in each directory for more information.

🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉

If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Please sign in to comment.