Make console destruction more deterministic

This fixes a crash on Linux when exiting the editor. It was caused by
C4Console::~C4Console being called by the C++ runtime after after main()
returned. The C4Console destructor then goes and deletes all the Qt
resources (QApplication and friends), and that caused a segfault, maybe
because some of the static Qt structures have already been deallocated.

Fix this by making the destruction of the Qt components deterministic. Add
a function "DeleteConsoleWindow" which deletes all the Qt components, and
call this function in C4Console::Clear.
console-destruction
Armin Burgmeier 2016-09-30 22:59:39 -10:00
parent a56d2fecdb
commit 2d324c10e0
7 changed files with 65 additions and 2 deletions

View File

@ -368,15 +368,18 @@ void C4Console::Default()
void C4Console::Clear() void C4Console::Clear()
{ {
if (pSurface) delete pSurface;
pSurface = 0;
C4Window::Clear(); C4Window::Clear();
C4ConsoleGUI::DeleteConsoleWindow();
EditCursor.Clear(); EditCursor.Clear();
ToolsDlg.Clear(); ToolsDlg.Clear();
PropertyDlgClose(); PropertyDlgClose();
ClearViewportMenu(); ClearViewportMenu();
ClearPlayerMenu(); ClearPlayerMenu();
ClearNetMenu(); ClearNetMenu();
if (pSurface) delete pSurface;
pSurface = 0;
#ifndef _WIN32 #ifndef _WIN32
Application.Quit(); Application.Quit();
#endif #endif
@ -622,6 +625,7 @@ bool C4ConsoleGUI::CreateConsoleWindow(C4AbstractApp * pApp)
return false; return false;
return true; return true;
} }
void C4ConsoleGUI::DeleteConsoleWindow() {}
void C4ConsoleGUI::DisplayInfoText(C4ConsoleGUI::InfoTextType, StdStrBuf&) {} void C4ConsoleGUI::DisplayInfoText(C4ConsoleGUI::InfoTextType, StdStrBuf&) {}
void C4ConsoleGUI::DoEnableControls(bool) {} void C4ConsoleGUI::DoEnableControls(bool) {}
bool C4ConsoleGUI::DoUpdateHaltCtrls(bool) {return 0;} bool C4ConsoleGUI::DoUpdateHaltCtrls(bool) {return 0;}

View File

@ -73,6 +73,10 @@ bool C4ConsoleGUI::CreateConsoleWindow(C4AbstractApp *application)
return true; return true;
} }
void C4ConsoleGUI::DeleteConsoleWindow()
{
}
void C4ConsoleGUI::Out(const char* message) void C4ConsoleGUI::Out(const char* message)
{ {
C4EditorWindowController* controller = ctrler(this); C4EditorWindowController* controller = ctrler(this);

View File

@ -123,6 +123,7 @@ public:
void SetInputFunctions(std::list<const char*> &functions); void SetInputFunctions(std::list<const char*> &functions);
bool CreateConsoleWindow(C4AbstractApp *application); bool CreateConsoleWindow(C4AbstractApp *application);
void DeleteConsoleWindow();
void Out(const char* message); void Out(const char* message);
bool ClearLog(); bool ClearLog();
void DisplayInfoText(InfoTextType type, StdStrBuf& text); void DisplayInfoText(InfoTextType type, StdStrBuf& text);

View File

@ -90,6 +90,15 @@ bool C4ConsoleGUI::CreateConsoleWindow(C4AbstractApp *application)
return true; return true;
} }
void C4ConsoleGUI::DeleteConsoleWindow()
{
if (Active)
{
state->DeleteConsoleWindow();
Active = false;
}
}
void C4ConsoleGUI::Out(const char* message) void C4ConsoleGUI::Out(const char* message)
{ {
// Log text: Add to log window // Log text: Add to log window

View File

@ -734,6 +734,46 @@ bool C4ConsoleGUIState::CreateConsoleWindow(C4AbstractApp *app)
return true; return true;
} }
void C4ConsoleGUIState::DeleteConsoleWindow()
{
// Reset to a state before CreateConsoleWindow was called
action_object = C4VNull;
is_object_selection_updating = false;
editcursor_mode = C4CNS_ModePlay;
drawing_tool = C4TLS_Brush;
landscape_mode = LandscapeMode::Dynamic;
net_enabled = false;
recording = false;
enabled = false;
window_menu_separator = nullptr;
status_cursor = status_framecounter = status_timefps = nullptr;
while (!viewports.empty())
{
auto vp = viewports.front();
viewports.erase(viewports.begin());
vp->deleteLater();
viewport_area->removeDockWidget(vp);
}
client_actions.clear();
player_actions.clear();
viewport_actions.clear();
viewport_area = nullptr;
disable_shortcut_filter.reset(nullptr);
definition_list_model.reset(nullptr);
object_list_model.reset(nullptr);
property_name_delegate.reset(nullptr);
property_delegate_factory.reset(nullptr);
property_model.reset(nullptr);
window.reset(nullptr);
application.reset(nullptr);
}
void C4ConsoleGUIState::Execute(bool redraw_only) void C4ConsoleGUIState::Execute(bool redraw_only)
{ {
// Nothing to do - Qt's event loop is handling everything. // Nothing to do - Qt's event loop is handling everything.

View File

@ -220,6 +220,7 @@ public:
void AddToolbarSpacer(int space); void AddToolbarSpacer(int space);
bool CreateConsoleWindow(C4AbstractApp *app); bool CreateConsoleWindow(C4AbstractApp *app);
void DeleteConsoleWindow();
void Execute(bool redraw_only=false); void Execute(bool redraw_only=false);
void Redraw() { Execute(true); } void Redraw() { Execute(true); }
void UpdateActionStates(); void UpdateActionStates();

View File

@ -830,6 +830,10 @@ bool C4ConsoleGUI::CreateConsoleWindow(C4AbstractApp *application)
return true; return true;
} }
void C4ConsoleGUI::DeleteConsoleWindow()
{
}
void C4ConsoleGUI::DoEnableControls(bool fEnable) void C4ConsoleGUI::DoEnableControls(bool fEnable)
{ {
// Set button images (edit modes & halt controls) // Set button images (edit modes & halt controls)