Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-21378

Infinite recursion while dragging toolbar of QMainWindow

    XMLWordPrintable

Details

    • 90b71dc0ff4ec9bb150a0de9933d6eb06d995a34 (4.8)

    Description

      Hi,

      We found a problem in QMainWindowLayout (Qt 4.6.3) that occurs when dragging QToolbars. We have the special situation that we use a resized image of the toolbar for dragging. This is done in our style by enlarging the BoundingRect when the test for the click position happens, so even positions outside the header will cause a drag operation.

      Since Qt automatically resizes the dragged toolbar, the mouse pointer may be outside the toolbar area while dragging (only the header area guarantees that the mouse pointer stays over the toolbar in spite of the resize). This causes an infinite recursion as soon as the release happens, if and only if the mouse pointer is over the main window:

      QtGuid4.dll!QMainWindowLayout::animationFinished(QWidget * widget=0x0c19b628) Line 1630 C++
      ...
      QtGuid4.dll!QMainWindowLayout::setGeometry(const QRect & _r=

      {...}) Line 1474 C++
      ...
      QtGuid4.dll!QMainWindowLayout::animationFinished(QWidget * widget=0x0c19b628) Line 1630 C++
      ... and so on (complete call stack below).

      This is only possible because in QMainWindowLayout::endSeparatorMove the saved state is cleared even if movingSeparator.isEmpty(). As a consequence, in QMainWindowLayout::setGeometry the state is invalid again and another call of "applyState" happens. This indirectly calls animationFinished, where all begins again.

      This can be fixed by avoiding the call of savedState.clear() in QMainWindowLayout::endSeparatorMove in case movingSeparator.isEmpty() (just like it is done in startSeparatorMove and separatorMove):
      bool QMainWindowLayout::endSeparatorMove(const QPoint&)
      {
      -    bool result = !movingSeparator.isEmpty();
      +    if (movingSeparator.isEmpty())
      +        return false;
          movingSeparator.clear();
          savedState.clear();
          return true;
      }
      


      Another, solution to avoid the inifinite recursion is by modifying animationFinished by moving the line "pluggingWidget=0;" above the call of "plug".
      *** src/gui/widgets/qmainwindowlayout.cpp	Wed Jun 02 04:03:16 2010
      --- src/gui/widgets/qmainwindowlayout.cpp	Thu Sep 08 16:25:36 2011
      ***************
      *** 1617,1622 ****
      --- 1617,1623 ----
        #endif
        
            if (widget == pluggingWidget) {
      +         pluggingWidget = 0;
        
        #ifndef QT_NO_DOCKWIDGET
                if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget))
      ***************
      *** 1629,1635 ****
        
                savedState.clear();
                currentGapPos.clear();
      -         pluggingWidget = 0;
                //applying the state will make sure that the currentGap is updated correctly
                //and all the geometries (especially the one from the central widget) is correct
                layoutState.apply(false);
      --- 1630,1635 ----
      


      This avoids that when animationFinished is called the next time, the condition (widget==pluggingWidget) will be false so "plug" isn't called again.


      The complete call stack for one recursion:

      QtGuid4.dll!QMainWindowLayout::animationFinished(QWidget * widget=0x0c19b628) Line 1630 C++
      QtGuid4.dll!QWidgetAnimator::abort(QWidget * w=0x0c19b628) Line 69 C++
      QtGuid4.dll!QWidgetAnimator::animationFinished() Line 76 C++
      QtGuid4.dll!QWidgetAnimator::qt_metacall(QMetaObject::Call _c=InvokeMetaMethod, int _id=0, void * * _a=0x000345f0) Line 75 C++
      QtCored4.dll!QMetaObject::metacall(QObject * object=0x0c31b678, QMetaObject::Call cl=InvokeMetaMethod, int idx=4, void * * argv=0x000345f0) Line 238 C++
      QtCored4.dll!QMetaObject::activate(QObject * sender=0x0e97bef8, const QMetaObject * m=0x67290c10, int local_signal_index=0, void * * argv=0x00000000) Line 3287 + 0x27 bytes C++
      QtCored4.dll!QAbstractAnimation::finished() Line 176 + 0x12 bytes C++
      QtCored4.dll!QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState=Stopped) Line 412 C++
      QtCored4.dll!QAbstractAnimation::stop() Line 760 C++
      QtCored4.dll!QAbstractAnimation::setCurrentTime(int msecs=0) Line 718 C++
      QtCored4.dll!QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState=Running) Line 397 C++
      QtCored4.dll!QAbstractAnimation::start(QAbstractAnimation::DeletionPolicy policy=DeleteWhenStopped) Line 743 C++
      QtGuid4.dll!QWidgetAnimator::animate(QWidget * widget=0x0c19b628, const QRect & _final_geometry={...}

      , bool animate=false) Line 110 C++
      QtGuid4.dll!QToolBarAreaLayout::apply(bool animate=false) Line 931 C++
      QtGuid4.dll!QMainWindowLayoutState::apply(bool animated=false) Line 235 C++
      QtGuid4.dll!QMainWindowLayout::applyState(QMainWindowLayoutState & newState=

      {...}, bool animate=false) Line 1926 C++
      QtGuid4.dll!QMainWindowLayout::setGeometry(const QRect & _r={...}

      ) Line 1474 C++
      QtGuid4.dll!QLayoutPrivate::doResize(const QSize & r=

      {...}) Line 683 C++
      QtGuid4.dll!QLayout::activate() Line 1261 C++
      QtGuid4.dll!QWidget::setVisible(bool visible=true) Line 7420 C++
      QtGuid4.dll!QWidget::show() Line 485 + 0x16 bytes C++
      QtGuid4.dll!QToolBarPrivate::setWindowState(bool floating=false, bool unplug=false, const QRect & rect={...}

      ) Line 187 C++
      QtGuid4.dll!QToolBarPrivate::plug(const QRect & r=

      {...}

      ) Line 408 C++
      QtGuid4.dll!QMainWindowLayout::animationFinished(QWidget * widget=0x0c19b628) Line 1630 C++

      Note that for reproducing the problem one must try to drag the toolbar quickly several times.
      Could you please add these or similar corrections in a future version.

      Best regards,
      Joachim

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            maheikki Markku Tapio Heikkilä (Inactive)
            joachim Joachim Eibl
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes