1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QHIGHDPISCALING_P_H
41#define QHIGHDPISCALING_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <QtGui/private/qtguiglobal_p.h>
55#include <QtCore/qlist.h>
56#include <QtCore/qloggingcategory.h>
57#include <QtCore/qmargins.h>
58#include <QtCore/qmath.h>
59#include <QtCore/qrect.h>
60#include <QtGui/qregion.h>
61#include <QtGui/qscreen.h>
62#include <QtGui/qvector2d.h>
63#include <QtGui/qwindow.h>
64
65QT_BEGIN_NAMESPACE
66
67Q_DECLARE_LOGGING_CATEGORY(lcScaling);
68
69class QScreen;
70class QPlatformScreen;
71typedef QPair<qreal, qreal> QDpi;
72
73#ifndef QT_NO_HIGHDPISCALING
74class Q_GUI_EXPORT QHighDpiScaling {
75 Q_GADGET
76public:
77 enum class DpiAdjustmentPolicy {
78 Unset,
79 Enabled,
80 Disabled,
81 UpOnly
82 };
83 Q_ENUM(DpiAdjustmentPolicy)
84
85 QHighDpiScaling() = delete;
86 ~QHighDpiScaling() = delete;
87 QHighDpiScaling(const QHighDpiScaling &) = delete;
88 QHighDpiScaling &operator=(const QHighDpiScaling &) = delete;
89 QHighDpiScaling(QHighDpiScaling &&) = delete;
90 QHighDpiScaling &operator=(QHighDpiScaling &&) = delete;
91
92 static void initHighDpiScaling();
93 static void updateHighDpiScaling();
94 static void setGlobalFactor(qreal factor);
95 static void setScreenFactor(QScreen *screen, qreal factor);
96
97 static bool isActive() { return m_active; }
98
99 struct Point {
100 enum Kind {
101 Invalid,
102 DeviceIndependent,
103 Native
104 };
105 Kind kind;
106 QPoint point;
107 };
108
109 struct ScaleAndOrigin
110 {
111 qreal factor;
112 QPoint origin;
113 };
114
115 static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, Point position = Point{ Point::Invalid, QPoint() });
116 static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, Point position = Point{ Point::Invalid, QPoint() });
117 static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, Point position = Point{ Point::Invalid, QPoint() });
118
119 template<typename C>
120 static qreal factor(C *context) {
121 return scaleAndOrigin(context).factor;
122 }
123
124 static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
125 static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
126 static QDpi logicalDpi(const QScreen *screen);
127
128private:
129 static qreal rawScaleFactor(const QPlatformScreen *screen);
130 static qreal roundScaleFactor(qreal rawFactor);
131 static QDpi effectiveLogicalDpi(const QPlatformScreen *screen, qreal rawFactor, qreal roundedFactor);
132 static qreal screenSubfactor(const QPlatformScreen *screen);
133 static QScreen *screenForPosition(Point position, QScreen *guess);
134
135 static qreal m_factor;
136 static bool m_active;
137 static bool m_usePlatformPluginDpi;
138 static bool m_platformPluginDpiScalingActive;
139 static bool m_globalScalingActive;
140 static bool m_screenFactorSet;
141 static QDpi m_logicalDpi;
142};
143
144namespace QHighDpi {
145
146inline qreal scale(qreal value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
147{
148 return value * scaleFactor;
149}
150
151inline QSize scale(const QSize &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
152{
153 return value * scaleFactor;
154}
155
156inline QSizeF scale(const QSizeF &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
157{
158 return value * scaleFactor;
159}
160
161inline QVector2D scale(const QVector2D &value, qreal scaleFactor, QPointF /* origin */ = QPointF(0, 0))
162{
163 return value * float(scaleFactor);
164}
165
166inline QPointF scale(const QPointF &pos, qreal scaleFactor, QPointF origin = QPointF(0, 0))
167{
168 return (pos - origin) * scaleFactor + origin;
169}
170
171inline QPoint scale(const QPoint &pos, qreal scaleFactor, QPoint origin = QPoint(0, 0))
172{
173 return (pos - origin) * scaleFactor + origin;
174}
175
176inline QRect scale(const QRect &rect, qreal scaleFactor, QPoint origin = QPoint(0, 0))
177{
178 return QRect(scale(rect.topLeft(), scaleFactor, origin), scale(rect.size(), scaleFactor));
179}
180
181inline QRectF scale(const QRectF &rect, qreal scaleFactor, QPoint origin = QPoint(0, 0))
182{
183 return QRectF(scale(rect.topLeft(), scaleFactor, origin), scale(rect.size(), scaleFactor));
184}
185
186inline QMargins scale(const QMargins &margins, qreal scaleFactor, QPoint origin = QPoint(0, 0))
187{
188 Q_UNUSED(origin);
189 return QMargins(qRound(qreal(margins.left()) * scaleFactor), qRound(qreal(margins.top()) * scaleFactor),
190 qRound(qreal(margins.right()) * scaleFactor), qRound(qreal(margins.bottom()) * scaleFactor));
191}
192
193template<typename T>
194QList<T> scale(const QList<T> &list, qreal scaleFactor, QPoint origin = QPoint(0, 0))
195{
196 if (!QHighDpiScaling::isActive())
197 return list;
198
199 QList<T> scaled;
200 scaled.reserve(list.size());
201 for (const T &item : list)
202 scaled.append(scale(item, scaleFactor, origin));
203 return scaled;
204}
205
206inline QRegion scale(const QRegion &region, qreal scaleFactor, QPoint origin = QPoint(0, 0))
207{
208 if (!QHighDpiScaling::isActive())
209 return region;
210
211 QRegion scaled;
212 for (const QRect &rect : region)
213 scaled += scale(QRectF(rect), scaleFactor, origin).toRect();
214 return scaled;
215}
216
217template <typename T>
218inline QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind) {
219 return QHighDpiScaling::Point{ QHighDpiScaling::Point::Invalid, QPoint() };
220}
221inline QHighDpiScaling::Point position(QPoint point, QHighDpiScaling::Point::Kind kind) {
222 return QHighDpiScaling::Point{ kind, point };
223}
224inline QHighDpiScaling::Point position(QPointF point, QHighDpiScaling::Point::Kind kind) {
225 return QHighDpiScaling::Point{ kind, point.toPoint() };
226}
227inline QHighDpiScaling::Point position(QRect rect, QHighDpiScaling::Point::Kind kind) {
228 return QHighDpiScaling::Point{ kind, rect.topLeft() };
229}
230inline QHighDpiScaling::Point position(QRectF rect, QHighDpiScaling::Point::Kind kind) {
231 return QHighDpiScaling::Point{ kind, rect.topLeft().toPoint() };
232}
233
234template <typename T, typename C>
235T fromNativePixels(const T &value, const C *context)
236{
237 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
238 return scale(value, qreal(1) / so.factor, so.origin);
239}
240
241template <typename T, typename C>
242T toNativePixels(const T &value, const C *context)
243{
244 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
245 return scale(value, so.factor, so.origin);
246}
247
248template <typename T, typename C>
249T fromNativeLocalPosition(const T &value, const C *context)
250{
251 return scale(value, qreal(1) / QHighDpiScaling::factor(context));
252}
253
254template <typename T, typename C>
255T toNativeLocalPosition(const T &value, const C *context)
256{
257 return scale(value, QHighDpiScaling::factor(context));
258}
259
260template <typename T, typename C>
261T fromNativeGlobalPosition(const T &value, const C *context)
262{
263 QHighDpiScaling::ScaleAndOrigin so =
264 QHighDpiScaling::scaleAndOrigin(context, position(value, QHighDpiScaling::Point::Native));
265 return scale(value, qreal(1) / so.factor, so.origin);
266}
267
268template <typename T, typename C>
269T toNativeGlobalPosition(const T &value, const C *context)
270{
271 QHighDpiScaling::ScaleAndOrigin so =
272 QHighDpiScaling::scaleAndOrigin(context, position(value, QHighDpiScaling::Point::DeviceIndependent));
273 return scale(value, so.factor, so.origin);
274}
275
276template <typename T, typename C>
277T fromNativeWindowGeometry(const T &value, const C *context)
278{
279 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
280 QPoint effectiveOrigin = (context && context->isTopLevel()) ? so.origin : QPoint(0,0);
281 return scale(value, qreal(1) / so.factor, effectiveOrigin);
282}
283
284template <typename T, typename C>
285T toNativeWindowGeometry(const T &value, const C *context)
286{
287 QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
288 QPoint effectiveOrigin = (context && context->isTopLevel()) ? so.origin : QPoint(0,0);
289 return scale(value, so.factor, effectiveOrigin);
290}
291
292template <typename T>
293inline T fromNative(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
294{
295 return scale(value, qreal(1) / scaleFactor, origin);
296}
297
298template <typename T>
299inline T toNative(const T &value, qreal scaleFactor, QPoint origin = QPoint(0, 0))
300{
301 return scale(value, scaleFactor, origin);
302}
303
304inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin)
305{
306 return scale(rect, qreal(1) / QHighDpiScaling::factor(screen), screenOrigin);
307}
308
309inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const QScreen *screen)
310{
311 return QRect(nativeScreenGeometry.topLeft(),
312 scale(nativeScreenGeometry.size(), qreal(1) / QHighDpiScaling::factor(screen)));
313}
314
315inline QRegion fromNativeLocalRegion(const QRegion &pixelRegion, const QWindow *window)
316{
317 return scale(pixelRegion, qreal(1) / QHighDpiScaling::factor(window));
318}
319
320// When mapping expose events to Qt rects: round top/left towards the origin and
321// bottom/right away from the origin, making sure that we cover the whole window.
322inline QRegion fromNativeLocalExposedRegion(const QRegion &pixelRegion, const QWindow *window)
323{
324 if (!QHighDpiScaling::isActive())
325 return pixelRegion;
326
327 const qreal scaleFactor = QHighDpiScaling::factor(window);
328 QRegion pointRegion;
329 for (const QRectF rect: pixelRegion)
330 pointRegion += QRectF(rect.topLeft() / scaleFactor, rect.size() / scaleFactor).toAlignedRect();
331
332 return pointRegion;
333}
334
335inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window)
336{
337 return scale(pointRegion, QHighDpiScaling::factor(window));
338}
339
340} // namespace QHighDpi
341#else // QT_NO_HIGHDPISCALING
342class Q_GUI_EXPORT QHighDpiScaling {
343public:
344 static inline void initHighDpiScaling() {}
345 static inline void updateHighDpiScaling() {}
346 static inline void setGlobalFactor(qreal) {}
347 static inline void setScreenFactor(QScreen *, qreal) {}
348
349 struct ScaleAndOrigin
350 {
351 qreal factor;
352 QPoint origin;
353 };
354 static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition = nullptr);
355 static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, QPoint *nativePosition = nullptr);
356 static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, QPoint *nativePosition = nullptr);
357
358 static inline bool isActive() { return false; }
359 static inline qreal factor(const QWindow *) { return 1.0; }
360 static inline qreal factor(const QScreen *) { return 1.0; }
361 static inline qreal factor(const QPlatformScreen *) { return 1.0; }
362 static inline QPoint origin(const QScreen *) { return QPoint(); }
363 static inline QPoint origin(const QPlatformScreen *) { return QPoint(); }
364 static inline QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *) { return pos; }
365 static inline QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *) { return pos; }
366 static inline QPointF mapPositionToGlobal(const QPointF &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; }
367 static inline QPointF mapPositionFromGlobal(const QPointF &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; }
368 static inline QDpi logicalDpi(const QScreen *screen) { return QDpi(-1,-1); }
369};
370
371namespace QHighDpi {
372 template <typename T> inline
373 T toNative(const T &value, ...) { return value; }
374 template <typename T> inline
375 T fromNative(const T &value, ...) { return value; }
376
377 template <typename T> inline
378 T fromNativeLocalPosition(const T &value, ...) { return value; }
379 template <typename T> inline
380 T toNativeLocalPosition(const T &value, ...) { return value; }
381
382 template <typename T> inline
383 T fromNativeLocalRegion(const T &value, ...) { return value; }
384 template <typename T> inline
385 T fromNativeLocalExposedRegion(const T &value, ...) { return value; }
386 template <typename T> inline
387 T toNativeLocalRegion(const T &value, ...) { return value; }
388
389 template <typename T> inline
390 T fromNativeScreenGeometry(const T &value, ...) { return value; }
391
392 template <typename T, typename U> inline
393 T toNativePixels(const T &value, const U*) {return value;}
394 template <typename T, typename U> inline
395 T fromNativePixels(const T &value, const U*) {return value;}
396}
397#endif // QT_NO_HIGHDPISCALING
398QT_END_NAMESPACE
399
400#endif // QHIGHDPISCALING_P_H
401