Blame src/lib/adwaitawindowmanager.cpp

Packit Bot 052d53
/*************************************************************************
Packit Bot 052d53
 * Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr>    *
Packit Bot 052d53
 *                                                                       *
Packit Bot 052d53
 * This program is free software; you can redistribute it and/or modify  *
Packit Bot 052d53
 * it under the terms of the GNU General Public License as published by  *
Packit Bot 052d53
 * the Free Software Foundation; either version 2 of the License, or     *
Packit Bot 052d53
 * (at your option) any later version.                                   *
Packit Bot 052d53
 *                                                                       *
Packit Bot 052d53
 * This program is distributed in the hope that it will be useful,       *
Packit Bot 052d53
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
Packit Bot 052d53
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
Packit Bot 052d53
 * GNU General Public License for more details.                          *
Packit Bot 052d53
 *                                                                       *
Packit Bot 052d53
 * You should have received a copy of the GNU General Public License     *
Packit Bot 052d53
 * along with this program; if not, write to the                         *
Packit Bot 052d53
 * Free Software Foundation, Inc.,                                       *
Packit Bot 052d53
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
Packit Bot 052d53
 *************************************************************************/
Packit Bot 052d53
Packit Bot 052d53
//////////////////////////////////////////////////////////////////////////////
Packit Bot 052d53
// adwaitawindowmanager.cpp
Packit Bot 052d53
// pass some window mouse press/release/move event actions to window manager
Packit Bot 052d53
// -------------------
Packit Bot 052d53
//
Packit Bot 052d53
// Copyright (c) 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
Packit Bot 052d53
//
Packit Bot 052d53
// Largely inspired from BeSpin style
Packit Bot 052d53
// Copyright (C) 2007 Thomas Luebking <thomas.luebking@web.de>
Packit Bot 052d53
//
Packit Bot 052d53
// Permission is hereby granted, free of charge, to any person obtaining a copy
Packit Bot 052d53
// of this software and associated documentation files (the "Software"), to
Packit Bot 052d53
// deal in the Software without restriction, including without limitation the
Packit Bot 052d53
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit Bot 052d53
// sell copies of the Software, and to permit persons to whom the Software is
Packit Bot 052d53
// furnished to do so, subject to the following conditions:
Packit Bot 052d53
//
Packit Bot 052d53
// The above copyright notice and this permission notice shall be included in
Packit Bot 052d53
// all copies or substantial portions of the Software.
Packit Bot 052d53
//
Packit Bot 052d53
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Bot 052d53
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Bot 052d53
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit Bot 052d53
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit Bot 052d53
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit Bot 052d53
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit Bot 052d53
// IN THE SOFTWARE.
Packit Bot 052d53
//////////////////////////////////////////////////////////////////////////////
Packit Bot 052d53
Packit Bot 052d53
#include "adwaitawindowmanager.h"
Packit Bot 052d53
// #include "adwaitahelper.h"
Packit Bot 052d53
Packit Bot 052d53
#include <QApplication>
Packit Bot 052d53
#include <QComboBox>
Packit Bot 052d53
#include <QDialog>
Packit Bot 052d53
#include <QDockWidget>
Packit Bot 052d53
#include <QGraphicsView>
Packit Bot 052d53
#include <QGroupBox>
Packit Bot 052d53
#include <QLabel>
Packit Bot 052d53
#include <QListView>
Packit Bot 052d53
#include <QMainWindow>
Packit Bot 052d53
#include <QMdiSubWindow>
Packit Bot 052d53
#include <QMenuBar>
Packit Bot 052d53
#include <QMouseEvent>
Packit Bot 052d53
#include <QProgressBar>
Packit Bot 052d53
#include <QScrollBar>
Packit Bot 052d53
#include <QStatusBar>
Packit Bot 052d53
#include <QStyle>
Packit Bot 052d53
#include <QStyleOptionGroupBox>
Packit Bot 052d53
#include <QTabBar>
Packit Bot 052d53
#include <QTabWidget>
Packit Bot 052d53
#include <QToolBar>
Packit Bot 052d53
#include <QToolButton>
Packit Bot 052d53
#include <QTreeView>
Packit Bot 052d53
Packit Bot 052d53
#include <QTextStream>
Packit Bot 052d53
Packit Bot 052d53
// needed to deal with device pixel ratio
Packit Bot 052d53
#include <QWindow>
Packit Bot 052d53
Packit Bot 052d53
namespace Adwaita
Packit Bot 052d53
{
Packit Bot 052d53
Packit Bot 052d53
//* provide application-wise event filter
Packit Bot 052d53
/**
Packit Bot 052d53
it us used to unlock dragging and make sure event look is properly restored
Packit Bot 052d53
after a drag has occurred
Packit Bot 052d53
*/
Packit Bot 052d53
class AppEventFilter: public QObject
Packit Bot 052d53
{
Packit Bot 052d53
Packit Bot 052d53
public:
Packit Bot 052d53
    //* constructor
Packit Bot 052d53
    explicit AppEventFilter(WindowManager *parent)
Packit Bot 052d53
        : QObject(parent)
Packit Bot 052d53
        , _parent(parent)
Packit Bot 052d53
    {}
Packit Bot 052d53
Packit Bot 052d53
    //* event filter
Packit Bot 052d53
    virtual bool eventFilter(QObject *object, QEvent *event)
Packit Bot 052d53
    {
Packit Bot 052d53
        if (event->type() == QEvent::MouseButtonRelease) {
Packit Bot 052d53
Packit Bot 052d53
            // stop drag timer
Packit Bot 052d53
            if (_parent->_dragTimer.isActive()) {
Packit Bot 052d53
                _parent->resetDrag();
Packit Bot 052d53
            }
Packit Bot 052d53
Packit Bot 052d53
            // unlock
Packit Bot 052d53
            if (_parent->isLocked()) {
Packit Bot 052d53
                _parent->setLocked(false);
Packit Bot 052d53
            }
Packit Bot 052d53
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        if (!_parent->enabled()) {
Packit Bot 052d53
            return false;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        /*
Packit Bot 052d53
        if a drag is in progress, the widget will not receive any event
Packit Bot 052d53
        we trigger on the first MouseMove or MousePress events that are received
Packit Bot 052d53
        by any widget in the application to detect that the drag is finished
Packit Bot 052d53
        */
Packit Bot 052d53
        if (_parent->useWMMoveResize() && _parent->_dragInProgress && _parent->_target && (event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress)) {
Packit Bot 052d53
            return appMouseEvent(object, event);
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
protected:
Packit Bot 052d53
    //* application-wise event.
Packit Bot 052d53
    /** needed to catch end of XMoveResize events */
Packit Bot 052d53
    bool appMouseEvent(QObject *, QEvent *event)
Packit Bot 052d53
    {
Packit Bot 052d53
        Q_UNUSED(event);
Packit Bot 052d53
Packit Bot 052d53
        /*
Packit Bot 052d53
        post some mouseRelease event to the target, in order to counter balance
Packit Bot 052d53
        the mouse press that triggered the drag. Note that it triggers a resetDrag
Packit Bot 052d53
        */
Packit Bot 052d53
        QMouseEvent mouseEvent(QEvent::MouseButtonRelease, _parent->_dragPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
Packit Bot 052d53
        qApp->sendEvent(_parent->_target.data(), &mouseEvent);
Packit Bot 052d53
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
private:
Packit Bot 052d53
    //* parent
Packit Bot 052d53
    WindowManager *_parent;
Packit Bot 052d53
};
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
WindowManager::WindowManager(QObject *parent)
Packit Bot 052d53
    : QObject(parent)
Packit Bot 052d53
    , _enabled(true)
Packit Bot 052d53
    , _useWMMoveResize(true)
Packit Bot 052d53
    , _dragMode(Adwaita::WD_FULL)
Packit Bot 052d53
    , _dragDistance(QApplication::startDragDistance())
Packit Bot 052d53
    , _dragDelay(QApplication::startDragTime())
Packit Bot 052d53
    , _dragAboutToStart(false)
Packit Bot 052d53
    , _dragInProgress(false)
Packit Bot 052d53
    , _locked(false)
Packit Bot 052d53
    , _cursorOverride(false)
Packit Bot 052d53
{
Packit Bot 052d53
    // install application wise event filter
Packit Bot 052d53
    _appEventFilter = new AppEventFilter(this);
Packit Bot 052d53
    qApp->installEventFilter(_appEventFilter);
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
void WindowManager::initialize(void)
Packit Bot 052d53
{
Packit Bot 052d53
    setEnabled(Adwaita::Config::WindowDragMode != Adwaita::WD_NONE);
Packit Bot 052d53
    setDragMode(Adwaita::Config::WindowDragMode);
Packit Bot 052d53
    setUseWMMoveResize(Adwaita::Config::UseWMMoveResize);
Packit Bot 052d53
Packit Bot 052d53
    setDragDistance(QApplication::startDragDistance());
Packit Bot 052d53
    setDragDelay(QApplication::startDragTime());
Packit Bot 052d53
Packit Bot 052d53
    initializeWhiteList();
Packit Bot 052d53
    initializeBlackList();
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
void WindowManager::registerWidget(QWidget *widget)
Packit Bot 052d53
{
Packit Bot 052d53
    if (isBlackListed(widget) || isDragable(widget)) {
Packit Bot 052d53
        /*
Packit Bot 052d53
        install filter for dragable widgets.
Packit Bot 052d53
        also install filter for blacklisted widgets
Packit Bot 052d53
        to be able to catch the relevant events and prevent
Packit Bot 052d53
        the drag to happen
Packit Bot 052d53
        */
Packit Bot 052d53
        widget->removeEventFilter(this);
Packit Bot 052d53
        widget->installEventFilter(this);
Packit Bot 052d53
    }
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
void WindowManager::unregisterWidget(QWidget *widget)
Packit Bot 052d53
{
Packit Bot 052d53
    if (widget) {
Packit Bot 052d53
        widget->removeEventFilter(this);
Packit Bot 052d53
    }
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
void WindowManager::initializeWhiteList(void)
Packit Bot 052d53
{
Packit Bot 052d53
    _whiteList.clear();
Packit Bot 052d53
Packit Bot 052d53
    // add user specified whitelisted classnames
Packit Bot 052d53
    _whiteList.insert(ExceptionId(QStringLiteral("MplayerWindow")));
Packit Bot 052d53
    _whiteList.insert(ExceptionId(QStringLiteral("ViewSliders@kmix")));
Packit Bot 052d53
    _whiteList.insert(ExceptionId(QStringLiteral("Sidebar_Widget@konqueror")));
Packit Bot 052d53
Packit Bot 052d53
    foreach (const QString &exception, Adwaita::Config::WindowDragWhiteList) {
Packit Bot 052d53
        ExceptionId id(exception);
Packit Bot 052d53
        if (!id.className().isEmpty()) {
Packit Bot 052d53
            _whiteList.insert(ExceptionId(exception));
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
void WindowManager::initializeBlackList(void)
Packit Bot 052d53
{
Packit Bot 052d53
    _blackList.clear();
Packit Bot 052d53
    _blackList.insert(ExceptionId(QStringLiteral("CustomTrackView@kdenlive")));
Packit Bot 052d53
    _blackList.insert(ExceptionId(QStringLiteral("MuseScore")));
Packit Bot 052d53
    _blackList.insert(ExceptionId(QStringLiteral("KGameCanvasWidget")));
Packit Bot 052d53
    foreach (const QString &exception, Adwaita::Config::WindowDragBlackList) {
Packit Bot 052d53
        ExceptionId id(exception);
Packit Bot 052d53
        if (!id.className().isEmpty()) {
Packit Bot 052d53
            _blackList.insert(ExceptionId(exception));
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::eventFilter(QObject *object, QEvent *event)
Packit Bot 052d53
{
Packit Bot 052d53
    if (!enabled()) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    switch (event->type()) {
Packit Bot 052d53
    case QEvent::MouseButtonPress:
Packit Bot 052d53
        return mousePressEvent(object, event);
Packit Bot 052d53
        break;
Packit Bot 052d53
    case QEvent::MouseMove:
Packit Bot 052d53
        if (object == _target.data()) {
Packit Bot 052d53
            return mouseMoveEvent(object, event);
Packit Bot 052d53
        }
Packit Bot 052d53
        break;
Packit Bot 052d53
    case QEvent::MouseButtonRelease:
Packit Bot 052d53
        if (_target) {
Packit Bot 052d53
            return mouseReleaseEvent(object, event);
Packit Bot 052d53
        }
Packit Bot 052d53
        break;
Packit Bot 052d53
    default:
Packit Bot 052d53
        break;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    return false;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
void WindowManager::timerEvent(QTimerEvent *event)
Packit Bot 052d53
{
Packit Bot 052d53
    if (event->timerId() == _dragTimer.timerId()) {
Packit Bot 052d53
        _dragTimer.stop();
Packit Bot 052d53
        if (_target) {
Packit Bot 052d53
            startDrag(_target.data(), _globalDragPoint);
Packit Bot 052d53
        }
Packit Bot 052d53
    } else {
Packit Bot 052d53
        return QObject::timerEvent(event);
Packit Bot 052d53
    }
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::mousePressEvent(QObject *object, QEvent *event)
Packit Bot 052d53
{
Packit Bot 052d53
    // cast event and check buttons/modifiers
Packit Bot 052d53
    QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
Packit Bot 052d53
    if (!(mouseEvent->modifiers() == Qt::NoModifier && mouseEvent->button() == Qt::LeftButton)) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // check lock
Packit Bot 052d53
    if (isLocked()) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    } else {
Packit Bot 052d53
        setLocked(true);
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // cast to widget
Packit Bot 052d53
    QWidget *widget = static_cast<QWidget *>(object);
Packit Bot 052d53
Packit Bot 052d53
    // check if widget can be dragged from current position
Packit Bot 052d53
    if (isBlackListed(widget) || !canDrag(widget)) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // retrieve widget's child at event position
Packit Bot 052d53
    QPoint position(mouseEvent->pos());
Packit Bot 052d53
    QWidget *child = widget->childAt(position);
Packit Bot 052d53
    if (!canDrag(widget, child, position)) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // save target and drag point
Packit Bot 052d53
    _target = widget;
Packit Bot 052d53
    _dragPoint = position;
Packit Bot 052d53
    _globalDragPoint = mouseEvent->globalPos();
Packit Bot 052d53
    _dragAboutToStart = true;
Packit Bot 052d53
Packit Bot 052d53
    // send a move event to the current child with same position
Packit Bot 052d53
    // if received, it is caught to actually start the drag
Packit Bot 052d53
    QPoint localPoint(_dragPoint);
Packit Bot 052d53
    if (child) {
Packit Bot 052d53
        localPoint = child->mapFrom(widget, localPoint);
Packit Bot 052d53
    } else {
Packit Bot 052d53
        child = widget;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    QMouseEvent localMouseEvent(QEvent::MouseMove, localPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
Packit Bot 052d53
    qApp->sendEvent(child, &localMouseEvent);
Packit Bot 052d53
Packit Bot 052d53
    // never eat event
Packit Bot 052d53
    return false;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::mouseMoveEvent(QObject *object, QEvent *event)
Packit Bot 052d53
{
Packit Bot 052d53
    Q_UNUSED(object);
Packit Bot 052d53
Packit Bot 052d53
    // stop timer
Packit Bot 052d53
    if (_dragTimer.isActive()) {
Packit Bot 052d53
        _dragTimer.stop();
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // cast event and check drag distance
Packit Bot 052d53
    QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
Packit Bot 052d53
    if (!_dragInProgress) {
Packit Bot 052d53
        if (_dragAboutToStart) {
Packit Bot 052d53
            if (mouseEvent->pos() == _dragPoint) {
Packit Bot 052d53
                // start timer,
Packit Bot 052d53
                _dragAboutToStart = false;
Packit Bot 052d53
                if (_dragTimer.isActive()) {
Packit Bot 052d53
                    _dragTimer.stop();
Packit Bot 052d53
                }
Packit Bot 052d53
                _dragTimer.start(_dragDelay, this);
Packit Bot 052d53
            } else {
Packit Bot 052d53
                resetDrag();
Packit Bot 052d53
            }
Packit Bot 052d53
        } else {
Packit Bot 052d53
            if (QPoint(mouseEvent->globalPos() - _globalDragPoint).manhattanLength() >= _dragDistance) {
Packit Bot 052d53
                _dragTimer.start(0, this);
Packit Bot 052d53
            }
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        return true;
Packit Bot 052d53
    } else if (!useWMMoveResize()) {
Packit Bot 052d53
        // use QWidget::move for the grabbing
Packit Bot 052d53
        /* this works only if the sending object and the target are identical */
Packit Bot 052d53
        QWidget *window(_target.data()->window());
Packit Bot 052d53
        window->move(window->pos() + mouseEvent->pos() - _dragPoint);
Packit Bot 052d53
        return true;
Packit Bot 052d53
    } else {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::mouseReleaseEvent(QObject *object, QEvent *event)
Packit Bot 052d53
{
Packit Bot 052d53
    Q_UNUSED(object);
Packit Bot 052d53
    Q_UNUSED(event);
Packit Bot 052d53
    resetDrag();
Packit Bot 052d53
    return false;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::isDragable(QWidget *widget)
Packit Bot 052d53
{
Packit Bot 052d53
    // check widget
Packit Bot 052d53
    if (!widget) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // accepted default types
Packit Bot 052d53
    if ((qobject_cast<QDialog *>(widget) && widget->isWindow()) ||
Packit Bot 052d53
        (qobject_cast<QMainWindow *>(widget) && widget->isWindow()) ||
Packit Bot 052d53
        qobject_cast<QGroupBox *>(widget)) {
Packit Bot 052d53
        return true;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // more accepted types, provided they are not dock widget titles
Packit Bot 052d53
    if ((qobject_cast<QMenuBar *>(widget) ||
Packit Bot 052d53
         qobject_cast<QTabBar *>(widget) ||
Packit Bot 052d53
         qobject_cast<QStatusBar *>(widget) ||
Packit Bot 052d53
         qobject_cast<QToolBar *>(widget)) &&
Packit Bot 052d53
         !isDockWidgetTitle(widget)) {
Packit Bot 052d53
        return true;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    if (widget->inherits("KScreenSaver") && widget->inherits("KCModule")) {
Packit Bot 052d53
        return true;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    if (isWhiteListed(widget)) {
Packit Bot 052d53
        return true;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // flat toolbuttons
Packit Bot 052d53
    if (QToolButton *toolButton = qobject_cast<QToolButton *>(widget)) {
Packit Bot 052d53
        if (toolButton->autoRaise()) return true;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // viewports
Packit Bot 052d53
    /*
Packit Bot 052d53
    one needs to check that
Packit Bot 052d53
    1/ the widget parent is a scrollarea
Packit Bot 052d53
    2/ it matches its parent viewport
Packit Bot 052d53
    3/ the parent is not blacklisted
Packit Bot 052d53
    */
Packit Bot 052d53
    if (QListView *listView = qobject_cast<QListView *>(widget->parentWidget())) {
Packit Bot 052d53
        if (listView->viewport() == widget && !isBlackListed(listView)) {
Packit Bot 052d53
            return true;
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    if (QTreeView *treeView = qobject_cast<QTreeView *>(widget->parentWidget())) {
Packit Bot 052d53
        if (treeView->viewport() == widget && !isBlackListed(treeView)) {
Packit Bot 052d53
            return true;
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    /*
Packit Bot 052d53
    catch labels in status bars.
Packit Bot 052d53
    this is because of kstatusbar
Packit Bot 052d53
    who captures buttonPress/release events
Packit Bot 052d53
    */
Packit Bot 052d53
    if (QLabel *label = qobject_cast<QLabel *>(widget)) {
Packit Bot 052d53
        if (label->textInteractionFlags().testFlag(Qt::TextSelectableByMouse)) {
Packit Bot 052d53
            return false;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        QWidget *parent = label->parentWidget();
Packit Bot 052d53
        while (parent) {
Packit Bot 052d53
            if (qobject_cast<QStatusBar *>(parent)) {
Packit Bot 052d53
                return true;
Packit Bot 052d53
            }
Packit Bot 052d53
            parent = parent->parentWidget();
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    return false;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::isBlackListed(QWidget *widget)
Packit Bot 052d53
{
Packit Bot 052d53
    // check against noAnimations propery
Packit Bot 052d53
    QVariant propertyValue(widget->property(PropertyNames::noWindowGrab));
Packit Bot 052d53
    if (propertyValue.isValid() && propertyValue.toBool()) {
Packit Bot 052d53
        return true;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // list-based blacklisted widgets
Packit Bot 052d53
    QString appName(qApp->applicationName());
Packit Bot 052d53
    foreach (const ExceptionId &id, _blackList) {
Packit Bot 052d53
        if (!id.appName().isEmpty() && id.appName() != appName) {
Packit Bot 052d53
            continue;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        if (id.className() == QStringLiteral("*") && !id.appName().isEmpty()) {
Packit Bot 052d53
            // if application name matches and all classes are selected
Packit Bot 052d53
            // disable the grabbing entirely
Packit Bot 052d53
            setEnabled(false);
Packit Bot 052d53
            return true;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        if (widget->inherits(id.className().toLatin1().data())) {
Packit Bot 052d53
            return true;
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    return false;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::isWhiteListed(QWidget *widget) const
Packit Bot 052d53
{
Packit Bot 052d53
    QString appName(qApp->applicationName());
Packit Bot 052d53
    foreach (const ExceptionId &id, _whiteList) {
Packit Bot 052d53
        if (!id.appName().isEmpty() && id.appName() != appName) {
Packit Bot 052d53
            continue;
Packit Bot 052d53
        }
Packit Bot 052d53
        if (widget->inherits(id.className().toLatin1().data())) {
Packit Bot 052d53
            return true;
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    return false;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::canDrag(QWidget *widget)
Packit Bot 052d53
{
Packit Bot 052d53
    // check if enabled
Packit Bot 052d53
    if (!enabled()) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // assume isDragable widget is already passed
Packit Bot 052d53
    // check some special cases where drag should not be effective
Packit Bot 052d53
Packit Bot 052d53
    // check mouse grabber
Packit Bot 052d53
    if (QWidget::mouseGrabber()) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    /*
Packit Bot 052d53
    check cursor shape.
Packit Bot 052d53
    Assume that a changed cursor means that some action is in progress
Packit Bot 052d53
    and should prevent the drag
Packit Bot 052d53
    */
Packit Bot 052d53
    if (widget->cursor().shape() != Qt::ArrowCursor) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // accept
Packit Bot 052d53
    return true;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_____________________________________________________________
Packit Bot 052d53
bool WindowManager::canDrag(QWidget *widget, QWidget *child, const QPoint &position)
Packit Bot 052d53
{
Packit Bot 052d53
    // retrieve child at given position and check cursor again
Packit Bot 052d53
    if (child && child->cursor().shape() != Qt::ArrowCursor) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    /*
Packit Bot 052d53
    check against children from which drag should never be enabled,
Packit Bot 052d53
    even if mousePress/Move has been passed to the parent
Packit Bot 052d53
    */
Packit Bot 052d53
    if (child && (qobject_cast<QComboBox *>(child) ||
Packit Bot 052d53
                  qobject_cast<QProgressBar *>(child) ||
Packit Bot 052d53
                  qobject_cast<QScrollBar *>(child))) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // tool buttons
Packit Bot 052d53
    if (QToolButton *toolButton = qobject_cast<QToolButton *>(widget)) {
Packit Bot 052d53
        if (dragMode() == Adwaita::WD_MINIMAL && !qobject_cast<QToolBar *>(widget->parentWidget())) {
Packit Bot 052d53
            return false;
Packit Bot 052d53
        }
Packit Bot 052d53
        return toolButton->autoRaise() && !toolButton->isEnabled();
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // check menubar
Packit Bot 052d53
    if (QMenuBar *menuBar = qobject_cast<QMenuBar *>(widget)) {
Packit Bot 052d53
        // do not drag from menubars embedded in Mdi windows
Packit Bot 052d53
        if (findParent<QMdiSubWindow *>(widget)) {
Packit Bot 052d53
            return false;
Packit Bot 052d53
        }
Packit Bot 052d53
        // check if there is an active action
Packit Bot 052d53
        if (menuBar->activeAction() && menuBar->activeAction()->isEnabled()) {
Packit Bot 052d53
            return false;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        // check if action at position exists and is enabled
Packit Bot 052d53
        if (QAction *action = menuBar->actionAt(position)) {
Packit Bot 052d53
            if (action->isSeparator()) {
Packit Bot 052d53
                return true;
Packit Bot 052d53
            }
Packit Bot 052d53
            if (action->isEnabled()) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            }
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        // return true in all other cases
Packit Bot 052d53
        return true;
Packit Bot 052d53
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    /*
Packit Bot 052d53
    in MINIMAL mode, anything that has not been already accepted
Packit Bot 052d53
    and does not come from a toolbar is rejected
Packit Bot 052d53
    */
Packit Bot 052d53
    if (dragMode() == Adwaita::WD_MINIMAL) {
Packit Bot 052d53
        if (qobject_cast<QToolBar *>(widget)) {
Packit Bot 052d53
            return true;
Packit Bot 052d53
        } else {
Packit Bot 052d53
            return false;
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    /* following checks are relevant only for WD_FULL mode */
Packit Bot 052d53
Packit Bot 052d53
    // tabbar. Make sure no tab is under the cursor
Packit Bot 052d53
    if (QTabBar *tabBar = qobject_cast<QTabBar *>(widget)) {
Packit Bot 052d53
        return tabBar->tabAt(position) == -1;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    /*
Packit Bot 052d53
    check groupboxes
Packit Bot 052d53
    prevent drag if unchecking grouboxes
Packit Bot 052d53
    */
Packit Bot 052d53
    if (QGroupBox *groupBox = qobject_cast<QGroupBox *>(widget)) {
Packit Bot 052d53
        // non checkable group boxes are always ok
Packit Bot 052d53
        if (!groupBox->isCheckable()) {
Packit Bot 052d53
            return true;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        // gather options to retrieve checkbox subcontrol rect
Packit Bot 052d53
        QStyleOptionGroupBox opt;
Packit Bot 052d53
        opt.initFrom(groupBox);
Packit Bot 052d53
Packit Bot 052d53
        if (groupBox->isFlat()) {
Packit Bot 052d53
            opt.features |= QStyleOptionFrameV2::Flat;
Packit Bot 052d53
        }
Packit Bot 052d53
        opt.lineWidth = 1;
Packit Bot 052d53
        opt.midLineWidth = 0;
Packit Bot 052d53
        opt.text = groupBox->title();
Packit Bot 052d53
        opt.textAlignment = groupBox->alignment();
Packit Bot 052d53
        opt.subControls = (QStyle::SC_GroupBoxFrame | QStyle::SC_GroupBoxCheckBox);
Packit Bot 052d53
Packit Bot 052d53
        if (!groupBox->title().isEmpty()) {
Packit Bot 052d53
            opt.subControls |= QStyle::SC_GroupBoxLabel;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        opt.state |= (groupBox->isChecked() ? QStyle::State_On : QStyle::State_Off);
Packit Bot 052d53
Packit Bot 052d53
        // check against groupbox checkbox
Packit Bot 052d53
        if (groupBox->style()->subControlRect(QStyle::CC_GroupBox, &opt, QStyle::SC_GroupBoxCheckBox, groupBox).contains(position)) {
Packit Bot 052d53
            return false;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        // check against groupbox label
Packit Bot 052d53
        if (!groupBox->title().isEmpty() && groupBox->style()->subControlRect(QStyle::CC_GroupBox, &opt, QStyle::SC_GroupBoxLabel, groupBox).contains(position)) {
Packit Bot 052d53
            return false;
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
        return true;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // labels
Packit Bot 052d53
    if (QLabel *label = qobject_cast<QLabel *>(widget)) {
Packit Bot 052d53
        if (label->textInteractionFlags().testFlag(Qt::TextSelectableByMouse)) return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // abstract item views
Packit Bot 052d53
    QAbstractItemView *itemView(nullptr);
Packit Bot 052d53
    if ((itemView = qobject_cast<QListView *>(widget->parentWidget())) ||
Packit Bot 052d53
        (itemView = qobject_cast<QTreeView *>(widget->parentWidget()))) {
Packit Bot 052d53
        if (widget == itemView->viewport()) {
Packit Bot 052d53
            // QListView
Packit Bot 052d53
            if (itemView->frameShape() != QFrame::NoFrame) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            } else if (itemView->selectionMode() != QAbstractItemView::NoSelection &&
Packit Bot 052d53
                       itemView->selectionMode() != QAbstractItemView::SingleSelection &&
Packit Bot 052d53
                       itemView->model() && itemView->model()->rowCount()) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            } else if (itemView->model() && itemView->indexAt(position).isValid()) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            }
Packit Bot 052d53
        }
Packit Bot 052d53
Packit Bot 052d53
    } else if ((itemView = qobject_cast<QAbstractItemView *>(widget->parentWidget()))) {
Packit Bot 052d53
        if (widget == itemView->viewport()) {
Packit Bot 052d53
            // QAbstractItemView
Packit Bot 052d53
            if (itemView->frameShape() != QFrame::NoFrame) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            } else if (itemView->indexAt(position).isValid()) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            }
Packit Bot 052d53
        }
Packit Bot 052d53
    } else if (QGraphicsView *graphicsView =  qobject_cast<QGraphicsView *>(widget->parentWidget()))  {
Packit Bot 052d53
        if (widget == graphicsView->viewport()) {
Packit Bot 052d53
            // QGraphicsView
Packit Bot 052d53
            if (graphicsView->frameShape() != QFrame::NoFrame) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            } else if (graphicsView->dragMode() != QGraphicsView::NoDrag) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            } else if (graphicsView->itemAt(position)) {
Packit Bot 052d53
                return false;
Packit Bot 052d53
            }
Packit Bot 052d53
        }
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    return true;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//____________________________________________________________
Packit Bot 052d53
void WindowManager::resetDrag(void)
Packit Bot 052d53
{
Packit Bot 052d53
    if ((!useWMMoveResize()) && _target && _cursorOverride) {
Packit Bot 052d53
        qApp->restoreOverrideCursor();
Packit Bot 052d53
        _cursorOverride = false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    _target.clear();
Packit Bot 052d53
    if (_dragTimer.isActive()) {
Packit Bot 052d53
        _dragTimer.stop();
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    _dragPoint = QPoint();
Packit Bot 052d53
    _globalDragPoint = QPoint();
Packit Bot 052d53
    _dragAboutToStart = false;
Packit Bot 052d53
    _dragInProgress = false;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//____________________________________________________________
Packit Bot 052d53
void WindowManager::startDrag(QWidget *widget, const QPoint &position)
Packit Bot 052d53
{
Packit Bot 052d53
    if (!(enabled() && widget)) {
Packit Bot 052d53
        return;
Packit Bot 052d53
    }
Packit Bot 052d53
    if (QWidget::mouseGrabber()) {
Packit Bot 052d53
        return;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    // ungrab pointer
Packit Bot 052d53
    // TODO uncomment once we move Helper to the library
Packit Bot 052d53
//     if (useWMMoveResize()) {
Packit Bot 052d53
//         if (Helper::isX11()) {
Packit Bot 052d53
//             startDragX11(widget, position);
Packit Bot 052d53
//         }
Packit Bot 052d53
//     } else if (!_cursorOverride) {
Packit Bot 052d53
//         qApp->setOverrideCursor(Qt::SizeAllCursor);
Packit Bot 052d53
//         _cursorOverride = true;
Packit Bot 052d53
//     }
Packit Bot 052d53
Packit Bot 052d53
    _dragInProgress = true;
Packit Bot 052d53
Packit Bot 052d53
    return;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//_______________________________________________________
Packit Bot 052d53
void WindowManager::startDragX11(QWidget *widget, const QPoint &position)
Packit Bot 052d53
{
Packit Bot 052d53
    Q_UNUSED(widget);
Packit Bot 052d53
    Q_UNUSED(position);
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//____________________________________________________________
Packit Bot 052d53
bool WindowManager::supportWMMoveResize(void) const
Packit Bot 052d53
{
Packit Bot 052d53
    return false;
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
//____________________________________________________________
Packit Bot 052d53
bool WindowManager::isDockWidgetTitle(const QWidget *widget) const
Packit Bot 052d53
{
Packit Bot 052d53
    if (!widget) {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
Packit Bot 052d53
    if (const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(widget->parent())) {
Packit Bot 052d53
        return widget == dockWidget->titleBarWidget();
Packit Bot 052d53
    } else {
Packit Bot 052d53
        return false;
Packit Bot 052d53
    }
Packit Bot 052d53
}
Packit Bot 052d53
Packit Bot 052d53
} // namespace Adwaita