vcl/inc/qt5/QtWidget.hxx |    3 +++
 vcl/qt5/QtFrame.cxx      |    5 +++--
 vcl/qt5/QtWidget.cxx     |   18 +++++++++++++-----
 3 files changed, 19 insertions(+), 7 deletions(-)

New commits:
commit a174fe91987160c0d57099d0aaf49dcc8e036f5b
Author:     Jan-Marek Glogowski <glo...@fbihome.de>
AuthorDate: Wed Apr 6 18:59:10 2022 +0200
Commit:     Jan-Marek Glogowski <glo...@fbihome.de>
CommitDate: Fri Apr 8 08:19:42 2022 +0200

    tdf#143135 Qt break recursive IM QueryCursorRect
    
    To reproduce the Impress crash, you need an IM, e.g. fcitx / ibus.
    This is triggered by having an active input, like double-clicking
    one of a presentations text fields, then leaving the window and
    switching back to it.
    
    This results in a stack exhaustion in a few seconds. The backtrace
    is basically:
    
    QWidget::setFocus
    QtFrame::ToTop
    sd::Window::GrabFocus
    ImplHandleExtTextInputPos
    QtWidget::inputMethodQuery
    QInputMethod::cursorRectangle
    QWidget::setFocus
    QApplication::setActiveWindow
    QtInstance::DoYield
    main
    
    I scratched my head over the longer backtrace for while, but there
    seems to be no good way to prevent this from LO's POV. The only
    alternative from the Qt VCL plugin is QtFrame::ToTop. That code
    is less ugly (no mutable or cached result), but QtWidget::
    inputMethodQuery is earlier in the backtrace.
    
    Change-Id: Ief3a8e44bca295cc676e75050d52d70a1da98a88
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132643
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Reviewed-by: Jan-Marek Glogowski <glo...@fbihome.de>
    (cherry picked from commit e81385277c091dabb1f6542a94229d7dcc77289b)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132612

diff --git a/vcl/inc/qt5/QtWidget.hxx b/vcl/inc/qt5/QtWidget.hxx
index 801cd290ff88..e2a22d3c9f18 100644
--- a/vcl/inc/qt5/QtWidget.hxx
+++ b/vcl/inc/qt5/QtWidget.hxx
@@ -19,6 +19,7 @@
 
 #pragma once
 
+#include <QtCore/QRect>
 #include <QtWidgets/QWidget>
 #include <rtl/ustring.hxx>
 
@@ -36,6 +37,8 @@ class QtWidget : public QWidget
 
     QtFrame& m_rFrame;
     bool m_bNonEmptyIMPreeditSeen;
+    mutable bool m_bInInputMethodQueryCursorRectangle;
+    mutable QRect m_aImCursorRectangle;
     int m_nDeltaX;
     int m_nDeltaY;
 
diff --git a/vcl/qt5/QtFrame.cxx b/vcl/qt5/QtFrame.cxx
index ad9c03d0bfa1..bcd95494dabd 100644
--- a/vcl/qt5/QtFrame.cxx
+++ b/vcl/qt5/QtFrame.cxx
@@ -795,8 +795,9 @@ void QtFrame::ToTop(SalFrameToTop nFlags)
         pWidget->activateWindow();
     else if ((nFlags & SalFrameToTop::GrabFocus) || (nFlags & 
SalFrameToTop::GrabFocusOnly))
     {
-        pWidget->activateWindow();
-        pWidget->setFocus();
+        if (!(nFlags & SalFrameToTop::GrabFocusOnly))
+            pWidget->activateWindow();
+        pWidget->setFocus(Qt::OtherFocusReason);
     }
 }
 
diff --git a/vcl/qt5/QtWidget.cxx b/vcl/qt5/QtWidget.cxx
index 86431a3488b1..ab8bf2dc0017 100644
--- a/vcl/qt5/QtWidget.cxx
+++ b/vcl/qt5/QtWidget.cxx
@@ -623,6 +623,7 @@ QtWidget::QtWidget(QtFrame& rFrame, Qt::WindowFlags f)
     : QWidget(Q_NULLPTR, f)
     , m_rFrame(rFrame)
     , m_bNonEmptyIMPreeditSeen(false)
+    , m_bInInputMethodQueryCursorRectangle(false)
     , m_nDeltaX(0)
     , m_nDeltaY(0)
 {
@@ -796,11 +797,18 @@ QVariant QtWidget::inputMethodQuery(Qt::InputMethodQuery 
property) const
         }
         case Qt::ImCursorRectangle:
         {
-            const qreal fRatio = m_rFrame.devicePixelRatioF();
-            SalExtTextInputPosEvent aPosEvent;
-            m_rFrame.CallCallback(SalEvent::ExtTextInputPos, &aPosEvent);
-            return QVariant(QRect(aPosEvent.mnX / fRatio, aPosEvent.mnY / 
fRatio,
-                                  aPosEvent.mnWidth / fRatio, 
aPosEvent.mnHeight / fRatio));
+            if (!m_bInInputMethodQueryCursorRectangle)
+            {
+                m_bInInputMethodQueryCursorRectangle = true;
+                SalExtTextInputPosEvent aPosEvent;
+                m_rFrame.CallCallback(SalEvent::ExtTextInputPos, &aPosEvent);
+                const qreal fRatio = m_rFrame.devicePixelRatioF();
+                m_aImCursorRectangle.setRect(aPosEvent.mnX / fRatio, 
aPosEvent.mnY / fRatio,
+                                             aPosEvent.mnWidth / fRatio,
+                                             aPosEvent.mnHeight / fRatio);
+                m_bInInputMethodQueryCursorRectangle = false;
+            }
+            return QVariant(m_aImCursorRectangle);
         }
         case Qt::ImAnchorPosition:
         {

Reply via email to