From a653603facde16a475f299428647efb04971e10a Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Mon, 6 Sep 2021 22:06:20 +0200 Subject: [PATCH] UI: Avoid the segfault on MainWindow destruction We destroy the log console before the final flush, take that into account => disable handle message for the ConsoleLogSinkDispatcher if the corresponding LogConsole was destroyed. This is a quick and dirty solution, but I don't know any other way for now! --- src/Lib/Log.hh | 7 ------- src/UI/LogConsole.cc | 45 +++++++++++++++++++++++++++++++++++++----- src/UI/LogConsole.hh | 35 ++++++++++++++++++++++++++++---- src/VivyApplication.cc | 6 ++++-- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/Lib/Log.hh b/src/Lib/Log.hh index 063187a9..428fb358 100644 --- a/src/Lib/Log.hh +++ b/src/Lib/Log.hh @@ -197,13 +197,6 @@ public: return dispatch; } - template <Derived<LogSinkDispatcher> DispatcherType, typename... Args> - DispatcherType *newUnmanagedDispatcher(Args &&...args) noexcept - { - DispatcherType *dispatch = new DispatcherType(std::forward<Args>(args)...); - return dispatch; - } - std::shared_ptr<Logger> newLogger(const StringType auto &category) noexcept { std::shared_ptr<Logger> logger = std::make_shared<Logger>(this, category); diff --git a/src/UI/LogConsole.cc b/src/UI/LogConsole.cc index 7428a1a6..18363b67 100644 --- a/src/UI/LogConsole.cc +++ b/src/UI/LogConsole.cc @@ -2,9 +2,29 @@ using namespace Vivy; -ConsoleLogSinkDispatcher::ConsoleLogSinkDispatcher(QWidget *parent) noexcept +ConsoleLogSinkDispatcher::ConsoleLogSinkDispatcher() noexcept : LogSinkDispatcher(std::string_view{ "console" }) - , QListWidget(parent) +{ +} + +void +ConsoleLogSinkDispatcher::handleLogMessage(const std::string_view strv, + const LogMessage &msg) noexcept +{ + if (console) + console->handleLogMessage(strv, msg); +} + +void +ConsoleLogSinkDispatcher::attachLogConsole(LogConsole *widget) noexcept +{ + console = widget; + if (widget) + widget->setDispatcher(shared_from_this()); +} + +LogConsole::LogConsole(QWidget *parent) noexcept + : QListWidget(parent) { setSortingEnabled(false); setSelectionMode(QAbstractItemView::NoSelection); @@ -13,8 +33,24 @@ ConsoleLogSinkDispatcher::ConsoleLogSinkDispatcher(QWidget *parent) noexcept setStyleSheet(style); } +LogConsole::~LogConsole() noexcept +{ + if (auto parentDispatcher = dispatcher.lock()) { + qDebug() << "Reset parent LogConsole pointer"; + parentDispatcher->attachLogConsole(nullptr); + } else { + qCritical() << "Failed to reset LogConsole from parent"; + } +} + void -ConsoleLogSinkDispatcher::setMessageCountLimit(int limit) +LogConsole::setDispatcher(std::shared_ptr<ConsoleLogSinkDispatcher> ptr) noexcept +{ + dispatcher = std::weak_ptr<ConsoleLogSinkDispatcher>(ptr); +} + +void +LogConsole::setMessageCountLimit(int limit) { if (limit <= 0) throw std::logic_error("Can't pass a negative count!"); @@ -22,8 +58,7 @@ ConsoleLogSinkDispatcher::setMessageCountLimit(int limit) } void -ConsoleLogSinkDispatcher::handleLogMessage(const std::string_view cat, - const LogMessage &msg) noexcept +LogConsole::handleLogMessage(const std::string_view cat, const LogMessage &msg) noexcept { while (count() >= messageLimit) { QListWidgetItem *itemWidget = item(0); diff --git a/src/UI/LogConsole.hh b/src/UI/LogConsole.hh index 2525f10e..a388e330 100644 --- a/src/UI/LogConsole.hh +++ b/src/UI/LogConsole.hh @@ -5,15 +5,42 @@ namespace Vivy { -class ConsoleLogSinkDispatcher final : public LogSinkDispatcher, public QListWidget { - VIVY_UNMOVABLE_OBJECT(ConsoleLogSinkDispatcher) +class LogConsole; +class ConsoleLogSinkDispatcher; + +class LogConsole final : public QListWidget { + VIVY_UNMOVABLE_OBJECT(LogConsole) int messageLimit{ 1'000 }; + std::weak_ptr<ConsoleLogSinkDispatcher> dispatcher; public: - explicit ConsoleLogSinkDispatcher(QWidget *parent = nullptr) noexcept; - void handleLogMessage(const std::string_view, const LogMessage &) noexcept override; + LogConsole(QWidget *parent = nullptr) noexcept; + ~LogConsole() noexcept override; void setMessageCountLimit(int limit); + void handleLogMessage(const std::string_view, const LogMessage &) noexcept; + + // Hacky boi to set the `LogConsole *` in the dispatcher to nullptr when + // the `LogConsole` is destroyed. + void setDispatcher(std::shared_ptr<ConsoleLogSinkDispatcher> ptr) noexcept; +}; + +// Log console dispatcher, this is a proxy for the LogConsole which is the real +// widget, we don't directly set the dispatcher being the widget because the +// QDockWidget will demete its child on destruction, but the dispatcher is +// already managed by the std::shared_ptr... +class ConsoleLogSinkDispatcher final + : public LogSinkDispatcher, + public std::enable_shared_from_this<ConsoleLogSinkDispatcher> { + VIVY_UNMOVABLE_OBJECT(ConsoleLogSinkDispatcher) + + LogConsole *console{ nullptr }; + +public: + explicit ConsoleLogSinkDispatcher() noexcept; + void handleLogMessage(const std::string_view, const LogMessage &) noexcept override; + + void attachLogConsole(LogConsole *const) noexcept; }; } diff --git a/src/VivyApplication.cc b/src/VivyApplication.cc index de244c0a..f511fe9d 100644 --- a/src/VivyApplication.cc +++ b/src/VivyApplication.cc @@ -84,13 +84,15 @@ VivyApplication::exec() noexcept // Show the main window, also set up the log console mainWindowPtr = std::make_shared<MainWindow>(); QDockWidget *logConsoleDock = new QDockWidget("Console", mainWindowPtr.get()); + LogConsole *logConsole = new LogConsole(mainWindowPtr.get()); std::shared_ptr<ConsoleLogSinkDispatcher> consoleLogSinkDispatcher = - logSink->newDispatcher<ConsoleLogSinkDispatcher>(nullptr); + logSink->newDispatcher<ConsoleLogSinkDispatcher>(); DockWidgetTitleBar::addToDock(logConsoleDock); + consoleLogSinkDispatcher->attachLogConsole(logConsole); logConsoleDock->setAllowedAreas(Qt::BottomDockWidgetArea); logConsoleDock->setFeatures(QDockWidget::DockWidgetMovable); - logConsoleDock->setWidget(consoleLogSinkDispatcher.get()); + logConsoleDock->setWidget(logConsole); mainWindowPtr->addDockWidget(Qt::BottomDockWidgetArea, logConsoleDock); mainWindowPtr->show(); -- GitLab