Skip to content

Commit f8a3229

Browse files
Merge pull request #1450 from contour-terminal/fix/race-on-mouseMove
Fix thread safety issue on mouse move event handling
2 parents cc5193a + 9aa91e1 commit f8a3229

File tree

4 files changed

+39
-4
lines changed

4 files changed

+39
-4
lines changed

metainfo.xml

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
<li>Fixes `scripts/install-deps.sh` for openSuSE (Tumbleweed) to install the correct dependencies.</li>
115115
<li>Fixes missing dependencies for release .deb packages (#1397).</li>
116116
<li>Fixes legacy keyboard input protocol not reporting non-Alt modifier (#1411).</li>
117+
<li>Fixes thread safety issue on mouse move event handling (#1444).</li>
117118
<li>Digitally sign MacOS release binaries using a valid Apple ID.</li>
118119
<li>Add support for authenticating to SSH servers with a private key without a password and without requesting for one - also allow password retry (#1425).</li>
119120
<li>Default history limit is now 1000 lines rather than 0 lines.</li>

src/contour/TerminalSession.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <crispy/StackTrace.h>
1616
#include <crispy/assert.h>
17+
#include <crispy/utils.h>
1718

1819
#include <QtCore/QDebug>
1920
#include <QtCore/QFileInfo>
@@ -827,7 +828,9 @@ void TerminalSession::sendMousePressEvent(Modifiers modifiers,
827828

828829
terminal().tick(steady_clock::now());
829830

830-
if (terminal().sendMousePressEvent(modifiers, button, pixelPosition, uiHandledHint))
831+
if (crispy::locked(_terminal, [&]() {
832+
return _terminal.sendMousePressEvent(modifiers, button, pixelPosition, uiHandledHint);
833+
}))
831834
return;
832835

833836
auto const sanitizedModifier = modifiers.contains(_config.bypassMouseProtocolModifiers)
@@ -852,7 +855,8 @@ void TerminalSession::sendMouseMoveEvent(vtbackend::Modifiers modifiers,
852855
terminal().tick(steady_clock::now());
853856

854857
auto constexpr UiHandledHint = false;
855-
terminal().sendMouseMoveEvent(modifiers, pos, pixelPosition, UiHandledHint);
858+
crispy::locked(_terminal,
859+
[&]() { _terminal.sendMouseMoveEvent(modifiers, pos, pixelPosition, UiHandledHint); });
856860

857861
if (pos != _currentMousePosition)
858862
{
@@ -871,8 +875,10 @@ void TerminalSession::sendMouseReleaseEvent(Modifiers modifiers,
871875
{
872876
terminal().tick(steady_clock::now());
873877

874-
auto const uiHandledHint = false;
875-
terminal().sendMouseReleaseEvent(modifiers, button, pixelPosition, uiHandledHint);
878+
crispy::locked(_terminal, [&]() {
879+
auto const uiHandledHint = false;
880+
_terminal.sendMouseReleaseEvent(modifiers, button, pixelPosition, uiHandledHint);
881+
});
876882
scheduleRedraw();
877883
}
878884

src/crispy/defines.h

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#if (defined(__cpp_concepts) && __cpp_concepts >= 201500L) \
1717
&& (defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L)
18+
#define CRISPY_CONCEPTS_SUPPORTED
1819
#define CRISPY_REQUIRES(x) requires x
1920
#else
2021
#define CRISPY_REQUIRES(x) /*!*/

src/crispy/utils.h

+27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <crispy/defines.h>
34
#include <crispy/escape.h>
45

56
#include <fmt/format.h>
@@ -11,13 +12,18 @@
1112
#include <filesystem>
1213
#include <fstream>
1314
#include <functional>
15+
#include <mutex>
1416
#include <optional>
1517
#include <sstream>
1618
#include <string>
1719
#include <string_view>
1820
#include <unordered_map>
1921
#include <vector>
2022

23+
#if defined(CRISPY_CONCEPTS_SUPPORTED)
24+
#include <concepts>
25+
#endif
26+
2127
namespace crispy
2228
{
2329

@@ -297,6 +303,27 @@ class finally // NOLINT(readability-identifier-naming)
297303
std::function<void()> _hook {};
298304
};
299305

306+
#if defined(CRISPY_CONCEPTS_SUPPORTED)
307+
308+
// clang-format off
309+
template <typename T>
310+
concept LockableConcept = requires(T t)
311+
{
312+
{ t.lock() } -> std::same_as<void>;
313+
{ t.unlock() } -> std::same_as<void>;
314+
};
315+
// clang-format on
316+
317+
#endif
318+
319+
template <typename L, typename F>
320+
CRISPY_REQUIRES(LockableConcept<L>)
321+
auto locked(L& lockable, F const& f)
322+
{
323+
auto const _ = std::scoped_lock { lockable };
324+
return f();
325+
}
326+
300327
inline std::optional<unsigned> fromHexDigit(char value)
301328
{
302329
if ('0' <= value && value <= '9')

0 commit comments

Comments
 (0)