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 }