Skip to content

Commit

Permalink
Fix possible stack overflow crash on Windows.
Browse files Browse the repository at this point in the history
  • Loading branch information
john-preston committed Sep 28, 2022
1 parent 14cc3ff commit d5ec7cc
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
35 changes: 33 additions & 2 deletions ui/widgets/time_input.cpp
Expand Up @@ -7,6 +7,7 @@
#include "ui/widgets/time_input.h"

#include "ui/widgets/fields/time_part_input.h"
#include "base/invoke_queued.h"

#include <QtCore/QRegularExpression>
#include <QTime>
Expand Down Expand Up @@ -146,7 +147,7 @@ void TimeInput::putNext(const object_ptr<TimePart> &field, QChar ch) {
field->setCursorPosition(1);
}
field->onTextEdited();
field->setFocus();
setFocusQueued(field);
}

void TimeInput::erasePrevious(const object_ptr<TimePart> &field) {
Expand All @@ -155,7 +156,37 @@ void TimeInput::erasePrevious(const object_ptr<TimePart> &field) {
field->setCursorPosition(text.size() - 1);
field->setText(text.mid(0, text.size() - 1));
}
field->setFocus();
setFocusQueued(field);
}

void TimeInput::setFocusQueued(const object_ptr<TimePart> &field) {
// There was a "Stack Overflow" crash in some input method handling.
//
// See https://github.com/telegramdesktop/tdesktop/issues/25129
//
// The stack is something like:
//
// ...
// QApplicationPrivate::sendMouseEvent
// ----
// QWidget::setFocus
// QWindow::focusObjectChanged
// QWindowsInputContext::setFocusObject
// QWindowsInputContext::reset
// QLineEdit::inputMethodEvent
// QWidgetLineControl::finishChange
// QLineEdit::textEdited
// MaskedInputField::onTextEdited
// TimePart::correctValue
// TimeInput::putNext
// ----
// QWidget::setFocus
// QWindow::focusObjectChanged
// ...
//
// So we try to break this loop by focusing the widget async.
const auto raw = field.data();
InvokeQueued(raw, [raw] { raw->setFocus(); });
}

bool TimeInput::setFocusFast() {
Expand Down
1 change: 1 addition & 0 deletions ui/widgets/time_input.h
Expand Up @@ -43,6 +43,7 @@ class TimeInput final : public RpWidget {
void setInnerFocus();
void putNext(const object_ptr<TimePart> &field, QChar ch);
void erasePrevious(const object_ptr<TimePart> &field);
void setFocusQueued(const object_ptr<TimePart> &field);
void setErrorShown(bool error);
void setFocused(bool focused);
void startBorderAnimation();
Expand Down

0 comments on commit d5ec7cc

Please sign in to comment.