Move window relayout before inserting the window to the manager (fix #3746)

This is necessary to prevent the manager to invalidate a window whose relayout is not finished. This can happen when a script opens a new window when another is currently opening. For instance a script whose canvas.onpaint handler opens another dialog.
This commit is contained in:
Martín Capello 2023-03-30 15:44:40 -03:00 committed by David Capello
parent 636cce6f0d
commit 8841f3da32
3 changed files with 22 additions and 7 deletions

View File

@ -183,6 +183,7 @@ PreviewEditorWindow::PreviewEditorWindow()
, m_refFrame(0)
, m_aniSpeed(1.0)
, m_relatedEditor(nullptr)
, m_opening(false)
{
setAutoRemap(false);
setWantFocus(false);
@ -343,6 +344,9 @@ Editor* PreviewEditorWindow::previewEditor() const
void PreviewEditorWindow::updateUsingEditor(Editor* editor)
{
if (m_opening)
return;
if (!m_isEnabled || !editor) {
hideWindow();
m_relatedEditor = nullptr;
@ -357,8 +361,11 @@ void PreviewEditorWindow::updateUsingEditor(Editor* editor)
Doc* document = editor->document();
Editor* miniEditor = (m_docView ? m_docView->editor(): nullptr);
if (!isVisible())
if (!isVisible()) {
m_opening = true;
openWindow();
m_opening = false;
}
// Document preferences used to store the preferred zoom/scroll point
auto& docPref = Preferences::instance().document(document);

View File

@ -70,6 +70,10 @@ namespace app {
doc::frame_t m_refFrame;
double m_aniSpeed;
Editor* m_relatedEditor;
// This flag indicates that the preview editor is being opened, it is used to avoid
// an infinite recursive loop when PreviewEditorWindow::updateUsingEditor calls the
// openWindow() method.
bool m_opening;
};
} // namespace app

View File

@ -1334,6 +1334,16 @@ void Manager::_openWindow(Window* window, bool center)
freeFocus();
}
// Relayout before inserting the window to the list of children widgets prevents
// the manager to invalidate a window currently being laid out when
// ui::Manager::getDefault()->invalidate() is called. This situation could happen,
// for instance, when a script opens a dialog whose canvas.onpaint handler opens
// another dialog, because the onpaint handler is executed during window layout.
if (center)
window->centerWindow(parentDisplay);
else
window->layout();
// Add the window to manager.
insertChild(0, window);
@ -1343,12 +1353,6 @@ void Manager::_openWindow(Window* window, bool center)
window->sendMessage(&msg);
}
// Relayout
if (center)
window->centerWindow(parentDisplay);
else
window->layout();
// If the window already was set a display, we don't setup it
// (i.e. in the case of combobox popup/window the display field is
// set to the same display where the ComboBox widget is located)