vcl/inc/qt5/QtFrame.hxx |    1 
 vcl/qt5/QtFrame.cxx     |   80 ++++++++++++++++++++++++++++++++++++++++++------
 vcl/qt5/QtWidget.cxx    |    6 +++
 3 files changed, 77 insertions(+), 10 deletions(-)

New commits:
commit b00a68a8e19370e106cd76258a3c1825f43613ee
Author:     Jan-Marek Glogowski <glo...@fbihome.de>
AuthorDate: Sun Oct 31 02:33:46 2021 +0200
Commit:     Jan-Marek Glogowski <glo...@fbihome.de>
CommitDate: Sun Oct 31 21:04:33 2021 +0100

    tdf#145363 Qt reparent modal dialogs on show
    
    Simply said, one can't have two modal dialogs open at the same
    parent in Qt. All modal windows must open as a stack, each
    parented to the previous one. This is kind of logical.
    
    Unexpectedly Qt totally breaks, if you open two modal dialogs on
    the same window. This happens, because the existing paragraph
    style dialog and the "sub" "list style" dialog are both children
    of their Writer window.
    
    I'm not sure the additionally introduced QWidget-based parent
    handling is strictly needed. It seems Ok.
    
    So for every visibility and modality change, we reparent the
    Qt widget, either on top of the modal stack or restore the
    original LO-based parent. The LO hierachy is never changed!
    
    Change-Id: Id209c9aa67774440089dc50a6648ac293950087a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124500
    Tested-by: Jenkins
    Reviewed-by: Jan-Marek Glogowski <glo...@fbihome.de>

diff --git a/vcl/inc/qt5/QtFrame.hxx b/vcl/inc/qt5/QtFrame.hxx
index 23c92d7e1da3..a338b106eaeb 100644
--- a/vcl/inc/qt5/QtFrame.hxx
+++ b/vcl/inc/qt5/QtFrame.hxx
@@ -132,6 +132,7 @@ class VCLPLUG_QT_PUBLIC QtFrame : public QObject, public 
SalFrame
     void SetWindowStateImpl(Qt::WindowStates eState);
 
     void fixICCCMwindowGroup();
+    void modalReparent(bool bVisible);
 
 public:
     QtFrame(QtFrame* pParent, SalFrameStyleFlags nSalFrameStyle, bool 
bUseCairo);
diff --git a/vcl/qt5/QtFrame.cxx b/vcl/qt5/QtFrame.cxx
index 73bdad874552..1ae4016d589d 100644
--- a/vcl/qt5/QtFrame.cxx
+++ b/vcl/qt5/QtFrame.cxx
@@ -417,24 +417,71 @@ void QtFrame::DrawMenuBar() { /* not needed */}
 
 void QtFrame::SetExtendedFrameStyle(SalExtStyle /*nExtStyle*/) { /* not needed 
*/}
 
+void QtFrame::modalReparent(bool bVisible)
+{
+#ifndef NDEBUG
+    auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance));
+    assert(pSalInst);
+    assert(pSalInst->IsMainThread());
+    assert(!asChild()->isVisible());
+    assert(asChild()->isModal());
+#endif
+
+    if (!bVisible)
+    {
+        m_pQWidget->setParent(m_pParent ? m_pParent->asChild() : nullptr,
+                              m_pQWidget->windowFlags());
+        return;
+    }
+
+    if (!QGuiApplication::modalWindow())
+        return;
+
+    QtInstance* pInst = static_cast<QtInstance*>(GetSalData()->m_pInstance);
+    for (auto* pFrame : pInst->getFrames())
+    {
+        QWidget* pQWidget = static_cast<QtFrame*>(pFrame)->asChild();
+        if (pQWidget->windowHandle() == QGuiApplication::modalWindow())
+        {
+            m_pQWidget->setParent(pQWidget, m_pQWidget->windowFlags());
+            break;
+        }
+    }
+}
+
 void QtFrame::Show(bool bVisible, bool bNoActivate)
 {
     assert(m_pQWidget);
     if (bVisible == asChild()->isVisible())
         return;
 
+    auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance));
+    assert(pSalInst);
+
+    if (!bVisible) // hide
+    {
+        pSalInst->RunInMainThread([this]() {
+            asChild()->hide();
+            if (m_pQWidget->isModal())
+                modalReparent(false);
+        });
+        return;
+    }
+
+    // show
     SetDefaultSize();
     SetDefaultPos();
 
-    auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance));
-    assert(pSalInst);
-    pSalInst->RunInMainThread([this, bVisible, bNoActivate]() {
-        asChild()->setVisible(bVisible);
-        asChild()->raise();
+    pSalInst->RunInMainThread([this, bNoActivate]() {
+        QWidget* const pChild = asChild();
+        if (m_pQWidget->isModal())
+            modalReparent(true);
+        pChild->show();
+        pChild->raise();
         if (!bNoActivate && !isPopup())
         {
-            asChild()->activateWindow();
-            asChild()->setFocus();
+            pChild->activateWindow();
+            pChild->setFocus();
         }
     });
 }
@@ -610,7 +657,7 @@ SalFrame* QtFrame::GetParent() const { return m_pParent; }
 
 void QtFrame::SetModal(bool bModal)
 {
-    if (!isWindow())
+    if (!isWindow() || asChild()->isModal() == bModal)
         return;
 
     auto* pSalInst(static_cast<QtInstance*>(GetSalData()->m_pInstance));
@@ -622,12 +669,20 @@ void QtFrame::SetModal(bool bModal)
 
         // modality change is only effective if the window is hidden
         if (bWasVisible)
+        {
             pChild->hide();
+            if (!bModal)
+                modalReparent(false);
+        }
 
         pChild->setWindowModality(bModal ? Qt::WindowModal : Qt::NonModal);
 
         if (bWasVisible)
+        {
+            if (bModal)
+                modalReparent(true);
             pChild->show();
+        }
     });
 }
 
@@ -1180,7 +1235,14 @@ void QtFrame::SimulateKeyPress(sal_uInt16 nKeyCode)
     SAL_WARN("vcl.qt", "missing simulate keypress " << nKeyCode);
 }
 
-void QtFrame::SetParent(SalFrame* pNewParent) { m_pParent = 
static_cast<QtFrame*>(pNewParent); }
+void QtFrame::SetParent(SalFrame* pNewParent)
+{
+    if (m_pParent == pNewParent)
+        return;
+    m_pParent = static_cast<QtFrame*>(pNewParent);
+    if (!m_pTopLevel)
+        m_pQWidget->setParent(m_pParent->asChild(), m_pQWidget->windowFlags());
+}
 
 void QtFrame::SetPluginParent(SystemParentData* /*pNewParent*/)
 {
diff --git a/vcl/qt5/QtWidget.cxx b/vcl/qt5/QtWidget.cxx
index 44952f9318b0..85bcd814b03a 100644
--- a/vcl/qt5/QtWidget.cxx
+++ b/vcl/qt5/QtWidget.cxx
@@ -23,6 +23,7 @@
 #include <QtFrame.hxx>
 #include <QtGraphics.hxx>
 #include <QtInstance.hxx>
+#include <QtMainWindow.hxx>
 #include <QtSvpGraphics.hxx>
 #include <QtTransferable.hxx>
 #include <QtTools.hxx>
@@ -616,7 +617,10 @@ void QtWidget::focusOutEvent(QFocusEvent*)
 }
 
 QtWidget::QtWidget(QtFrame& rFrame, Qt::WindowFlags f)
-    : QWidget(Q_NULLPTR, f)
+    : QWidget(!rFrame.GetTopLevelWindow() && rFrame.GetParent()
+                  ? static_cast<QtFrame*>(rFrame.GetParent())->asChild()
+                  : Q_NULLPTR,
+              f)
     , m_rFrame(rFrame)
     , m_bNonEmptyIMPreeditSeen(false)
     , m_nDeltaX(0)

Reply via email to