25df527743
In addition to the below (original) description, this commit introduces a ThrottledFunc template that can throttle _any_ function. It applies that type to muffle updates to the scrollbar. --- Redo #3531 but without the bug that it caused (#3622) which is why it was reverted. I'm sorry if I explain this badly. If you don't understand a part, make sure to let me know and I will explain it better. ### Explanation How it worked before: `Terminal` signals that viewport changed -> `TermControl::_TerminalScrollPositionChanged` gets called on the terminal thread -> it dispatches work for later to be ran the UI thread to updates the scrollbar's values Why it's bad: * If we have many viewport changes, it will create a long stack of operations to run. Instead, we should just update the scroll bar with the most recent information that we know. * Imagine if the rate that the work gets pushed on the UI thread is greater than the rate that it can handle: it might freeze? * No need to be real time, we can wait just a little bit (8ms) to accumulate viewport changes before we actually change the scroll bar's value because it appears to be expensive (see perf below). Now: `Terminal` signals that viewport changed -> `TermControl::_TerminalScrollPositionChanged` gets called on the terminal thread -> it tells the `ScrollBarUpdater` about a new update -> the `ScrollBarUpdater` only runs one job (I don't know if that's the right term) on the UI thread at a time. If a job is already running but hasn't updated the scroll bar yet, it changes the setting in the already existing job to update the scroll bar with the new values. A job "waits" some time before doing the update to throttle updates because we don't need real time scroll bar updates. -> eventually, it updates the scroll bar If the user scrolls when a scroll bar update is pending, we keep the scroll bar's Maximum and Minimum but let the user choose its new Value with the `CancelPendingValueChange` method. ### Note Also I changed a little bit the code from the Terminal to notify the TermControl less often when possible. I tried to scroll with the scroll bar, with the mouse wheel. I tried to scroll while content is being outputted. I tried to reproduce the crash from #2248 without success (good). Co-authored-by: Leonard Hecker <leonard@hecker.io> Closes #3622
55 lines
1.2 KiB
C++
55 lines
1.2 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#pragma once
|
|
#include "pch.h"
|
|
|
|
template<typename T>
|
|
class ThreadSafeOptional
|
|
{
|
|
public:
|
|
template<class... Args>
|
|
bool Emplace(Args&&... args)
|
|
{
|
|
std::lock_guard guard{ _lock };
|
|
|
|
bool hadValue = _inner.has_value();
|
|
_inner.emplace(std::forward<Args>(args)...);
|
|
return !hadValue;
|
|
}
|
|
|
|
std::optional<T> Take()
|
|
{
|
|
std::lock_guard guard{ _lock };
|
|
|
|
std::optional<T> value;
|
|
_inner.swap(value);
|
|
|
|
return value;
|
|
}
|
|
|
|
// Method Description:
|
|
// - If the optional has a value, then call the specified function with a
|
|
// reference to the value.
|
|
// - This method is always thread-safe. It can be called multiple times on
|
|
// different threads.
|
|
// Arguments:
|
|
// - f: the function to call with a reference to the value
|
|
// Return Value:
|
|
// - <none>
|
|
template<typename F>
|
|
void ModifyValue(F f)
|
|
{
|
|
std::lock_guard guard{ _lock };
|
|
|
|
if (_inner.has_value())
|
|
{
|
|
f(_inner.value());
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::mutex _lock;
|
|
std::optional<T> _inner;
|
|
};
|