File indexing completed on 2024-04-28 05:26:27

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