Close editors on session destructions.

This commit is contained in:
John Preston
2026-06-15 16:41:35 +04:00
parent f7c2ff3896
commit a47aad46ac
3 changed files with 70 additions and 0 deletions
@@ -46,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "iv/iv_delegate_impl.h"
#include "iv/iv_instance.h"
#include "iv/iv_data.h"
#include "iv/editor/iv_editor_session.h"
#include "lang/lang_translator.h"
#include "lang/lang_cloud_manager.h"
#include "lang/lang_hardcoded.h"
@@ -214,6 +215,7 @@ void Application::closeAdditionalWindows() {
}
}
_iv->closeAll();
Iv::Editor::CloseAllWindows();
}
Application::~Application() {
@@ -983,6 +983,7 @@ private:
void showWindow() {
_backgroundHold = shared_from_this();
registerLiveAndTrackSession();
auto descriptor = ShowWindowDescriptor{
.session = _session,
.peer = _peer,
@@ -1039,6 +1040,63 @@ private:
}
}
public:
static void CloseAll() {
auto live = std::vector<std::weak_ptr<ArticleSession>>();
std::swap(live, Live());
for (const auto &weak : live) {
if (const auto strong = weak.lock()) {
strong->forceClose();
}
}
}
private:
// Registry of all editor sessions that currently own a window, so that
// they can be force-closed on session clear or application shutdown.
[[nodiscard]] static std::vector<std::weak_ptr<ArticleSession>> &Live() {
static auto result = std::vector<std::weak_ptr<ArticleSession>>();
return result;
}
void registerLiveAndTrackSession() {
auto &live = Live();
live.erase(
std::remove_if(
live.begin(),
live.end(),
[](const std::weak_ptr<ArticleSession> &weak) {
return weak.expired();
}),
live.end());
live.push_back(weak_from_this());
_session->data().sessionDataAboutToBeCleared(
) | rpl::on_next([weak = weak_from_this()] {
// Holds a strong reference for the duration of the call, so that
// dropping the self-hold inside forceClose() doesn't run
// ~ArticleSession re-entrantly while this handler is on the stack.
if (const auto strong = weak.lock()) {
strong->forceClose();
}
}, _lifetime);
}
// Destroys the editor window synchronously and releases the self-hold.
// The caller must hold a strong reference (see CloseAll() and the session
// clear handler) so that the eventual ~ArticleSession runs after this
// returns rather than re-entrantly.
void forceClose() {
if (!_windowHost && !_backgroundHold) {
return;
}
_editor = nullptr;
_submitButton = nullptr;
_windowHost = nullptr;
_editorShow = nullptr;
_backgroundHold = nullptr;
}
void handleMediaDialogResult(
QPointer<Widget> editor,
FileDialog::OpenResult &&result) {
@@ -1931,4 +1989,8 @@ void ShowEditBox(
});
}
void CloseAllWindows() {
ArticleSession::CloseAll();
}
} // namespace Iv::Editor
@@ -29,4 +29,10 @@ void ShowEditBox(
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item);
// Synchronously destroys all open editor windows. Called on application
// shutdown (before ~Sandbox) so that no editor top-level widget survives
// to be destroyed from ~QApplication, where the lib_ui native event filter
// would re-enter the already destroyed Sandbox machinery and crash.
void CloseAllWindows();
} // namespace Iv::Editor