forked from Mirrors/openclonk
Fix some Qt editor crashes
Fix use-after-delete on proplists by item view and crash on recursive execution of message processing.qteditor
parent
771a333e21
commit
74b3983f7f
|
@ -58,6 +58,14 @@ void C4ConsoleQtObjectListModel::Invalidate()
|
|||
emit layoutChanged();
|
||||
}
|
||||
|
||||
void C4ConsoleQtObjectListModel::OnItemRemoved(C4PropList *p)
|
||||
{
|
||||
for (auto idx : this->persistentIndexList())
|
||||
if (idx.internalPointer() == p)
|
||||
this->changePersistentIndex(idx, QModelIndex());
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void C4ConsoleQtObjectListModel::SetSelection(class C4EditCursorSelection &rSelection)
|
||||
{
|
||||
// Reflect selection change in view
|
||||
|
@ -132,12 +140,12 @@ QVariant C4ConsoleQtObjectListModel::data(const QModelIndex & index, int role) c
|
|||
else if (role == Qt::ForegroundRole)
|
||||
{
|
||||
// Deleted proplist?
|
||||
if (!data) return clr_deleted;
|
||||
if (!data) return QVariant(clr_deleted);
|
||||
// Object?
|
||||
C4Object *obj = data->GetObject();
|
||||
if (obj) return QVariant(); // default
|
||||
// Effect
|
||||
return clr_effect;
|
||||
return QVariant(clr_effect);
|
||||
}
|
||||
// Nothing to show
|
||||
return QVariant();
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
|
||||
// Refresh object list on next redraw
|
||||
void Invalidate();
|
||||
void OnItemRemoved(C4PropList *p);
|
||||
|
||||
// Callback from EditCursor when selection was changed e.g. from viewport
|
||||
void SetSelection(class C4EditCursorSelection &rSelection);
|
||||
|
|
|
@ -150,6 +150,22 @@ void C4ConsoleViewportWidget::closeEvent(QCloseEvent * event)
|
|||
}
|
||||
|
||||
|
||||
/* Recursion check to avoid some crashing Qt re-entry */
|
||||
|
||||
class ExecRecursionCheck
|
||||
{
|
||||
static int counter;
|
||||
public:
|
||||
ExecRecursionCheck() { ++counter; }
|
||||
~ExecRecursionCheck() { --counter; }
|
||||
|
||||
bool IsRecursion() const { return counter > 1; }
|
||||
};
|
||||
|
||||
int ExecRecursionCheck::counter = 0;
|
||||
|
||||
|
||||
|
||||
/* Console main window */
|
||||
|
||||
C4ConsoleQtMainWindow::C4ConsoleQtMainWindow(C4AbstractApp *app, C4ConsoleGUIState *state)
|
||||
|
@ -339,6 +355,8 @@ void C4ConsoleGUIState::AddToolbarSpacer(int space)
|
|||
|
||||
bool C4ConsoleGUIState::CreateConsoleWindow(C4AbstractApp *app)
|
||||
{
|
||||
// No Qt main loop execution during console creation
|
||||
ExecRecursionCheck no_qt_recursion;
|
||||
// Basic Qt+Main window setup from .ui file
|
||||
int fake_argc = 0;
|
||||
application.reset(new QApplication(fake_argc, NULL));
|
||||
|
@ -396,22 +414,28 @@ bool C4ConsoleGUIState::CreateConsoleWindow(C4AbstractApp *app)
|
|||
return true;
|
||||
}
|
||||
|
||||
void C4ConsoleGUIState::Execute()
|
||||
void C4ConsoleGUIState::Execute(bool redraw_only)
|
||||
{
|
||||
// Avoid recursion in message processing; it's causing random crashes
|
||||
ExecRecursionCheck recursion_check;
|
||||
if (recursion_check.IsRecursion()) return;
|
||||
// Qt window message handling and object cleanup
|
||||
if (application)
|
||||
{
|
||||
application->processEvents();
|
||||
application->sendPostedEvents(0, QEvent::DeferredDelete);
|
||||
if (redraw_only)
|
||||
{
|
||||
// process only non-critical events
|
||||
application->processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
else
|
||||
{
|
||||
// process everything
|
||||
application->processEvents();
|
||||
application->sendPostedEvents(0, QEvent::DeferredDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C4ConsoleGUIState::Redraw()
|
||||
{
|
||||
// process only non-critical events
|
||||
if (application) application->processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
|
||||
// Set action pressed/checked and enabled states
|
||||
void C4ConsoleGUIState::UpdateActionStates()
|
||||
{
|
||||
|
|
|
@ -182,8 +182,8 @@ public:
|
|||
|
||||
void AddToolbarSpacer(int space);
|
||||
bool CreateConsoleWindow(C4AbstractApp *app);
|
||||
void Execute();
|
||||
void Redraw();
|
||||
void Execute(bool redraw_only=false);
|
||||
void Redraw() { Execute(true); }
|
||||
void UpdateActionStates();
|
||||
void UpdateMatTex();
|
||||
void UpdateBackMatTex();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <C4Console.h>
|
||||
#include <C4Object.h>
|
||||
#include <C4GameObjects.h>
|
||||
#include <C4Effect.h>
|
||||
|
||||
|
||||
#ifdef USE_GTK
|
||||
|
@ -865,7 +866,7 @@ void C4ObjectListDlg::Update(C4EditCursorSelection &rSelection)
|
|||
// Could do some crazy fine-grained updates. But updating is cheap enough...
|
||||
void C4ObjectListDlg::OnObjectRemove(C4ObjectList * pList, C4ObjectLink * pLnk)
|
||||
{
|
||||
if (view_model) view_model->Invalidate();
|
||||
if (view_model) view_model->OnItemRemoved(pLnk->Obj);
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnObjectAdded(C4ObjectList * pList, C4ObjectLink * pLnk)
|
||||
|
@ -890,7 +891,7 @@ void C4ObjectListDlg::OnEffectAdded(C4Effect *fx)
|
|||
|
||||
void C4ObjectListDlg::OnEffectRemoved(C4Effect *fx)
|
||||
{
|
||||
if (view_model) view_model->Invalidate();
|
||||
if (view_model) view_model->OnItemRemoved(fx);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue