1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
7 
8     SPDX-License-Identifier: GPL-2.0-or-later
9 */
10 
11 #ifndef KWIN_UTILS_H
12 #define KWIN_UTILS_H
13 
14 // cmake stuff
15 #include <config-kwin.h>
16 #include <kwinconfig.h>
17 // kwin
18 #include <kwinglobals.h>
19 // Qt
20 #include <QLoggingCategory>
21 #include <QList>
22 #include <QMatrix4x4>
23 #include <QPoint>
24 #include <QRect>
25 #include <QScopedPointer>
26 #include <QProcess>
27 // system
28 #include <climits>
29 Q_DECLARE_LOGGING_CATEGORY(KWIN_CORE)
Q_DECLARE_LOGGING_CATEGORY(KWIN_VIRTUALKEYBOARD)30 Q_DECLARE_LOGGING_CATEGORY(KWIN_VIRTUALKEYBOARD)
31 namespace KWin
32 {
33 Q_NAMESPACE
34 
35 const QPoint invalidPoint(INT_MIN, INT_MIN);
36 
37 enum Layer {
38     UnknownLayer = -1,
39     FirstLayer = 0,
40     DesktopLayer = FirstLayer,
41     BelowLayer,
42     NormalLayer,
43     DockLayer,
44     AboveLayer,
45     NotificationLayer, // layer for windows of type notification
46     ActiveLayer, // active fullscreen, or active dialog
47     PopupLayer, // tooltips, sub- and context menus
48     CriticalNotificationLayer, // layer for notifications that should be shown even on top of fullscreen
49     OnScreenDisplayLayer, // layer for On Screen Display windows such as volume feedback
50     UnmanagedLayer, // layer for override redirect windows.
51     NumLayers, // number of layers, must be last
52 };
53 Q_ENUM_NS(Layer)
54 
55 enum StrutArea {
56     StrutAreaInvalid = 0, // Null
57     StrutAreaTop     = 1 << 0,
58     StrutAreaRight   = 1 << 1,
59     StrutAreaBottom  = 1 << 2,
60     StrutAreaLeft    = 1 << 3,
61     StrutAreaAll     = StrutAreaTop | StrutAreaRight | StrutAreaBottom | StrutAreaLeft,
62 };
63 Q_DECLARE_FLAGS(StrutAreas, StrutArea)
64 
65 class StrutRect : public QRect
66 {
67 public:
68     explicit StrutRect(QRect rect = QRect(), StrutArea area = StrutAreaInvalid);
69     StrutRect(int x, int y, int width, int height, StrutArea area = StrutAreaInvalid);
70     StrutRect(const StrutRect& other);
71     StrutRect &operator=(const StrutRect& other);
72     inline StrutArea area() const {
73         return m_area;
74     }
75 private:
76     StrutArea m_area;
77 };
78 typedef QVector<StrutRect> StrutRects;
79 
80 enum ShadeMode {
81     ShadeNone, // not shaded
82     ShadeNormal, // normally shaded - isShade() is true only here
83     ShadeHover, // "shaded", but visible due to hover unshade
84     ShadeActivated // "shaded", but visible due to alt+tab to the window
85 };
86 
87 /**
88  * Maximize mode. These values specify how a window is maximized.
89  *
90  * @note these values are written to session files, don't change the order
91  */
92 enum MaximizeMode {
93     MaximizeRestore    = 0, ///< The window is not maximized in any direction.
94     MaximizeVertical   = 1, ///< The window is maximized vertically.
95     MaximizeHorizontal = 2, ///< The window is maximized horizontally.
96     /// Equal to @p MaximizeVertical | @p MaximizeHorizontal
97     MaximizeFull = MaximizeVertical | MaximizeHorizontal,
98 };
99 
100 inline
101 MaximizeMode operator^(MaximizeMode m1, MaximizeMode m2)
102 {
103     return MaximizeMode(int(m1) ^ int(m2));
104 }
105 
106 enum class QuickTileFlag {
107     None        = 0,
108     Left        = 1 << 0,
109     Right       = 1 << 1,
110     Top         = 1 << 2,
111     Bottom      = 1 << 3,
112     Horizontal  = Left | Right,
113     Vertical    = Top | Bottom,
114     Maximize    = Left | Right | Top | Bottom,
115 };
116 Q_DECLARE_FLAGS(QuickTileMode, QuickTileFlag)
117 
118 template <typename T> using ScopedCPointer = QScopedPointer<T, QScopedPointerPodDeleter>;
119 
120 void KWIN_EXPORT updateXTime();
121 void KWIN_EXPORT grabXServer();
122 void KWIN_EXPORT ungrabXServer();
123 bool KWIN_EXPORT grabXKeyboard(xcb_window_t w = XCB_WINDOW_NONE);
124 void KWIN_EXPORT ungrabXKeyboard();
125 
126 /**
127  * QPainter::setWindow() doesn't work as expected when the device pixel ratio of the paint
128  * device is less than 1.
129  *
130  * QPainter simply doesn't allow the effective scale factor to be less than 1. Use this function
131  * to determine the effective device pixel ratio by which the window rect has to be scaled.
132  */
133 qreal KWIN_EXPORT qPainterEffectiveDevicePixelRatio(const QPainter *painter);
134 
135 static inline QRegion mapRegion(const QMatrix4x4 &matrix, const QRegion &region)
136 {
137     QRegion result;
138     for (const QRect &rect : region) {
139         result += matrix.mapRect(rect);
140     }
141     return result;
142 }
143 
144 /**
145  * Small helper class which performs grabXServer in the ctor and
146  * ungrabXServer in the dtor. Use this class to ensure that grab and
147  * ungrab are matched.
148  */
149 class XServerGrabber
150 {
151 public:
152     XServerGrabber() {
153         grabXServer();
154     }
155     ~XServerGrabber() {
156         ungrabXServer();
157     }
158 };
159 
160 // the docs say it's UrgencyHint, but it's often #defined as XUrgencyHint
161 #ifndef UrgencyHint
162 #define UrgencyHint XUrgencyHint
163 #endif
164 
165 // converting between X11 mouse/keyboard state mask and Qt button/keyboard states
166 Qt::MouseButton x11ToQtMouseButton(int button);
167 Qt::MouseButton KWIN_EXPORT x11ToQtMouseButton(int button);
168 Qt::MouseButtons KWIN_EXPORT x11ToQtMouseButtons(int state);
169 Qt::KeyboardModifiers KWIN_EXPORT x11ToQtKeyboardModifiers(int state);
170 
171 /**
172  * Separate the concept of an unet QPoint and 0,0
173  */
174 class ClearablePoint
175 {
176 public:
177     inline bool isValid() const {
178         return m_valid;
179     }
180 
181     inline void clear(){
182         m_valid = false;
183     }
184 
185     inline void setPoint(const QPoint &point) {
186         m_point = point; m_valid = true;
187     }
188 
189     inline QPoint point() const {
190         return m_point;
191     }
192 
193 private:
194     QPoint m_point;
195     bool m_valid = false;
196 };
197 
198 /**
199  * QProcess subclass which unblocks SIGUSR in the child process.
200  */
201 class KWIN_EXPORT Process : public QProcess
202 {
203     Q_OBJECT
204 public:
205     explicit Process(QObject *parent = nullptr);
206     ~Process() override;
207 
208 #ifndef KCMRULES
209 protected:
210     void setupChildProcess() override;
211 #endif
212 };
213 
214 /**
215  * The DamageJournal class is a helper that tracks last N damage regions.
216  */
217 class KWIN_EXPORT DamageJournal
218 {
219 public:
220     /**
221      * Returns the maximum number of damage regions that can be stored in the journal.
222      */
223     int capacity() const
224     {
225         return m_capacity;
226     }
227 
228     /**
229      * Sets the maximum number of damage regions that can be stored in the journal
230      * to @a capacity.
231      */
232     void setCapacity(int capacity)
233     {
234         m_capacity = capacity;
235     }
236 
237     /**
238      * Adds the specified @a region to the journal.
239      */
240     void add(const QRegion &region)
241     {
242         while (m_log.size() >= m_capacity) {
243             m_log.takeLast();
244         }
245         m_log.prepend(region);
246     }
247 
248     /**
249      * Clears the damage journal. Typically, one would want to clear the damage journal
250      * if a buffer swap fails for some reason.
251      */
252     void clear()
253     {
254         m_log.clear();
255     }
256 
257     /**
258      * Accumulates the damage regions in the log up to the specified @a bufferAge.
259      *
260      * If the specified buffer age value refers to a damage region older than the last
261      * one in the journal, @a fallback will be returned.
262      */
263     QRegion accumulate(int bufferAge, const QRegion &fallback = QRegion()) const
264     {
265         QRegion region;
266         if (bufferAge > 0 && bufferAge <= m_log.size()) {
267             for (int i = 0; i < bufferAge - 1; ++i) {
268                 region |= m_log[i];
269             }
270         } else {
271             region = fallback;
272         }
273         return region;
274     }
275 
276 private:
277     QList<QRegion> m_log;
278     int m_capacity = 10;
279 };
280 
281 } // namespace
282 
283 // Must be outside namespace
284 Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::StrutAreas)
285 Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::QuickTileMode)
286 
287 #endif
288