File indexing completed on 2024-04-21 16:31:17

0001 /*****************************************************************************
0002  *   Copyright 2010 Craig Drummond <craig.p.drummond@gmail.com>              *
0003  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0004  *                                                                           *
0005  *   This program is free software; you can redistribute it and/or modify    *
0006  *   it under the terms of the GNU Lesser General Public License as          *
0007  *   published by the Free Software Foundation; either version 2.1 of the    *
0008  *   License, or (at your option) version 3, or any later version accepted   *
0009  *   by the membership of KDE e.V. (or its successor approved by the         *
0010  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0011  *   Section 6 of version 3 of the license.                                  *
0012  *                                                                           *
0013  *   This program is distributed in the hope that it will be useful,         *
0014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0016  *   Lesser General Public License for more details.                         *
0017  *                                                                           *
0018  *   You should have received a copy of the GNU Lesser General Public        *
0019  *   License along with this library. If not,                                *
0020  *   see <http://www.gnu.org/licenses/>.                                     *
0021  *****************************************************************************/
0022 
0023 // Copied from oxygenwindowmanager.cpp svnversion: 1139230
0024 
0025 //////////////////////////////////////////////////////////////////////////////
0026 // windowmanager.cpp
0027 // pass some window mouse press/release/move event actions to window manager
0028 // -------------------
0029 //
0030 // Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
0031 //
0032 // Largely inspired from BeSpin style
0033 // Copyright (C) 2007 Thomas Luebking <thomas.luebking@web.de>
0034 //
0035 // Permission is hereby granted, free of charge, to any person obtaining a copy
0036 // of this software and associated documentation files (the "Software"), to
0037 // deal in the Software without restriction, including without limitation the
0038 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
0039 // sell copies of the Software, and to permit persons to whom the Software is
0040 // furnished to do so, subject to the following conditions:
0041 //
0042 // The above copyright notice and this permission notice shall be included in
0043 // all copies or substantial portions of the Software.
0044 //
0045 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0046 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0047 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0048 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0049 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0050 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
0051 // IN THE SOFTWARE.
0052 //////////////////////////////////////////////////////////////////////////////
0053 
0054 #include "windowmanager.h"
0055 #include "qtcurve.h"
0056 #include <common/common.h>
0057 #include "utils.h"
0058 
0059 #include <QProgressBar>
0060 #include <QApplication>
0061 #include <QComboBox>
0062 #include <QDialog>
0063 #include <QDockWidget>
0064 #include <QGroupBox>
0065 #include <QLabel>
0066 #include <QListView>
0067 #include <QMainWindow>
0068 #include <QMenuBar>
0069 #include <QMouseEvent>
0070 #include <QStatusBar>
0071 #include <QStyle>
0072 #include <QStyleOptionGroupBox>
0073 #include <QTabBar>
0074 #include <QTabWidget>
0075 #include <QToolBar>
0076 #include <QToolButton>
0077 #include <QTreeView>
0078 #include <QGraphicsView>
0079 
0080 #include <QTextStream>
0081 #include <QTextDocument>
0082 
0083 #ifdef QTC_QT4_ENABLE_KDE
0084 #  include <KGlobalSettings>
0085 #endif
0086 
0087 #include <qtcurve-utils/x11wmmove.h>
0088 
0089 namespace QtCurve {
0090 WindowManager::WindowManager(QObject *parent):
0091     QObject( parent),
0092     _enabled(true),
0093     _useWMMoveResize(qtcX11Enabled()),
0094     _dragMode(WM_DRAG_NONE),
0095 #ifdef QTC_QT4_ENABLE_KDE
0096     _dragDistance(KGlobalSettings::dndEventDelay()),
0097 #else
0098     _dragDistance(QApplication::startDragDistance()),
0099 #endif
0100     _dragDelay(QApplication::startDragTime()),
0101     _dragAboutToStart(false),
0102     _dragInProgress(false),
0103     _locked(false),
0104     _cursorOverride(false)
0105 {
0106     // install application wise event filter
0107     _appEventFilter = new AppEventFilter(this);
0108     qApp->installEventFilter(_appEventFilter);
0109 }
0110 
0111     //_____________________________________________________________
0112     void WindowManager::initialize( int windowDrag, const QStringList &whiteList, const QStringList &blackList )
0113     {
0114 
0115         setEnabled( windowDrag );
0116         setDragMode( windowDrag );
0117 //CPD: Why???        setUseWMMoveResize( OxygenStyleConfigData::useWMMoveResize() );
0118 
0119 #ifdef QTC_QT4_ENABLE_KDE
0120         setDragDistance( KGlobalSettings::dndEventDelay() );
0121 #endif
0122         setDragDelay( QApplication::startDragTime() );
0123 
0124         initializeWhiteList( whiteList );
0125         initializeBlackList( blackList );
0126 
0127     }
0128 
0129     void WindowManager::registerWidget( QWidget* widget )
0130     {
0131         if (isBlackListed(widget)) {
0132             /*
0133             also install filter for blacklisted widgets
0134             to be able to catch the relevant events and prevent
0135             the drag to happen
0136             */
0137             widget->installEventFilter(this);
0138         } else if (isDragable(widget)) {
0139             widget->installEventFilter(this);
0140         }
0141     }
0142 
0143     void WindowManager::unregisterWidget( QWidget* widget )
0144     {
0145         if (widget) {
0146             widget->removeEventFilter(this);
0147         }
0148     }
0149 
0150     //_____________________________________________________________
0151     void WindowManager::initializeWhiteList( const QStringList &list )
0152     {
0153         _whiteList.clear();
0154 
0155         // add user specified whitelisted classnames
0156         _whiteList.insert( ExceptionId( "MplayerWindow" ) );
0157         _whiteList.insert( ExceptionId( "ViewSliders@kmix" ) );
0158         _whiteList.insert( ExceptionId( "Sidebar_Widget@konqueror" ) );
0159 
0160         foreach (const QString& exception, list) {
0161             ExceptionId id(exception);
0162             if (!id.className().isEmpty()) {
0163                 _whiteList.insert(exception);
0164             }
0165         }
0166     }
0167 
0168     //_____________________________________________________________
0169     void WindowManager::initializeBlackList( const QStringList &list )
0170     {
0171 
0172         _blackList.clear();
0173         _blackList.insert( ExceptionId( "CustomTrackView@kdenlive" ) );
0174         _blackList.insert( ExceptionId( "MuseScore" ) );
0175         foreach (const QString& exception, list) {
0176             ExceptionId id(exception);
0177             if (!id.className().isEmpty()) {
0178                 _blackList.insert(exception);
0179             }
0180         }
0181 
0182     }
0183 
0184     //_____________________________________________________________
0185     bool WindowManager::eventFilter( QObject* object, QEvent* event )
0186     {
0187         if( !enabled() ) return false;
0188 
0189         switch ( event->type() )
0190         {
0191             case QEvent::MouseButtonPress:
0192                 return mousePressEvent( object, event );
0193             break;
0194 
0195             case QEvent::MouseMove:
0196                 if ( object == _target.data() ) return mouseMoveEvent( object, event );
0197             break;
0198 
0199             case QEvent::MouseButtonRelease:
0200                 if ( _target ) return mouseReleaseEvent( object, event );
0201             break;
0202 
0203             default:
0204             break;
0205 
0206         }
0207 
0208         return false;
0209 
0210     }
0211 
0212     //_____________________________________________________________
0213     void WindowManager::timerEvent( QTimerEvent* event )
0214     {
0215 
0216         if( event->timerId() == _dragTimer.timerId() )
0217         {
0218             _dragTimer.stop();
0219             if( _target )
0220             { startDrag( _target.data(), _globalDragPoint ); }
0221 
0222         } else {
0223 
0224             return QObject::timerEvent( event );
0225 
0226         }
0227 
0228     }
0229 
0230     //_____________________________________________________________
0231     bool WindowManager::mousePressEvent( QObject* object, QEvent* event )
0232     {
0233 
0234         // cast event and check buttons/modifiers
0235         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>( event );
0236         if( !( mouseEvent->modifiers() == Qt::NoModifier && mouseEvent->button() == Qt::LeftButton ) )
0237         { return false; }
0238 
0239         // check lock
0240         if( isLocked() ) return false;
0241         else setLocked( true );
0242 
0243         // cast to widget
0244         QWidget *widget = static_cast<QWidget*>( object );
0245 
0246         // check if widget can be dragged from current position
0247         if( isBlackListed( widget ) || !canDrag( widget ) ) return false;
0248 
0249         // retrieve widget's child at event position
0250         QPoint position( mouseEvent->pos() );
0251         QWidget* child = widget->childAt( position );
0252         if( !canDrag( widget, child, position ) ) return false;
0253 
0254         // save target and drag point
0255         _target = widget;
0256         _dragPoint = position;
0257         _globalDragPoint = mouseEvent->globalPos();
0258         _dragAboutToStart = true;
0259 
0260         // send a move event to the current child with same position
0261         // if received, it is caught to actually start the drag
0262         QPoint localPoint( _dragPoint );
0263         if( child ) localPoint = child->mapFrom( widget, localPoint );
0264         else child = widget;
0265         QMouseEvent localMouseEvent( QEvent::MouseMove, localPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
0266         qApp->sendEvent( child, &localMouseEvent );
0267 
0268         // never eat event
0269         return false;
0270 
0271     }
0272 
0273     //_____________________________________________________________
0274     bool WindowManager::mouseMoveEvent( QObject* object, QEvent* event )
0275     {
0276 
0277         Q_UNUSED( object );
0278 
0279         // stop timer
0280         if( _dragTimer.isActive() ) _dragTimer.stop();
0281 
0282         // cast event and check drag distance
0283         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>( event );
0284         if( !_dragInProgress )
0285         {
0286 
0287             if( _dragAboutToStart )
0288             {
0289                 if( mouseEvent->globalPos() == _globalDragPoint )
0290                 {
0291                     // start timer,
0292                     _dragAboutToStart = false;
0293                     if( _dragTimer.isActive() ) _dragTimer.stop();
0294                     _dragTimer.start( _dragDelay, this );
0295 
0296                 } else resetDrag();
0297 
0298             } else if( QPoint( mouseEvent->globalPos() - _globalDragPoint ).manhattanLength() >= _dragDistance )
0299             { _dragTimer.start( 0, this ); }
0300             return true;
0301 
0302         } else if( !useWMMoveResize() ) {
0303 
0304             // use QWidget::move for the grabbing
0305             /* this works only if the sending object and the target are identical */
0306             QWidget* window( _target.data()->window() );
0307             window->move( window->pos() + mouseEvent->pos() - _dragPoint );
0308             return true;
0309 
0310         } else return false;
0311 
0312     }
0313 
0314     //_____________________________________________________________
0315     bool WindowManager::mouseReleaseEvent( QObject* object, QEvent* event )
0316     {
0317         Q_UNUSED( object );
0318         Q_UNUSED( event );
0319         resetDrag();
0320         return false;
0321     }
0322 
0323     //_____________________________________________________________
0324     bool WindowManager::isDragable( QWidget* widget )
0325     {
0326 
0327         // check widget
0328         if (!widget) {
0329             return false;
0330         }
0331         // accepted default types
0332         if ((qobject_cast<QDialog*>(widget) && widget->isWindow()) ||
0333             (qobject_cast<QMainWindow*>(widget) && widget->isWindow()) ||
0334             qobject_cast<QGroupBox*>(widget)) {
0335             return true;
0336         }
0337         // more accepted types, provided they are not dock widget titles
0338         if ((qobject_cast<QMenuBar*>(widget) ||
0339              qobject_cast<QTabBar*>(widget) ||
0340              qobject_cast<QStatusBar*>(widget) ||
0341              qobject_cast<QToolBar*>(widget)) &&
0342             !isDockWidgetTitle(widget)) {
0343             return true;
0344         }
0345         if (widget->inherits("KScreenSaver") && widget->inherits("KCModule")) {
0346             return true;
0347         }
0348         if (isWhiteListed(widget)) {
0349             return true;
0350         }
0351         // flat toolbuttons
0352         if (QToolButton *toolButton = qobject_cast<QToolButton*>(widget)) {
0353             if (toolButton->autoRaise()) {
0354                 return true;
0355             }
0356         }
0357         // viewports
0358         /*
0359         one needs to check that
0360         1/ the widget parent is a scrollarea
0361         2/ it matches its parent viewport
0362         3/ the parent is not blacklisted
0363         */
0364         if (QListView *listView =
0365             qobject_cast<QListView*>(widget->parentWidget())) {
0366             if (listView->viewport() == widget && !isBlackListed(listView)) {
0367                 return true;
0368             }
0369         }
0370 
0371         if (QTreeView *treeView =
0372             qobject_cast<QTreeView*>(widget->parentWidget())) {
0373             if (treeView->viewport() == widget && !isBlackListed(treeView)) {
0374                 return true;
0375             }
0376         }
0377 
0378         //if( QGraphicsView* graphicsView = qobject_cast<QGraphicsView*>( widget->parentWidget() ) )
0379         //{ if( graphicsView->viewport() == widget && !isBlackListed( graphicsView ) ) return true; }
0380 
0381         /*
0382         catch labels in status bars.
0383         this is because of kstatusbar
0384         who captures buttonPress/release events
0385         */
0386         if (QLabel *label = qobject_cast<QLabel*>(widget)) {
0387             if (label->textInteractionFlags()
0388                 .testFlag(Qt::TextSelectableByMouse))
0389                 return false;
0390             QWidget *parent = label->parentWidget();
0391             while (parent) {
0392                 if (qobject_cast<QStatusBar*>(parent))
0393                     return true;
0394                 parent = parent->parentWidget();
0395             }
0396         }
0397         return false;
0398     }
0399 
0400     //_____________________________________________________________
0401     bool WindowManager::isBlackListed( QWidget* widget )
0402     {
0403 
0404         // check against noAnimations propery
0405         QVariant propertyValue( widget->property( "_kde_no_window_grab" ) );
0406         if( propertyValue.isValid() && propertyValue.toBool() ) return true;
0407 
0408         // list-based blacklisted widgets
0409         QString appName( qApp->applicationName() );
0410         foreach (const ExceptionId &id, const_(_blackList)) {
0411             if (!id.appName().isEmpty() && id.appName() != appName)
0412                 continue;
0413             if (id.className() == "*" && !id.appName().isEmpty()) {
0414                 // if application name matches and all classes are selected
0415                 // disable the grabbing entirely
0416                 setEnabled( false );
0417                 return true;
0418             }
0419             if (widget->inherits(id.className().toLatin1())) {
0420                 return true;
0421             }
0422         }
0423         return false;
0424     }
0425 
0426     //_____________________________________________________________
0427     bool WindowManager::isWhiteListed( QWidget* widget ) const
0428     {
0429 
0430         QString appName(qApp->applicationName());
0431         foreach (const ExceptionId &id, const_(_whiteList)) {
0432             if (!id.appName().isEmpty() && id.appName() != appName)
0433                 continue;
0434             if (widget->inherits(id.className().toLatin1())) {
0435                 return true;
0436             }
0437         }
0438         return false;
0439     }
0440 
0441     //_____________________________________________________________
0442     bool WindowManager::canDrag( QWidget* widget )
0443     {
0444 
0445         // check if enabled
0446         if( !enabled() ) return false;
0447 
0448         // assume isDragable widget is already passed
0449         // check some special cases where drag should not be effective
0450 
0451         // check mouse grabber
0452         if( QWidget::mouseGrabber() ) return false;
0453 
0454         /*
0455         check cursor shape.
0456         Assume that a changed cursor means that some action is in progress
0457         and should prevent the drag
0458         */
0459         if( widget->cursor().shape() != Qt::ArrowCursor ) return false;
0460 
0461         // accept
0462         return true;
0463 
0464     }
0465 
0466     //_____________________________________________________________
0467     bool WindowManager::canDrag( QWidget* widget, QWidget* child, const QPoint& position )
0468     {
0469 
0470         // retrieve child at given position and check cursor again
0471         if( child && child->cursor().shape() != Qt::ArrowCursor ) return false;
0472 
0473         /*
0474         check against children from which drag should never be enabled,
0475         even if mousePress/Move has been passed to the parent
0476         */
0477         if( child && (
0478           qobject_cast<QComboBox*>(child ) ||
0479           qobject_cast<QProgressBar*>( child ) ) )
0480         { return false; }
0481 
0482         // tool buttons
0483         if( QToolButton* toolButton = qobject_cast<QToolButton*>( widget ) )
0484         {
0485             if( dragMode() < WM_DRAG_ALL && !qobject_cast<QToolBar*>(widget->parentWidget() ) ) return false;
0486             return toolButton->autoRaise() && !toolButton->isEnabled();
0487         }
0488 
0489         // check menubar
0490         if( QMenuBar* menuBar = qobject_cast<QMenuBar*>( widget ) )
0491         {
0492 
0493             // check if there is an active action
0494             if( menuBar->activeAction() && menuBar->activeAction()->isEnabled() ) return false;
0495 
0496             // check if action at position exists and is enabled
0497             if( QAction* action = menuBar->actionAt( position ) )
0498             {
0499                 if( action->isSeparator() ) return true;
0500                 if( action->isEnabled() ) return false;
0501             }
0502 
0503             // return true in all other cases
0504             return true;
0505 
0506         }
0507 
0508         if(dragMode() < WM_DRAG_MENU_AND_TOOLBAR && qobject_cast<QToolBar*>( widget ))
0509             return false;
0510 
0511         /*
0512         in MINIMAL mode, anything that has not been already accepted
0513         and does not come from a toolbar is rejected
0514         */
0515         if( dragMode() < WM_DRAG_ALL )
0516         {
0517             if( qobject_cast<QToolBar*>( widget ) ) return true;
0518             else return false;
0519         }
0520 
0521         /* following checks are relevant only for WD_FULL mode */
0522 
0523         // tabbar. Make sure no tab is under the cursor
0524         if (QTabBar *tabBar = qobject_cast<QTabBar*>(widget)) {
0525             return tabBar->tabAt(position) == -1;
0526         }
0527 
0528         /*
0529         check groupboxes
0530         prevent drag if unchecking grouboxes
0531         */
0532         if (QGroupBox *groupBox = qobject_cast<QGroupBox*>(widget)) {
0533             // non checkable group boxes are always ok
0534             if( !groupBox->isCheckable() ) return true;
0535 
0536             // gather options to retrieve checkbox subcontrol rect
0537             QStyleOptionGroupBox opt;
0538             opt.initFrom( groupBox );
0539             if( groupBox->isFlat() ) opt.features |= QStyleOptionFrameV2::Flat;
0540             opt.lineWidth = 1;
0541             opt.midLineWidth = 0;
0542             opt.text = groupBox->title();
0543             opt.textAlignment = groupBox->alignment();
0544             opt.subControls = (QStyle::SC_GroupBoxFrame | QStyle::SC_GroupBoxCheckBox);
0545             if (!groupBox->title().isEmpty()) opt.subControls |= QStyle::SC_GroupBoxLabel;
0546 
0547             opt.state |= (groupBox->isChecked() ? QStyle::State_On : QStyle::State_Off);
0548 
0549             // check against groupbox checkbox
0550             if( groupBox->style()->subControlRect(QStyle::CC_GroupBox, &opt, QStyle::SC_GroupBoxCheckBox, groupBox ).contains( position ) )
0551             { return false; }
0552 
0553             // check against groupbox label
0554             if( !groupBox->title().isEmpty() && groupBox->style()->subControlRect(QStyle::CC_GroupBox, &opt, QStyle::SC_GroupBoxLabel, groupBox ).contains( position ) )
0555             { return false; }
0556 
0557             return true;
0558 
0559         }
0560 
0561         // labels
0562         if (QLabel *label = qobject_cast<QLabel*>(widget)) {
0563             if (label->textInteractionFlags().testFlag(
0564                     Qt::TextSelectableByMouse)) {
0565                 return false;
0566             }
0567         }
0568 
0569         // abstract item views
0570         QAbstractItemView* itemView(nullptr);
0571         if ((itemView = qobject_cast<QListView*>(widget->parentWidget())) ||
0572             (itemView = qobject_cast<QTreeView*>(widget->parentWidget()))) {
0573             if (widget == itemView->viewport()) {
0574                 // QListView
0575                 if (itemView->frameShape() != QFrame::NoFrame) {
0576                     return false;
0577                 } else if (itemView->selectionMode() !=
0578                            QAbstractItemView::NoSelection &&
0579                            itemView->selectionMode() !=
0580                            QAbstractItemView::SingleSelection &&
0581                            itemView->model() && itemView->model()->rowCount()) {
0582                     return false;
0583                 } else if (itemView->model() &&
0584                            itemView->indexAt(position).isValid()) {
0585                     return false;
0586                 }
0587             }
0588         } else if ((itemView = qobject_cast<QAbstractItemView*>(
0589                         widget->parentWidget()))) {
0590             if (widget == itemView->viewport()) {
0591                 // QAbstractItemView
0592                 if (itemView->frameShape() != QFrame::NoFrame) {
0593                     return false;
0594                 } else if (itemView->indexAt(position).isValid()) {
0595                     return false;
0596                 }
0597             }
0598         } else if (QGraphicsView *graphicsView =
0599                    qobject_cast<QGraphicsView*>(widget->parentWidget()))  {
0600 
0601             if (widget == graphicsView->viewport()) {
0602                 // QGraphicsView
0603                 if (graphicsView->frameShape() != QFrame::NoFrame) {
0604                     return false;
0605                 } else if (graphicsView->dragMode() != QGraphicsView::NoDrag) {
0606                     return false;
0607                 } else if (graphicsView->itemAt(position)) {
0608                     return false;
0609                 }
0610             }
0611         }
0612         return true;
0613     }
0614 
0615     //____________________________________________________________
0616     void WindowManager::resetDrag()
0617     {
0618 
0619         if( (!useWMMoveResize() ) && _target && _cursorOverride ) {
0620 
0621           qApp->restoreOverrideCursor();
0622           _cursorOverride = false;
0623 
0624         }
0625 
0626         _target.clear();
0627         if( _dragTimer.isActive() ) _dragTimer.stop();
0628         _dragPoint = QPoint();
0629         _globalDragPoint = QPoint();
0630         _dragAboutToStart = false;
0631         _dragInProgress = false;
0632 
0633     }
0634 
0635 void
0636 WindowManager::startDrag(QWidget *widget, const QPoint &position)
0637 {
0638     if (!(enabled() && widget) || QWidget::mouseGrabber()) {
0639         return;
0640     }
0641     // DO NOT condition compile on QTC_ENABLE_X11.
0642     // There's no direct linkage on X11 and the following code will just do
0643     // nothing if X11 is not enabled (either at compile time or at run time).
0644     // ungrab pointer
0645     if (useWMMoveResize()) {
0646         qtcX11MoveTrigger(widget->window()->internalWinId(),
0647                           position.x(), position.y());
0648     }
0649     // shouldn't there be an 'else' here??
0650     if (!useWMMoveResize()) {
0651         if (!_cursorOverride) {
0652             qApp->setOverrideCursor(Qt::SizeAllCursor);
0653             _cursorOverride = true;
0654         }
0655     }
0656     _dragInProgress = true;
0657     return;
0658 }
0659 
0660 bool
0661 WindowManager::isDockWidgetTitle(const QWidget *widget) const
0662 {
0663     QTC_RET_IF_FAIL(widget, false);
0664     if (const QDockWidget *dockWidget =
0665         qobject_cast<const QDockWidget*>(widget->parent())) {
0666             return widget == dockWidget->titleBarWidget();
0667     } else {
0668         return false;
0669     }
0670 }
0671 
0672     //____________________________________________________________
0673     bool WindowManager::AppEventFilter::eventFilter( QObject* object, QEvent* event )
0674     {
0675 
0676         if( event->type() == QEvent::MouseButtonRelease )
0677         {
0678 
0679             // stop drag timer
0680             if( _parent->_dragTimer.isActive() )
0681             { _parent->resetDrag(); }
0682 
0683             // unlock
0684             if( _parent->isLocked() )
0685             { _parent->setLocked( false ); }
0686 
0687         }
0688 
0689         if( !_parent->enabled() ) return false;
0690 
0691         /*
0692         if a drag is in progress, the widget will not receive any event
0693         we trigger on the first MouseMove or MousePress events that are received
0694         by any widget in the application to detect that the drag is finished
0695         */
0696         if( _parent->useWMMoveResize() && _parent->_dragInProgress && _parent->_target && ( event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress ) )
0697         { return appMouseEvent( object, event ); }
0698 
0699         return false;
0700 
0701     }
0702 
0703     //_____________________________________________________________
0704     bool WindowManager::AppEventFilter::appMouseEvent( QObject* object, QEvent* event )
0705     {
0706 
0707         Q_UNUSED( object );
0708 
0709         // store target window (see later)
0710         QWidget* window( _parent->_target.data()->window() );
0711 
0712         /*
0713         post some mouseRelease event to the target, in order to counter balance
0714         the mouse press that triggered the drag. Note that it triggers a resetDrag
0715         */
0716         QMouseEvent mouseEvent( QEvent::MouseButtonRelease, _parent->_dragPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
0717         qApp->sendEvent( _parent->_target.data(), &mouseEvent );
0718 
0719         if( event->type() == QEvent::MouseMove )
0720         {
0721             /*
0722             HACK: quickly move the main cursor out of the window and back
0723             this is needed to get the focus right for the window children
0724             the origin of this issue is unknown at the moment
0725             */
0726             const QPoint cursor = QCursor::pos();
0727             QCursor::setPos(window->mapToGlobal( window->rect().topRight() ) + QPoint(1, 0) );
0728             QCursor::setPos(cursor);
0729 
0730         }
0731 
0732         return true;
0733 
0734     }
0735 
0736 
0737 }