File indexing completed on 2024-05-12 13:30:26

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef breezewindowmanager_h
0008 #define breezewindowmanager_h
0009 
0010 #include "breeze.h"
0011 #include "breezestyleconfigdata.h"
0012 #include "config-breeze.h"
0013 
0014 #include <QEvent>
0015 
0016 #include <QApplication>
0017 #include <QBasicTimer>
0018 #include <QObject>
0019 #include <QSet>
0020 #include <QString>
0021 #include <QWidget>
0022 
0023 #if BREEZE_HAVE_QTQUICK
0024 #include <QQuickItem>
0025 #endif
0026 
0027 namespace Breeze
0028 {
0029 class WindowManager : public QObject
0030 {
0031     Q_OBJECT
0032 
0033 public:
0034     //* constructor
0035     explicit WindowManager(QObject *);
0036 
0037     //* initialize
0038     /** read relevant options from config */
0039     void initialize();
0040 
0041     //* register widget
0042     void registerWidget(QWidget *);
0043 
0044 #if BREEZE_HAVE_QTQUICK
0045     //* register quick item
0046     void registerQuickItem(QQuickItem *);
0047 #endif
0048 
0049     //* unregister widget
0050     void unregisterWidget(QWidget *);
0051 
0052     //* event filter [reimplemented]
0053     bool eventFilter(QObject *, QEvent *) override;
0054 
0055 protected:
0056     //* timer event,
0057     /** used to start drag if button is pressed for a long enough time */
0058     void timerEvent(QTimerEvent *) override;
0059 
0060     //* mouse press event
0061     bool mousePressEvent(QObject *, QEvent *);
0062 
0063     //* mouse move event
0064     bool mouseMoveEvent(QObject *, QEvent *);
0065 
0066     //* mouse release event
0067     bool mouseReleaseEvent(QObject *, QEvent *);
0068 
0069     //*@name configuration
0070     //@{
0071 
0072     //* enable state
0073     bool enabled() const
0074     {
0075         return _enabled;
0076     }
0077 
0078     //* enable state
0079     void setEnabled(bool value)
0080     {
0081         _enabled = value;
0082     }
0083 
0084     //* drag mode
0085     int dragMode() const
0086     {
0087         return _dragMode;
0088     }
0089 
0090     //* drag mode
0091     void setDragMode(int value)
0092     {
0093         _dragMode = value;
0094     }
0095 
0096     //* drag distance (pixels)
0097     void setDragDistance(int value)
0098     {
0099         _dragDistance = value;
0100     }
0101 
0102     //* drag delay (msec)
0103     void setDragDelay(int value)
0104     {
0105         _dragDelay = value;
0106     }
0107 
0108     //* set list of whiteListed widgets
0109     /**
0110     white list is read from options and is used to adjust
0111     per-app window dragging issues
0112     */
0113     void initializeWhiteList();
0114 
0115     //* set list of blackListed widgets
0116     /**
0117     black list is read from options and is used to adjust
0118     per-app window dragging issues
0119     */
0120     void initializeBlackList();
0121 
0122     //@}
0123 
0124     //* returns true if widget is dragable
0125     bool isDragable(QWidget *);
0126 
0127     //* returns true if widget is dragable
0128     bool isBlackListed(QWidget *);
0129 
0130     //* returns true if widget is dragable
0131     bool isWhiteListed(QWidget *) const;
0132 
0133     //* returns true if drag can be started from current widget
0134     bool canDrag(QWidget *);
0135 
0136     //* returns true if drag can be started from current widget and position
0137     /** child at given position is passed as second argument */
0138     bool canDrag(QWidget *, QWidget *, const QPoint &);
0139 
0140     //* reset drag
0141     void resetDrag();
0142 
0143     //* start drag
0144     void startDrag(QWindow *);
0145 
0146     //* utility function
0147     bool isDockWidgetTitle(const QWidget *) const;
0148 
0149     //*@name lock
0150     //@{
0151 
0152     void setLocked(bool value)
0153     {
0154         _locked = value;
0155     }
0156 
0157     //* lock
0158     bool isLocked() const
0159     {
0160         return _locked;
0161     }
0162 
0163     //@}
0164 
0165     //* returns first widget matching given class, or nullptr if none
0166     template<typename T>
0167     T findParent(const QWidget *) const;
0168 
0169 private:
0170     //* enability
0171     bool _enabled = true;
0172 
0173     //* drag mode
0174     int _dragMode = StyleConfigData::WD_FULL;
0175 
0176     //* drag distance
0177     /** this is copied from kwin::geometry */
0178     int _dragDistance = QApplication::startDragDistance();
0179 
0180     //* drag delay
0181     /** this is copied from kwin::geometry */
0182     int _dragDelay = QApplication::startDragTime();
0183 
0184     //* wrapper for exception id
0185     class ExceptionId
0186     {
0187     public:
0188         //* constructor
0189         explicit ExceptionId(const QString &value)
0190         {
0191             const QStringList args(value.split(QChar::fromLatin1('@')));
0192             if (args.isEmpty()) {
0193                 return;
0194             }
0195             _exception.second = args[0].trimmed();
0196             if (args.size() > 1) {
0197                 _exception.first = args[1].trimmed();
0198             }
0199         }
0200 
0201         const QString &appName() const
0202         {
0203             return _exception.first;
0204         }
0205 
0206         const QString &className() const
0207         {
0208             return _exception.second;
0209         }
0210 
0211     private:
0212         QPair<QString, QString> _exception;
0213 
0214         friend uint qHash(const ExceptionId &value)
0215         {
0216             return qHash(value._exception);
0217         }
0218 
0219         friend bool operator==(const ExceptionId &lhs, const ExceptionId &rhs)
0220         {
0221             return lhs._exception == rhs._exception;
0222         }
0223     };
0224 
0225     //* exception set
0226     using ExceptionSet = QSet<ExceptionId>;
0227 
0228     //* list of white listed special widgets
0229     /**
0230     it is read from options and is used to adjust
0231     per-app window dragging issues
0232     */
0233     ExceptionSet _whiteList;
0234 
0235     //* list of black listed special widgets
0236     /**
0237     it is read from options and is used to adjust
0238     per-app window dragging issues
0239     */
0240     ExceptionSet _blackList;
0241 
0242     //* drag point
0243     QPoint _dragPoint;
0244     QPoint _globalDragPoint;
0245 
0246     //* drag timer
0247     QBasicTimer _dragTimer;
0248 
0249     //* target being dragged
0250     /** Weak pointer is used in case the target gets deleted while drag is in progress */
0251     WeakPointer<QWidget> _target;
0252 
0253 #if BREEZE_HAVE_QTQUICK
0254     WeakPointer<QQuickItem> _quickTarget;
0255 #endif
0256 
0257     //* true if drag is about to start
0258     bool _dragAboutToStart = false;
0259 
0260     //* true if drag is in progress
0261     bool _dragInProgress = false;
0262 
0263     //* true if drag is locked
0264     bool _locked = false;
0265 
0266     //* true if the event we are intercepting passed trough a QQuickWidget.
0267     /**In this case we shouldn't start a drag, because if it was to start, we would have done it in the event filter of a qquickwidget.
0268      * Event handlers don't accept input events, but they do block QQuickItems to receive the event, so the event may have been
0269      * managed by an handler and not blocked by the root qml item.
0270      **/
0271     bool _eventInQQuickWidget = false;
0272 
0273     //* application event filter
0274     QObject *_appEventFilter = nullptr;
0275 
0276     //* allow access of all private members to the app event filter
0277     friend class AppEventFilter;
0278 };
0279 
0280 //____________________________________________________________________
0281 template<typename T>
0282 T WindowManager::findParent(const QWidget *widget) const
0283 {
0284     if (!widget) {
0285         return nullptr;
0286     }
0287     for (QWidget *parent = widget->parentWidget(); parent; parent = parent->parentWidget()) {
0288         if (T cast = qobject_cast<T>(parent)) {
0289             return cast;
0290         }
0291     }
0292 
0293     return nullptr;
0294 }
0295 
0296 }
0297 
0298 #endif