diff options
95 files changed, 2469 insertions, 1049 deletions
diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index 12ae8a65d8..ff0032d623 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -265,6 +265,25 @@ public class ExtractStyle { final int defaultBackgroundColor; final int defaultTextColor; + // wrapper for accessing a TypedArray with style values and + // retrieving either device-indpendent pixel values or device + // pixel valies, depending on if useDevicePixels below is set + Boolean m_useDevicePixels; + // ### should possibly return float + int getTypedArraDimensionSize(TypedArray a, int index, int defValue) + { + if (m_useDevicePixels) + return a.getDimensionPixelSize(index, defValue); + return (int) a.getDimension(index, (float)defValue); + } + + int getTypedArraDimensionOffset(TypedArray a, int index, int defValue) + { + if (m_useDevicePixels) + return a.getDimensionPixelOffset(index, defValue); + return (int) a.getDimension(index, (float)defValue); + } + class SimpleJsonWriter { private OutputStreamWriter m_writer; @@ -1180,19 +1199,19 @@ public class ExtractStyle { if (attr == View_background) json.put("View_background", getDrawable(a.getDrawable(attr), styleName + "_View_background", null)); else if (attr == View_padding) - json.put("View_padding", a.getDimensionPixelSize(attr, -1)); + json.put("View_padding", getTypedArraDimensionSize(a, attr, -1)); else if (attr == View_paddingLeft) - json.put("View_paddingLeft", a.getDimensionPixelSize(attr, -1)); + json.put("View_paddingLeft", getTypedArraDimensionSize(a, attr, -1)); else if (attr == View_paddingTop) - json.put("View_paddingTop", a.getDimensionPixelSize(attr, -1)); + json.put("View_paddingTop", getTypedArraDimensionSize(a, attr, -1)); else if (attr == View_paddingRight) - json.put("View_paddingRight", a.getDimensionPixelSize(attr, -1)); + json.put("View_paddingRight", getTypedArraDimensionSize(a, attr, -1)); else if (attr == View_paddingBottom) - json.put("View_paddingBottom", a.getDimensionPixelSize(attr, -1)); + json.put("View_paddingBottom", getTypedArraDimensionSize(a, attr, -1)); else if (attr == View_scrollX) - json.put("View_paddingBottom", a.getDimensionPixelOffset(attr, 0)); + json.put("View_paddingBottom", getTypedArraDimensionOffset(a, attr, 0)); else if (attr == View_scrollY) - json.put("View_scrollY", a.getDimensionPixelOffset(attr, 0)); + json.put("View_scrollY", getTypedArraDimensionOffset(a, attr, 0)); else if (attr == View_id) json.put("View_id", a.getResourceId(attr, -1)); else if (attr == View_tag) @@ -1232,7 +1251,7 @@ public class ExtractStyle { else if (attr == View_scrollbarDefaultDelayBeforeFade) json.put("View_scrollbarDefaultDelayBeforeFade", a.getInt(attr, 0)); else if (attr == View_scrollbarSize) - json.put("View_scrollbarSize", a.getDimensionPixelSize(attr, -1)); + json.put("View_scrollbarSize", getTypedArraDimensionSize(a, attr, -1)); else if (attr == View_scrollbarThumbHorizontal) json.put("View_scrollbarThumbHorizontal", getDrawable(a.getDrawable(attr), styleName + "_View_scrollbarThumbHorizontal", null)); else if (attr == View_scrollbarThumbVertical) @@ -1256,17 +1275,17 @@ public class ExtractStyle { else if (attr == View_nextFocusDown) json.put("View_nextFocusDown", a.getResourceId(attr, -1)); else if (attr == View_minWidth) - json.put("View_minWidth", a.getDimensionPixelSize(attr, 0)); + json.put("View_minWidth", getTypedArraDimensionSize(a, attr, 0)); else if (attr == View_minHeight) - json.put("View_minHeight", a.getDimensionPixelSize(attr, 0)); + json.put("View_minHeight", getTypedArraDimensionSize(a, attr, 0)); else if (attr == View_onClick) json.put("View_onClick", a.getString(attr)); else if (attr == View_overScrollMode) json.put("View_overScrollMode", a.getInt(attr, 1)); else if (attr == View_paddingStart) - json.put("View_paddingStart", a.getDimensionPixelSize(attr, 0)); + json.put("View_paddingStart", getTypedArraDimensionSize(a, attr, 0)); else if (attr == View_paddingEnd) - json.put("View_paddingEnd", a.getDimensionPixelSize(attr, 0)); + json.put("View_paddingEnd", getTypedArraDimensionSize(a, attr, 0)); } a.recycle(); } catch (Exception e) { @@ -1293,7 +1312,7 @@ public class ExtractStyle { else if (attr == TextAppearance_textColorLink) json.put("TextAppearance_textColorLink", getColorStateList(a.getColorStateList(attr))); else if (attr == TextAppearance_textSize) - json.put("TextAppearance_textSize", a.getDimensionPixelSize(attr, 15)); + json.put("TextAppearance_textSize", getTypedArraDimensionSize(a, attr, 15)); else if (attr == TextAppearance_typeface) json.put("TextAppearance_typeface", a.getInt(attr, -1)); else if (attr == TextAppearance_textStyle) @@ -1354,7 +1373,7 @@ public class ExtractStyle { else if (attr == TextAppearance_textColorLink) textColorLink = appearance.getColorStateList(attr); else if (attr == TextAppearance_textSize) - textSize = appearance.getDimensionPixelSize(attr, textSize); + textSize = getTypedArraDimensionSize(appearance, attr, textSize); else if (attr == TextAppearance_typeface) typefaceIndex = appearance.getInt(attr, -1); else if (attr == TextAppearance_textStyle) @@ -1407,7 +1426,7 @@ public class ExtractStyle { else if (attr == TextView_drawableEnd) json.put("TextView_drawableEnd", getDrawable(a.getDrawable(attr), styleName + "_TextView_drawableEnd", null)); else if (attr == TextView_drawablePadding) - json.put("TextView_drawablePadding", a.getDimensionPixelSize(attr, 0)); + json.put("TextView_drawablePadding", getTypedArraDimensionSize(a, attr, 0)); else if (attr == TextView_textCursorDrawable) { try { json.put("TextView_textCursorDrawable", getDrawable(a.getDrawable(attr), styleName + "_TextView_textCursorDrawable", null)); @@ -1421,27 +1440,27 @@ public class ExtractStyle { }else if (attr == TextView_maxLines) json.put("TextView_maxLines", a.getInt(attr, -1)); else if (attr == TextView_maxHeight) - json.put("TextView_maxHeight", a.getDimensionPixelSize(attr, -1)); + json.put("TextView_maxHeight", getTypedArraDimensionSize(a, attr, -1)); else if (attr == TextView_lines) json.put("TextView_lines", a.getInt(attr, -1)); else if (attr == TextView_height) - json.put("TextView_height", a.getDimensionPixelSize(attr, -1)); + json.put("TextView_height", getTypedArraDimensionSize(a, attr, -1)); else if (attr == TextView_minLines) json.put("TextView_minLines", a.getInt(attr, -1)); else if (attr == TextView_minHeight) - json.put("TextView_minHeight", a.getDimensionPixelSize(attr, -1)); + json.put("TextView_minHeight", getTypedArraDimensionSize(a, attr, -1)); else if (attr == TextView_maxEms) json.put("TextView_maxEms", a.getInt(attr, -1)); else if (attr == TextView_maxWidth) - json.put("TextView_maxWidth", a.getDimensionPixelSize(attr, -1)); + json.put("TextView_maxWidth", getTypedArraDimensionSize(a, attr, -1)); else if (attr == TextView_ems) json.put("TextView_ems", a.getInt(attr, -1)); else if (attr == TextView_width) - json.put("TextView_width", a.getDimensionPixelSize(attr, -1)); + json.put("TextView_width", getTypedArraDimensionSize(a, attr, -1)); else if (attr == TextView_minEms) json.put("TextView_minEms", a.getInt(attr, -1)); else if (attr == TextView_minWidth) - json.put("TextView_minWidth", a.getDimensionPixelSize(attr, -1)); + json.put("TextView_minWidth", getTypedArraDimensionSize(a, attr, -1)); else if (attr == TextView_gravity) json.put("TextView_gravity", a.getInt(attr, -1)); else if (attr == TextView_hint) @@ -1485,7 +1504,7 @@ public class ExtractStyle { else if (attr == TextView_textColorLink) textColorLink = a.getColorStateList(attr); else if (attr == TextView_textSize) - textSize = a.getDimensionPixelSize(attr, textSize); + textSize = getTypedArraDimensionSize(a, attr, textSize); else if (attr == TextView_typeface) typefaceIndex = a.getInt(attr, typefaceIndex); else if (attr == TextView_textStyle) @@ -1493,7 +1512,7 @@ public class ExtractStyle { else if (attr == TextView_password) json.put("TextView_password", a.getBoolean(attr,false)); else if (attr == TextView_lineSpacingExtra) - json.put("TextView_lineSpacingExtra", a.getDimensionPixelSize(attr, 0)); + json.put("TextView_lineSpacingExtra", getTypedArraDimensionSize(a, attr, 0)); else if (attr == TextView_lineSpacingMultiplier) json.put("TextView_lineSpacingMultiplier", a.getFloat(attr, 1.0f)); else if (attr == TextView_inputType) @@ -1588,8 +1607,8 @@ public class ExtractStyle { json.put("ImageView_baselineAlignBottom", a.getBoolean(ImageView_baselineAlignBottom, false)); json.put("ImageView_adjustViewBounds", a.getBoolean(ImageView_adjustViewBounds, false)); - json.put("ImageView_maxWidth", a.getDimensionPixelSize(ImageView_maxWidth, Integer.MAX_VALUE)); - json.put("ImageView_maxHeight", a.getDimensionPixelSize(ImageView_maxHeight, Integer.MAX_VALUE)); + json.put("ImageView_maxWidth", getTypedArraDimensionSize(a, ImageView_maxWidth, Integer.MAX_VALUE)); + json.put("ImageView_maxHeight", getTypedArraDimensionSize(a, ImageView_maxHeight, Integer.MAX_VALUE)); int index = a.getInt(ImageView_scaleType, -1); if (index >= 0) json.put("ImageView_scaleType", sScaleTypeArray[index]); @@ -1646,10 +1665,10 @@ public class ExtractStyle { int mMaxWidth = 48; int mMinHeight = 24; int mMaxHeight = 48; - mMinWidth = a.getDimensionPixelSize(getField(styleableClass, "ProgressBar_minWidth"), mMinWidth); - mMaxWidth = a.getDimensionPixelSize(getField(styleableClass, "ProgressBar_maxWidth"), mMaxWidth); - mMinHeight = a.getDimensionPixelSize(getField(styleableClass, "ProgressBar_minHeight"), mMinHeight); - mMaxHeight = a.getDimensionPixelSize(getField(styleableClass, "ProgressBar_maxHeight"), mMaxHeight); + mMinWidth = getTypedArraDimensionSize(a, getField(styleableClass, "ProgressBar_minWidth"), mMinWidth); + mMaxWidth = getTypedArraDimensionSize(a, getField(styleableClass, "ProgressBar_maxWidth"), mMaxWidth); + mMinHeight = getTypedArraDimensionSize(a, getField(styleableClass, "ProgressBar_minHeight"), mMinHeight); + mMaxHeight = getTypedArraDimensionSize(a, getField(styleableClass, "ProgressBar_maxHeight"), mMaxHeight); json.put("ProgressBar_indeterminateDuration", a.getInt(getField(styleableClass, "ProgressBar_indeterminateDuration"), 4000)); json.put("ProgressBar_minWidth", mMinWidth); @@ -1737,9 +1756,9 @@ public class ExtractStyle { json.put("Switch_textOn", a.getText(getField(styleableClass, "Switch_textOn"))); json.put("Switch_textOff", a.getText(getField(styleableClass, "Switch_textOff"))); - json.put("Switch_switchMinWidth", a.getDimensionPixelSize(getField(styleableClass, "Switch_switchMinWidth"), 0)); - json.put("Switch_switchPadding", a.getDimensionPixelSize(getField(styleableClass, "Switch_switchPadding"), 0)); - json.put("Switch_thumbTextPadding", a.getDimensionPixelSize(getField(styleableClass, "Switch_thumbTextPadding"), 0)); + json.put("Switch_switchMinWidth", getTypedArraDimensionSize(a, getField(styleableClass, "Switch_switchMinWidth"), 0)); + json.put("Switch_switchPadding", getTypedArraDimensionSize(a, getField(styleableClass, "Switch_switchPadding"), 0)); + json.put("Switch_thumbTextPadding", getTypedArraDimensionSize(a, getField(styleableClass, "Switch_thumbTextPadding"), 0)); if (Build.VERSION.SDK_INT >= 21) { json.put("Switch_showText", a.getBoolean(getField(styleableClass, "Switch_showText"), true)); @@ -1834,7 +1853,7 @@ public class ExtractStyle { if (divider != null) json.put("ListView_divider", getDrawable(divider, styleName + "_ListView_divider", null)); - json.put("ListView_dividerHeight", a.getDimensionPixelSize(getField(styleableClass, "ListView_dividerHeight"), 0)); + json.put("ListView_dividerHeight", getTypedArraDimensionSize(a, getField(styleableClass, "ListView_dividerHeight"), 0)); a.recycle(); writer.name(styleName).value(json); @@ -1905,7 +1924,7 @@ public class ExtractStyle { if (d != null) json.put("ActionBar_divider", getDrawable(d, styleName + "_ActionBar_divider", null)); - json.put("ActionBar_itemPadding", a.getDimensionPixelSize(getField(styleableClass, "ActionBar_itemPadding"), 0)); + json.put("ActionBar_itemPadding", getTypedArraDimensionSize(a, getField(styleableClass, "ActionBar_itemPadding"), 0)); a.recycle(); writer.name(styleName).value(json); @@ -1928,7 +1947,7 @@ public class ExtractStyle { if (d != null) json.put("LinearLayout_divider", getDrawable(d, styleName + "_LinearLayout_divider", null)); json.put("LinearLayout_showDividers", a.getInt(getField(styleableClass, "LinearLayout_showDividers"), 0)); - json.put("LinearLayout_dividerPadding", a.getDimensionPixelSize(getField(styleableClass, "LinearLayout_dividerPadding"), 0)); + json.put("LinearLayout_dividerPadding", getTypedArraDimensionSize(a, getField(styleableClass, "LinearLayout_dividerPadding"), 0)); a.recycle(); writer.name(styleName).value(json); @@ -1981,29 +2000,11 @@ public class ExtractStyle { return json; } - public ExtractStyle(Context context, String extractPath) + public void extractStyleToJson(String path) { -// Log.i(MinistroService.TAG, "Extract " + extractPath); - m_extractPath = extractPath + "/"; - new File(m_extractPath).mkdirs(); -// MinistroActivity.nativeChmode(m_extractPath, 0755); - m_context = context; - m_theme = context.getTheme(); - TypedArray array = m_theme.obtainStyledAttributes(new int[]{ - android.R.attr.colorBackground, - android.R.attr.textColorPrimary, - android.R.attr.textColor - }); - defaultBackgroundColor = array.getColor(0, 0); - int textColor = array.getColor(1, 0xFFFFFF); - if (textColor == 0xFFFFFF) - textColor = array.getColor(2, 0xFFFFFF); - defaultTextColor = textColor; - array.recycle(); - try { - SimpleJsonWriter jsonWriter = new SimpleJsonWriter(m_extractPath+"style.json"); + SimpleJsonWriter jsonWriter = new SimpleJsonWriter(path); jsonWriter.beginObject(); try { jsonWriter.name("defaultStyle").value(extractDefaultPalette()); @@ -2047,4 +2048,33 @@ public class ExtractStyle { e.printStackTrace(); } } + + public ExtractStyle(Context context, String extractPath) + { +// Log.i(MinistroService.TAG, "Extract " + extractPath); + m_extractPath = extractPath + "/"; + new File(m_extractPath).mkdirs(); +// MinistroActivity.nativeChmode(m_extractPath, 0755); + m_context = context; + m_theme = context.getTheme(); + TypedArray array = m_theme.obtainStyledAttributes(new int[]{ + android.R.attr.colorBackground, + android.R.attr.textColorPrimary, + android.R.attr.textColor + }); + defaultBackgroundColor = array.getColor(0, 0); + int textColor = array.getColor(1, 0xFFFFFF); + if (textColor == 0xFFFFFF) + textColor = array.getColor(2, 0xFFFFFF); + defaultTextColor = textColor; + array.recycle(); + + // Write two versions of the style file + // style.json with values in device pixels + // style_dip.json with values in device independent pixels + m_useDevicePixels = false; // ### write device-independent pixels only for now + extractStyleToJson(m_extractPath + "style.json"); + m_useDevicePixels = false; + extractStyleToJson(m_extractPath + "style_dip.json"); + } } diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index d6cd49f44c..18fa2f8fde 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -786,7 +786,8 @@ public class QtActivityDelegate m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); QtNative.setApplicationDisplayMetrics(metrics.widthPixels, metrics.heightPixels, 0, 0, - metrics.xdpi, metrics.ydpi, metrics.scaledDensity); + metrics.xdpi, metrics.ydpi, + metrics.scaledDensity, metrics.density); } m_layout = new QtLayout(m_activity); m_editText = new QtEditText(m_activity, this); diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java index 09fef4a705..8f2d656bcc 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java @@ -64,7 +64,8 @@ public class QtLayout extends ViewGroup DisplayMetrics metrics = new DisplayMetrics(); ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics); QtNative.setApplicationDisplayMetrics(metrics.widthPixels, - metrics.heightPixels, w, h, metrics.xdpi, metrics.ydpi, metrics.scaledDensity); + metrics.heightPixels, w, h, metrics.xdpi, metrics.ydpi, + metrics.scaledDensity, metrics.density); } @Override diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index 80f7fb5c85..b7363e5d87 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -72,6 +72,7 @@ public class QtNative private static double m_displayMetricsXDpi = .0; private static double m_displayMetricsYDpi = .0; private static double m_displayMetricsScaledDensity = 1.0; + private static double m_displayMetricsDensity = 1.0; private static int m_oldx, m_oldy; private static final int m_moveThreshold = 0; private static ClipboardManager m_clipboardManager = null; @@ -215,7 +216,8 @@ public class QtNative m_displayMetricsDesktopHeightPixels, m_displayMetricsXDpi, m_displayMetricsYDpi, - m_displayMetricsScaledDensity); + m_displayMetricsScaledDensity, + m_displayMetricsDensity); if (params.length() > 0 && !params.startsWith("\t")) params = "\t" + params; startQtApplication(f.getAbsolutePath() + params, environment); @@ -230,7 +232,8 @@ public class QtNative int desktopHeightPixels, double XDpi, double YDpi, - double scaledDensity) + double scaledDensity, + double density) { /* Fix buggy dpi report */ if (XDpi < android.util.DisplayMetrics.DENSITY_LOW) @@ -246,7 +249,8 @@ public class QtNative desktopHeightPixels, XDpi, YDpi, - scaledDensity); + scaledDensity, + density); } else { m_displayMetricsScreenWidthPixels = screenWidthPixels; m_displayMetricsScreenHeightPixels = screenHeightPixels; @@ -255,6 +259,7 @@ public class QtNative m_displayMetricsXDpi = XDpi; m_displayMetricsYDpi = YDpi; m_displayMetricsScaledDensity = scaledDensity; + m_displayMetricsDensity = density; } } } @@ -596,7 +601,8 @@ public class QtNative int desktopHeightPixels, double XDpi, double YDpi, - double scaledDensity); + double scaledDensity, + double density); public static native void handleOrientationChanged(int newRotation, int nativeOrientation); // screen methods diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 3c192a237e..7aeba45b3b 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -3891,6 +3891,10 @@ int QImage::metric(PaintDeviceMetric metric) const return d->devicePixelRatio; break; + case PdmDevicePixelRatioScaled: + return d->devicePixelRatio * QPaintDevice::devicePixelRatioFScale; + break; + default: qWarning("QImage::metric(): Unhandled metric type %d", metric); break; diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp index b63be19153..02a510ce29 100644 --- a/src/gui/image/qpicture.cpp +++ b/src/gui/image/qpicture.cpp @@ -961,6 +961,9 @@ int QPicture::metric(PaintDeviceMetric m) const case PdmDevicePixelRatio: val = 1; break; + case PdmDevicePixelRatioScaled: + val = 1 * QPaintDevice::devicePixelRatioFScale; + break; default: val = 0; qWarning("QPicture::metric: Invalid metric command"); diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp index f24cbc3db9..92f87b6ea9 100644 --- a/src/gui/image/qpixmap_blitter.cpp +++ b/src/gui/image/qpixmap_blitter.cpp @@ -115,6 +115,8 @@ int QBlittablePlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) con return qt_defaultDpiY(); case QPaintDevice::PdmDevicePixelRatio: return devicePixelRatio(); + case QPaintDevice::PdmDevicePixelRatioScaled: + return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale; default: qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric); break; diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 9c8835a7a0..6d4e90a6c4 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -288,6 +288,9 @@ int QRasterPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const return qt_defaultDpiY(); case QPaintDevice::PdmDevicePixelRatio: return image.devicePixelRatio(); + case QPaintDevice::PdmDevicePixelRatioScaled: + return image.devicePixelRatio() * QPaintDevice::devicePixelRatioFScale; + default: qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric); break; diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index af6a417608..73a5a7b6ab 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -75,7 +75,9 @@ HEADERS += \ kernel/qplatformgraphicsbuffer.h \ kernel/qplatformgraphicsbufferhelper.h \ kernel/qinputdevicemanager_p.h \ - kernel/qinputdevicemanager_p_p.h + kernel/qinputdevicemanager_p_p.h \ + kernel/qhighdpiscaling_p.h + SOURCES += \ kernel/qgenericpluginfactory.cpp \ @@ -131,7 +133,9 @@ SOURCES += \ kernel/qrasterwindow.cpp \ kernel/qplatformgraphicsbuffer.cpp \ kernel/qplatformgraphicsbufferhelper.cpp \ - kernel/qinputdevicemanager.cpp + kernel/qinputdevicemanager.cpp \ + kernel/qhighdpiscaling.cpp + contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { HEADERS += \ diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index 6ed750eda1..d52ecb7a68 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -43,6 +43,7 @@ #include <qpa/qplatformcursor.h> #include <private/qguiapplication_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -177,9 +178,14 @@ QT_BEGIN_NAMESPACE */ QPoint QCursor::pos(const QScreen *screen) { - if (screen) - if (const QPlatformCursor *cursor = screen->handle()->cursor()) - return cursor->pos(); + if (screen) { + if (const QPlatformCursor *cursor = screen->handle()->cursor()) { + QPlatformScreen *ps = screen->handle(); + QPoint nativePos = cursor->pos(); + ps = ps->screenForPosition(nativePos); + return QHighDpi::fromNativePixels(nativePos, ps->screen()); + } + } return QGuiApplicationPrivate::lastCursorPosition.toPoint(); } @@ -231,12 +237,12 @@ void QCursor::setPos(QScreen *screen, int x, int y) { if (screen) { if (QPlatformCursor *cursor = screen->handle()->cursor()) { - const QPoint pos = QPoint(x, y); + const QPoint devicePos = QHighDpi::toNativePixels(QPoint(x, y), screen); // Need to check, since some X servers generate null mouse move // events, causing looping in applications which call setPos() on // every mouse move event. - if (pos != cursor->pos()) - cursor->setPos(pos); + if (devicePos != cursor->pos()) + cursor->setPos(devicePos); } } } diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 024578ccdd..7866f65b7e 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -959,8 +959,10 @@ QWindow *QGuiApplication::topLevelAt(const QPoint &pos) QList<QScreen *>::const_iterator end = screens.constEnd(); while (screen != end) { - if ((*screen)->geometry().contains(pos)) - return (*screen)->handle()->topLevelAt(pos); + if ((*screen)->geometry().contains(pos)) { + const QPoint devicePosition = QHighDpi::toNativePixels(pos, *screen); + return (*screen)->handle()->topLevelAt(devicePosition); + } ++screen; } return 0; @@ -1116,6 +1118,9 @@ void QGuiApplicationPrivate::createPlatformIntegration() // this flag. QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); + + QHighDpiScaling::initHighDPiScaling(); + // Load the platform integration QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH")); @@ -1820,7 +1825,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo points << point; QEvent::Type type; - QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); + QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type); QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers); fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; @@ -2030,6 +2035,11 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf window->d_func()->setTopLevelScreen(screen, false /* recreate */); else // Fall back to default behavior, and try to find some appropriate screen window->setScreen(0); + // we may have changed scaling, so trigger resize event if needed + if (window->handle()) { + QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window), QRect()); + processGeometryChangeEvent(&gce); + } } } diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp new file mode 100644 index 0000000000..be127a54f3 --- /dev/null +++ b/src/gui/kernel/qhighdpiscaling.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhighdpiscaling_p.h" +#include "qguiapplication.h" +#include "qscreen.h" +#include "qplatformintegration.h" +#include "private/qscreen_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcScaling, "qt.scaling"); + +static const char legacyDevicePixelEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; +static const char scaleFactorEnvVar[] = "QT_SCALE_FACTOR"; +static const char autoScreenEnvVar[] = "QT_AUTO_SCREEN_SCALE_FACTOR"; + +static inline qreal initialScaleFactor() +{ + + qreal result = 1; + if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) { + bool ok; + const qreal f = qgetenv(scaleFactorEnvVar).toDouble(&ok); + if (ok && f > 0) { + qCDebug(lcScaling) << "Apply " << scaleFactorEnvVar << f; + result = f; + } + } else { + if (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar)) { + qWarning() << "Warning:" << legacyDevicePixelEnvVar << "is deprecated. Instead use:"; + qWarning() << " " << scaleFactorEnvVar << "to set the application global scale factor."; + qWarning() << " " << autoScreenEnvVar << "to enable platform plugin controlled per-screen factors."; + + int dpr = qEnvironmentVariableIntValue(legacyDevicePixelEnvVar); + if (dpr > 0) + result = dpr; + } + } + return result; +} + +/*! + \class QHighDpiScaling + \since 5.6 + \internal + \preliminary + \ingroup qpa + + \brief Collection of utility functions for UI scaling. +*/ + + +qreal QHighDpiScaling::m_factor; + +bool QHighDpiScaling::m_active; //"overall active" - is there any scale factor set. +bool QHighDpiScaling::m_perScreenActive; // different screens may have different scale +bool QHighDpiScaling::m_usePixelDensity; // use scale factor from platform plugin + +void QHighDpiScaling::initHighDPiScaling() +{ + m_factor = initialScaleFactor(); + bool usePlatformPluginPixelDensity = qEnvironmentVariableIsSet(autoScreenEnvVar) + || qgetenv(legacyDevicePixelEnvVar).toLower() == "auto"; + + // m_active below is "overall active" - is there any scale factor set. + m_active = !qFuzzyCompare(m_factor, qreal(1)) || usePlatformPluginPixelDensity; + m_usePixelDensity = usePlatformPluginPixelDensity; + m_perScreenActive = m_usePixelDensity; +} + +/* + Sets the global scale factor which is applied to all windows. +*/ +void QHighDpiScaling::setGlobalFactor(qreal factor) +{ + if (qFuzzyCompare(factor, QHighDpiScaling::m_factor)) + return; + if (!QGuiApplication::allWindows().isEmpty()) { + qWarning() << Q_FUNC_INFO << "QHighDpiScaling::setFactor: Should only be called when no windows exist."; + } + + QHighDpiScaling::m_active = !qFuzzyCompare(factor, qreal(1)); + QHighDpiScaling::m_factor = QHighDpiScaling::m_active ? factor : qreal(1); + Q_FOREACH (QScreen *screen, QGuiApplication::screens()) + screen->d_func()->updateHighDpi(); +} + +static const char *scaleFactorProperty = "_q_scaleFactor"; + +/* + Sets a per-screen scale factor. +*/ +void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor) +{ + m_active = true; + m_perScreenActive = true; + screen->setProperty(scaleFactorProperty, QVariant(factor)); +} + +/* + +QPoint QXcbScreen::mapToNative(const QPoint &pos) const +{ + const int dpr = int(devicePixelRatio()); + return (pos - m_geometry.topLeft()) * dpr + m_nativeGeometry.topLeft(); +} + +QPoint QXcbScreen::mapFromNative(const QPoint &pos) const +{ + const int dpr = int(devicePixelRatio()); + return (pos - m_nativeGeometry.topLeft()) / dpr + m_geometry.topLeft(); +} + + + */ + + +QPoint QHighDpiScaling::mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen) +{ + if (!platformScreen) + return pos; + const qreal scaleFactor = factor(platformScreen); + const QPoint topLeft = platformScreen->geometry().topLeft(); + return (pos - topLeft) * scaleFactor + topLeft; +} + +QPoint QHighDpiScaling::mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen) +{ + if (!platformScreen) + return pos; + const qreal scaleFactor = factor(platformScreen); + const QPoint topLeft = platformScreen->geometry().topLeft(); + return (pos - topLeft) / scaleFactor + topLeft; +} + +qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) +{ + qreal factor = qreal(1.0); + if (m_perScreenActive && screen) { + if (m_usePixelDensity) + factor *= screen->pixelDensity(); + QVariant screenFactor = screen->screen()->property(scaleFactorProperty); + if (screenFactor.isValid()) + factor *= screenFactor.toReal(); + } + return factor; +} + +qreal QHighDpiScaling::factor(const QScreen *screen) +{ + // Fast path for when scaling in Qt is not used at all. + if (!m_active) + return qreal(1.0); + + // The effective factor for a given screen is the product of the + // screen and global sub-factors + qreal factor = m_factor; + if (screen) + factor *= screenSubfactor(screen->handle()); + return factor; +} + +qreal QHighDpiScaling::factor(const QPlatformScreen *platformScreen) +{ + if (!m_active) + return qreal(1.0); + + return m_factor * screenSubfactor(platformScreen); +} + +qreal QHighDpiScaling::factor(const QWindow *window) +{ + if (!m_active || !window) + return qreal(1.0); + + return factor(window->screen()); +} + +QPoint QHighDpiScaling::origin(const QScreen *screen) +{ + return screen->geometry().topLeft(); +} + +QPoint QHighDpiScaling::origin(const QPlatformScreen *platformScreen) +{ + return platformScreen->geometry().topLeft(); +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h new file mode 100644 index 0000000000..8347214823 --- /dev/null +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -0,0 +1,484 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHIGHDPISCALING_P_H +#define QHIGHDPISCALING_P_H + +#include <QtCore/qglobal.h> +#include <QtCore/qmargins.h> +#include <QtCore/qrect.h> +#include <QtCore/qvector.h> +#include <QtCore/qloggingcategory.h> +#include <QtGui/qregion.h> +#include <QtGui/qscreen.h> +#include <QtGui/qwindow.h> + +// This file implmements utility functions for high-dpi scaling on operating +// systems that do not provide native scaling support. +// +// The functions support creating a logical device-independent +// coordinate system which is related to the device pixel coordinate +// through a scaling factor. +// +// Several scaling factors can be set: +// - A process-global scale factor +// - the QT_SCALE_FACTOR environment variable. +// - QHighDpiScaling::setFactor(factor); +// - A per-window scale factor +// - QHighDpiScaling::setWindowFactor(window, factor); +// +// With these functions in use most of the Qt API will then operate in +// the device-independent coordinate system. For example, setting +// the scale factor to 2.0 will make Qt see half of the "device" +// window geometry. Desktop and event geometry will be scaled +// to match. +// +// Integer scaling factors work best. Glitch-free graphics at non-integer +// scaling factors can not be guaranteed. + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcScaling); + +class QScreen; +class QPlatformScreen; + +class Q_GUI_EXPORT QHighDpiScaling { +public: + static void initHighDPiScaling(); + static void setGlobalFactor(qreal factor); + static void setScreenFactor(QScreen *window, qreal factor); + + static bool isActive() { return m_active; } + static qreal factor(const QWindow *window); + static qreal factor(const QScreen *screen); + static qreal factor(const QPlatformScreen *platformScreen); + static QPoint origin(const QScreen *screen); + static QPoint origin(const QPlatformScreen *platformScreen); + static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen); + static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen); +private: + static qreal screenSubfactor(const QPlatformScreen *screen); + + static qreal m_factor; + static bool m_active; + static bool m_perScreenActive; + static bool m_usePixelDensity; +}; + +// Coordinate system conversion functions: +// QHighDpi::fromNativePixels : from physical(screen/backing) to logical pixels +// QHighDpi::toNativePixels : from logical to physical pixels + +namespace QHighDpi { + +// inline QRect fromNativeGeometry(const QRect &pixelRect, const QPlatformScreen *platformScreen) +// { +// return QRect(pixelRect.topLeft(), pixelRect.size() / QHighDpiScaling::factor(platformScreen)); +// } + +// inline QRect toNativeGeometry(const QRect &pointRect, const QPlatformScreen *platformScreen) +// { +// return QRect(pointRect.topLeft(), pointRect.size() * QHighDpiScaling::factor(platformScreen)); +// } + +inline QPoint fromNative(const QPoint &pos, qreal scaleFactor, const QPoint &origin) +{ + return (pos - origin) / scaleFactor + origin; +} + +inline QPoint toNative(const QPoint &pos, qreal scaleFactor, const QPoint &origin) +{ + return (pos - origin) * scaleFactor + origin; +} + +inline QPoint fromNative(const QPoint &pos, qreal scaleFactor) +{ + return pos / scaleFactor; +} + +inline QPoint toNative(const QPoint &pos, qreal scaleFactor) +{ + return pos * scaleFactor; +} + +inline QSize fromNative(const QSize &size, qreal scaleFactor) +{ + return size / scaleFactor; // TODO: ### round up ### +} + +inline QSize toNative(const QSize &size, qreal scaleFactor) +{ + return size * scaleFactor; +} + +inline QRect fromNative(const QRect &rect, qreal scaleFactor, const QPoint &origin) +{ + return QRect(fromNative(rect.topLeft(), scaleFactor, origin), fromNative(rect.size(), scaleFactor)); +} + +inline QRect toNative(const QRect &rect, qreal scaleFactor, const QPoint &origin) +{ + return QRect(toNative(rect.topLeft(), scaleFactor, origin), toNative(rect.size(), scaleFactor)); + +} + +inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin) +{ + return toNative(rect, QHighDpiScaling::factor(screen), screenOrigin); +} + +inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const QScreen *screen) +{ + return QRect(nativeScreenGeometry.topLeft(), fromNative(nativeScreenGeometry.size(), QHighDpiScaling::factor(screen))); +} + +inline QPoint fromNativeLocalPosition(const QPoint &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos / scaleFactor; +} + +inline QPoint toNativeLocalPosition(const QPoint &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos * scaleFactor; +} + +inline QPointF fromNativeLocalPosition(const QPointF &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos / scaleFactor; +} + +inline QPointF toNativeLocalPosition(const QPointF &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos * scaleFactor; +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QPlatformScreen *platformScreen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(platformScreen); + const QPoint origin = QHighDpiScaling::origin(platformScreen); + return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin), + fromNative(pixelRect.size(), scaleFactor)); +} + +inline QRect toNativePixels(const QRect &pointRect, const QPlatformScreen *platformScreen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(platformScreen); + const QPoint origin = QHighDpiScaling::origin(platformScreen); + return QRect(toNative(pointRect.topLeft(), scaleFactor, origin), + toNative(pointRect.size(), scaleFactor)); +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin), + fromNative(pixelRect.size(), scaleFactor)); +} + +inline QRect toNativePixels(const QRect &pointRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRect(toNative(pointRect.topLeft(), scaleFactor, origin), + toNative(pointRect.size(), scaleFactor)); +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return fromNativePixels(pixelRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRect(pixelRect.topLeft() / scaleFactor, fromNative(pixelRect.size(), scaleFactor)); + } +} + +inline QRectF toNativePixels(const QRectF &pointRect, const QScreen *screen) +{ + //######## + return toNativePixels(pointRect.toRect(), screen); +} + +inline QRect toNativePixels(const QRect &pointRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return toNativePixels(pointRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRect(pointRect.topLeft() * scaleFactor, toNative(pointRect.size(), scaleFactor)); + } +} + +inline QRectF fromNativePixels(const QRectF &pixelRect, const QScreen *screen) +{ + //######## + return fromNativePixels(pixelRect.toRect(), screen); +} + +inline QRectF fromNativePixels(const QRectF &pixelRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return fromNativePixels(pixelRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRectF(pixelRect.topLeft() / scaleFactor, pixelRect.size() / scaleFactor); + } +} + +inline QRectF toNativePixels(const QRectF &pointRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return toNativePixels(pointRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRectF(pointRect.topLeft() * scaleFactor, pointRect.size() * scaleFactor); + } +} + +inline QSize fromNativePixels(const QSize &pixelSize, const QWindow *window) +{ + return pixelSize / QHighDpiScaling::factor(window); +} + +inline QSize toNativePixels(const QSize &pointSize, const QWindow *window) +{ + return pointSize * QHighDpiScaling::factor(window); +} + +inline QSizeF fromNativePixels(const QSizeF &pixelSize, const QWindow *window) +{ + return pixelSize / QHighDpiScaling::factor(window); +} + +inline QSizeF toNativePixels(const QSizeF &pointSize, const QWindow *window) +{ + return pointSize * QHighDpiScaling::factor(window); +} + +inline QPoint fromNativePixels(const QPoint &pixelPoint, const QScreen *screen) +{ + return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPoint fromNativePixels(const QPoint &pixelPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return fromNativePixels(pixelPoint, window->screen()); + else + return pixelPoint / QHighDpiScaling::factor(window); +} + +inline QPoint toNativePixels(const QPoint &pointPoint, const QScreen *screen) +{ + return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPoint toNativePixels(const QPoint &pointPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return toNativePixels(pointPoint, window->screen()); + else + return pointPoint * QHighDpiScaling::factor(window); +} + +inline QPointF fromNativePixels(const QPointF &pixelPoint, const QScreen *screen) +{ + return fromNativePixels(pixelPoint.toPoint(), screen); //############### +} + +inline QPointF fromNativePixels(const QPointF &pixelPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return fromNativePixels(pixelPoint, window->screen()); + else + return pixelPoint / QHighDpiScaling::factor(window); +} + +inline QPointF toNativePixels(const QPointF &pointPoint, const QScreen *screen) +{ + return toNativePixels(pointPoint.toPoint(), screen); //########### +} + +inline QPointF toNativePixels(const QPointF &pointPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return toNativePixels(pointPoint, window->screen()); + else + return pointPoint * QHighDpiScaling::factor(window); +} + +inline QMargins fromNativePixels(const QMargins &pixelMargins, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QMargins(pixelMargins.left() / scaleFactor, pixelMargins.top() / scaleFactor, + pixelMargins.right() / scaleFactor, pixelMargins.bottom() / scaleFactor); +} + +inline QMargins toNativePixels(const QMargins &pointMargins, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QMargins(pointMargins.left() * scaleFactor, pointMargins.top() * scaleFactor, + pointMargins.right() * scaleFactor, pointMargins.bottom() * scaleFactor); +} +#if 1 + //############## expose regions need special handling +inline QRegion fromNativeLocalRegion(const QRegion &pixelRegion, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelRegion; + + qreal scaleFactor = QHighDpiScaling::factor(window); + QRegion pointRegion; + foreach (const QRect &rect, pixelRegion.rects()) + pointRegion += QRect(fromNative(rect.topLeft(), scaleFactor), + fromNative(rect.size(), scaleFactor)); + return pointRegion; +} + +inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointRegion; + + qreal scaleFactor = QHighDpiScaling::factor(window); + QRegion pixelRegon; + foreach (const QRect &rect, pointRegion.rects()) + pixelRegon += QRect(toNative(rect.topLeft(), scaleFactor), + toNative(rect.size(), scaleFactor)); + return pixelRegon; +} +#endif +// Any T that has operator/() +template <typename T> +T fromNativePixels(const T &pixelValue, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelValue; + + return pixelValue / QHighDpiScaling::factor(window); + +} + + //##### ????? +template <typename T> +T fromNativePixels(const T &pixelValue, const QScreen *screen) +{ + if (!QHighDpiScaling::isActive()) + return pixelValue; + + return pixelValue / QHighDpiScaling::factor(screen); + +} + +// Any T that has operator*() +template <typename T> +T toNativePixels(const T &pointValue, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointValue; + + return pointValue * QHighDpiScaling::factor(window); +} + +template <typename T> +T toNativePixels(const T &pointValue, const QScreen *screen) +{ + if (!QHighDpiScaling::isActive()) + return pointValue; + + return pointValue * QHighDpiScaling::factor(screen); +} + + +// Any QVector<T> where T has operator/() +template <typename T> +QVector<T> fromNativePixels(const QVector<T> &pixelValues, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelValues; + + QVector<T> pointValues; + foreach (const T& pixelValue, pixelValues) + pointValues.append(pixelValue / QHighDpiScaling::factor(window)); + return pointValues; +} + +// Any QVector<T> where T has operator*() +template <typename T> +QVector<T> toNativePixels(const QVector<T> &pointValues, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointValues; + + QVector<T> pixelValues; + foreach (const T& pointValue, pointValues) + pixelValues.append(pointValue * QHighDpiScaling::factor(window)); + return pixelValues; +} + +#if 0 +// Any QPair<T, U> where T and U has operator/() +template <typename T, typename U> +QPair<T, U> fromNativePixels(const QPair<T, U> &pixelPair, const QWindow *window) +{ + return qMakePair(fromNativePixels(pixelPair.first, window), + fromNativePixels(pixelPair.second, window)); +} + +// Any QPair<T, U> where T and U has operator*() +template <typename T, typename U> +QPair<T, U> toNativePixels(const QPair<T, U> &pointPair, const QWindow *window) +{ + return qMakePair(QHighDpi::toNativePixels(pointPair.first, window), + QHighDpi::toNativePixels(pointPair.second, window)); +} +#endif +} + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/kernel/qopenglwindow.cpp b/src/gui/kernel/qopenglwindow.cpp index b2025faaf1..3a1126d318 100644 --- a/src/gui/kernel/qopenglwindow.cpp +++ b/src/gui/kernel/qopenglwindow.cpp @@ -664,15 +664,10 @@ int QOpenGLWindow::metric(PaintDeviceMetric metric) const if (d->paintDevice) return d->paintDevice->depth(); break; - case PdmDevicePixelRatio: - if (d->paintDevice) - return devicePixelRatio(); - break; default: break; } return QPaintDeviceWindow::metric(metric); - } /*! diff --git a/src/gui/kernel/qpaintdevicewindow.cpp b/src/gui/kernel/qpaintdevicewindow.cpp index ff661d017d..3ce83a0ad7 100644 --- a/src/gui/kernel/qpaintdevicewindow.cpp +++ b/src/gui/kernel/qpaintdevicewindow.cpp @@ -155,8 +155,10 @@ int QPaintDeviceWindow::metric(PaintDeviceMetric metric) const return qRound(screen->physicalDotsPerInchY()); break; case PdmDevicePixelRatio: - if (screen) - return screen->devicePixelRatio(); + return int(QWindow::devicePixelRatio()); + break; + case PdmDevicePixelRatioScaled: + return int(QWindow::devicePixelRatio() * devicePixelRatioFScale); break; default: break; diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 4d973d47a5..e935907a62 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -39,7 +39,6 @@ #include <qpa/qplatformtheme.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qpixmap_raster_p.h> -#include <qpa/qplatformscreen_p.h> #include <private/qdnd_p.h> #include <private/qsimpledrag_p.h> @@ -450,7 +449,7 @@ QList<int> QPlatformIntegration::possibleKeys(const QKeyEvent *) const void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary) { QScreen *screen = new QScreen(ps); - ps->d_func()->screen = screen; + if (isPrimary) { QGuiApplicationPrivate::screen_list.prepend(screen); } else { @@ -469,8 +468,9 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary) */ void QPlatformIntegration::destroyScreen(QPlatformScreen *screen) { - QGuiApplicationPrivate::screen_list.removeOne(screen->d_func()->screen); - delete screen->d_func()->screen; + QScreen *qScreen = screen->screen(); + QGuiApplicationPrivate::screen_list.removeOne(qScreen); + delete qScreen; delete screen; } diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index edf546799f..3a4adbc436 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformintegration.h> #include <QtGui/qscreen.h> #include <QtGui/qwindow.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -97,6 +98,32 @@ QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const } /*! + Find the sibling screen corresponding to \a globalPos. + + Returns this screen if no suitable screen is found at the position. + */ +const QPlatformScreen *QPlatformScreen::screenForPosition(const QPoint &point) const +{ + QPlatformScreen *that = const_cast<QPlatformScreen*>(this); + return that->screenForPosition(point); +} + +/*! + \overload + */ +QPlatformScreen *QPlatformScreen::screenForPosition(const QPoint &point) +{ + if (!geometry().contains(point)) { + Q_FOREACH (QPlatformScreen* screen, virtualSiblings()) { + if (screen->geometry().contains(point)) + return screen; + } + } + return this; +} + + +/*! Returns a list of all the platform screens that are part of the same virtual desktop. @@ -156,11 +183,13 @@ QDpi QPlatformScreen::logicalDpi() const } /*! - Reimplement this function in subclass to return the device pixel - ratio for the screen. This is the ratio between physical pixels - and device-independent pixels. + Reimplement this function in subclass to return the device pixel ratio + for the screen. This is the ratio between physical pixels and the + device-independent pixels of the windowing system. The default + implementation returns 1.0. - \sa QPlatformWindow::devicePixelRatio(); + \sa QPlatformWindow::devicePixelRatio() + \sa QPlatformScreen::pixelDensity() */ qreal QPlatformScreen::devicePixelRatio() const { @@ -168,6 +197,26 @@ qreal QPlatformScreen::devicePixelRatio() const } /*! + Reimplement this function in subclass to return the pixel density of the + screen. This is the scale factor needed to make a low-dpi application + usable on this screen. The default implementation returns 1.0. In + addition the platform integration must return true for the PlatformScreenPixelDensity + Capability for this value to have an effect. + + Returning something else than 1 from this function causes Qt to + apply the scale factor to the application's coordinate system. + This is different from devicePixelRatio, which reports a scale + factor already applied by the windowing system. A platform plugin + typically implements one (or none) of these two functions. + + \sa QPlatformWindow::devicePixelRatio() +*/ +qreal QPlatformScreen::pixelDensity() const +{ + return 1.0; +} + +/*! Reimplement this function in subclass to return the vertical refresh rate of the screen, in Hz. @@ -290,8 +339,8 @@ void QPlatformScreen::resizeMaximizedWindows() // 'screen()' still has the old geometry info while 'this' has the new geometry info const QRect oldGeometry = screen()->geometry(); const QRect oldAvailableGeometry = screen()->availableGeometry(); - const QRect newGeometry = geometry(); - const QRect newAvailableGeometry = availableGeometry(); + const QRect newGeometry = deviceIndependentGeometry(); + const QRect newAvailableGeometry = QHighDpi::fromNative(availableGeometry(), QHighDpiScaling::factor(this), newGeometry.topLeft()); // make sure maximized and fullscreen windows are updated for (int i = 0; i < windows.size(); ++i) { @@ -393,6 +442,26 @@ QRect QPlatformScreen::mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation return rect; } +QRect QPlatformScreen::deviceIndependentGeometry() const +{ + qreal scaleFactor = QHighDpiScaling::factor(this); + QRect nativeGeometry = geometry(); + return QRect(nativeGeometry.topLeft(), QHighDpi::fromNative(nativeGeometry.size(), scaleFactor)); +} + + +QRect QPlatformScreen::screenGeometry() const +{ + qreal scaleFactor = QHighDpiScaling::factor(this); + QRect geometry = screen()->geometry(); + return QRect(geometry.topLeft(), QHighDpi::toNative(geometry.size(), scaleFactor)); +} + +QRect QPlatformScreen::screenAvailableGeometry() const +{ + return QHighDpi::toNativePixels(screen()->availableGeometry(), this); +} + /*! Returns a hint about this screen's subpixel layout structure. diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h index 551cb788c9..0bd0b77751 100644 --- a/src/gui/kernel/qplatformscreen.h +++ b/src/gui/kernel/qplatformscreen.h @@ -96,6 +96,7 @@ public: virtual QSizeF physicalSize() const; virtual QDpi logicalDpi() const; virtual qreal devicePixelRatio() const; + virtual qreal pixelDensity() const; virtual qreal refreshRate() const; @@ -105,6 +106,8 @@ public: virtual QWindow *topLevelAt(const QPoint &point) const; virtual QList<QPlatformScreen *> virtualSiblings() const; + const QPlatformScreen *screenForPosition(const QPoint &point) const; + QPlatformScreen *screenForPosition(const QPoint &point); QScreen *screen() const; @@ -121,6 +124,13 @@ public: static QTransform transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target); static QRect mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect); + // The platform screen's geometry in device independent coordinates + QRect deviceIndependentGeometry() const; + + // Accessors for QScreen geometry in native coordinates. Platform plugins should use these + // instead of accessing QScreen directly. + QRect screenGeometry() const; + QRect screenAvailableGeometry() const; protected: void resizeMaximizedWindows(); @@ -129,7 +139,7 @@ protected: private: Q_DISABLE_COPY(QPlatformScreen) - friend class QPlatformIntegration; + friend class QScreenPrivate; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index 114fcf8062..34a1fabc76 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -39,8 +39,10 @@ #include <qpa/qwindowsysteminterface.h> #include <QtGui/qwindow.h> #include <QtGui/qscreen.h> +#include <private/qhighdpiscaling_p.h> #include <private/qwindow_p.h> + QT_BEGIN_NAMESPACE /*! @@ -481,13 +483,25 @@ QString QPlatformWindow::formatWindowTitle(const QString &title, const QString & QPlatformScreen *QPlatformWindow::screenForGeometry(const QRect &newGeometry) const { QPlatformScreen *currentScreen = screen(); - if (!parent() && currentScreen && !currentScreen->geometry().intersects(newGeometry)) { + QPlatformScreen *fallback = currentScreen; + QPoint center = newGeometry.center(); + if (!parent() && currentScreen && !currentScreen->geometry().contains(center)) { Q_FOREACH (QPlatformScreen* screen, currentScreen->virtualSiblings()) { - if (screen->geometry().intersects(newGeometry)) + if (screen->geometry().contains(center)) return screen; + if (screen->geometry().intersects(newGeometry)) + fallback = screen; } } - return currentScreen; + return fallback; +} + +/*! + Returns a size with both dimentions bounded to [0, QWINDOWSIZE_MAX] +*/ +QSize QPlatformWindow::constrainWindowSize(const QSize &size) +{ + return size.expandedTo(QSize(0, 0)).boundedTo(QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX)); } /*! @@ -565,7 +579,7 @@ void QPlatformWindow::invalidateSurface() QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight) { - QRect rect(initialGeometry); + QRect rect(QHighDpi::fromNativePixels(initialGeometry, w)); if (rect.width() == 0) { const int minWidth = w->minimumWidth(); rect.setWidth(minWidth > 0 ? minWidth : defaultWidth); @@ -593,7 +607,7 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, } } } - return rect; + return QHighDpi::toNativePixels(rect, w); } /*! @@ -627,6 +641,55 @@ void QPlatformWindow::requestUpdate() } /*! + Returns the QWindow minimum size. +*/ +QSize QPlatformWindow::windowMinimumSize() const +{ + return QHighDpi::toNativePixels(constrainWindowSize(window()->minimumSize()), window()); +} + +/*! + Returns the QWindow maximum size. +*/ +QSize QPlatformWindow::windowMaximumSize() const +{ + return QHighDpi::toNativePixels(constrainWindowSize(window()->maximumSize()), window()); +} + +/*! + Returns the QWindow base size. +*/ +QSize QPlatformWindow::windowBaseSize() const +{ + return QHighDpi::toNativePixels(window()->baseSize(), window()); +} + +/*! + Returns the QWindow size increment. +*/ +QSize QPlatformWindow::windowSizeIncrement() const +{ + QSize increment = window()->sizeIncrement(); + if (!QHighDpiScaling::isActive()) + return increment; + + // Normalize the increment. If not set the increment can be + // (-1, -1) or (0, 0). Make that (1, 1) which is scalable. + if (increment.isEmpty()) + increment = QSize(1, 1); + + return QHighDpi::toNativePixels(increment, window()); +} + +/*! + Returns the QWindow geometry. +*/ +QRect QPlatformWindow::windowGeometry() const +{ + return QHighDpi::toNativePixels(window()->geometry(), window()); +} + +/*! \class QPlatformWindow \since 4.8 \internal diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index c7c1efdc58..c1f2a4bdf1 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -130,9 +130,18 @@ public: const QRect &initialGeometry, int defaultWidth, int defaultHeight); virtual void requestUpdate(); + + // Window property accessors. Platform plugins should use these + // instead of accessing QWindow directly. + QSize windowMinimumSize() const; + QSize windowMaximumSize() const; + QSize windowBaseSize() const; + QSize windowSizeIncrement() const; + QRect windowGeometry() const; protected: static QString formatWindowTitle(const QString &title, const QString &separator); QPlatformScreen *screenForGeometry(const QRect &newGeometry) const; + static QSize constrainWindowSize(const QSize &size); QScopedPointer<QPlatformWindowPrivate> d_ptr; private: diff --git a/src/gui/kernel/qrasterwindow.cpp b/src/gui/kernel/qrasterwindow.cpp index c04eb71420..fc1739ca0e 100644 --- a/src/gui/kernel/qrasterwindow.cpp +++ b/src/gui/kernel/qrasterwindow.cpp @@ -108,8 +108,6 @@ int QRasterWindow::metric(PaintDeviceMetric metric) const switch (metric) { case PdmDepth: return d->backingstore->paintDevice()->depth(); - case PdmDevicePixelRatio: - return d->backingstore->paintDevice()->devicePixelRatio(); default: break; } diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index 5785722918..af88a44957 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -36,6 +36,7 @@ #include "qpixmap.h" #include "qguiapplication_p.h" #include <qpa/qplatformscreen.h> +#include <qpa/qplatformscreen_p.h> #include <QtCore/QDebug> #include <QtCore/private/qobject_p.h> @@ -63,11 +64,37 @@ QT_BEGIN_NAMESPACE */ QScreen::QScreen(QPlatformScreen *screen) - : QObject(*new QScreenPrivate(screen), 0) + : QObject(*new QScreenPrivate(), 0) { + Q_D(QScreen); + d->setPlatformScreen(screen); +} + +void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen) +{ + Q_Q(QScreen); + platformScreen = screen; + platformScreen->d_func()->screen = q; + orientation = platformScreen->orientation(); + geometry = platformScreen->deviceIndependentGeometry(); + availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft()); + logicalDpi = platformScreen->logicalDpi(); + refreshRate = platformScreen->refreshRate(); + // safeguard ourselves against buggy platform behavior... + if (refreshRate < 1.0) + refreshRate = 60.0; + + updatePrimaryOrientation(); + + filteredOrientation = orientation; + if (filteredOrientation == Qt::PrimaryOrientation) + filteredOrientation = primaryOrientation; + + updateHighDpi(); } + /*! Destroys the screen. */ @@ -259,7 +286,7 @@ qreal QScreen::logicalDotsPerInch() const qreal QScreen::devicePixelRatio() const { Q_D(const QScreen); - return d->platformScreen->devicePixelRatio(); + return d->platformScreen->devicePixelRatio() * QHighDpiScaling::factor(this); } /*! diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h index f60fafcf63..a6018128e2 100644 --- a/src/gui/kernel/qscreen.h +++ b/src/gui/kernel/qscreen.h @@ -154,6 +154,7 @@ private: friend class QGuiApplicationPrivate; friend class QPlatformIntegration; friend class QPlatformScreen; + friend class QHighDpiScaling; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/kernel/qscreen_p.h b/src/gui/kernel/qscreen_p.h index d341b71932..4492eddd45 100644 --- a/src/gui/kernel/qscreen_p.h +++ b/src/gui/kernel/qscreen_p.h @@ -47,6 +47,7 @@ #include <QtGui/qscreen.h> #include <qpa/qplatformscreen.h> +#include "qhighdpiscaling_p.h" #include <QtCore/private/qobject_p.h> @@ -54,25 +55,19 @@ QT_BEGIN_NAMESPACE class QScreenPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QScreen) public: - QScreenPrivate(QPlatformScreen *screen) - : platformScreen(screen) + QScreenPrivate() + : platformScreen(0) , orientationUpdateMask(0) { - orientation = platformScreen->orientation(); - geometry = platformScreen->geometry(); - availableGeometry = platformScreen->availableGeometry(); - logicalDpi = platformScreen->logicalDpi(); - refreshRate = platformScreen->refreshRate(); - // safeguard ourselves against buggy platform behavior... - if (refreshRate < 1.0) - refreshRate = 60.0; - - updatePrimaryOrientation(); + } - filteredOrientation = orientation; - if (filteredOrientation == Qt::PrimaryOrientation) - filteredOrientation = primaryOrientation; + void setPlatformScreen(QPlatformScreen *screen); + void updateHighDpi() + { + geometry = platformScreen->deviceIndependentGeometry(); + availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft()); } void updatePrimaryOrientation(); diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index b850f53014..162dbfee20 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -55,6 +55,7 @@ #include <private/qdnd_p.h> #include <private/qshapedpixmapdndwindow_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -106,6 +107,12 @@ void QBasicDrag::disableEventFilter() qApp->removeEventFilter(this); } + +static inline QPoint getNativeMousePos(QEvent *e, QObject *o) +{ + return QHighDpi::toNativePixels(static_cast<QMouseEvent *>(e)->globalPos(), qobject_cast<QWindow*>(o)); +} + bool QBasicDrag::eventFilter(QObject *o, QEvent *e) { Q_UNUSED(o); @@ -139,19 +146,21 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e) } case QEvent::MouseMove: - move(static_cast<QMouseEvent *>(e)); + { + QPoint nativePosition = getNativeMousePos(e, o); + move(nativePosition); return true; // Eat all mouse events - + } case QEvent::MouseButtonRelease: disableEventFilter(); if (canDrop()) { - drop(static_cast<QMouseEvent *>(e)); + QPoint nativePosition = getNativeMousePos(e, o); + drop(nativePosition); } else { cancel(); } exitDndEventLoop(); return true; // Eat all mouse events - case QEvent::MouseButtonPress: case QEvent::MouseButtonDblClick: case QEvent::Wheel: @@ -227,13 +236,13 @@ void QBasicDrag::cancel() m_drag_icon_window->setVisible(false); } -void QBasicDrag::move(const QMouseEvent *e) +void QBasicDrag::move(const QPoint &globalPos) { if (m_drag) - m_drag_icon_window->updateGeometry(e->globalPos()); + m_drag_icon_window->updateGeometry(globalPos); } -void QBasicDrag::drop(const QMouseEvent *) +void QBasicDrag::drop(const QPoint &) { disableEventFilter(); restoreCursor(); @@ -330,14 +339,15 @@ void QSimpleDrag::cancel() } } -void QSimpleDrag::move(const QMouseEvent *me) +void QSimpleDrag::move(const QPoint &globalPos) { - QBasicDrag::move(me); - QWindow *window = topLevelAt(me->globalPos()); + //### not high-DPI aware + QBasicDrag::move(globalPos); + QWindow *window = topLevelAt(globalPos); if (!window) return; - const QPoint pos = me->globalPos() - window->geometry().topLeft(); + const QPoint pos = globalPos - window->geometry().topLeft(); const QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions()); @@ -345,14 +355,16 @@ void QSimpleDrag::move(const QMouseEvent *me) setCanDrop(qt_response.isAccepted()); } -void QSimpleDrag::drop(const QMouseEvent *me) +void QSimpleDrag::drop(const QPoint &globalPos) { - QBasicDrag::drop(me); - QWindow *window = topLevelAt(me->globalPos()); + //### not high-DPI aware + + QBasicDrag::drop(globalPos); + QWindow *window = topLevelAt(globalPos); if (!window) return; - const QPoint pos = me->globalPos() - window->geometry().topLeft(); + const QPoint pos = globalPos - window->geometry().topLeft(); const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(window, drag()->mimeData(),pos, drag()->supportedActions()); if (response.isAccepted()) { diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h index 7812f8b863..728ae7bd15 100644 --- a/src/gui/kernel/qsimpledrag_p.h +++ b/src/gui/kernel/qsimpledrag_p.h @@ -73,8 +73,8 @@ protected: virtual void startDrag(); virtual void cancel(); - virtual void move(const QMouseEvent *me); - virtual void drop(const QMouseEvent *me); + virtual void move(const QPoint &globalPos) = 0; + virtual void drop(const QPoint &globalPos) = 0; virtual void endDrag(); QShapedPixmapWindow *shapedPixmapWindow() const { return m_drag_icon_window; } @@ -111,8 +111,8 @@ public: protected: virtual void startDrag() Q_DECL_OVERRIDE; virtual void cancel() Q_DECL_OVERRIDE; - virtual void move(const QMouseEvent *me) Q_DECL_OVERRIDE; - virtual void drop(const QMouseEvent *me) Q_DECL_OVERRIDE; + virtual void move(const QPoint &globalPos) Q_DECL_OVERRIDE; + virtual void drop(const QPoint &globalPos) Q_DECL_OVERRIDE; private: QWindow *m_current_window; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index e697efe31c..4465a9aeb4 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -47,6 +47,7 @@ #ifndef QT_NO_ACCESSIBILITY # include "qaccessible.h" #endif +#include "qhighdpiscaling_p.h" #include <private/qevent_p.h> @@ -1085,13 +1086,13 @@ qreal QWindow::devicePixelRatio() const { Q_D(const QWindow); - // If there is no platform window, do the second best thing and - // return the app global devicePixelRatio. This is the highest - // devicePixelRatio found on the system screens, and will be - // correct for single-display systems (a very common case). + // If there is no platform window use the app global devicePixelRatio, + // which is the the highest devicePixelRatio found on the system + // screens, and will be correct for single-display systems (a very common case). if (!d->platformWindow) return qApp->devicePixelRatio(); - return d->platformWindow->devicePixelRatio(); + + return d->platformWindow->devicePixelRatio() * QHighDpiScaling::factor(this); } /*! @@ -1431,7 +1432,13 @@ void QWindow::setGeometry(const QRect &rect) d->positionPolicy = QWindowPrivate::WindowFrameExclusive; if (d->platformWindow) { - d->platformWindow->setGeometry(rect); + QRect nativeRect; + QScreen *newScreen = d->screenForGeometry(rect); + if (newScreen && isTopLevel()) + nativeRect = QHighDpi::toNativePixels(rect, newScreen); + else + nativeRect = QHighDpi::toNativePixels(rect, this); + d->platformWindow->setGeometry(nativeRect); } else { d->geometry = rect; @@ -1446,6 +1453,26 @@ void QWindow::setGeometry(const QRect &rect) } } +//######### This logic duplicated three times!!!!! +// equivalent to QPlatformWindow::screenForGeometry, but in platform independent coordinates +QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry) +{ + Q_Q(QWindow); + QScreen *currentScreen = q->screen(); + QScreen *fallback = currentScreen; + QPoint center = newGeometry.center(); + if (!q->parent() && currentScreen && !currentScreen->geometry().contains(center)) { + Q_FOREACH (QScreen* screen, currentScreen->virtualSiblings()) { + if (screen->geometry().contains(center)) + return screen; + if (screen->geometry().intersects(newGeometry)) + fallback = screen; + } + } + return fallback; +} + + /*! Returns the geometry of the window, excluding its window frame. @@ -1455,7 +1482,7 @@ QRect QWindow::geometry() const { Q_D(const QWindow); if (d->platformWindow) - return d->platformWindow->geometry(); + return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this); return d->geometry; } @@ -1468,7 +1495,7 @@ QMargins QWindow::frameMargins() const { Q_D(const QWindow); if (d->platformWindow) - return d->platformWindow->frameMargins(); + return QHighDpi::fromNativePixels(d->platformWindow->frameMargins(), this); return QMargins(); } @@ -1482,7 +1509,7 @@ QRect QWindow::frameGeometry() const Q_D(const QWindow); if (d->platformWindow) { QMargins m = frameMargins(); - return d->platformWindow->geometry().adjusted(-m.left(), -m.top(), m.right(), m.bottom()); + return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this).adjusted(-m.left(), -m.top(), m.right(), m.bottom()); } return d->geometry; } @@ -1499,7 +1526,7 @@ QPoint QWindow::framePosition() const Q_D(const QWindow); if (d->platformWindow) { QMargins margins = frameMargins(); - return d->platformWindow->geometry().topLeft() - QPoint(margins.left(), margins.top()); + return QHighDpi::fromNativePixels(d->platformWindow->geometry().topLeft(), this) - QPoint(margins.left(), margins.top()); } return d->geometry.topLeft(); } @@ -1515,7 +1542,7 @@ void QWindow::setFramePosition(const QPoint &point) d->positionPolicy = QWindowPrivate::WindowFrameInclusive; d->positionAutomatic = false; if (d->platformWindow) { - d->platformWindow->setGeometry(QRect(point, size())); + d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(point, size()), this)); } else { d->geometry.moveTopLeft(point); } @@ -1575,7 +1602,7 @@ void QWindow::resize(const QSize &newSize) { Q_D(QWindow); if (d->platformWindow) { - d->platformWindow->setGeometry(QRect(position(), newSize)); + d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(position(), newSize), this)); } else { const QSize oldSize = d->geometry.size(); d->geometry.setSize(newSize); diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 4fc63acf28..23a6d800c0 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -136,6 +136,7 @@ public: void connectToScreen(QScreen *topLevelScreen); void disconnectFromScreen(); void emitScreenChangedRecursion(QScreen *newScreen); + QScreen *screenForGeometry(const QRect &rect); virtual void clearFocusObject(); virtual QRectF closestAcceptableGeometry(const QRectF &rect) const; diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 823387b702..6f01f9a466 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformdrag.h> #include <qpa/qplatformintegration.h> #include <qdebug.h> +#include "qhighdpiscaling_p.h" QT_BEGIN_NAMESPACE @@ -139,7 +140,7 @@ void QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState */ void QWindowSystemInterface::handleGeometryChange(QWindow *tlw, const QRect &newRect, const QRect &oldRect) { - QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw,newRect, oldRect); + QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw, QHighDpi::fromNativePixels(newRect, tlw), QHighDpi::fromNativePixels(oldRect, tlw)); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -168,7 +169,7 @@ void QWindowSystemInterface::handleMouseEvent(QWindow *w, ulong timestamp, const Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { QWindowSystemInterfacePrivate::MouseEvent * e = - new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, local, global, b, mods, source); + new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -185,7 +186,7 @@ void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, ulong timest QWindowSystemInterfacePrivate::MouseEvent * e = new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QWindowSystemInterfacePrivate::FrameStrutMouse, - local, global, b, mods, source); + QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -366,14 +367,14 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con // Simple case: vertical deltas only: if (angleDelta.y() != 0 && angleDelta.x() == 0) { - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); return; } // Simple case: horizontal deltas only: if (angleDelta.y() == 0 && angleDelta.x() != 0) { - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); return; } @@ -381,12 +382,12 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con // Both horizontal and vertical deltas: Send two wheel events. // The first event contains the Qt 5 pixel and angle delta as points, // and in addition the Qt 4 compatibility vertical angle delta. - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); // The second event contains null pixel and angle points and the // Qt 4 compatibility horizontal angle delta. - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -449,7 +450,10 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *w, QTouchDevice *device, handleTouchEvent(w, time, device, points, mods); } -QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, QEvent::Type *type) +QList<QTouchEvent::TouchPoint> + QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, + const QWindow *window, + QEvent::Type *type) { QList<QTouchEvent::TouchPoint> touchPoints; Qt::TouchPointStates states; @@ -464,16 +468,16 @@ QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints p.setState(point->state); const QPointF screenPos = point->area.center(); - p.setScreenPos(screenPos); - p.setScreenRect(point->area); + p.setScreenPos(QHighDpi::fromNativePixels(screenPos, window)); + p.setScreenRect(QHighDpi::fromNativePixels(point->area, window)); // The local pos and rect are not set, they will be calculated // when the event gets processed by QGuiApplication. - p.setNormalizedPos(point->normalPosition); - p.setVelocity(point->velocity); + p.setNormalizedPos(QHighDpi::fromNativePixels(point->normalPosition, window)); + p.setVelocity(QHighDpi::fromNativePixels(point->velocity, window)); p.setFlags(point->flags); - p.setRawScreenPositions(point->rawPositions); + p.setRawScreenPositions(QHighDpi::fromNativePixels(point->rawPositions, window)); touchPoints.append(p); ++point; @@ -491,6 +495,27 @@ QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints return touchPoints; } +QList<QWindowSystemInterface::TouchPoint> + QWindowSystemInterfacePrivate::toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList, + const QWindow *window) +{ + QList<QWindowSystemInterface::TouchPoint> newList; + newList.reserve(pointList.size()); + foreach (const QTouchEvent::TouchPoint &pt, pointList) { + QWindowSystemInterface::TouchPoint p; + p.id = pt.id(); + p.flags = pt.flags(); + p.normalPosition = QHighDpi::toNativeLocalPosition(pt.normalizedPos(), window); + p.area = QHighDpi::toNativePixels(pt.screenRect(), window); + p.pressure = pt.pressure(); + p.state = pt.state(); + p.velocity = pt.velocity(); + p.rawPositions = pt.rawScreenPositions(); + newList.append(p); + } + return newList; +} + void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTouchDevice *device, const QList<TouchPoint> &points, Qt::KeyboardModifiers mods) { @@ -501,7 +526,7 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTo return; QEvent::Type type; - QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); + QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, tlw, &type); QWindowSystemInterfacePrivate::TouchEvent *e = new QWindowSystemInterfacePrivate::TouchEvent(tlw, timestamp, type, device, touchPoints, mods); @@ -534,14 +559,14 @@ void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt:: void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const QRect &geometry, const QRect &availableGeometry) { QWindowSystemInterfacePrivate::ScreenGeometryEvent *e = - new QWindowSystemInterfacePrivate::ScreenGeometryEvent(screen, geometry, availableGeometry); + new QWindowSystemInterfacePrivate::ScreenGeometryEvent(screen, QHighDpi::fromNativeScreenGeometry(geometry, screen), QHighDpi::fromNative(availableGeometry, screen, geometry.topLeft())); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY) { QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e = - new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); + new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); // ### tja QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -560,7 +585,7 @@ void QWindowSystemInterface::handleThemeChange(QWindow *tlw) void QWindowSystemInterface::handleExposeEvent(QWindow *tlw, const QRegion ®ion) { - QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, region); + QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, QHighDpi::fromNativeLocalRegion(region, tlw)); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -645,12 +670,12 @@ int QWindowSystemInterface::windowSystemEventsQueued() #ifndef QT_NO_DRAGANDDROP QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions) { - return QGuiApplicationPrivate::processDrag(w, dropData, p,supportedActions); + return QGuiApplicationPrivate::processDrag(w, dropData, QHighDpi::fromNativeLocalPosition(p, w) ,supportedActions); } QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions) { - return QGuiApplicationPrivate::processDrop(w, dropData, p,supportedActions); + return QGuiApplicationPrivate::processDrop(w, dropData, QHighDpi::fromNativeLocalPosition(p, w),supportedActions); } #endif // QT_NO_DRAGANDDROP @@ -684,8 +709,11 @@ void QWindowSystemInterface::handleTabletEvent(QWindow *w, ulong timestamp, cons Qt::KeyboardModifiers modifiers) { QWindowSystemInterfacePrivate::TabletEvent *e = - new QWindowSystemInterfacePrivate::TabletEvent(w, timestamp, local, global, device, pointerType, buttons, pressure, - xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers); + new QWindowSystemInterfacePrivate::TabletEvent(w,timestamp, + QHighDpi::fromNativeLocalPosition(local, w), + QHighDpi::fromNativePixels(global, w), + device, pointerType, buttons, pressure, + xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -837,7 +865,6 @@ Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int return QWindowSystemInterface::tryHandleShortcutEventToObject(o, timestamp, k, mods, text, autorep, count); } - Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *w, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier) @@ -882,4 +909,5 @@ bool QWindowSystemEventHandler::sendEvent(QWindowSystemInterfacePrivate::WindowS return true; } + QT_END_NAMESPACE diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 7160971305..cbc3bad7cd 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -488,7 +488,12 @@ public: static QWaitCondition eventsFlushed; static QMutex flushEventMutex; - static QList<QTouchEvent::TouchPoint> convertTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, QEvent::Type *type); + static QList<QTouchEvent::TouchPoint> + fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, + const QWindow *window, QEvent::Type *type = Q_NULLPTR); + static QList<QWindowSystemInterface::TouchPoint> + toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList, + const QWindow *window); static void installWindowSystemEventHandler(QWindowSystemEventHandler *handler); static void removeWindowSystemEventhandler(QWindowSystemEventHandler *handler); diff --git a/src/gui/opengl/qopenglpaintdevice.cpp b/src/gui/opengl/qopenglpaintdevice.cpp index e509b26a95..62e016c475 100644 --- a/src/gui/opengl/qopenglpaintdevice.cpp +++ b/src/gui/opengl/qopenglpaintdevice.cpp @@ -275,6 +275,9 @@ int QOpenGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const return qRound(d_ptr->dpmy * 0.0254); case PdmDevicePixelRatio: return d_ptr->devicePixelRatio; + case PdmDevicePixelRatioScaled: + return d_ptr->devicePixelRatio * QPaintDevice::devicePixelRatioFScale; + default: qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric); return 0; diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 19074e4c47..7b0a4e2ed4 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -38,22 +38,26 @@ #include <qpa/qplatformintegration.h> #include <qscreen.h> #include <qdebug.h> +#include <qscopedpointer.h> #include <private/qguiapplication_p.h> #include <private/qwindow_p.h> +#include <private/qhighdpiscaling_p.h> + QT_BEGIN_NAMESPACE class QBackingStorePrivate { public: QBackingStorePrivate(QWindow *w) - : window(w) + : window(w), highDpiBackingstore(0) { } QWindow *window; QPlatformBackingStore *platformBackingStore; + QScopedPointer<QImage> highDpiBackingstore; QRegion staticContents; QSize size; }; @@ -102,7 +106,7 @@ void QBackingStore::flush(const QRegion ®ion, QWindow *win, const QPoint &off } #endif - d_ptr->platformBackingStore->flush(win, region, offset); + d_ptr->platformBackingStore->flush(win, QHighDpi::toNativeLocalRegion(region, d_ptr->window), offset); } /*! @@ -112,7 +116,12 @@ void QBackingStore::flush(const QRegion ®ion, QWindow *win, const QPoint &off */ QPaintDevice *QBackingStore::paintDevice() { - return d_ptr->platformBackingStore->paintDevice(); + QPaintDevice *device = d_ptr->platformBackingStore->paintDevice(); + + if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) + return d_ptr->highDpiBackingstore.data(); + + return device; } /*! @@ -150,7 +159,35 @@ QWindow* QBackingStore::window() const void QBackingStore::beginPaint(const QRegion ®ion) { - d_ptr->platformBackingStore->beginPaint(region); + if (d_ptr->highDpiBackingstore && + d_ptr->highDpiBackingstore->devicePixelRatio() != d_ptr->window->devicePixelRatio()) + resize(size()); + + // When QtGui is applying a high-dpi scale factor the backing store + // creates a "large" backing store image. This image needs to be + // painted on as a high-dpi image, which is done by setting + // devicePixelRatio. Do this on a separate image instance that shares + // the image data to avoid having the new devicePxielRatio be propagated + // back to the platform plugin. + QPaintDevice *device = d_ptr->platformBackingStore->paintDevice(); + if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) { + QImage *source = reinterpret_cast<QImage *>(device); + const bool needsNewImage = d_ptr->highDpiBackingstore.isNull() + || source->data_ptr() != d_ptr->highDpiBackingstore->data_ptr() + || source->size() != d_ptr->highDpiBackingstore->size() + || source->devicePixelRatio() != d_ptr->highDpiBackingstore->devicePixelRatio(); + if (needsNewImage) { + qCDebug(lcScaling) << "QBackingStore::beginPaint new backingstore for" << d_ptr->window; + qCDebug(lcScaling) << " source size" << source->size() << "dpr" << source->devicePixelRatio(); + d_ptr->highDpiBackingstore.reset( + new QImage(source->bits(), source->width(), source->height(), source->format())); + qreal targetDevicePixelRatio = d_ptr->window->devicePixelRatio(); + d_ptr->highDpiBackingstore->setDevicePixelRatio(targetDevicePixelRatio); + qCDebug(lcScaling) <<" destination size" << d_ptr->highDpiBackingstore->size() + << "dpr" << targetDevicePixelRatio; + } + } + d_ptr->platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window)); } /*! @@ -171,7 +208,7 @@ void QBackingStore::endPaint() void QBackingStore::resize(const QSize &size) { d_ptr->size = size; - d_ptr->platformBackingStore->resize(size, d_ptr->staticContents); + d_ptr->platformBackingStore->resize(QHighDpi::toNativePixels(size, d_ptr->window), d_ptr->staticContents); } /*! @@ -194,7 +231,7 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy) Q_UNUSED(dx); Q_UNUSED(dy); - return d_ptr->platformBackingStore->scroll(area, dx, dy); + return d_ptr->platformBackingStore->scroll(QHighDpi::toNativeLocalRegion(area, d_ptr->window), QHighDpi::toNativePixels(dx, d_ptr->window), QHighDpi::toNativePixels(dy, d_ptr->window)); } void QBackingStore::setStaticContents(const QRegion ®ion) diff --git a/src/gui/painting/qpaintdevice.cpp b/src/gui/painting/qpaintdevice.cpp index bbf8e8f170..27d4bbcfd7 100644 --- a/src/gui/painting/qpaintdevice.cpp +++ b/src/gui/painting/qpaintdevice.cpp @@ -41,6 +41,8 @@ QPaintDevice::QPaintDevice() Q_DECL_NOEXCEPT painters = 0; } +qreal QPaintDevice::devicePixelRatioFScale = 10000000.0; + QPaintDevice::~QPaintDevice() { if (paintingActive()) @@ -79,7 +81,13 @@ Q_GUI_EXPORT int qt_paint_device_metric(const QPaintDevice *device, QPaintDevice int QPaintDevice::metric(PaintDeviceMetric m) const { + // Fallback: A subclass has not implemented PdmDevicePixelRatioScaled but might + // have implemented PdmDevicePixelRatio. + if (m == PdmDevicePixelRatioScaled) + return this->metric(PdmDevicePixelRatio) * devicePixelRatioFScale; + qWarning("QPaintDevice::metrics: Device has no metric information"); + if (m == PdmDpiX) { return 72; } else if (m == PdmDpiY) { @@ -95,4 +103,5 @@ int QPaintDevice::metric(PaintDeviceMetric m) const } } + QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintdevice.h b/src/gui/painting/qpaintdevice.h index 4eb972786b..b699956e99 100644 --- a/src/gui/painting/qpaintdevice.h +++ b/src/gui/painting/qpaintdevice.h @@ -58,7 +58,8 @@ public: PdmDpiY, PdmPhysicalDpiX, PdmPhysicalDpiY, - PdmDevicePixelRatio + PdmDevicePixelRatio, + PdmDevicePixelRatioScaled }; virtual ~QPaintDevice(); @@ -76,9 +77,13 @@ public: int physicalDpiX() const { return metric(PdmPhysicalDpiX); } int physicalDpiY() const { return metric(PdmPhysicalDpiY); } int devicePixelRatio() const { return metric(PdmDevicePixelRatio); } + qreal devicePixelRatioF() const { return metric(PdmDevicePixelRatioScaled) / devicePixelRatioFScale; } int colorCount() const { return metric(PdmNumColors); } int depth() const { return metric(PdmDepth); } + // ### Classes that are not QPaintDevice subclasses are implementing metric(), + // ### and need to access this constant. Add it here as a static constant for now + static qreal devicePixelRatioFScale; protected: QPaintDevice() Q_DECL_NOEXCEPT; virtual int metric(PaintDeviceMetric metric) const; @@ -87,7 +92,6 @@ protected: virtual QPainter *sharedPainter() const; ushort painters; // refcount - private: Q_DISABLE_COPY(QPaintDevice) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index c17ea9c878..99a9f823a1 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -219,18 +219,18 @@ QTransform QPainterPrivate::viewTransform() const return QTransform(); } -int QPainterPrivate::effectiveDevicePixelRatio() const +qreal QPainterPrivate::effectiveDevicePixelRatio() const { // Special cases for devices that does not support PdmDevicePixelRatio go here: if (device->devType() == QInternal::Printer) - return 1; + return qreal(1); - return qMax(1, device->metric(QPaintDevice::PdmDevicePixelRatio)); + return qMax(qreal(1), device->devicePixelRatioF()); } QTransform QPainterPrivate::hidpiScaleTransform() const { - int devicePixelRatio = effectiveDevicePixelRatio(); + const qreal devicePixelRatio = effectiveDevicePixelRatio(); return QTransform::fromScale(devicePixelRatio, devicePixelRatio); } @@ -5110,7 +5110,7 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm) x += d->state->matrix.dx(); y += d->state->matrix.dy(); } - int scale = pm.devicePixelRatio(); + qreal scale = pm.devicePixelRatio(); d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h)); } } diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 3ea4e35b8d..e8b675365f 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -240,7 +240,7 @@ public: } QTransform viewTransform() const; - int effectiveDevicePixelRatio() const; + qreal effectiveDevicePixelRatio() const; QTransform hidpiScaleTransform() const; static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev); void detachPainterPrivate(QPainter *q); diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 6ea0800538..011094b56b 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -1318,6 +1318,9 @@ int QPdfEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const case QPaintDevice::PdmDevicePixelRatio: val = 1; break; + case QPaintDevice::PdmDevicePixelRatioScaled: + val = 1 * QPaintDevice::devicePixelRatioFScale; + break; default: qWarning("QPdfWriter::metric: Invalid metric command"); return 0; diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 5d31ab9711..f03895a16e 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -558,6 +558,9 @@ namespace { case PdmDevicePixelRatio: val = 1; break; + case PdmDevicePixelRatioScaled: + val = devicePixelRatioFScale; + break; default: val = 0; qWarning("DrawTextItemDevice::metric: Invalid metric command"); diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp index e85890baf2..1ba2cb31ca 100644 --- a/src/gui/text/qtextimagehandler.cpp +++ b/src/gui/text/qtextimagehandler.cpp @@ -256,10 +256,10 @@ void QTextImageHandler::drawObject(QPainter *p, const QRectF &rect, QTextDocumen const QTextImageFormat imageFormat = format.toImageFormat(); if (QCoreApplication::instance()->thread() != QThread::currentThread()) { - const QImage image = getImage(doc, imageFormat, p->device()->devicePixelRatio()); + const QImage image = getImage(doc, imageFormat, p->device()->devicePixelRatioF()); p->drawImage(rect, image, image.rect()); } else { - const QPixmap pixmap = getPixmap(doc, imageFormat, p->device()->devicePixelRatio()); + const QPixmap pixmap = getPixmap(doc, imageFormat, p->device()->devicePixelRatioF()); p->drawPixmap(rect, pixmap, pixmap.rect()); } } diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 5aec058532..ad99d3707f 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -4494,7 +4494,7 @@ QImage QGLWidget::grabFrameBuffer(bool withAlpha) { makeCurrent(); QImage res; - qreal pixelRatio = devicePixelRatio(); + qreal pixelRatio = devicePixelRatioF(); int w = pixelRatio * width(); int h = pixelRatio * height(); if (format().rgba()) @@ -4907,7 +4907,7 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con GLdouble win_x = 0, win_y = 0, win_z = 0; qgluProject(x, y, z, &model[0], &proj[0], &view[0], &win_x, &win_y, &win_z); - const int dpr = d->glcx->device()->devicePixelRatio(); + const int dpr = d->glcx->device()->devicePixelRatioF(); win_x /= dpr; win_y /= dpr; win_y = height - win_y; // y is inverted diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 3479fccf58..8a03f9a0b7 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -1285,6 +1285,9 @@ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const case QPaintDevice::PdmDevicePixelRatio: return 1; + case QPaintDevice::PdmDevicePixelRatioScaled: + return 1 * QPaintDevice::devicePixelRatioFScale; + default: qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric); break; diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index 89cf01d8ec..16f1a3830e 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -62,6 +62,8 @@ int QGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const } case PdmDevicePixelRatio: return 1; + case PdmDevicePixelRatioScaled: + return 1 * QPaintDevice::devicePixelRatioFScale; default: qWarning("QGLPaintDevice::metric() - metric %d not known", metric); return 0; diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 49d2df9e1d..a9e3f15f9e 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -458,6 +458,9 @@ int QGLPixelBuffer::metric(PaintDeviceMetric metric) const case QPaintDevice::PdmDevicePixelRatio: return 1; + case QPaintDevice::PdmDevicePixelRatioScaled: + return QPaintDevice::devicePixelRatioFScale; + default: qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric); break; diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 19ab051162..184fc58cf0 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -55,6 +55,7 @@ #include <QtCore/private/qjnihelpers_p.h> #include <QtCore/private/qjni_p.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <qpa/qwindowsysteminterface.h> @@ -109,6 +110,8 @@ static QAndroidPlatformIntegration *m_androidPlatformIntegration = nullptr; static int m_desktopWidthPixels = 0; static int m_desktopHeightPixels = 0; static double m_scaledDensity = 0; +static double m_density = 1.0; +static bool m_highDpiScalingEnabled = true; static volatile bool m_pauseApplication; @@ -157,6 +160,21 @@ namespace QtAndroid return m_scaledDensity; } + double density() + { + return m_density; + } + + bool highDpiScalingEnabled() + { + return m_highDpiScalingEnabled; + } + + double pixelDensity() + { + return QtAndroid::highDpiScalingEnabled() ? m_density : 1.0; + } + JavaVM *javaVM() { return m_javaVM; @@ -541,7 +559,8 @@ static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/, jint widthPixels, jint heightPixels, jint desktopWidthPixels, jint desktopHeightPixels, - jdouble xdpi, jdouble ydpi, jdouble scaledDensity) + jdouble xdpi, jdouble ydpi, + jdouble scaledDensity, jdouble density) { // Android does not give us the correct screen size for immersive mode, but // the surface does have the right size @@ -552,6 +571,10 @@ static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/, m_desktopWidthPixels = desktopWidthPixels; m_desktopHeightPixels = desktopHeightPixels; m_scaledDensity = scaledDensity; + m_density = density; + + if (m_highDpiScalingEnabled) + QHighDpiScaling::setGlobalFactor(density); if (!m_androidPlatformIntegration) { QAndroidPlatformIntegration::setDefaultDisplayMetrics(desktopWidthPixels, @@ -677,7 +700,7 @@ static JNINativeMethod methods[] = { {"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication}, {"quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin}, {"terminateQt", "()V", (void *)terminateQt}, - {"setDisplayMetrics", "(IIIIDDD)V", (void *)setDisplayMetrics}, + {"setDisplayMetrics", "(IIIIDDDD)V", (void *)setDisplayMetrics}, {"setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface}, {"updateWindow", "()V", (void *)updateWindow}, {"updateApplicationState", "(I)V", (void *)updateApplicationState}, diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 4d037f4b74..f8eca17393 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -71,6 +71,9 @@ namespace QtAndroid int desktopWidthPixels(); int desktopHeightPixels(); double scaledDensity(); + double density(); + bool highDpiScalingEnabled(); + double pixelDensity(); JavaVM *javaVM(); AAssetManager *assetManager(); jclass applicationClass(); diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 7a509e4d61..76c0bfa75d 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -52,6 +52,7 @@ #include <QtGui/QGuiApplication> #include <QtGui/QWindow> #include <QtGui/private/qwindow_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -81,8 +82,10 @@ private: QAndroidPlatformScreen::QAndroidPlatformScreen():QObject(),QPlatformScreen() { - m_availableGeometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth, QAndroidPlatformIntegration::m_defaultGeometryHeight); - m_size = QSize(QAndroidPlatformIntegration::m_defaultScreenWidth, QAndroidPlatformIntegration::m_defaultScreenHeight); + m_availableGeometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth, + QAndroidPlatformIntegration::m_defaultGeometryHeight); + m_size = QSize(QAndroidPlatformIntegration::m_defaultScreenWidth, + QAndroidPlatformIntegration::m_defaultScreenHeight); // Raster only apps should set QT_ANDROID_RASTER_IMAGE_DEPTH to 16 // is way much faster than 32 if (qEnvironmentVariableIntValue("QT_ANDROID_RASTER_IMAGE_DEPTH") == 16) { @@ -109,6 +112,16 @@ QAndroidPlatformScreen::~QAndroidPlatformScreen() } } +QRect QAndroidPlatformScreen::geometry() const +{ + return QRect(QPoint(), m_size); +} + +QRect QAndroidPlatformScreen::availableGeometry() const +{ + return m_availableGeometry; +} + QWindow *QAndroidPlatformScreen::topWindow() const { foreach (QAndroidPlatformWindow *w, m_windowStack) @@ -378,7 +391,7 @@ void QAndroidPlatformScreen::doRedraw() QDpi QAndroidPlatformScreen::logicalDpi() const { - qreal lDpi = QtAndroid::scaledDensity() * 72; + qreal lDpi = 72; return QDpi(lDpi, lDpi); } diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index 403d6036f0..f1e3effb25 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -58,8 +58,8 @@ public: QAndroidPlatformScreen(); ~QAndroidPlatformScreen(); - QRect geometry() const { return QRect(QPoint(), m_size); } - QRect availableGeometry() const { return m_availableGeometry; } + QRect geometry() const; + QRect availableGeometry() const; int depth() const { return m_depth; } QImage::Format format() const { return m_format; } QSizeF physicalSize() const { return m_physicalSize; } diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index 3e2ae7c939..1bfec1df8c 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -31,6 +31,7 @@ ** ****************************************************************************/ +#include "androidjnimain.h" #include "androidjnimenu.h" #include "qandroidplatformtheme.h" #include "qandroidplatformmenubar.h" @@ -245,7 +246,7 @@ static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette) // Font size (in pixels) attributeIterator = item.find(QLatin1String("TextAppearance_textSize")); if (attributeIterator != item.constEnd()) - font.setPixelSize(int(attributeIterator.value().toDouble())); + font.setPixelSize(int(attributeIterator.value().toDouble() / QtAndroid::pixelDensity())); // Font style attributeIterator = item.find(QLatin1String("TextAppearance_textStyle")); diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 6a4f7ed8ee..cd8af5092a 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -54,6 +54,7 @@ QPaintDevice *QCocoaBackingStore::paintDevice() // Receate the backing store buffer if the effective buffer size has changed, // either due to a window resize or devicePixelRatio change. QSize effectiveBufferSize = m_requestedSize * windowDevicePixelRatio; + if (m_qImage.size() != effectiveBufferSize) { QImage::Format format = (window()->format().hasAlpha() || cocoaWindow->m_drawContentBorderGradient) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index e5fedcd051..c61d6580fa 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -606,7 +606,7 @@ void QCocoaWindow::show(bool becauseOfAncestor) && !m_hiddenByClipping) { // ... NOR clipped if (m_isNSWindowChild) { m_hiddenByAncestor = false; - setCocoaGeometry(window()->geometry()); + setCocoaGeometry(windowGeometry()); } if (!m_hiddenByClipping) { // setCocoaGeometry() can change the clipping status [m_nsWindow orderFront:nil]; @@ -645,7 +645,7 @@ void QCocoaWindow::setVisible(bool visible) if (parentCocoaWindow) { // The parent window might have moved while this window was hidden, // update the window geometry if there is a parent. - setGeometry(window()->geometry()); + setGeometry(windowGeometry()); if (window()->type() == Qt::Popup) { // QTBUG-30266: a window should not be resizable while a transient popup is open @@ -864,8 +864,8 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags) // no-WindowMaximizeButtonHint windows. From a Qt perspective it migth be expected // that the button would be removed in the latter case, but disabling it is more // in line with the platform style guidelines. - bool fixedSizeNoZoom = (window()->minimumSize().isValid() && window()->maximumSize().isValid() - && window()->minimumSize() == window()->maximumSize()); + bool fixedSizeNoZoom = (windowMinimumSize().isValid() && windowMaximumSize().isValid() + && windowMinimumSize() == windowMaximumSize()); bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint) && !(flags & Qt::WindowMaximizeButtonHint)); [[m_nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:!(fixedSizeNoZoom || customizeNoZoom)]; } @@ -1054,20 +1054,20 @@ void QCocoaWindow::propagateSizeHints() #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::propagateSizeHints" << this; - qDebug() << " min/max " << window()->minimumSize() << window()->maximumSize(); - qDebug() << "size increment" << window()->sizeIncrement(); - qDebug() << " basesize" << window()->baseSize(); - qDebug() << " geometry" << geometry(); + qDebug() << " min/max " << windowMinimumSize() << windowMaximumSize(); + qDebug() << "size increment" << windowSizeIncrement(); + qDebug() << " basesize" << windowBaseSize(); + qDebug() << " geometry" << windowGeometry(); #endif // Set the minimum content size. - const QSize minimumSize = window()->minimumSize(); + const QSize minimumSize = windowMinimumSize(); if (!minimumSize.isValid()) // minimumSize is (-1, -1) when not set. Make that (0, 0) for Cocoa. [m_nsWindow setContentMinSize : NSMakeSize(0.0, 0.0)]; [m_nsWindow setContentMinSize : NSMakeSize(minimumSize.width(), minimumSize.height())]; // Set the maximum content size. - const QSize maximumSize = window()->maximumSize(); + const QSize maximumSize = windowMaximumSize(); [m_nsWindow setContentMaxSize : NSMakeSize(maximumSize.width(), maximumSize.height())]; // The window may end up with a fixed size; in this case the zoom button should be disabled. @@ -1075,13 +1075,14 @@ void QCocoaWindow::propagateSizeHints() // sizeIncrement is observed to take values of (-1, -1) and (0, 0) for windows that should be // resizable and that have no specific size increment set. Cocoa expects (1.0, 1.0) in this case. - if (!window()->sizeIncrement().isEmpty()) - [m_nsWindow setResizeIncrements : qt_mac_toNSSize(window()->sizeIncrement())]; + const QSize sizeIncrement = windowSizeIncrement(); + if (!sizeIncrement.isEmpty()) + [m_nsWindow setResizeIncrements : qt_mac_toNSSize(sizeIncrement)]; else [m_nsWindow setResizeIncrements : NSMakeSize(1.0, 1.0)]; QRect rect = geometry(); - QSize baseSize = window()->baseSize(); + QSize baseSize = windowBaseSize(); if (!baseSize.isNull() && baseSize.isValid()) { [m_nsWindow setFrame:NSMakeRect(rect.x(), rect.y(), baseSize.width(), baseSize.height()) display:YES]; } @@ -1327,7 +1328,7 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) | NSWindowCollectionBehaviorFullScreenAuxiliary; m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone; m_nsWindow.collectionBehavior = collectionBehavior; - setCocoaGeometry(window()->geometry()); + setCocoaGeometry(windowGeometry()); QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; if (siblings.contains(this)) { @@ -1341,7 +1342,7 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) } else { // Child windows have no NSWindow, link the NSViews instead. [m_parentCocoaWindow->m_contentView addSubview : m_contentView]; - QRect rect = window()->geometry(); + QRect rect = windowGeometry(); // Prevent setting a (0,0) window size; causes opengl context // "Invalid Drawable" warnings. if (rect.isNull()) @@ -1393,7 +1394,7 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow() { QMacAutoReleasePool pool; - QRect rect = initialGeometry(window(), window()->geometry(), defaultWindowWidth, defaultWindowHeight); + QRect rect = initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight); NSRect frame = qt_mac_flipRect(rect); Qt::WindowType type = window()->type(); diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm index cb3e6e2cc5..d4552eade4 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm @@ -211,6 +211,9 @@ int QMacPrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const case QPaintDevice::PdmDevicePixelRatio: val = 1; break; + case QPaintDevice::PdmDevicePixelRatioScaled: + val = 1 * QPaintDevice::devicePixelRatioFScale; + break; default: val = 0; qWarning("QPrinter::metric: Invalid metric command"); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp index fee9ad88fa..bc6590ef64 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp @@ -113,6 +113,9 @@ int QWindowsDirect2DPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) case QPaintDevice::PdmDevicePixelRatio: return 1; break; + case QPaintDevice::PdmDevicePixelRatioScaled: + return 1 * devicePixelRatioFScale; + break; case QPaintDevice::PdmWidthMM: case QPaintDevice::PdmHeightMM: return -1; diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 16c278d9df..3f19e4401a 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -35,10 +35,10 @@ #include "qwindowswindow.h" #include "qwindowsnativeimage.h" #include "qwindowscontext.h" -#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <QtGui/QPainter> +#include <private/qhighdpiscaling_p.h> #include <QtCore/QDebug> @@ -68,10 +68,12 @@ QPaintDevice *QWindowsBackingStore::paintDevice() return &m_image->image(); } -void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoint &offset) +void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, + const QPoint &offset) { Q_ASSERT(window); + const QRect br = region.boundingRect(); if (QWindowsContext::verbose > 1) qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br; QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window); @@ -81,9 +83,8 @@ void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoin const Qt::WindowFlags flags = window->flags(); if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) { // Windows with alpha: Use blend function to update. - const QMargins marginsDP = rw->frameMarginsDp(); - const QRect r = rw->geometryDp() + marginsDP; - const QPoint frameOffset(marginsDP.left(), marginsDP.top()); + QRect r = QHighDpi::toNativePixels(window->frameGeometry(), window); + QPoint frameOffset(QHighDpi::toNativePixels(QPoint(window->frameMargins().left(), window->frameMargins().top()), window)); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; @@ -127,15 +128,14 @@ void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoin } } -void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip) +void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) { - const QSize size = sizeDip * QWindowsScaling::factor(); if (m_image.isNull() || m_image->image().size() != size) { #ifndef QT_NO_DEBUG_OUTPUT if (QWindowsContext::verbose && lcQpaBackingStore().isDebugEnabled()) { qCDebug(lcQpaBackingStore) - << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << sizeDip << ' ' - << regionDip << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); + << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << region + << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); } #endif const QImage::Format format = window()->format().hasAlpha() ? @@ -144,10 +144,10 @@ void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip QWindowsNativeImage *oldwni = m_image.data(); QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format); - if (oldwni && !regionDip.isEmpty()) { + if (oldwni && !region.isEmpty()) { const QImage &oldimg(oldwni->image()); QImage &newimg(newwni->image()); - QRegion staticRegion = QWindowsScaling::mapToNative(regionDip); + QRegion staticRegion(region); staticRegion &= QRect(0, 0, oldimg.width(), oldimg.height()); staticRegion &= QRect(0, 0, newimg.width(), newimg.height()); QPainter painter(&newimg); @@ -156,38 +156,36 @@ void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip painter.drawImage(rect, oldimg, rect); } - if (QWindowsScaling::isActive()) - newwni->setDevicePixelRatio(QWindowsScaling::factor()); m_image.reset(newwni); } } Q_GUI_EXPORT void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); -bool QWindowsBackingStore::scroll(const QRegion &areaDip, int dxDip, int dyDip) +bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy) { if (m_image.isNull() || m_image->image().isNull()) return false; - const QPoint dp = QPoint(dxDip, dyDip) * QWindowsScaling::factor(); - const QVector<QRect> rects = areaDip.rects(); + const QVector<QRect> rects = area.rects(); + const QPoint offset(dx, dy); for (int i = 0; i < rects.size(); ++i) - qt_scrollRectInImage(m_image->image(), QWindowsScaling::mapToNative(rects.at(i)), dp); + qt_scrollRectInImage(m_image->image(), rects.at(i), offset); return true; } -void QWindowsBackingStore::beginPaint(const QRegion ®ionDip) +void QWindowsBackingStore::beginPaint(const QRegion ®ion) { if (QWindowsContext::verbose > 1) - qCDebug(lcQpaBackingStore) <<__FUNCTION__ << regionDip; + qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region; if (m_image->image().hasAlphaChannel()) { QPainter p(&m_image->image()); p.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; - foreach (const QRect &r, regionDip.rects()) - p.fillRect(QWindowsScaling::mapToNative(r), blank); + foreach (const QRect &r, region.rects()) + p.fillRect(r, blank); } } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index 41ad29babc..4badcf1b09 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -35,7 +35,6 @@ #define QWINDOWSBACKINGSTORE_H #include "qtwindows_additional.h" -#include "qwindowsscaling.h" #include <qpa/qplatformbackingstore.h> #include <QtCore/QScopedPointer> @@ -53,12 +52,7 @@ public: ~QWindowsBackingStore(); QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE - { - flushDp(window, QWindowsScaling::mapToNative(region.boundingRect()), - offset * QWindowsScaling::factor()); - } - void flushDp(QWindow *window, const QRect &boundingRect, const QPoint &offset); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; void resize(const QSize &size, const QRegion &r) Q_DECL_OVERRIDE; bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; void beginPaint(const QRegion &) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index a532e92397..27323a2fd6 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -51,7 +51,6 @@ #endif #include "qwindowsscreen.h" #include "qwindowstheme.h" -#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <qpa/qwindowsysteminterface.h> @@ -1228,9 +1227,7 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg) } } - QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, - pos / QWindowsScaling::factor(), - globalPos / QWindowsScaling::factor(), + QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos, QWindowsKeyMapper::queryKeyboardModifiers()); return true; } diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 5f443f2675..1fbef61029 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -36,7 +36,6 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsscreen.h" -#include "qwindowsscaling.h" #include <QtGui/QBitmap> #include <QtGui/QImage> @@ -646,13 +645,12 @@ QWindowsCursor::CursorState QWindowsCursor::cursorState() QPoint QWindowsCursor::pos() const { - return mousePosition() / QWindowsScaling::factor(); + return mousePosition(); } void QWindowsCursor::setPos(const QPoint &pos) { - const QPoint posDp = pos * QWindowsScaling::factor(); - SetCursorPos(posDp.x() , posDp.y()); + SetCursorPos(pos.x() , pos.y()); } /*! diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index e10add9c7c..1e693641ca 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -33,7 +33,7 @@ #include "qwindowsdrag.h" #include "qwindowscontext.h" -#include "qwindowsscaling.h" +#include "qwindowsscreen.h" #ifndef QT_NO_CLIPBOARD # include "qwindowsclipboard.h" #endif @@ -43,7 +43,6 @@ #include "qwindowswindow.h" #include "qwindowsmousehandler.h" #include "qwindowscursor.h" -#include "qwindowsscaling.h" #include <QtGui/QMouseEvent> #include <QtGui/QPixmap> @@ -52,6 +51,7 @@ #include <QtGui/QGuiApplication> #include <qpa/qwindowsysteminterface_p.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtCore/QDebug> #include <QtCore/QBuffer> @@ -280,6 +280,13 @@ QDebug operator<<(QDebug d, const QWindowsOleDropSource::CursorEntry &e) } #endif // !QT_NO_DEBUG_OUTPUT +static qreal dragScaleFactor() +{ + const QWindowsScreenManager &screenManager = QWindowsContext::instance()->screenManager(); + const QWindowsScreen *screen = screenManager.screenAtDp(QWindowsCursor::mousePosition()); + return screen ? QHighDpiScaling::factor(screen) : qreal(1); +} + /*! \brief Blend custom pixmap with cursors. */ @@ -289,19 +296,22 @@ void QWindowsOleDropSource::createCursors() const QDrag *drag = m_drag->currentDrag(); const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); - const int scaleFactor = QWindowsScaling::factor(); - const QSize pixmapSizeDp = pixmap.size() * scaleFactor; + + const qreal scaleFactor = dragScaleFactor(); const bool scalePixmap = hasPixmap && m_mode != TouchDrag // Touch drag: pixmap is shown in a separate QWindow, which will be scaled. && (scaleFactor != 1 && scaleFactor != qRound(pixmap.devicePixelRatio())); - const QPixmap drawPixmap = scalePixmap - ? pixmap.scaled(pixmapSizeDp, Qt::KeepAspectRatio, Qt::SmoothTransformation) : pixmap; - + const QPixmap scaledPixmap = scalePixmap + ? pixmap.scaled((QSizeF(pixmap.size()) * scaleFactor).toSize(), + Qt::KeepAspectRatio, Qt::SmoothTransformation) + : pixmap; Qt::DropAction actions[] = { Qt::MoveAction, Qt::CopyAction, Qt::LinkAction, Qt::IgnoreAction }; int actionCount = int(sizeof(actions) / sizeof(actions[0])); if (!hasPixmap) --actionCount; // No Qt::IgnoreAction unless pixmap - const QPoint hotSpot = drag->hotSpot() * scaleFactor; + const QPoint hotSpot = scalePixmap + ? (QPointF(drag->hotSpot()) * scaleFactor).toPoint() + : drag->hotSpot(); for (int cnum = 0; cnum < actionCount; ++cnum) { const Qt::DropAction action = actions[cnum]; QPixmap cursorPixmap = drag->dragCursor(action); @@ -321,14 +331,14 @@ void QWindowsOleDropSource::createCursors() if (hasPixmap) { const int x1 = qMin(-hotSpot.x(), 0); - const int x2 = qMax(pixmapSizeDp.width() - hotSpot.x(), cursorPixmap.width()); + const int x2 = qMax(scaledPixmap.width() - hotSpot.x(), cursorPixmap.width()); const int y1 = qMin(-hotSpot.y(), 0); - const int y2 = qMax(pixmapSizeDp.height() - hotSpot.y(), cursorPixmap.height()); + const int y2 = qMax(scaledPixmap.height() - hotSpot.y(), cursorPixmap.height()); QPixmap newCursor(x2 - x1 + 1, y2 - y1 + 1); newCursor.fill(Qt::transparent); QPainter p(&newCursor); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); - p.drawPixmap(pmDest, drawPixmap); + p.drawPixmap(pmDest, scaledPixmap); p.drawPixmap(qMax(0, hotSpot.x()),qMax(0, hotSpot.y()), cursorPixmap); newPixmap = newCursor; newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); @@ -454,7 +464,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) if (!m_touchDragWindow) m_touchDragWindow = new QWindowsDragCursorWindow; m_touchDragWindow->setPixmap(e.pixmap); - m_touchDragWindow->setFramePosition((QWindowsCursor::mousePosition() - e.hotSpot) / QWindowsScaling::factor()); + m_touchDragWindow->setFramePosition(QWindowsCursor::mousePosition() - e.hotSpot); if (!m_touchDragWindow->isVisible()) m_touchDragWindow->show(); break; @@ -530,9 +540,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); const QPlatformDragQtResponse response = - QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), - m_lastPoint / QWindowsScaling::factor(), - actions); + QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); m_answerRect = response.answerRect(); const Qt::DropAction action = response.acceptedAction(); @@ -625,7 +633,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), - m_lastPoint / QWindowsScaling::factor(), + m_lastPoint, translateToQDragDropActions(m_chosenEffect)); if (response.isAccepted()) { diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 0cce171340..485b876fc7 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -36,7 +36,6 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowsmousehandler.h" -#include "qwindowsscaling.h" #include <QtCore/QDebug> #include <QtCore/QObject> @@ -243,10 +242,9 @@ void QWindowsInputContext::cursorRectChanged() if (!m_compositionContext.hwnd) return; const QInputMethod *inputMethod = QGuiApplication::inputMethod(); - const QRect cursorRectangleDip = inputMethod->cursorRectangle().toRect(); - if (!cursorRectangleDip.isValid()) + const QRect cursorRectangle = inputMethod->cursorRectangle().toRect(); + if (!cursorRectangle.isValid()) return; - const QRect cursorRectangle = QWindowsScaling::mapToNative(cursorRectangleDip); qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 9b0f126241..05c7e6b240 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -33,7 +33,6 @@ ****************************************************************************/ #include "qwindowsintegration.h" -#include "qwindowsscaling.h" #include "qwindowswindow.h" #include "qwindowscontext.h" #include "qwindowsopenglcontext.h" @@ -64,6 +63,7 @@ # include "qwindowssessionmanager.h" #endif #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/qpa/qplatforminputcontextfactory_p.h> #include <QtCore/private/qeventdispatcher_win_p.h> @@ -223,12 +223,8 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL m_context.setProcessDpiAwareness(dpiAwareness); dpiAwarenessSet = true; } - // Determine suitable scale factor, don't mix Windows and Qt scaling - if (dpiAwareness != QtWindows::ProcessDpiUnaware) - QWindowsScaling::setFactor(QWindowsScaling::determineUiScaleFactor()); qCDebug(lcQpaWindows) - << __FUNCTION__ << "DpiAwareness=" << dpiAwareness <<",Scaling=" - << QWindowsScaling::factor(); + << __FUNCTION__ << "DpiAwareness=" << dpiAwareness; QTouchDevice *touchDevice = m_context.touchDevice(); if (touchDevice) { @@ -307,7 +303,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const { QWindowsWindowData requested; requested.flags = window->flags(); - requested.geometry = QWindowsScaling::mapToNative(window->geometry()); + requested.geometry = QHighDpi::toNativePixels(window->geometry(), window); // Apply custom margins (see QWindowsWindow::setCustomMargins())). const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); if (customMarginsV.isValid()) @@ -327,7 +323,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const window->setFlags(obtained.flags); // Trigger geometry change signals of QWindow. if ((obtained.flags & Qt::Desktop) != Qt::Desktop && requested.geometry != obtained.geometry) - QWindowSystemInterface::handleGeometryChange(window, QWindowsScaling::mapFromNative(obtained.geometry)); + QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); } return obtained; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index d47c7df9e0..3636bb7893 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -35,12 +35,12 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsguieventdispatcher.h" -#include "qwindowsscaling.h" #include "qwindowsinputcontext.h" #include <QtGui/QWindow> #include <qpa/qwindowsysteminterface.h> #include <private/qguiapplication_p.h> +#include <private/qhighdpiscaling_p.h> #include <QtGui/QKeyEvent> #if defined(WM_APPCOMMAND) @@ -792,10 +792,12 @@ static void showSystemMenu(QWindow* w) #undef enabled #undef disabled #endif // !Q_OS_WINCE - const QPoint topLeft = topLevel->geometry().topLeft() * QWindowsScaling::factor(); + const QPoint pos = QHighDpi::toNativePixels(topLevel->geometry().topLeft(), topLevel); const int ret = TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, - topLeft.x(), topLeft.y(), topLevelHwnd, 0); + pos.x(), pos.y(), + topLevelHwnd, + 0); if (ret) qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, ret, 0); } diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index db635b602b..a8aea05fd8 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -211,10 +211,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, const QPoint globalPosition = winEventPosition; const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition); const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons(); - QWindowSystemInterface::handleFrameStrutMouseEvent(window, - clientPosition / QWindowsScaling::factor(), - globalPosition / QWindowsScaling::factor(), - buttons, + QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, + globalPosition, buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); return false; // Allow further event processing (dragging of windows). @@ -279,7 +277,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // ChildWindowFromPointEx() may not find the Qt window (failing with ERROR_ACCESS_DENIED) if (!currentWindowUnderMouse) { const QRect clientRect(QPoint(0, 0), window->size()); - if (clientRect.contains(winEventPosition / QWindowsScaling::factor())) + if (clientRect.contains(winEventPosition)) currentWindowUnderMouse = window; } @@ -366,10 +364,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, m_windowUnderMouse = currentWindowUnderMouse; } - QWindowSystemInterface::handleMouseEvent(window, - winEventPosition / QWindowsScaling::factor(), - globalPosition / QWindowsScaling::factor(), - buttons, + QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); m_previousCaptureWindow = hasCapture ? window : 0; @@ -404,11 +399,9 @@ static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int del } if (handleEvent) { - const QPoint posDip = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos) / QWindowsScaling::factor(); QWindowSystemInterface::handleWheelEvent(receiver, - posDip, globalPos / QWindowsScaling::factor(), - delta / QWindowsScaling::factor(), - orientation, mods); + QWindowsGeometryHint::mapFromGlobal(receiver, globalPos), + globalPos, delta, orientation, mods); } } @@ -495,7 +488,6 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND hwnd, Q_ASSERT(QWindowsContext::user32dll.getTouchInputInfo); QWindowsContext::user32dll.getTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); - const qreal screenPosFactor = 0.01 / qreal(QWindowsScaling::factor()); for (int i = 0; i < winTouchPointCount; ++i) { const TOUCHINPUT &winTouchInput = winTouchInputs[i]; int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1); @@ -509,9 +501,9 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (m_lastTouchPositions.contains(id)) touchPoint.normalPosition = m_lastTouchPositions.value(id); - const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) * screenPosFactor; + const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) / qreal(100.); if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA) - touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) * screenPosFactor); + touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) / qreal(100.)); touchPoint.area.moveCenter(screenPos); QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(), screenPos.y() / screenGeometry.height()); diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.h b/src/plugins/platforms/windows/qwindowsnativeimage.h index 6f9ce93ef0..80a1de1ea5 100644 --- a/src/plugins/platforms/windows/qwindowsnativeimage.h +++ b/src/plugins/platforms/windows/qwindowsnativeimage.h @@ -57,8 +57,6 @@ public: HDC hdc() const { return m_hdc; } - void setDevicePixelRatio(qreal scaleFactor) { m_image.setDevicePixelRatio(scaleFactor); } - static QImage::Format systemFormat(); private: diff --git a/src/plugins/platforms/windows/qwindowsscaling.cpp b/src/plugins/platforms/windows/qwindowsscaling.cpp deleted file mode 100644 index 6ab7f254fd..0000000000 --- a/src/plugins/platforms/windows/qwindowsscaling.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwindowsscaling.h" -#include "qwindowsscreen.h" - -#include <QtCore/QDebug> -#include <QtCore/QCoreApplication> - -QT_BEGIN_NAMESPACE - -/*! - \class QWindowsScaling - \brief Windows scaling utilities - - \internal - \ingroup qt-lighthouse-win -*/ - -int QWindowsScaling::m_factor = 1; - -static const char devicePixelRatioEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; - -// Suggest a scale factor by checking monitor sizes. -int QWindowsScaling::determineUiScaleFactor() -{ - if (!qEnvironmentVariableIsSet(devicePixelRatioEnvVar)) - return 1; - const QByteArray envDevicePixelRatioEnv = qgetenv(devicePixelRatioEnvVar); - // Auto: Suggest a scale factor by checking monitor resolution. - if (envDevicePixelRatioEnv == "auto") { - const int maxResolution = QWindowsScreen::maxMonitorHorizResolution(); - return maxResolution > 180 ? maxResolution / 96 : 1; - } - // Get factor from environment - bool ok = false; - const int envFactor = envDevicePixelRatioEnv.toInt(&ok); - return ok && envFactor > 0 ? envFactor : 1; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscaling.h b/src/plugins/platforms/windows/qwindowsscaling.h deleted file mode 100644 index 39e554bbe2..0000000000 --- a/src/plugins/platforms/windows/qwindowsscaling.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINDOWSSCALING_H -#define QWINDOWSSCALING_H - -#include <QtGui/QRegion> -#include <QtCore/QVector> -#include <QtCore/QRect> - -QT_BEGIN_NAMESPACE - -enum -#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC) - : int -#endif -{ QWINDOWSIZE_MAX = 16777215 }; - -class QWindowsScaling { -public: - static bool isActive() { return m_factor > 1; } - static int factor() { return m_factor; } - static void setFactor(int factor) { m_factor = factor; } - static int determineUiScaleFactor(); - - // Scaling helpers for size constraints. - static int mapToNativeConstrained(int qt) - { return m_factor != 1 && qt > 0 && qt < QWINDOWSIZE_MAX ? qt * m_factor : qt; } - - static int mapFromNativeConstrained(int dp) - { return m_factor != 1 && dp > 0 && dp < QWINDOWSIZE_MAX ? dp / m_factor : dp; } - - static QSize mapToNativeConstrained(const QSize &qt) - { return QSize(mapToNativeConstrained(qt.width()), mapToNativeConstrained(qt.height())); } - - static QRect mapToNative(const QRect &qRect) - { - return QRect(qRect.x() * m_factor, qRect.y() * m_factor, qRect.width() * m_factor, qRect.height() * m_factor); - } - - static QRect mapFromNative(const QRect &dp) - { - return isActive() ? - QRect(dp.x() / m_factor, dp.y() / m_factor, (dp.width() + 1) / m_factor, (dp.height() + 1) / m_factor) : - dp; - } - - static QRegion mapToNative(const QRegion ®ionQt) - { - if (!QWindowsScaling::isActive() || regionQt.isEmpty()) - return regionQt; - - QRegion result; - foreach (const QRect &rectQt, regionQt.rects()) - result += QWindowsScaling::mapToNative(rectQt); - return result; - } - - static QRegion mapFromNative(const QRegion ®ionDp) - { - if (!QWindowsScaling::isActive() || regionDp.isEmpty()) - return regionDp; - - QRegion result; - foreach (const QRect &rectDp, regionDp.rects()) - result += QWindowsScaling::mapFromNative(rectDp); - return result; - } - -private: - static int m_factor; -}; - -QT_END_NAMESPACE - -#endif // QWINDOWSSCALING_H diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 7756c77001..7f3bb96503 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -43,6 +43,7 @@ #include <QtGui/QPixmap> #include <QtGui/QGuiApplication> #include <qpa/qwindowsysteminterface.h> +#include <private/qhighdpiscaling_p.h> #include <QtGui/QScreen> #include <QtCore/QDebug> @@ -116,12 +117,14 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL); #endif if (hdc) { + if (!QHighDpiScaling::isActive()) { // Assume 96 DPI to get fonts right when scaling. #ifndef Q_OS_WINCE - const QDpi dpi = monitorDPI(hMonitor); - data->dpi = dpi.first ? dpi : deviceDPI(hdc); + const QDpi dpi = monitorDPI(hMonitor); + data->dpi = dpi.first ? dpi : deviceDPI(hdc); #else - data->dpi = deviceDPI(hdc); + data->dpi = deviceDPI(hdc); #endif + } data->depth = GetDeviceCaps(hdc, BITSPIXEL); data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); @@ -218,36 +221,14 @@ QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) : { } -BOOL QT_WIN_CALLBACK monitorResolutionEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) -{ - QWindowsScreenData data; - if (monitorData(hMonitor, &data)) { - int *maxHorizResolution = reinterpret_cast<int *>(p); - const int horizResolution = qRound(data.dpi.first); - if (horizResolution > *maxHorizResolution) - *maxHorizResolution = horizResolution; - } - return TRUE; -} - -int QWindowsScreen::maxMonitorHorizResolution() -{ - int result = 0; - EnumDisplayMonitors(0, 0, monitorResolutionEnumCallback, (LPARAM)&result); - return result; -} - Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0); -QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const +QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const { RECT r; HWND hwnd = window ? (HWND)window : GetDesktopWindow(); GetClientRect(hwnd, &r); - const int x = qX * QWindowsScaling::factor(); - const int y = qY * QWindowsScaling::factor(); - int width = qWidth * QWindowsScaling::factor(); - int height = qHeight * QWindowsScaling::factor(); + if (width < 0) width = r.right - r.left; if (height < 0) height = r.bottom - r.top; @@ -271,10 +252,6 @@ QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int q DeleteObject(bitmap); ReleaseDC(0, display_dc); - if (QWindowsScaling::isActive()) { - const qreal factor = 1.0 / qreal(QWindowsScaling::factor()); - return pixmap.transformed(QTransform::fromScale(factor, factor)); - } return pixmap; } @@ -285,7 +262,7 @@ QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int q QWindow *QWindowsScreen::topLevelAt(const QPoint &point) const { QWindow *result = 0; - if (QWindow *child = QWindowsScreen::windowAt(point * QWindowsScaling::factor(), CWP_SKIPINVISIBLE)) + if (QWindow *child = QWindowsScreen::windowAt(point, CWP_SKIPINVISIBLE)) result = QWindowsWindow::topLevelOf(child); qCDebug(lcQpaWindows) <<__FUNCTION__ << point << result; return result; @@ -313,6 +290,12 @@ QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w) return 0; } +qreal QWindowsScreen::pixelDensity() const +{ + const qreal physicalDpi = m_data.geometry.width() / m_data.physicalSizeMM.width() * qreal(25.4); + return qRound(physicalDpi / 96); +} + /*! \brief Determine siblings in a virtual desktop system. @@ -542,7 +525,7 @@ void QWindowsScreenManager::clearScreens() const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const { foreach (QWindowsScreen *scr, m_screens) { - if (scr->geometryDp().contains(p)) + if (scr->geometry().contains(p)) return scr; } return Q_NULLPTR; diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 7352c45777..67e7ff644b 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -34,7 +34,6 @@ #ifndef QWINDOWSSCREEN_H #define QWINDOWSSCREEN_H -#include "qwindowsscaling.h" #include "qtwindowsglobal.h" #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" @@ -82,16 +81,14 @@ public: static QWindowsScreen *screenOf(const QWindow *w = 0); - QRect geometryDp() const { return m_data.geometry; } - QRect geometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(geometryDp()); } - QRect availableGeometryDp() const { return m_data.availableGeometry; } - QRect availableGeometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(availableGeometryDp()); } + QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } + QRect availableGeometry() const Q_DECL_OVERRIDE { return m_data.availableGeometry; } int depth() const Q_DECL_OVERRIDE { return m_data.depth; } QImage::Format format() const Q_DECL_OVERRIDE { return m_data.format; } QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_data.physicalSizeMM; } - QDpi logicalDpi() const Q_DECL_OVERRIDE - { return QDpi(m_data.dpi.first / QWindowsScaling::factor(), m_data.dpi.second / QWindowsScaling::factor()); } - qreal devicePixelRatio() const Q_DECL_OVERRIDE { return QWindowsScaling::factor(); } + QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_data.dpi; } + qreal pixelDensity() const Q_DECL_OVERRIDE; + qreal devicePixelRatio() const Q_DECL_OVERRIDE { return 1.0; } qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; } QString name() const Q_DECL_OVERRIDE { return m_data.name; } Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; } @@ -112,7 +109,6 @@ public: #endif // !QT_NO_CURSOR const QWindowsScreenData &data() const { return m_data; } - static int maxMonitorHorizResolution(); private: QWindowsScreenData m_data; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 7b871be015..05bddec530 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -32,7 +32,6 @@ ****************************************************************************/ #include "qwindowstabletsupport.h" -#include "qwindowsscaling.h" #ifndef QT_NO_TABLETEVENT @@ -399,8 +398,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() // in which case we snap the position to the mouse position. // It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext // area is always the virtual desktop. - const QRect virtualDesktopArea - = QWindowsScaling::mapToNative(QGuiApplication::primaryScreen()->virtualGeometry()); + const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount << "target:" << QGuiApplicationPrivate::tabletPressTarget; @@ -420,7 +418,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() QPoint globalPos = globalPosF.toPoint(); // Get Mouse Position and compare to tablet info - QPoint mouseLocation = QWindowsCursor::mousePosition(); + const QPoint mouseLocation = QWindowsCursor::mousePosition(); // Positions should be almost the same if we are in absolute // mode. If they are not, use the mouse location. @@ -475,9 +473,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } - const QPointF localPosDip = QPointF(localPos / QWindowsScaling::factor()); - const QPointF globalPosDip = globalPosF / qreal(QWindowsScaling::factor()); - QWindowSystemInterface::handleTabletEvent(target, localPosDip, globalPosDip, + QWindowSystemInterface::handleTabletEvent(target, QPointF(localPos), globalPosF, currentDevice, currentPointer, static_cast<Qt::MouseButtons>(packet.pkButtons), pressureNew, tiltX, tiltY, diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index d3f67e9eaa..873052973e 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -43,7 +43,6 @@ #include "qwindowsintegration.h" #include "qt_windows.h" #include "qwindowsfontdatabase.h" -#include "qwindowsscaling.h" #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" # include "winuser.h" @@ -68,6 +67,7 @@ #include <QtGui/QPainter> #include <QtGui/QPixmapCache> #include <qpa/qwindowsysteminterface.h> +#include <private/qhighdpiscaling_p.h> #include <private/qsystemlibrary_p.h> #include <algorithm> @@ -495,7 +495,8 @@ static QPixmap loadIconFromShell32(int resourceId, QSizeF size) QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const { - const int scaleFactor = QWindowsScaling::factor(); + const QScreen *primaryScreen = QGuiApplication::primaryScreen(); + const int scaleFactor = primaryScreen ? qRound(QHighDpiScaling::factor(primaryScreen)) : 1; const QSizeF pixmapSize = size * scaleFactor; int resourceId = -1; LPCTSTR iconName = 0; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 543c08135f..d6677bb228 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -36,7 +36,6 @@ #include "qwindowscontext.h" #include "qwindowsdrag.h" #include "qwindowsscreen.h" -#include "qwindowsscaling.h" #include "qwindowsintegration.h" #include "qwindowsopenglcontext.h" #ifdef QT_NO_CURSOR @@ -49,8 +48,9 @@ #include <QtGui/QRegion> #include <QtGui/QOpenGLContext> #include <private/qsystemlibrary_p.h> -#include <private/qwindow_p.h> +#include <private/qwindow_p.h> // QWINDOWSIZE_MAX #include <private/qguiapplication_p.h> +#include <private/qhighdpiscaling_p.h> #include <qpa/qwindowsysteminterface.h> #include <QtCore/QDebug> @@ -169,7 +169,7 @@ static QPoint windowPlacementOffset(HWND hwnd, const QPoint &point) const QWindowsScreen *screen = screenManager.screens().size() == 1 ? screenManager.screens().first() : screenManager.screenAtDp(point); if (screen) - return screen->availableGeometryDp().topLeft() - screen->geometryDp().topLeft(); + return screen->availableGeometry().topLeft() - screen->geometry().topLeft(); #else Q_UNUSED(hwnd) Q_UNUSED(point) @@ -608,9 +608,7 @@ QWindowsWindowData const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w); - const QRect geometryDip = QWindowsScaling::mapFromNative(data.geometry); - QRect fixedGeometryDip = QPlatformWindow::initialGeometry(w, geometryDip, defaultWindowWidth, defaultWindowHeight); - const QRect rect = fixedGeometryDip != geometryDip ? QWindowsScaling::mapToNative(fixedGeometryDip) : data.geometry; + const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight); if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); @@ -718,8 +716,8 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang */ QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) : - minimumSize(QWindowsScaling::mapToNativeConstrained(w->minimumSize())), - maximumSize(QWindowsScaling::mapToNativeConstrained(w->maximumSize())), + minimumSize(QHighDpi::toNativePixelsConstrained(w->minimumSize(), w)), + maximumSize(QHighDpi::toNativePixelsConstrained(w->maximumSize(), w)), customMargins(cm) { } @@ -953,8 +951,7 @@ void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) clearFlag(Exposed); else setFlag(Exposed); - QWindowSystemInterface::handleExposeEvent(window(), - QWindowsScaling::mapFromNative(region)); + QWindowSystemInterface::handleExposeEvent(window(), region); } static inline QWindow *findTransientChild(const QWindow *parent) @@ -1134,7 +1131,7 @@ bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const return m_data.embedded; } -QPoint QWindowsWindow::mapToGlobalDp(const QPoint &pos) const +QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos); @@ -1142,7 +1139,7 @@ QPoint QWindowsWindow::mapToGlobalDp(const QPoint &pos) const return pos; } -QPoint QWindowsWindow::mapFromGlobalDp(const QPoint &pos) const +QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos); @@ -1323,22 +1320,22 @@ static QRect normalFrameGeometry(HWND hwnd) return QRect(); } -QRect QWindowsWindow::normalGeometryDp() const +QRect QWindowsWindow::normalGeometry() const { // Check for fake 'fullscreen' mode. const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen; const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); - const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMarginsDp(); + const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; } -void QWindowsWindow::setGeometryDp(const QRect &rectIn) +void QWindowsWindow::setGeometry(const QRect &rectIn) { QRect rect = rectIn; // This means it is a call from QWindow::setFramePosition() and // the coordinates include the frame (size is still the contents rectangle). if (QWindowsGeometryHint::positionIncludesFrame(window())) { - const QMargins margins = frameMarginsDp(); + const QMargins margins = frameMargins(); rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top())); } if (m_windowState == Qt::WindowMinimized) @@ -1407,9 +1404,8 @@ void QWindowsWindow::handleGeometryChange() return; const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); - const QRect geometryDip = QWindowsScaling::mapFromNative(m_data.geometry); - QPlatformWindow::setGeometry(geometryDip); - QWindowSystemInterface::handleGeometryChange(window(), geometryDip); + QPlatformWindow::setGeometry(m_data.geometry); + QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive // expose events when shrinking, synthesize. if (!testFlag(OpenGL_ES2) && isExposed() @@ -1417,7 +1413,7 @@ void QWindowsWindow::handleGeometryChange() fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } if (previousGeometry.topLeft() != m_data.geometry.topLeft()) { - QPlatformScreen *newScreen = screenForGeometry(geometryDip); + QPlatformScreen *newScreen = screenForGeometry(m_data.geometry); if (newScreen != screen()) QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); } @@ -1429,7 +1425,7 @@ void QWindowsWindow::handleGeometryChange() void QWindowsWindow::setGeometry_sys(const QRect &rect) const { - const QMargins margins = frameMarginsDp(); + const QMargins margins = frameMargins(); const QRect frameGeometry = rect + margins; qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << window() @@ -1468,7 +1464,7 @@ QRect QWindowsWindow::frameGeometry_sys() const QRect QWindowsWindow::geometry_sys() const { - return frameGeometry_sys().marginsRemoved(frameMarginsDp()); + return frameGeometry_sys().marginsRemoved(frameMargins()); } /*! @@ -1540,7 +1536,7 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) { qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: " << m_data.flags << "\n to: " << flags; - const QRect oldGeometry = geometryDp(); + const QRect oldGeometry = geometry(); if (m_data.flags != flags) { m_data.flags = flags; if (m_data.hwnd) { @@ -1626,8 +1622,9 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) bool QWindowsWindow::isFullScreen_sys() const { - return window()->isTopLevel() - && geometry_sys() == QWindowsScaling::mapToNative(window()->screen()->geometry()); + const QWindow *w = window(); + return w->isTopLevel() + && geometry_sys() == QHighDpi::toNativePixels(w->screen()->geometry(), w); } /*! @@ -1697,15 +1694,14 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) // Use geometry of QWindow::screen() within creation or the virtual screen the // window is in (QTBUG-31166, QTBUG-30724). const QScreen *screen = window()->screen(); - const QRect rDip = screen->geometry(); - const QRect r = QWindowsScaling::mapToNative(rDip); + const QRect r = QHighDpi::toNativePixels(screen->geometry(), window()); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); if (!wasSync) clearFlag(SynchronousGeometryChangeEvent); - QWindowSystemInterface::handleGeometryChange(window(), rDip); + QWindowSystemInterface::handleGeometryChange(window(), r); QWindowSystemInterface::flushWindowSystemEvents(); } else if (newState != Qt::WindowMinimized) { // Restore saved state. @@ -1804,7 +1800,7 @@ void QWindowsWindow::propagateSizeHints() qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); } -bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp) +bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins) { #ifndef Q_OS_WINCE if (!qWindow->isTopLevel()) // Implement hasHeightForWidth(). @@ -1812,26 +1808,20 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow * WINDOWPOS *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam); if ((windowPos->flags & (SWP_NOCOPYBITS | SWP_NOSIZE))) return false; - const QRect suggestedFrameGeometryDp(windowPos->x, windowPos->y, - windowPos->cx, windowPos->cy); - const qreal factor = QWindowsScaling::factor(); - const QRect suggestedGeometryDp = suggestedFrameGeometryDp - marginsDp; - const QRectF suggestedGeometry = QRectF(QPointF(suggestedGeometryDp.topLeft()) / factor, - QSizeF(suggestedGeometryDp.size()) / factor); + const QRect suggestedFrameGeometry(windowPos->x, windowPos->y, + windowPos->cx, windowPos->cy); + const QRect suggestedGeometry = suggestedFrameGeometry - margins; const QRectF correctedGeometryF = qt_window_private(const_cast<QWindow *>(qWindow))->closestAcceptableGeometry(suggestedGeometry); if (!correctedGeometryF.isValid()) return false; - const QRect correctedFrameGeometryDp - = QRectF(correctedGeometryF.topLeft() * factor, - correctedGeometryF.size() * factor).toRect() - + marginsDp; - if (correctedFrameGeometryDp == suggestedFrameGeometryDp) + const QRect correctedFrameGeometry = correctedGeometryF.toRect() + margins; + if (correctedFrameGeometry == suggestedFrameGeometry) return false; - windowPos->x = correctedFrameGeometryDp.left(); - windowPos->y = correctedFrameGeometryDp.top(); - windowPos->cx = correctedFrameGeometryDp.width(); - windowPos->cy = correctedFrameGeometryDp.height(); + windowPos->x = correctedFrameGeometry.left(); + windowPos->y = correctedFrameGeometry.top(); + windowPos->cx = correctedFrameGeometry.width(); + windowPos->cy = correctedFrameGeometry.height(); return true; #else // !Q_OS_WINCE Q_UNUSED(message) @@ -1841,11 +1831,11 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow * bool QWindowsWindow::handleGeometryChanging(MSG *message) const { - const QMargins marginsDp = window()->isTopLevel() ? frameMarginsDp() : QMargins(); - return QWindowsWindow::handleGeometryChangingMessage(message, window(), marginsDp); + const QMargins margins = window()->isTopLevel() ? frameMargins() : QMargins(); + return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins); } -QMargins QWindowsWindow::frameMarginsDp() const +QMargins QWindowsWindow::frameMargins() const { // Frames are invalidated by style changes (window state, flags). // As they are also required for geometry calculations in resize @@ -1892,17 +1882,17 @@ static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion) } } -static HRGN qRegionToWinRegion(const QRegion ®ionDip) +static HRGN qRegionToWinRegion(const QRegion ®ion) { - const QVector<QRect> rects = regionDip.rects(); + const QVector<QRect> rects = region.rects(); if (rects.isEmpty()) return NULL; const int rectCount = rects.size(); if (rectCount == 1) - return createRectRegion(QWindowsScaling::mapToNative(regionDip.boundingRect())); - HRGN hRegion = createRectRegion(QWindowsScaling::mapToNative(rects.front())); + return createRectRegion(region.boundingRect()); + HRGN hRegion = createRectRegion(rects.front()); for (int i = 1; i < rectCount; ++i) - addRectToWinRegion(QWindowsScaling::mapToNative(rects.at(i)), &hRegion); + addRectToWinRegion(rects.at(i), &hRegion); return hRegion; } @@ -1916,7 +1906,7 @@ void QWindowsWindow::setMask(const QRegion ®ion) // Mask is in client area coordinates, so offset it in case we have a frame if (window()->isTopLevel()) { - const QMargins margins = frameMarginsDp(); + const QMargins margins = frameMargins(); OffsetRgn(winRegion, margins.left(), margins.top()); } @@ -2053,23 +2043,23 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re || (m_data.flags & Qt::FramelessWindowHint)) { return false; } - const QSize minimumSize = QWindowsScaling::mapToNativeConstrained(w->minimumSize()); + const QSize minimumSize = w->minimumSize(); if (minimumSize.isEmpty()) return false; - const QSize maximumSize = QWindowsScaling::mapToNativeConstrained(w->maximumSize()); + const QSize maximumSize = w->maximumSize(); const bool fixedWidth = minimumSize.width() == maximumSize.width(); const bool fixedHeight = minimumSize.height() == maximumSize.height(); if (!fixedWidth && !fixedHeight) return false; - const QPoint localPos = mapFromGlobalDp(globalPos); - const QSize size = w->size() * QWindowsScaling::factor(); + const QPoint localPos = w->mapFromGlobal(QHighDpi::fromNativePixels(globalPos, w)); + const QSize size = w->size(); if (fixedHeight) { if (localPos.y() >= size.height()) { *result = HTBORDER; // Unspecified border, no resize cursor. return true; } if (localPos.y() < 0) { - const QMargins margins = frameMarginsDp(); + const QMargins margins = frameMargins(); const int topResizeBarPos = margins.left() - margins.top(); if (localPos.y() < topResizeBarPos) { *result = HTCAPTION; // Extend caption over top resize bar, let's user move the window. @@ -2245,10 +2235,6 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon) The property can be set using QPlatformNativeInterface::setWindowProperty() or, before platform window creation, by setting a dynamic property on the QWindow (see QWindowsIntegration::createPlatformWindow()). - - Note: The function uses (unscaled) device pixels since the QWizard also - uses AdjustWindowRect() and using device independent pixels would introduce - rounding errors. */ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index fff90b4b11..d96022e3a5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -38,7 +38,6 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" #endif -#include "qwindowsscaling.h" #include "qwindowscursor.h" #include <qpa/qplatformwindow.h> @@ -145,28 +144,18 @@ public: ~QWindowsWindow(); QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } - void setGeometryDp(const QRect &rectIn); - void setGeometry(const QRect &rect) Q_DECL_OVERRIDE - { setGeometryDp(QWindowsScaling::mapToNative(rect)); } - QRect geometryDp() const { return m_data.geometry; } - QRect geometry() const Q_DECL_OVERRIDE - { return QWindowsScaling::mapFromNative(geometryDp()); } - QRect normalGeometryDp() const; - QRect normalGeometry() const Q_DECL_OVERRIDE - { return QWindowsScaling::mapFromNative(normalGeometryDp()); } - qreal devicePixelRatio() const Q_DECL_OVERRIDE - { return qreal(QWindowsScaling::factor()); } + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; + QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } + QRect normalGeometry() const Q_DECL_OVERRIDE; + void setVisible(bool visible) Q_DECL_OVERRIDE; bool isVisible() const; bool isExposed() const Q_DECL_OVERRIDE { return testFlag(Exposed); } bool isActive() const Q_DECL_OVERRIDE; bool isEmbedded(const QPlatformWindow *parentWindow) const Q_DECL_OVERRIDE; - QPoint mapToGlobalDp(const QPoint &pos) const; - QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE - { return mapToGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } - QPoint mapFromGlobalDp(const QPoint &pos) const; - QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE - { return mapFromGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } + QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; @@ -184,8 +173,7 @@ public: void propagateSizeHints() Q_DECL_OVERRIDE; static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp); bool handleGeometryChanging(MSG *message) const; - QMargins frameMarginsDp() const; - QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMarginsDp() / QWindowsScaling::factor(); } + QMargins frameMargins() const Q_DECL_OVERRIDE; void setOpacity(qreal level) Q_DECL_OVERRIDE; void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; @@ -196,7 +184,7 @@ public: bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; } - bool startSystemResize(const QPoint &, Qt::Corner corner) Q_DECL_OVERRIDE; + bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE; void setFrameStrutEventsEnabled(bool enabled); bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); } diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index a0460630a7..665a1f954d 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -40,7 +40,6 @@ SOURCES += \ $$PWD/qwindowsservices.cpp \ $$PWD/qwindowsnativeimage.cpp \ $$PWD/qwindowsnativeinterface.cpp \ - $$PWD/qwindowsscaling.cpp \ $$PWD/qwindowsopengltester.cpp HEADERS += \ @@ -67,7 +66,6 @@ HEADERS += \ $$PWD/qplatformfunctions_wince.h \ $$PWD/qwindowsnativeimage.h \ $$PWD/qwindowsnativeinterface.h \ - $$PWD/qwindowsscaling.h \ $$PWD/qwindowsopengltester.h INCLUDEPATH += $$PWD diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index c0f5477f82..e62d515b62 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -49,6 +49,7 @@ #include <qdebug.h> #include <qpainter.h> #include <qscreen.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <qpa/qplatformgraphicsbuffer.h> #include <algorithm> @@ -313,14 +314,7 @@ void QXcbBackingStore::beginPaint(const QRegion ®ion) if (!m_image) return; - int dpr = int(m_image->image()->devicePixelRatio()); - const int windowDpr = int(window()->devicePixelRatio()); - if (windowDpr != dpr) { - resize(window()->size(), QRegion()); - dpr = int(m_image->image()->devicePixelRatio()); - } - - m_paintRegion = dpr == 1 ? region : QTransform::fromScale(dpr,dpr).map(region); + m_paintRegion = region; m_image->preparePaint(m_paintRegion); if (m_image->image()->hasAlphaChannel()) { @@ -369,18 +363,10 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin if (!m_image || m_image->size().isEmpty()) return; - const int dpr = int(window->devicePixelRatio()); - -#ifndef QT_NO_DEBUG - const int imageDpr = int(m_image->image()->devicePixelRatio()); - if (dpr != imageDpr) - qWarning() << "QXcbBackingStore::flush() wrong devicePixelRatio for backingstore image" << dpr << imageDpr; -#endif - - QSize imageSize = m_image->size() / dpr; //because we multiply with the DPR later + QSize imageSize = m_image->size(); QRegion clipped = region; - clipped &= QRect(0, 0, window->width(), window->height()); + clipped &= QRect(QPoint(), QHighDpi::toNativePixels(window->size(), window)); clipped &= QRect(0, 0, imageSize.width(), imageSize.height()).translated(-offset); QRect bounds = clipped.boundingRect(); @@ -398,8 +384,8 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin QVector<QRect> rects = clipped.rects(); for (int i = 0; i < rects.size(); ++i) { - QRect rect = QRect(rects.at(i).topLeft() * dpr, rects.at(i).size() * dpr); - m_image->put(platformWindow->xcb_window(), rect.topLeft(), rect.translated(offset * dpr)); + QRect rect = QRect(rects.at(i).topLeft(), rects.at(i).size()); + m_image->put(platformWindow->xcb_window(), rect.topLeft(), rect.translated(offset)); } Q_XCB_NOOP(connection()); @@ -430,9 +416,7 @@ void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, c void QXcbBackingStore::resize(const QSize &size, const QRegion &) { - const int dpr = int(window()->devicePixelRatio()); - const QSize xSize = size * dpr; - if (m_image && xSize == m_image->size() && dpr == m_image->image()->devicePixelRatio()) + if (m_image && size == m_image->size()) return; Q_XCB_NOOP(connection()); @@ -445,13 +429,11 @@ void QXcbBackingStore::resize(const QSize &size, const QRegion &) QXcbWindow* win = static_cast<QXcbWindow *>(pw); delete m_image; - m_image = new QXcbShmImage(screen, xSize, win->depth(), win->imageFormat()); - m_image->image()->setDevicePixelRatio(dpr); + m_image = new QXcbShmImage(screen, size, win->depth(), win->imageFormat()); // Slow path for bgr888 VNC: Create an additional image, paint into that and // swap R and B while copying to m_image after each paint. if (win->imageNeedsRgbSwap()) { - m_rgbImage = QImage(xSize, win->imageFormat()); - m_rgbImage.setDevicePixelRatio(dpr); + m_rgbImage = QImage(size, win->imageFormat()); } Q_XCB_NOOP(connection()); } @@ -463,14 +445,12 @@ bool QXcbBackingStore::scroll(const QRegion &area, int dx, int dy) if (!m_image || m_image->image()->isNull()) return false; - const int dpr = int(m_image->image()->devicePixelRatio()); - QRegion xArea = dpr == 1 ? area : QTransform::fromScale(dpr,dpr).map(area); m_image->preparePaint(area); - QPoint delta(dx * dpr, dy * dpr); - const QVector<QRect> xRects = xArea.rects(); - for (int i = 0; i < xRects.size(); ++i) - qt_scrollRectInImage(*m_image->image(), xRects.at(i), delta); + QPoint delta(dx, dy); + const QVector<QRect> rects = area.rects(); + for (int i = 0; i < rects.size(); ++i) + qt_scrollRectInImage(*m_image->image(), rects.at(i), delta); return true; } diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index c7784ddb48..e165c753ab 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -870,9 +870,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin } } if (!angleDelta.isNull()) { - const int dpr = int(platformWindow->devicePixelRatio()); - QPoint local(fixed1616ToReal(xiDeviceEvent->event_x)/dpr, fixed1616ToReal(xiDeviceEvent->event_y)/dpr); - QPoint global(fixed1616ToReal(xiDeviceEvent->root_x)/dpr, fixed1616ToReal(xiDeviceEvent->root_y)/dpr); + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); if (modifiers & Qt::AltModifier) { std::swap(angleDelta.rx(), angleDelta.ry()); @@ -898,9 +897,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin angleDelta.setX(-120); } if (!angleDelta.isNull()) { - const int dpr = int(platformWindow->devicePixelRatio()); - QPoint local(fixed1616ToReal(xiDeviceEvent->event_x)/dpr, fixed1616ToReal(xiDeviceEvent->event_y)/dpr); - QPoint global(fixed1616ToReal(xiDeviceEvent->root_x)/dpr, fixed1616ToReal(xiDeviceEvent->root_y)/dpr); + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); if (modifiers & Qt::AltModifier) std::swap(angleDelta.rx(), angleDelta.ry()); diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index e51ab85e30..d8389bff7a 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -635,15 +635,14 @@ QPoint QXcbCursor::pos() const { QPoint p; queryPointer(connection(), 0, &p); - return m_screen->mapFromNative(p); + return p; } void QXcbCursor::setPos(const QPoint &pos) { - const QPoint xPos = m_screen->mapToNative(pos); xcb_window_t root = 0; queryPointer(connection(), &root, 0); - xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, xPos.x(), xPos.y()); + xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y()); xcb_flush(xcb_connection()); } diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 1d13adf851..8d4878e12e 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -71,12 +71,16 @@ QT_BEGIN_NAMESPACE const int xdnd_version = 5; +static inline xcb_window_t xcb_window(QPlatformWindow *w) +{ + return static_cast<QXcbWindow *>(w)->xcb_window(); +} + static inline xcb_window_t xcb_window(QWindow *w) { return static_cast<QXcbWindow *>(w->handle())->xcb_window(); } - static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w) { xcb_window_t proxy = XCB_NONE; @@ -297,15 +301,9 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md return 0; } -void QXcbDrag::move(const QMouseEvent *me) +void QXcbDrag::move(const QPoint &globalPos) { - // The mouse event is in the coordinate system of the window that started the drag. - // We do not know which window that was at this point, so we just use the device pixel ratio - // of the QGuiApplication. This will break once we support screens with different DPR. Fixing - // this properly requires some redesign of the drag and drop architecture. - static const int dpr = int(qApp->devicePixelRatio()); - QBasicDrag::move(me); - QPoint globalPos = me->globalPos(); + QBasicDrag::move(globalPos); if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) return; @@ -340,7 +338,7 @@ void QXcbDrag::move(const QMouseEvent *me) // qt_xdnd_current_screen = screen; xcb_window_t rootwin = current_screen->root(); xcb_translate_coordinates_reply_t *translate = - ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x() * dpr, globalPos.y() * dpr); + ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y()); if (!translate) return; @@ -443,7 +441,7 @@ void QXcbDrag::move(const QMouseEvent *me) DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; if (w) - handleEnter(w->window(), &enter); + handleEnter(w, &enter); else if (target) xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter); waiting_for_status = false; @@ -463,7 +461,7 @@ void QXcbDrag::move(const QMouseEvent *me) move.type = atom(QXcbAtom::XdndPosition); move.data.data32[0] = connection()->clipboard()->owner(); move.data.data32[1] = 0; // flags - move.data.data32[2] = (globalPos.x() * dpr << 16) + globalPos.y() * dpr; + move.data.data32[2] = (globalPos.x() << 16) + globalPos.y(); move.data.data32[3] = connection()->time(); move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers())); DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; @@ -471,15 +469,15 @@ void QXcbDrag::move(const QMouseEvent *me) source_time = connection()->time(); if (w) - handle_xdnd_position(w->window(), &move); + handle_xdnd_position(w, &move); else xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); } } -void QXcbDrag::drop(const QMouseEvent *event) +void QXcbDrag::drop(const QPoint &globalPos) { - QBasicDrag::drop(event); + QBasicDrag::drop(globalPos); if (!current_target) return; @@ -505,7 +503,7 @@ void QXcbDrag::drop(const QMouseEvent *event) connection()->time(), current_target, current_proxy_target, - (w ? w->window() : 0), + w, // current_embeddig_widget, currentDrag(), QTime::currentTime() @@ -518,7 +516,7 @@ void QXcbDrag::drop(const QMouseEvent *event) } if (w) { - handleDrop(w->window(), &drop); + handleDrop(w, &drop); } else { xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop); } @@ -664,7 +662,7 @@ static bool checkEmbedded(QWidget* w, const XEvent* xe) #endif -void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *event) +void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event) { Q_UNUSED(window); DEBUG() << "handleEnter" << window; @@ -704,17 +702,14 @@ void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *ev DEBUG() << " " << connection()->atomName(xdnd_types.at(i)); } -void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e) +void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *e) { QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff); Q_ASSERT(w); QRect geometry = w->geometry(); - const int dpr = int(w->handle()->devicePixelRatio()); - - p /= dpr; p -= geometry.topLeft(); - if (!w || (w->type() == Qt::Desktop)) + if (!w || !w->window() || (w->window()->type() == Qt::Desktop)) return; if (e->data.data32[0] != xdnd_dragsource) { @@ -723,7 +718,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t } currentPosition = p; - currentWindow = w; + currentWindow = w->window(); // timestamp from the source if (e->data.data32[3] != XCB_NONE) { @@ -740,7 +735,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t supported_actions = Qt::DropActions(toDropAction(e->data.data32[4])); } - QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w,dropData,p,supported_actions); + QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w->window(),dropData,p,supported_actions); QRect answerRect(p + geometry.topLeft(), QSize(1,1)); answerRect = qt_response.answerRect().translated(geometry.topLeft()).intersected(geometry); @@ -796,7 +791,7 @@ namespace }; } -void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event) +void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_event_t *event) { xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); xcb_generic_event_t *nextEvent; @@ -830,12 +825,10 @@ void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event) updateCursor(Qt::IgnoreAction); } - static const int dpr = int(qApp->devicePixelRatio()); - if ((event->data.data32[1] & 2) == 0) { QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff); QSize s((event->data.data32[3] & 0xffff0000) >> 16, event->data.data32[3] & 0x0000ffff); - source_sameanswer = QRect(p / dpr, s / dpr); + source_sameanswer = QRect(p, s); } else { source_sameanswer = QRect(); } @@ -861,10 +854,10 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event) DEBUG("xdndHandleStatus end"); } -void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event) +void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event) { DEBUG("xdnd leave"); - if (!currentWindow || w != currentWindow.data()) + if (!currentWindow || w != currentWindow.data()->handle()) return; // sanity // ### @@ -879,7 +872,7 @@ void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event) DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource); } - QWindowSystemInterface::handleDrag(w,0,QPoint(),Qt::IgnoreAction); + QWindowSystemInterface::handleDrag(w->window(),0,QPoint(),Qt::IgnoreAction); xdnd_dragsource = 0; xdnd_types.clear(); @@ -909,7 +902,7 @@ void QXcbDrag::send_leave() w = 0; if (w) - handleLeave(w->window(), (const xcb_client_message_event_t *)&leave); + handleLeave(w, (const xcb_client_message_event_t *)&leave); else xcb_send_event(xcb_connection(), false,current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&leave); @@ -920,7 +913,7 @@ void QXcbDrag::send_leave() waiting_for_status = false; } -void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event) +void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event) { DEBUG("xdndHandleDrop"); if (!currentWindow) { diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index 95da76b732..699d402ea6 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -53,8 +53,8 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_DRAGANDDROP -class QMouseEvent; class QWindow; +class QPlatformWindow; class QXcbConnection; class QXcbWindow; class QXcbDropData; @@ -72,14 +72,14 @@ public: void startDrag() Q_DECL_OVERRIDE; void cancel() Q_DECL_OVERRIDE; - void move(const QMouseEvent *me) Q_DECL_OVERRIDE; - void drop(const QMouseEvent *me) Q_DECL_OVERRIDE; + void move(const QPoint &globalPos) Q_DECL_OVERRIDE; + void drop(const QPoint &globalPos) Q_DECL_OVERRIDE; void endDrag() Q_DECL_OVERRIDE; - void handleEnter(QWindow *window, const xcb_client_message_event_t *event); - void handlePosition(QWindow *w, const xcb_client_message_event_t *event); - void handleLeave(QWindow *w, const xcb_client_message_event_t *event); - void handleDrop(QWindow *, const xcb_client_message_event_t *event); + void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event); + void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event); + void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event); + void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event); void handleStatus(const xcb_client_message_event_t *event); void handleSelectionRequest(const xcb_selection_request_event_t *event); @@ -99,7 +99,7 @@ private: void init(); - void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event); + void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event); void handle_xdnd_status(const xcb_client_message_event_t *event); void send_leave(); @@ -146,7 +146,7 @@ private: xcb_timestamp_t timestamp; xcb_window_t target; xcb_window_t proxy_target; - QWindow *targetWindow; + QPlatformWindow *targetWindow; // QWidget *embedding_widget; QPointer<QDrag> drag; QTime time; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index c14ec0bb3f..de1aeb2797 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -44,6 +44,7 @@ #include <qpa/qwindowsysteminterface.h> #include <private/qmath_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -86,7 +87,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe , m_orientation(Qt::PrimaryOrientation) , m_refreshRate(60) , m_forcedDpi(-1) - , m_devicePixelRatio(1) + , m_pixelDensity(1) , m_hintStyle(QFontEngine::HintStyle(-1)) , m_noFontHinting(false) , m_subpixelType(QFontEngine::SubpixelAntialiasingType(-1)) @@ -107,9 +108,8 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe updateGeometry(output ? output->timestamp : 0); } - const int dpr = int(devicePixelRatio()); if (m_geometry.isEmpty()) { - m_geometry = QRect(QPoint(), m_virtualSize/dpr); + m_geometry = QRect(QPoint(), m_virtualSize); m_nativeGeometry = QRect(QPoint(), m_virtualSize); } if (m_availableGeometry.isEmpty()) @@ -117,12 +117,6 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe readXResources(); - // disable font hinting when we do UI scaling - static bool dpr_scaling_enabled = (qgetenv("QT_DEVICE_PIXEL_RATIO").toInt() > 1 - || qgetenv("QT_DEVICE_PIXEL_RATIO").toLower() == "auto"); - if (dpr_scaling_enabled) - m_noFontHinting = true; - QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> rootAttribs( xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes_unchecked(xcb_connection(), screen()->root), NULL)); @@ -233,9 +227,8 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const { xcb_window_t root = screen()->root; - int dpr = int(devicePixelRatio()); - int x = p.x() / dpr; - int y = p.y() / dpr; + int x = p.x(); + int y = p.y(); xcb_window_t parent = root; xcb_window_t child = root; @@ -269,31 +262,6 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const return 0; } - -QPoint QXcbScreen::mapToNative(const QPoint &pos) const -{ - const int dpr = int(devicePixelRatio()); - return (pos - m_geometry.topLeft()) * dpr + m_nativeGeometry.topLeft(); -} - -QPoint QXcbScreen::mapFromNative(const QPoint &pos) const -{ - const int dpr = int(devicePixelRatio()); - return (pos - m_nativeGeometry.topLeft()) / dpr + m_geometry.topLeft(); -} - -QRect QXcbScreen::mapToNative(const QRect &rect) const -{ - const int dpr = int(devicePixelRatio()); - return QRect(mapToNative(rect.topLeft()), rect.size() * dpr); -} - -QRect QXcbScreen::mapFromNative(const QRect &rect) const -{ - const int dpr = int(devicePixelRatio()); - return QRect(mapFromNative(rect.topLeft()), rect.size() / dpr); -} - void QXcbScreen::windowShown(QXcbWindow *window) { // Freedesktop.org Startup Notification @@ -355,6 +323,7 @@ QDpi QXcbScreen::virtualDpi() const Q_MM_PER_INCH * m_virtualSize.height() / m_virtualSizeMillimeters.height()); } + QDpi QXcbScreen::logicalDpi() const { static const int overrideDpi = qEnvironmentVariableIntValue("QT_FONT_DPI"); @@ -362,22 +331,14 @@ QDpi QXcbScreen::logicalDpi() const return QDpi(overrideDpi, overrideDpi); if (m_forcedDpi > 0) { - int primaryDpr = int(connection()->screens().at(0)->devicePixelRatio()); - return QDpi(m_forcedDpi/primaryDpr, m_forcedDpi/primaryDpr); + return QDpi(m_forcedDpi, m_forcedDpi); } return virtualDpi(); } - -qreal QXcbScreen::devicePixelRatio() const +qreal QXcbScreen::pixelDensity() const { - static int override_dpr = qEnvironmentVariableIntValue("QT_DEVICE_PIXEL_RATIO"); - static bool auto_dpr = qgetenv("QT_DEVICE_PIXEL_RATIO").toLower() == "auto"; - if (override_dpr > 0) - return override_dpr; - if (auto_dpr) - return m_devicePixelRatio; - return 1.0; + return m_pixelDensity; } QPlatformCursor *QXcbScreen::cursor() const @@ -536,11 +497,10 @@ void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation) free(workArea); qreal dpi = xGeometry.width() / physicalSize().width() * qreal(25.4); - m_devicePixelRatio = qRound(dpi/96); - const int dpr = int(devicePixelRatio()); // we may override m_devicePixelRatio - m_geometry = QRect(xGeometry.topLeft(), xGeometry.size()/dpr); + m_pixelDensity = qRound(dpi/96); + m_geometry = QRect(xGeometry.topLeft(), xGeometry.size()); m_nativeGeometry = QRect(xGeometry.topLeft(), xGeometry.size()); - m_availableGeometry = QRect(mapFromNative(xAvailableGeometry.topLeft()), xAvailableGeometry.size()/dpr); + m_availableGeometry = QRect(xAvailableGeometry.topLeft(), xAvailableGeometry.size()); QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); } diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index ec05e3bb25..e31436d9d0 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -96,7 +96,7 @@ public: QSizeF physicalVirtualSize() const { return m_virtualSizeMillimeters; } QDpi virtualDpi() const; QDpi logicalDpi() const Q_DECL_OVERRIDE; - qreal devicePixelRatio() const Q_DECL_OVERRIDE; + qreal pixelDensity() const Q_DECL_OVERRIDE; QPlatformCursor *cursor() const Q_DECL_OVERRIDE; qreal refreshRate() const Q_DECL_OVERRIDE { return m_refreshRate; } Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_orientation; } @@ -141,11 +141,6 @@ public: QXcbXSettings *xSettings() const; - QPoint mapToNative(const QPoint &pos) const; - QPoint mapFromNative(const QPoint &pos) const; - QRect mapToNative(const QRect &rect) const; - QRect mapFromNative(const QRect &rect) const; - private: static bool xResource(const QByteArray &identifier, const QByteArray &expectedIdentifier, @@ -177,7 +172,7 @@ private: QXcbCursor *m_cursor; int m_refreshRate; int m_forcedDpi; - int m_devicePixelRatio; + int m_pixelDensity; QFontEngine::HintStyle m_hintStyle; bool m_noFontHinting; QFontEngine::SubpixelAntialiasingType m_subpixelType; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index d2da137591..3bc0df6f57 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -37,6 +37,7 @@ #include <QScreen> #include <QtGui/QIcon> #include <QtGui/QRegion> +#include <QtGui/private/qhighdpiscaling_p.h> #include "qxcbintegration.h" #include "qxcbconnection.h" @@ -140,73 +141,11 @@ enum QX11EmbedMessageType { const quint32 XEMBED_VERSION = 0; -static inline QRect mapLocalGeometryToNative(const QRect &qtRect, int dpr) -{ - return QRect(qtRect.x() * dpr, qtRect.y() * dpr, qtRect.width() * dpr, qtRect.height() * dpr); -} - -// When mapping expose events to Qt rects: round top/left towards the origin and -// bottom/right away from the origin, making sure that we cover the whole widget - -static inline QPoint dpr_floor(const QPoint &p, int dpr) -{ - return QPoint(p.x()/dpr, p.y()/dpr); -} - -static inline QPoint dpr_ceil(const QPoint &p, int dpr) -{ - return QPoint((p.x() + dpr - 1) / dpr, (p.y() + dpr - 1) / dpr); -} - -static inline QSize dpr_ceil(const QSize &s, int dpr) -{ - return QSize((s.width() + dpr - 1) / dpr, (s.height() + dpr - 1) / dpr); -} - -static inline QRect mapExposeFromNative(const QRect &xRect, int dpr) -{ - return QRect(dpr_floor(xRect.topLeft(), dpr), dpr_ceil(xRect.bottomRight(), dpr)); -} - -static inline QRect mapLocalGeometryFromNative(const QRect &xRect, int dpr) -{ - return QRect(xRect.topLeft() / dpr, dpr_ceil(xRect.size(), dpr)); -} - QXcbScreen *QXcbWindow::parentScreen() { return parent() ? static_cast<QXcbWindow*>(parent())->parentScreen() : m_xcbScreen; } -QPoint QXcbWindow::mapToNative(const QPoint &pos, const QXcbScreen *screen) const -{ - if (parent()) - return pos * int(screen->devicePixelRatio()); - else - return screen->mapToNative(pos); -} -QPoint QXcbWindow::mapFromNative(const QPoint &pos, const QXcbScreen *screen) const -{ - if (parent()) - return pos / int(screen->devicePixelRatio()); - else - return screen->mapFromNative(pos); -} -QRect QXcbWindow::mapToNative(const QRect &rect, const QXcbScreen *screen) const -{ - if (parent()) - return mapLocalGeometryToNative(rect, int(screen->devicePixelRatio())); - else - return screen->mapToNative(rect); -} -QRect QXcbWindow::mapFromNative(const QRect &rect, const QXcbScreen *screen) const -{ - if (parent()) - return mapLocalGeometryFromNative(rect, int(screen->devicePixelRatio())); - else - return screen->mapFromNative(rect); -} - // Returns \c true if we should set WM_TRANSIENT_FOR on \a w static inline bool isTransient(const QWindow *w) { @@ -382,7 +321,7 @@ void QXcbWindow::create() Qt::WindowType type = window()->type(); QXcbScreen *currentScreen = xcbScreen(); - QRect rect = window()->geometry(); + QRect rect = windowGeometry(); QXcbScreen *platformScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect)); m_xcbScreen = platformScreen; @@ -420,22 +359,19 @@ void QXcbWindow::create() // Parameters to XCreateWindow() are frame corner + inner size. // This fits in case position policy is frame inclusive. There is // currently no way to implement it for frame-exclusive geometries. - QPlatformWindow::setGeometry(rect); if (platformScreen != currentScreen) QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen()); - const int dpr = int(devicePixelRatio()); - - QSize minimumSize = window()->minimumSize(); + const QSize minimumSize = windowMinimumSize(); if (rect.width() > 0 || rect.height() > 0) { - rect.setWidth(qBound(1, rect.width(), XCOORD_MAX/dpr)); - rect.setHeight(qBound(1, rect.height(), XCOORD_MAX/dpr)); + rect.setWidth(qBound(1, rect.width(), XCOORD_MAX)); + rect.setHeight(qBound(1, rect.height(), XCOORD_MAX)); } else if (minimumSize.width() > 0 || minimumSize.height() > 0) { rect.setSize(minimumSize); } else { - rect.setWidth(defaultWindowWidth); - rect.setHeight(defaultWindowHeight); + rect.setWidth(QHighDpi::toNativePixels(int(defaultWindowWidth), platformScreen->QPlatformScreen::screen())); + rect.setHeight(QHighDpi::toNativePixels(int(defaultWindowHeight), platformScreen->QPlatformScreen::screen())); } xcb_window_t xcb_parent_id = platformScreen->root(); @@ -479,9 +415,7 @@ void QXcbWindow::create() m_visualId = visualInfo->visualid; - const QRect xRect = mapToNative(rect, platformScreen); - - m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, xRect.x(), xRect.y(), xRect.width(), xRect.height(), + m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(), 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBackPixel|CWBorderPixel|CWColormap, &a); @@ -537,16 +471,14 @@ void QXcbWindow::create() } m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap); - const QRect xRect = mapToNative(rect, platformScreen); - Q_XCB_CALL(xcb_create_window(xcb_connection(), m_depth, m_window, // window id xcb_parent_id, // parent window id - xRect.x(), - xRect.y(), - xRect.width(), - xRect.height(), + rect.x(), + rect.y(), + rect.width(), + rect.height(), 0, // border width XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class m_visualId, // visual @@ -709,15 +641,14 @@ void QXcbWindow::setGeometry(const QRect &rect) propagateSizeHints(); - QXcbScreen *currentScreen = xcbScreen(); + QXcbScreen *currentScreen = m_xcbScreen; QXcbScreen *newScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect)); if (!newScreen) - newScreen = currentScreen; + newScreen = xcbScreen(); m_xcbScreen = newScreen; - const QRect xRect = mapToNative(rect, newScreen); - const QRect wmGeometry = windowToWmGeometry(xRect); + const QRect wmGeometry = windowToWmGeometry(rect); if (newScreen != currentScreen) QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); @@ -1348,7 +1279,7 @@ void QXcbWindow::updateMotifWmHintsBeforeMap() mwmhints.flags &= ~MWM_HINTS_INPUT_MODE; } - if (window()->minimumSize() == window()->maximumSize()) { + if (windowMinimumSize() == windowMaximumSize()) { // fixed size, remove the resize handle (since mwm/dtwm // isn't smart enough to do it itself) mwmhints.flags |= MWM_HINTS_FUNCTIONS; @@ -1634,8 +1565,7 @@ void QXcbWindow::propagateSizeHints() xcb_size_hints_t hints; memset(&hints, 0, sizeof(hints)); - const int dpr = int(devicePixelRatio()); - const QRect xRect = windowToWmGeometry(mapToNative(geometry(), xcbScreen())); + const QRect xRect = windowToWmGeometry(geometry()); QWindow *win = window(); @@ -1645,10 +1575,10 @@ void QXcbWindow::propagateSizeHints() xcb_size_hints_set_size(&hints, true, xRect.width(), xRect.height()); xcb_size_hints_set_win_gravity(&hints, m_gravity); - QSize minimumSize = win->minimumSize() * dpr; - QSize maximumSize = win->maximumSize() * dpr; - QSize baseSize = win->baseSize() * dpr; - QSize sizeIncrement = win->sizeIncrement() * dpr; + QSize minimumSize = windowMinimumSize(); + QSize maximumSize = windowMaximumSize(); + QSize baseSize = windowBaseSize(); + QSize sizeIncrement = windowSizeIncrement(); if (minimumSize.width() > 0 || minimumSize.height() > 0) xcb_size_hints_set_min_size(&hints, @@ -1896,10 +1826,9 @@ QRect QXcbWindow::systemTrayWindowGlobalGeometry() const class ExposeCompressor { public: - ExposeCompressor(xcb_window_t window, QRegion *region, int devicePixelRatio) + ExposeCompressor(xcb_window_t window, QRegion *region) : m_window(window) , m_region(region) - , m_dpr(devicePixelRatio) , m_pending(true) { } @@ -1915,7 +1844,7 @@ public: return false; if (expose->count == 0) m_pending = false; - *m_region |= mapExposeFromNative(QRect(expose->x, expose->y, expose->width, expose->height), m_dpr); + *m_region |= QRect(expose->x, expose->y, expose->width, expose->height); return true; } @@ -1927,7 +1856,6 @@ public: private: xcb_window_t m_window; QRegion *m_region; - int m_dpr; bool m_pending; }; @@ -1941,16 +1869,14 @@ bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result) void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { - const int dpr = int(devicePixelRatio()); - QRect x_rect(event->x, event->y, event->width, event->height); - QRect rect = mapExposeFromNative(x_rect, dpr); + QRect rect(event->x, event->y, event->width, event->height); if (m_exposeRegion.isEmpty()) m_exposeRegion = rect; else m_exposeRegion |= rect; - ExposeCompressor compressor(m_window, &m_exposeRegion, dpr); + ExposeCompressor compressor(m_window, &m_exposeRegion); xcb_generic_event_t *filter = 0; do { filter = connection()->checkEvent(compressor); @@ -2002,13 +1928,13 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } #ifndef QT_NO_DRAGANDDROP } else if (event->type == atom(QXcbAtom::XdndEnter)) { - connection()->drag()->handleEnter(window(), event); + connection()->drag()->handleEnter(this, event); } else if (event->type == atom(QXcbAtom::XdndPosition)) { - connection()->drag()->handlePosition(window(), event); + connection()->drag()->handlePosition(this, event); } else if (event->type == atom(QXcbAtom::XdndLeave)) { - connection()->drag()->handleLeave(window(), event); + connection()->drag()->handleLeave(this, event); } else if (event->type == atom(QXcbAtom::XdndDrop)) { - connection()->drag()->handleDrop(window(), event); + connection()->drag()->handleDrop(this, event); #endif } else if (event->type == atom(QXcbAtom::_XEMBED)) { handleXEmbedMessage(event); @@ -2028,26 +1954,6 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } } -// Temporary workaround for bug in QPlatformScreen::screenForGeometry -// we need the native geometries to detect our screen, but that's not -// available in cross-platform code. Will be fixed properly when highDPI -// support is refactored to expose the native coordinate system. - -QXcbScreen *QXcbWindow::screenForNativeGeometry(const QRect &newGeometry) const -{ - QXcbScreen *currentScreen = xcbScreen(); - if (!currentScreen && QGuiApplication::primaryScreen()) - currentScreen = static_cast<QXcbScreen*>(QGuiApplication::primaryScreen()->handle()); - if (currentScreen && !parent() && !currentScreen->nativeGeometry().intersects(newGeometry)) { - Q_FOREACH (QPlatformScreen* screen, currentScreen->virtualSiblings()) { - QXcbScreen *xcbScreen = static_cast<QXcbScreen*>(screen); - if (xcbScreen->nativeGeometry().intersects(newGeometry)) - return xcbScreen; - } - } - return currentScreen; -} - void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event) { bool fromSendEvent = (event->response_type & 0x80); @@ -2064,19 +1970,18 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } } - const QRect nativeRect = QRect(pos, QSize(event->width, event->height)); - QXcbScreen *newScreen = parent() ? parentScreen() : screenForNativeGeometry(nativeRect); + const QRect rect = QRect(pos, QSize(event->width, event->height)); + QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(rect); QXcbScreen *currentScreen = m_xcbScreen; - m_xcbScreen = newScreen; + m_xcbScreen = static_cast<QXcbScreen*>(newScreen); if (!newScreen) return; - const QRect rect = mapFromNative(nativeRect, newScreen); QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); if (newScreen != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); m_configureNotifyPending = false; @@ -2109,11 +2014,10 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const if (!m_embedded) return pos; - const int dpr = int(devicePixelRatio()); QPoint ret; xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcb_window(), xcbScreen()->root(), - pos.x() * dpr, pos.y() * dpr); + pos.x(), pos.y()); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { @@ -2122,7 +2026,7 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const free(reply); } - return mapFromNative(ret, xcbScreen()); + return ret; } QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const @@ -2130,17 +2034,15 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const if (!m_embedded) return pos; - const int dpr = int(devicePixelRatio()); QPoint ret; - QPoint xPos = mapToNative(pos, xcbScreen()); xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcbScreen()->root(), xcb_window(), - xPos.x(), xPos.y()); + pos.x(), pos.y()); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { - ret.setX(reply->dst_x / dpr); - ret.setY(reply->dst_y / dpr); + ret.setX(reply->dst_x); + ret.setY(reply->dst_y); free(reply); } @@ -2156,7 +2058,7 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) if (m_configureNotifyPending) m_deferredExpose = true; else - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size() * int(devicePixelRatio()))); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); } } @@ -2188,9 +2090,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS); } } - const int dpr = int(devicePixelRatio()); - QPoint local(event_x / dpr, event_y / dpr); - QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); + QPoint local(event_x, event_y); + QPoint global(root_x, root_y); if (isWheel) { if (!connection()->isAtLeastXI21()) { @@ -2212,9 +2113,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y, int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) { - const int dpr = int(devicePixelRatio()); - QPoint local(event_x / dpr, event_y / dpr); - QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); + QPoint local(event_x, event_y); + QPoint global(root_x, root_y); if (detail >= 4 && detail <= 7) { // mouse wheel, handled in handleButtonPressEvent() @@ -2227,11 +2127,8 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) { - if (!xcbScreen()) - return; - const int dpr = int(devicePixelRatio()); - QPoint local(event_x / dpr, event_y / dpr); - QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); + QPoint local(event_x, event_y); + QPoint global(root_x, root_y); handleMouseEvent(timestamp, local, global, modifiers); } @@ -2359,11 +2256,10 @@ void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) if (ignoreEnterEvent(event)) return; - const int dpr = int(devicePixelRatio()); - const QPoint local(event->event_x/dpr, event->event_y/dpr); + const QPoint local(event->event_x, event->event_y); if (!xcbScreen()) return; - QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); + QPoint global = QPoint(event->root_x, event->root_y); QWindowSystemInterface::handleEnterEvent(window(), local, global); } @@ -2379,11 +2275,10 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0; if (enterWindow) { - const int dpr = int(devicePixelRatio()); - QPoint local(enter->event_x/dpr, enter->event_y/dpr); + QPoint local(enter->event_x, enter->event_y); if (!xcbScreen()) return; - QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); + QPoint global = QPoint(event->root_x, event->root_y); QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global); } else { @@ -2560,7 +2455,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) xev.type = moveResize; xev.window = xcb_window(); xev.format = 32; - const QPoint globalPos = mapToNative(window()->mapToGlobal(pos), xcbScreen()); + const QPoint globalPos = window()->mapToGlobal(pos); xev.data.data32[0] = globalPos.x(); xev.data.data32[1] = globalPos.y(); const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner; @@ -2686,10 +2581,9 @@ void QXcbWindow::setMask(const QRegion ®ion) xcb_shape_mask(connection()->xcb_connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, xcb_window(), 0, 0, XCB_NONE); } else { - const int dpr = devicePixelRatio(); QVector<xcb_rectangle_t> rects; foreach (const QRect &r, region.rects()) - rects.push_back(qRectToXCBRectangle(mapLocalGeometryToNative(r, dpr))); + rects.push_back(qRectToXCBRectangle(r)); xcb_shape_rectangles(connection()->xcb_connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, xcb_window(), 0, 0, rects.size(), &rects[0]); @@ -2727,11 +2621,6 @@ void QXcbWindow::postSyncWindowRequest() } } -qreal QXcbWindow::devicePixelRatio() const -{ - return xcbScreen() ? xcbScreen()->devicePixelRatio() : 1.0; -} - QXcbScreen *QXcbWindow::xcbScreen() const { return static_cast<QXcbScreen *>(screen()); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 07019223c8..1010600e44 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -163,8 +163,6 @@ public: void postSyncWindowRequest(); void clearSyncWindowRequest() { m_pendingSyncRequest = 0; } - qreal devicePixelRatio() const Q_DECL_OVERRIDE; - QXcbScreen *xcbScreen() const; virtual void create(); @@ -180,10 +178,6 @@ protected: virtual void *createVisual() { return Q_NULLPTR; } virtual bool supportsSyncProtocol() { return !window()->supportsOpenGL(); } - QPoint mapToNative(const QPoint &pos, const QXcbScreen *screen) const; - QPoint mapFromNative(const QPoint &pos, const QXcbScreen *screen) const; - QRect mapToNative(const QRect &rect, const QXcbScreen *screen) const; - QRect mapFromNative(const QRect &rect, const QXcbScreen *screen) const; QXcbScreen *parentScreen(); void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 9bfdc62e60..14e0abf7c7 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -695,7 +695,7 @@ void QOpenGLWidgetPrivate::recreateFbo() format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setSamples(samples); - const QSize deviceSize = q->size() * q->devicePixelRatio(); + const QSize deviceSize = q->size() * q->devicePixelRatioF(); fbo = new QOpenGLFramebufferObject(deviceSize, format); if (samples > 0) resolvedFbo = new QOpenGLFramebufferObject(deviceSize); @@ -704,7 +704,7 @@ void QOpenGLWidgetPrivate::recreateFbo() context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); paintDevice->setSize(deviceSize); - paintDevice->setDevicePixelRatio(q->devicePixelRatio()); + paintDevice->setDevicePixelRatio(q->devicePixelRatioF()); emit q->resized(); } @@ -778,8 +778,8 @@ void QOpenGLWidgetPrivate::initialize() } paintDevice = new QOpenGLWidgetPaintDevice(q); - paintDevice->setSize(q->size() * q->devicePixelRatio()); - paintDevice->setDevicePixelRatio(q->devicePixelRatio()); + paintDevice->setSize(q->size() * q->devicePixelRatioF()); + paintDevice->setDevicePixelRatio(q->devicePixelRatioF()); context = ctx.take(); initialized = true; @@ -808,7 +808,7 @@ void QOpenGLWidgetPrivate::invokeUserPaint() QOpenGLFunctions *f = ctx->functions(); QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbo->handle(); - f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio()); + f->glViewport(0, 0, q->width() * q->devicePixelRatioF(), q->height() * q->devicePixelRatioF()); q->paintGL(); flushPending = true; @@ -859,8 +859,8 @@ QImage QOpenGLWidgetPrivate::grabFramebuffer() render(); resolveSamples(); q->makeCurrent(); - QImage res = qt_gl_read_framebuffer(q->size() * q->devicePixelRatio(), false, false); - res.setDevicePixelRatio(q->devicePixelRatio()); + QImage res = qt_gl_read_framebuffer(q->size() * q->devicePixelRatioF(), false, false); + res.setDevicePixelRatio(q->devicePixelRatioF()); return res; } @@ -879,7 +879,7 @@ void QOpenGLWidgetPrivate::resizeViewportFramebuffer() if (!initialized) return; - if (!fbo || q->size() * q->devicePixelRatio() != fbo->size()) + if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size()) recreateFbo(); } @@ -1196,6 +1196,7 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const return QWidget::metric(metric); QWidget *tlw = window(); + QWindow *window = tlw ? tlw->windowHandle() : 0; QScreen *screen = tlw && tlw->windowHandle() ? tlw->windowHandle()->screen() : 0; if (!screen && QGuiApplication::primaryScreen()) screen = QGuiApplication::primaryScreen(); @@ -1243,8 +1244,13 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const else return qRound(dpmy * 0.0254); case PdmDevicePixelRatio: - if (screen) - return screen->devicePixelRatio(); + if (window) + return int(window->devicePixelRatio()); + else + return 1.0; + case PdmDevicePixelRatioScaled: + if (window) + return int(window->devicePixelRatio() * devicePixelRatioFScale); else return 1.0; default: @@ -1304,7 +1310,7 @@ bool QOpenGLWidget::event(QEvent *e) } break; case QEvent::ScreenChangeInternal: - if (d->initialized && d->paintDevice->devicePixelRatio() != devicePixelRatio()) + if (d->initialized && d->paintDevice->devicePixelRatioF() != devicePixelRatioF()) d->recreateFbo(); break; default: diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index b4943bbe05..6e7479d29a 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -68,6 +68,7 @@ #include "private/qstylesheetstyle_p.h" #include "private/qstyle_p.h" #include "qfileinfo.h" +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/qinputmethod.h> #include <QtGui/qopenglcontext.h> #include <QtGui/private/qopenglcontext_p.h> @@ -2028,7 +2029,7 @@ void QWidgetPrivate::setSystemClip(QPaintDevice *paintDevice, const QRegion ® // Transform the system clip region from device-independent pixels to device pixels QPaintEngine *paintEngine = paintDevice->paintEngine(); QTransform scaleTransform; - const qreal devicePixelRatio = paintDevice->devicePixelRatio(); + const qreal devicePixelRatio = paintDevice->devicePixelRatioF(); scaleTransform.scale(devicePixelRatio, devicePixelRatio); paintEngine->d_func()->systemClip = scaleTransform.map(region); } @@ -5354,7 +5355,7 @@ void QWidgetPrivate::render_helper(QPainter *painter, const QPoint &targetOffset if (size.isNull()) return; - const qreal pixmapDevicePixelRatio = qreal(painter->device()->devicePixelRatio()); + const qreal pixmapDevicePixelRatio = painter->device()->devicePixelRatioF(); QPixmap pixmap(size * pixmapDevicePixelRatio); pixmap.setDevicePixelRatio(pixmapDevicePixelRatio); @@ -11824,13 +11825,11 @@ void QWidgetPrivate::updateFrameStrut() Q_Q(QWidget); if (q->data->fstrut_dirty) { if (QTLWExtra *te = maybeTopData()) { - if (te->window) { - if (const QPlatformWindow *pw = te->window->handle()) { - const QMargins margins = pw->frameMargins(); - if (!margins.isNull()) { - te->frameStrut.setCoords(margins.left(), margins.top(), margins.right(), margins.bottom()); - q->data->fstrut_dirty = false; - } + if (te->window && te->window->handle()) { + const QMargins margins = te->window->frameMargins(); + if (!margins.isNull()) { + te->frameStrut.setCoords(margins.left(), margins.top(), margins.right(), margins.bottom()); + q->data->fstrut_dirty = false; } } } @@ -12647,6 +12646,9 @@ int QWidget::metric(PaintDeviceMetric m) const return qRound(screen->physicalDotsPerInchY()); } else if (m == PdmDevicePixelRatio) { return topLevelWindow ? topLevelWindow->devicePixelRatio() : qApp->devicePixelRatio(); + } else if (m == PdmDevicePixelRatioScaled) { + return (QPaintDevice::devicePixelRatioFScale * + (topLevelWindow ? topLevelWindow->devicePixelRatio() : qApp->devicePixelRatio())); } else { val = QPaintDevice::metric(m);// XXX } @@ -12762,7 +12764,7 @@ void QWidgetPrivate::setMask_sys(const QRegion ®ion) Q_Q(QWidget); if (const QWindow *window = q->windowHandle()) if (QPlatformWindow *platformWindow = window->handle()) - platformWindow->setMask(region); + platformWindow->setMask(QHighDpi::toNativeLocalRegion(region, window)); } /*! @@ -12862,7 +12864,7 @@ QDebug operator<<(QDebug debug, const QWidget *widget) frameGeometry.bottom() - geometry.bottom()); debug << ", margins=" << margins; } - debug << ", devicePixelRatio=" << widget->devicePixelRatio(); + debug << ", devicePixelRatio=" << widget->devicePixelRatioF(); if (const WId wid = widget->internalWinId()) debug << ", winId=0x" << hex << wid << dec; } diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 01d6d89857..633e710853 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -45,6 +45,7 @@ #include <qpa/qplatformtheme.h> #include <qpa/qplatformwindow.h> #include <private/qgesturemanager_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -671,7 +672,7 @@ void QWidgetWindow::updateNormalGeometry() // Ask platform window, default to widget geometry. QRect normalGeometry; if (const QPlatformWindow *pw = handle()) - normalGeometry = pw->normalGeometry(); + normalGeometry = QHighDpi::fromNativePixels(pw->normalGeometry(), this); if (!normalGeometry.isValid() && effectiveState(m_widget->windowState()) == Qt::WindowNoState) normalGeometry = m_widget->geometry(); if (normalGeometry.isValid()) diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 50c8fd7ed8..518f985b13 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1977,7 +1977,7 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD } } - int devicePixelRatio = p->device()->devicePixelRatio(); + int devicePixelRatio = p->device()->devicePixelRatioF(); int width = devicePixelRatio * (int(macRect.size.width) + extraWidth); int height = devicePixelRatio * (int(macRect.size.height) + extraHeight); @@ -7204,7 +7204,7 @@ CGContextRef qt_mac_cg_context(const QPaintDevice *pdev) } CGContextTranslateCTM(ret, 0, pm->height()); - int devicePixelRatio = pdev->devicePixelRatio(); + qreal devicePixelRatio = pdev->devicePixelRatioF(); CGContextScaleCTM(ret, devicePixelRatio, devicePixelRatio); CGContextScaleCTM(ret, 1, -1); return ret; diff --git a/src/widgets/styles/qwindowsstyle_p_p.h b/src/widgets/styles/qwindowsstyle_p_p.h index 3d1206b369..c8778cc914 100644 --- a/src/widgets/styles/qwindowsstyle_p_p.h +++ b/src/widgets/styles/qwindowsstyle_p_p.h @@ -65,7 +65,7 @@ public: static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = 0, const QWidget *widget = 0); static int fixedPixelMetric(QStyle::PixelMetric pm); static int devicePixelRatio(const QWidget *widget = 0) - { return widget ? widget->devicePixelRatio() : QWindowsStylePrivate::appDevicePixelRatio(); } + { return widget ? int(widget->devicePixelRatioF()) : QWindowsStylePrivate::appDevicePixelRatio(); } bool hasSeenAlt(const QWidget *widget) const; bool altDown() const { return alt_down; } diff --git a/src/widgets/widgets/qlabel.cpp b/src/widgets/widgets/qlabel.cpp index 409e4a34f9..c70bc4baef 100644 --- a/src/widgets/widgets/qlabel.cpp +++ b/src/widgets/widgets/qlabel.cpp @@ -1085,7 +1085,7 @@ void QLabel::paintEvent(QPaintEvent *) d->cachedimage = new QImage(d->pixmap->toImage()); delete d->scaledpixmap; QImage scaledImage = - d->cachedimage->scaled(cr.size() * devicePixelRatio(), + d->cachedimage->scaled(cr.size() * devicePixelRatioF(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); d->scaledpixmap = new QPixmap(QPixmap::fromImage(scaledImage)); } diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index d361aa12a6..9304d91b9a 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -35,6 +35,7 @@ #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformintegration.h> #include <private/qguiapplication_p.h> +#include <private/qhighdpiscaling_p.h> #include <QtGui/QPainter> #include <QtTest/QtTest> @@ -265,6 +266,11 @@ void tst_QWindow::positioning_data() #endif } +static inline bool qFuzzyCompare(const QPoint &p1, const QPoint p2) +{ + return (p1 - p2).manhattanLength() <= 2; +} + void tst_QWindow::positioning() { if (!QGuiApplicationPrivate::platformIntegration()->hasCapability( @@ -327,21 +333,23 @@ void tst_QWindow::positioning() // if our positioning is actually fully respected by the window manager // test whether it correctly handles frame positioning as well if (originalPos == geometry.topLeft() && (originalMargins.top() != 0 || originalMargins.left() != 0)) { - QPoint framePos = QPlatformScreen::platformScreenForWindow(&window)->availableGeometry().center(); + const QPlatformScreen *pScreen = QPlatformScreen::platformScreenForWindow(&window); + const QRect availableGeometry = QHighDpi::fromNativeScreenGeometry(pScreen->availableGeometry(), pScreen->screen()); + const QPoint framePos = availableGeometry.center(); window.reset(); const QPoint oldFramePos = window.framePosition(); window.setFramePosition(framePos); QTRY_VERIFY(window.received(QEvent::Move)); - if (window.framePosition() != framePos) { + if (!qFuzzyCompare(window.framePosition(), framePos)) { qDebug() << "About to fail auto-test. Here is some additional information:"; qDebug() << "window.framePosition() == " << window.framePosition(); qDebug() << "old frame position == " << oldFramePos; qDebug() << "We received " << window.received(QEvent::Move) << " move events"; qDebug() << "frame positions after each move event:" << window.m_framePositionsOnMove; } - QTRY_COMPARE(framePos, window.framePosition()); + QTRY_VERIFY(qFuzzyCompare(window.framePosition(), framePos)); QTRY_COMPARE(originalMargins, window.frameMargins()); QCOMPARE(window.position(), window.framePosition() + QPoint(originalMargins.left(), originalMargins.top())); @@ -661,8 +669,9 @@ void tst_QWindow::testInputEvents() QCOMPARE(window.keyReleaseCode, int(Qt::Key_A)); QPointF local(12, 34); - QWindowSystemInterface::handleMouseEvent(&window, local, local, Qt::LeftButton); - QWindowSystemInterface::handleMouseEvent(&window, local, local, Qt::NoButton); + const QPointF deviceLocal = QHighDpi::toNativeLocalPosition(local, &window); + QWindowSystemInterface::handleMouseEvent(&window, deviceLocal, deviceLocal, Qt::LeftButton); + QWindowSystemInterface::handleMouseEvent(&window, deviceLocal, deviceLocal, Qt::NoButton); QCoreApplication::processEvents(); QCOMPARE(window.mousePressButton, int(Qt::LeftButton)); QCOMPARE(window.mouseReleaseButton, int(Qt::LeftButton)); @@ -688,15 +697,17 @@ void tst_QWindow::testInputEvents() // Now with null pointer as window. local param should not be utilized: // handleMouseEvent() with tlw == 0 means the event is in global coords only. window.mousePressButton = window.mouseReleaseButton = 0; - QPointF nonWindowGlobal(window.geometry().topRight() + QPoint(200, 50)); // not inside the window - QWindowSystemInterface::handleMouseEvent(0, nonWindowGlobal, nonWindowGlobal, Qt::LeftButton); - QWindowSystemInterface::handleMouseEvent(0, nonWindowGlobal, nonWindowGlobal, Qt::NoButton); + const QPointF nonWindowGlobal(window.geometry().topRight() + QPoint(200, 50)); // not inside the window + const QPointF deviceNonWindowGlobal = QHighDpi::toNativePixels(nonWindowGlobal, window.screen()); + QWindowSystemInterface::handleMouseEvent(0, deviceNonWindowGlobal, deviceNonWindowGlobal, Qt::LeftButton); + QWindowSystemInterface::handleMouseEvent(0, deviceNonWindowGlobal, deviceNonWindowGlobal, Qt::NoButton); QCoreApplication::processEvents(); QCOMPARE(window.mousePressButton, 0); QCOMPARE(window.mouseReleaseButton, 0); - QPointF windowGlobal = window.mapToGlobal(local.toPoint()); - QWindowSystemInterface::handleMouseEvent(0, windowGlobal, windowGlobal, Qt::LeftButton); - QWindowSystemInterface::handleMouseEvent(0, windowGlobal, windowGlobal, Qt::NoButton); + const QPointF windowGlobal = window.mapToGlobal(local.toPoint()); + const QPointF deviceWindowGlobal = QHighDpi::toNativePixels(windowGlobal, window.screen()); + QWindowSystemInterface::handleMouseEvent(0, deviceWindowGlobal, deviceWindowGlobal, Qt::LeftButton); + QWindowSystemInterface::handleMouseEvent(0, deviceWindowGlobal, deviceWindowGlobal, Qt::NoButton); QCoreApplication::processEvents(); QCOMPARE(window.mousePressButton, int(Qt::LeftButton)); QCOMPARE(window.mouseReleaseButton, int(Qt::LeftButton)); @@ -718,7 +729,7 @@ void tst_QWindow::touchToMouseTranslation() const QRectF moveArea(105, 108, 4, 4); tp1.id = 1; tp1.state = Qt::TouchPointPressed; - tp1.area = pressArea; + tp1.area = QHighDpi::toNativePixels(pressArea, &window); tp2.id = 2; tp2.state = Qt::TouchPointPressed; points << tp1 << tp2; @@ -729,7 +740,7 @@ void tst_QWindow::touchToMouseTranslation() tp1.state = Qt::TouchPointStationary; tp2.id = 1; tp2.state = Qt::TouchPointMoved; - tp2.area = moveArea; + tp2.area = QHighDpi::toNativePixels(moveArea, &window); points.clear(); points << tp1 << tp2; QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points); @@ -946,12 +957,13 @@ void tst_QWindow::touchCancelWithTouchToMouse() tp1.id = 1; tp1.state = Qt::TouchPointPressed; - tp1.area = QRect(100, 100, 4, 4); + const QRect area(100, 100, 4, 4); + tp1.area = QHighDpi::toNativePixels(area, &window); points << tp1; QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points); QCoreApplication::processEvents(); QTRY_COMPARE(window.mousePressButton, int(Qt::LeftButton)); - QTRY_COMPARE(window.mousePressScreenPos, points[0].area.center()); + QTRY_VERIFY(qFuzzyCompare(window.mousePressScreenPos.toPoint(), area.center())); // Cancel the touch. Should result in a mouse release for windows that have // have an active touch-to-mouse sequence. @@ -1149,8 +1161,9 @@ void tst_QWindow::mouseEventSequence() ulong timestamp = 0; QPointF local(12, 34); - QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::LeftButton); - QWindowSystemInterface::handleMouseEvent(&window, timestamp++, local, local, Qt::NoButton); + const QPointF deviceLocal = QHighDpi::toNativePixels(local, &window); + QWindowSystemInterface::handleMouseEvent(&window, timestamp++, deviceLocal, deviceLocal, Qt::LeftButton); + QWindowSystemInterface::handleMouseEvent(&window, timestamp++, deviceLocal, deviceLocal, Qt::NoButton); QCoreApplication::processEvents(); QCOMPARE(window.mousePressedCount, 1); QCOMPARE(window.mouseReleasedCount, 1); @@ -1337,14 +1350,16 @@ void tst_QWindow::tabletEvents() window.setGeometry(QRect(m_availableTopLeft + QPoint(10, 10), m_testWindowSize)); qGuiApp->installEventFilter(&window); - QPoint local(10, 10); - QPoint global = window.mapToGlobal(local); - QWindowSystemInterface::handleTabletEvent(&window, true, local, global, 1, 2, 0.5, 1, 2, 0.1, 0, 0, 0); + const QPoint local(10, 10); + const QPoint global = window.mapToGlobal(local); + const QPoint deviceLocal = QHighDpi::toNativeLocalPosition(local, &window).toPoint(); + const QPoint deviceGlobal = QHighDpi::toNativePixels(global, window.screen()); + QWindowSystemInterface::handleTabletEvent(&window, true, deviceLocal, deviceGlobal, 1, 2, 0.5, 1, 2, 0.1, 0, 0, 0); QCoreApplication::processEvents(); QTRY_VERIFY(window.eventType == QEvent::TabletPress); QTRY_COMPARE(window.eventGlobal.toPoint(), global); QTRY_COMPARE(window.eventLocal.toPoint(), local); - QWindowSystemInterface::handleTabletEvent(&window, false, local, global, 1, 2, 0.5, 1, 2, 0.1, 0, 0, 0); + QWindowSystemInterface::handleTabletEvent(&window, false, deviceLocal, deviceGlobal, 1, 2, 0.5, 1, 2, 0.1, 0, 0, 0); QCoreApplication::processEvents(); QTRY_VERIFY(window.eventType == QEvent::TabletRelease); diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp index 105afa9a91..f7c871fc0f 100644 --- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp @@ -1653,6 +1653,7 @@ void tst_QTextLayout::testTabDPIScale() case QPaintDevice::PdmPhysicalDpiY: return 72; case QPaintDevice::PdmDevicePixelRatio: + case QPaintDevice::PdmDevicePixelRatioScaled: ; // fall through } return 0; diff --git a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp index c8d3122e6d..0e679dc661 100644 --- a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp +++ b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp @@ -1086,6 +1086,8 @@ public: { if (PdmDevicePixelRatio == metric) return 1; + if (PdmDevicePixelRatioScaled == metric) + return 1 * QPaintDevice::devicePixelRatioFScale; if (PdmDpiY == metric) return 96; if (PdmDpiX == metric) diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp index c33fd5a951..5d833eea28 100644 --- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -62,6 +62,7 @@ #endif #include <qpa/qwindowsysteminterface.h> +#include <private/qhighdpiscaling_p.h> #include "../../../qtest-config.h" @@ -2038,8 +2039,10 @@ void tst_QApplication::touchEventPropagation() QVERIFY(QTest::qWaitForWindowExposed(&window)); // QPA always takes screen positions and since we map the TouchPoint back to QPA's structure first, // we must ensure there is a screen position in the TouchPoint that maps to a local 0, 0. - pressedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0))); - releasedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0))); + const QPoint deviceGlobalPos = + QHighDpi::toNativePixels(window.mapToGlobal(QPoint(0, 0)), window.windowHandle()->screen()); + pressedTouchPoints[0].setScreenPos(deviceGlobalPos); + releasedTouchPoints[0].setScreenPos(deviceGlobalPos); QWindowSystemInterface::handleTouchEvent(window.windowHandle(), 0, @@ -2091,8 +2094,10 @@ void tst_QApplication::touchEventPropagation() widget.setObjectName("2. widget"); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - pressedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0))); - releasedTouchPoints[0].setScreenPos(window.mapToGlobal(QPoint(0, 0))); + const QPoint deviceGlobalPos = + QHighDpi::toNativePixels(window.mapToGlobal(QPoint(0, 0)), window.windowHandle()->screen()); + pressedTouchPoints[0].setScreenPos(deviceGlobalPos); + releasedTouchPoints[0].setScreenPos(deviceGlobalPos); QWindowSystemInterface::handleTouchEvent(window.windowHandle(), 0, diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 68ccaef43f..38a45117a1 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -51,6 +51,7 @@ #include <qdesktopwidget.h> #include <private/qwidget_p.h> #include <private/qapplication_p.h> +#include <private/qhighdpiscaling_p.h> #include <qcalendarwidget.h> #include <qmainwindow.h> #include <qdockwidget.h> @@ -84,6 +85,7 @@ # include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformintegration.h> +#include <private/qhighdpiscaling_p.h> static HWND winHandleOf(const QWidget *w) { @@ -193,6 +195,11 @@ static QByteArray msgComparisonFailed(T v1, const char *op, T v2) return s.toLocal8Bit(); } +static inline bool qFuzzyCompare(const QPoint &p1, const QPoint p2) +{ + return (p1 - p2).manhattanLength() <= 2; +} + class tst_QWidget : public QObject { Q_OBJECT @@ -1906,7 +1913,7 @@ void tst_QWidget::windowState() widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized); QTest::qWait(100); QVERIFY(!(widget1.windowState() & Qt::WindowMaximized)); - QTRY_COMPARE(widget1.pos(), pos); + QTRY_VERIFY(qFuzzyCompare(widget1.pos(), pos)); QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); widget1.setWindowState(Qt::WindowMinimized); @@ -1927,7 +1934,7 @@ void tst_QWidget::windowState() widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized); QTest::qWait(100); QVERIFY(!(widget1.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized))); - QTRY_COMPARE(widget1.pos(), pos); + QTRY_VERIFY(qFuzzyCompare(widget1.pos(), pos)); QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); widget1.setWindowState(Qt::WindowFullScreen); @@ -1948,7 +1955,7 @@ void tst_QWidget::windowState() widget1.setWindowState(Qt::WindowNoState); QTest::qWait(100); VERIFY_STATE(Qt::WindowNoState); - QTRY_COMPARE(widget1.pos(), pos); + QTRY_VERIFY(qFuzzyCompare(widget1.pos(), pos)); QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); widget1.setWindowState(Qt::WindowFullScreen); @@ -1981,7 +1988,7 @@ void tst_QWidget::windowState() QVERIFY(!(widget1.windowState() & stateMask)); QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); - QTRY_COMPARE(widget1.pos(), pos); + QTRY_VERIFY(qFuzzyCompare(widget1.pos(), pos)); QTRY_COMPARE(widget1.size(), size); } @@ -3676,6 +3683,8 @@ void tst_QWidget::optimizedResizeMove() void tst_QWidget::optimizedResize_topLevel() { + if (QHighDpiScaling::isActive()) + QSKIP("Skip due to rounding errors in the regions."); StaticWidget topLevel; topLevel.gotPaintEvent = false; topLevel.show(); diff --git a/tests/manual/highdpi/dragwidget.cpp b/tests/manual/highdpi/dragwidget.cpp new file mode 100644 index 0000000000..b203566696 --- /dev/null +++ b/tests/manual/highdpi/dragwidget.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** + ** + ** Copyright (C) 2015 The Qt Company Ltd. + ** Contact: http://www.qt.io/licensing/ + ** + ** This file is part of the test suite of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL21$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and The Qt Company. For licensing terms + ** and conditions see http://www.qt.io/terms-conditions. For further + ** information use the contact form at http://www.qt.io/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 2.1 or version 3 as published by the Free + ** Software Foundation and appearing in the file LICENSE.LGPLv21 and + ** LICENSE.LGPLv3 included in the packaging of this file. Please review the + ** following information to ensure the GNU Lesser General Public License + ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and + ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** As a special exception, The Qt Company gives you certain additional + ** rights. These rights are described in The Qt Company LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include <QtWidgets> +#include "dragwidget.h" + +class FramedLabel : public QLabel +{ +public: + FramedLabel(const QString &text, QWidget *parent) + : QLabel(text, parent) + { + setAutoFillBackground(true); + setFrameShape(QFrame::Panel); + setFrameShadow(QFrame::Raised); + } +}; + +DragWidget::DragWidget(QString text, QWidget *parent) + : QWidget(parent), otherWindow(0) +{ + int x = 5; + int y = 5; + + bool createChildWindow = text.isEmpty(); // OK, yes this is a hack... + if (text.isEmpty()) + text = "You can drag from this window and drop text here"; + + QStringList words = text.split(' '); + foreach (QString word, words) { + if (!word.isEmpty()) { + FramedLabel *wordLabel = new FramedLabel(word, this); + wordLabel->move(x, y); + wordLabel->show(); + x += wordLabel->width() + 2; + if (x >= 245) { + x = 5; + y += wordLabel->height() + 2; + } + } + } + + /* + QPalette newPalette = palette(); + newPalette.setColor(QPalette::Window, Qt::white); + setPalette(newPalette); + */ + + setAcceptDrops(true); + setMinimumSize(400, qMax(200, y)); + setWindowTitle(tr("Draggable Text Window %1").arg(createChildWindow ? 1 : 2)); + if (createChildWindow) + otherWindow = new DragWidget("Here is a second window that accepts drops"); +} + +void DragWidget::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasText()) { + if (event->source() == this) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } else { + event->acceptProposedAction(); + } + } else { + event->ignore(); + } +} + +void DragWidget::dragMoveEvent(QDragMoveEvent * event) +{ + dragPos = event->pos(); + dragTimer.start(500, this); + update(); +} + +void DragWidget::dragLeaveEvent(QDragLeaveEvent *) +{ + dragTimer.stop(); + update(); +} + + +void DragWidget::dropEvent(QDropEvent *event) +{ + if (event->mimeData()->hasText()) { + const QMimeData *mime = event->mimeData(); + QStringList pieces = mime->text().split(QRegExp("\\s+"), + QString::SkipEmptyParts); + QPoint position = event->pos(); + QPoint hotSpot; + + QList<QByteArray> hotSpotPos = mime->data("application/x-hotspot").split(' '); + if (hotSpotPos.size() == 2) { + hotSpot.setX(hotSpotPos.first().toInt()); + hotSpot.setY(hotSpotPos.last().toInt()); + } + dropPos = position - hotSpot; + dropTimer.start(500, this); + update(); + + foreach (QString piece, pieces) { + FramedLabel *newLabel = new FramedLabel(piece, this); + newLabel->move(position - hotSpot); + newLabel->show(); + + position += QPoint(newLabel->width(), 0); + } + + if (event->source() == this) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } else { + event->acceptProposedAction(); + } + } else { + event->ignore(); + } + foreach (QObject *child, children()) { + if (child->inherits("QWidget")) { + QWidget *widget = static_cast<QWidget *>(child); + if (!widget->isVisible()) + widget->deleteLater(); + } + } +} + +void DragWidget::mousePressEvent(QMouseEvent *event) +{ + QLabel *child = static_cast<QLabel*>(childAt(event->pos())); + if (!child) + return; + + QPoint hotSpot = event->pos() - child->pos(); + + QMimeData *mimeData = new QMimeData; + mimeData->setText(child->text()); + mimeData->setData("application/x-hotspot", + QByteArray::number(hotSpot.x()) + " " + QByteArray::number(hotSpot.y())); + + QPixmap pixmap(child->size()); + child->render(&pixmap); + + QDrag *drag = new QDrag(this); + drag->setMimeData(mimeData); + drag->setPixmap(pixmap); + drag->setHotSpot(hotSpot); + + Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); + + if (dropAction == Qt::MoveAction) + child->close(); +} + +void DragWidget::timerEvent(QTimerEvent *e) +{ + if (e->timerId() == dragTimer.timerId()) + dragTimer.stop(); + if (e->timerId() == dropTimer.timerId()) + dropTimer.stop(); + update(); +} + +void DragWidget::paintEvent(QPaintEvent *) +{ + QPainter p(this); + p.fillRect(rect(), Qt::white); + + if (dropTimer.isActive()) { + p.setBrush(Qt::red); + p.drawEllipse(dropPos, 50, 50); + } + + if (dragTimer.isActive()) { + p.setPen(QPen(Qt::blue, 5)); + QPoint p1 = (rect().topLeft()*3 + rect().bottomRight())/4; + QPoint p2 = (rect().topLeft() + rect().bottomRight()*3)/4; + p.drawLine(p1, dragPos); + p.drawLine(p2, dragPos); + } +} + +void DragWidget::showEvent(QShowEvent *) +{ + if (otherWindow) + otherWindow->show(); +} + +void DragWidget::hideEvent(QHideEvent *) +{ + if (otherWindow) + otherWindow->hide(); +} diff --git a/tests/manual/highdpi/dragwidget.h b/tests/manual/highdpi/dragwidget.h new file mode 100644 index 0000000000..0d9631e2f8 --- /dev/null +++ b/tests/manual/highdpi/dragwidget.h @@ -0,0 +1,68 @@ +/**************************************************************************** + ** + ** Copyright (C) 2015 The Qt Company Ltd. + ** Contact: http://www.qt.io/licensing/ + ** + ** This file is part of the test suite of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL21$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and The Qt Company. For licensing terms + ** and conditions see http://www.qt.io/terms-conditions. For further + ** information use the contact form at http://www.qt.io/contact-us. + ** + ** GNU Lesser General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU Lesser + ** General Public License version 2.1 or version 3 as published by the Free + ** Software Foundation and appearing in the file LICENSE.LGPLv21 and + ** LICENSE.LGPLv3 included in the packaging of this file. Please review the + ** following information to ensure the GNU Lesser General Public License + ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and + ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** As a special exception, The Qt Company gives you certain additional + ** rights. These rights are described in The Qt Company LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef DRAGWIDGET_H +#define DRAGWIDGET_H + +#include <QWidget> +#include <QBasicTimer> + +QT_BEGIN_NAMESPACE +class QDragEnterEvent; +class QDropEvent; +QT_END_NAMESPACE + +class DragWidget : public QWidget +{ +public: + DragWidget(QString text = QString(), QWidget *parent = 0); + +protected: + void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE; + void dragLeaveEvent(QDragLeaveEvent *event) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void dragMoveEvent(QDragMoveEvent * event) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; + void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; + void hideEvent(QHideEvent *event) Q_DECL_OVERRIDE; +private: + QPoint dragPos; + QPoint dropPos; + QBasicTimer dragTimer; + QBasicTimer dropTimer; + QWidget *otherWindow; +}; + +#endif // DRAGWIDGET_H diff --git a/tests/manual/highdpi/highdpi.pro b/tests/manual/highdpi/highdpi.pro index 7a2979c74c..7d6b42535e 100644 --- a/tests/manual/highdpi/highdpi.pro +++ b/tests/manual/highdpi/highdpi.pro @@ -1,10 +1,17 @@ TEMPLATE = app TARGET = highdpi INCLUDEPATH += . -QT += widgets -CONFIG+=console +QT += widgets gui-private +CONFIG +=console +CONFIG -= app_bundle +CONFIG += c++11 # Input -SOURCES += main.cpp +SOURCES += \ + dragwidget.cpp \ + main.cpp + +HEADERS += \ + dragwidget.h RESOURCES += \ highdpi.qrc diff --git a/tests/manual/highdpi/main.cpp b/tests/manual/highdpi/main.cpp index fd14523a97..9b7f278765 100644 --- a/tests/manual/highdpi/main.cpp +++ b/tests/manual/highdpi/main.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include <QMainWindow> +#include <QMenuBar> #include <QLabel> #include <QHBoxLayout> #include <QApplication> @@ -39,6 +40,7 @@ #include <QStyle> #include <QToolBar> #include <QPushButton> +#include <QButtonGroup> #include <QLineEdit> #include <QScrollBar> #include <QSlider> @@ -49,10 +51,150 @@ #include <QWindow> #include <QScreen> #include <QFile> +#include <QMouseEvent> #include <QTemporaryDir> #include <QCommandLineParser> #include <QCommandLineOption> +#include <QDebug> +#include <private/qhighdpiscaling_p.h> +#include "dragwidget.h" + +class DemoContainerBase +{ +public: + virtual ~DemoContainerBase() {} + QString name() { return option().names().first(); } + virtual QCommandLineOption &option() = 0; + virtual void makeVisible(bool visible) = 0; +}; + +typedef QList<DemoContainerBase*> DemoContainerList ; + + +template <class T> +class DemoContainer : public DemoContainerBase +{ +public: + DemoContainer(const QString &optionName, const QString &description) + : m_widget(0), m_option(optionName, description) + { + } + ~DemoContainer() { delete m_widget; } + + QCommandLineOption &option() { return m_option; } + + void makeVisible(bool visible) { + if (visible && !m_widget) + m_widget = new T; + if (m_widget) + m_widget->setVisible(visible); + } +private: + QWidget *m_widget; + QCommandLineOption m_option; +}; + +class DemoController : public QWidget +{ +Q_OBJECT +public: + DemoController(DemoContainerList *demos, QCommandLineParser *parser); + ~DemoController(); +private slots: + void handleButton(int id, bool toggled); +private: + DemoContainerList *m_demos; + QButtonGroup *m_group; +}; + +DemoController::DemoController(DemoContainerList *demos, QCommandLineParser *parser) + : m_demos(demos) +{ + setWindowTitle("screen scale factors"); + setObjectName("controller"); // make WindowScaleFactorSetter skip this window + + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + + // set up one scale control line per screen + QList<QScreen *> screens = QGuiApplication::screens(); + foreach (QScreen *screen, screens) { + // create scale control line + QHBoxLayout *row = new QHBoxLayout; + QSize screenSize = screen->geometry().size(); + QString screenId = screen->name() + " " + QString::number(screenSize.width()) + + " " + QString::number(screenSize.height()); + QLabel *label = new QLabel(screenId); + QSlider *slider = new QSlider(); + slider->setOrientation(Qt::Horizontal); + slider->setMinimum(1); + slider->setMaximum(40); + slider->setValue(10); + slider->setTracking(false); + slider->setTickInterval(5); + slider->setTickPosition(QSlider::TicksBelow); + QLabel *scaleFactorLabel = new QLabel("1.0"); + + // set up layouts + row->addWidget(label); + row->addWidget(slider); + row->addWidget(scaleFactorLabel); + layout->addLayout(row); + + // handle slider position change + connect(slider, &QSlider::sliderMoved, [scaleFactorLabel, screen](int scaleFactor){ + // slider value is scale factor times ten; + qreal scalefactorF = qreal(scaleFactor) / 10.0; + + // update label, add ".0" if needed. + QString number = QString::number(scalefactorF); + if (!number.contains(".")) + number.append(".0"); + scaleFactorLabel->setText(number); + }); + // handle slider value change + connect(slider, &QSlider::valueChanged, [scaleFactorLabel, screen](int scaleFactor){ + // slider value is scale factor times ten; + qreal scalefactorF = qreal(scaleFactor) / 10.0; + + // set scale factor for screen + qreal oldFactor = QHighDpiScaling::factor(screen); + QHighDpiScaling::setScreenFactor(screen, scalefactorF); + qreal newFactor = QHighDpiScaling::factor(screen); + + qDebug() << "factor was / is" << oldFactor << newFactor; + }); + } + + m_group = new QButtonGroup(this); + m_group->setExclusive(false); + + for (int i = 0; i < m_demos->size(); ++i) { + DemoContainerBase *demo = m_demos->at(i); + QPushButton *button = new QPushButton(demo->name()); + button->setToolTip(demo->option().description()); + button->setCheckable(true); + layout->addWidget(button); + m_group->addButton(button, i); + + if (parser->isSet(demo->option())) { + demo->makeVisible(true); + button->setChecked(true); + } + } + connect(m_group, SIGNAL(buttonToggled(int, bool)), this, SLOT(handleButton(int, bool))); +} + +DemoController::~DemoController() +{ + qDeleteAll(*m_demos); +} + +void DemoController::handleButton(int id, bool toggled) +{ + m_demos->at(id)->makeVisible(toggled); +} class PixmapPainter : public QWidget { @@ -69,7 +211,6 @@ public: QIcon qtIcon; }; - PixmapPainter::PixmapPainter() { pixmap1X = QPixmap(":/qticon32.png"); @@ -172,15 +313,18 @@ class MainWindow : public QMainWindow { public: MainWindow(); + QMenu *addNewMenu(const QString &title, int itemCount = 5); QIcon qtIcon; QIcon qtIcon1x; QIcon qtIcon2x; QToolBar *fileToolBar; + int menuCount; }; MainWindow::MainWindow() + :menuCount(0) { // beware that QIcon auto-loads the @2x versions. qtIcon1x.addFile(":/qticon16.png"); @@ -192,8 +336,33 @@ MainWindow::MainWindow() // fileToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); fileToolBar->addAction(new QAction(qtIcon1x, QString("1x"), this)); fileToolBar->addAction(new QAction(qtIcon2x, QString("2x"), this)); + addNewMenu("&Edit"); + addNewMenu("&Build"); + addNewMenu("&Debug", 4); + addNewMenu("&Transmogrify", 7); + addNewMenu("T&ools"); + addNewMenu("&Help", 2); } + +QMenu *MainWindow::addNewMenu(const QString &title, int itemCount) +{ + QMenu *menu = menuBar()->addMenu(title); + for (int i = 0; i < itemCount; i++) { + menuCount++; + QString s = "Menu item " + QString::number(menuCount); + if (i == 3) { + QMenu *subMenu = menu->addMenu(s); + for (int j = 1; j < 4; j++) + subMenu->addAction(QString::fromLatin1("SubMenu item %1.%2").arg(menuCount).arg(j)); + } else { + menu->addAction(s); + } + } + return menu; +} + + class StandardIcons : public QWidget { public: @@ -205,7 +374,7 @@ public: int dy = 50; int maxX = 500; - for (int iconIndex = QStyle::SP_TitleBarMenuButton; iconIndex < QStyle::SP_MediaVolumeMuted; ++iconIndex) { + for (uint iconIndex = QStyle::SP_TitleBarMenuButton; iconIndex < QStyle::SP_MediaVolumeMuted; ++iconIndex) { QIcon icon = qApp->style()->standardIcon(QStyle::StandardPixmap(iconIndex)); QPainter p(this); p.drawPixmap(x, y, icon.pixmap(dx - 5, dy - 5)); @@ -295,8 +464,10 @@ public: void paintEvent(QPaintEvent *) { QPainter painter(this); - int y = 40; - for (int fontSize = 2; fontSize < 18; fontSize += 2) { + + // Points + int y = 10; + for (int fontSize = 6; fontSize < 18; fontSize += 2) { QFont font; font.setPointSize(fontSize); QString string = QString(QStringLiteral("%1 The quick brown fox jumped over the lazy Doug.")).arg(fontSize); @@ -304,6 +475,17 @@ public: painter.drawText(10, y, string); y += (fontSize * 2.5); } + + // Pixels + y = 160; + for (int fontSize = 6; fontSize < 18; fontSize += 2) { + QFont font; + font.setPixelSize(fontSize); + QString string = QString(QStringLiteral("%1 The quick brown fox jumped over the lazy Doug.")).arg(fontSize); + painter.setFont(font); + painter.drawText(10, y, string); + y += (fontSize * 2.5); + } } }; @@ -461,97 +643,295 @@ public: } }; +class LinePainter : public QWidget +{ +public: + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); -int main(int argc, char **argv) + QPoint lastMousePoint; + QVector<QPoint> linePoints; +}; + +void LinePainter::paintEvent(QPaintEvent *) { - QApplication app(argc, argv); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QCoreApplication::setApplicationVersion(QT_VERSION_STR); + QPainter p(this); + p.fillRect(QRect(QPoint(0, 0), size()), QBrush(Qt::gray)); - QCommandLineParser parser; - parser.setApplicationDescription("High DPI tester"); - parser.addHelpOption(); - parser.addVersionOption(); - QCommandLineOption pixmapPainterOption("pixmap", "Test pixmap painter"); - parser.addOption(pixmapPainterOption); - QCommandLineOption labelOption("label", "Test Labels"); - parser.addOption(labelOption); - QCommandLineOption mainWindowOption("mainwindow", "Test QMainWindow"); - parser.addOption(mainWindowOption); - QCommandLineOption standardIconsOption("standard-icons", "Test standard icons"); - parser.addOption(standardIconsOption); - QCommandLineOption cachingOption("caching", "Test caching"); - parser.addOption(cachingOption); - QCommandLineOption styleOption("styles", "Test style"); - parser.addOption(styleOption); - QCommandLineOption fontsOption("fonts", "Test fonts"); - parser.addOption(fontsOption); - QCommandLineOption iconDrawingOption("icondrawing", "Test icon drawing"); - parser.addOption(iconDrawingOption); - QCommandLineOption buttonsOption("buttons", "Test buttons"); - parser.addOption(buttonsOption); + // Default antialiased line + p.setRenderHint(QPainter::Antialiasing); + p.drawLines(linePoints); + + // Cosmetic 1 antialiased line + QPen pen; + pen.setCosmetic(true); + pen.setWidth(1); + p.setPen(pen); + p.translate(3, 3); + p.drawLines(linePoints); + + // Aliased cosmetic 1 line + p.setRenderHint(QPainter::Antialiasing, false); + p.translate(3, 3); + p.drawLines(linePoints); +} - parser.process(app); +void LinePainter::mousePressEvent(QMouseEvent *event) +{ + lastMousePoint = event->pos(); +} + +void LinePainter::mouseReleaseEvent(QMouseEvent *) +{ + lastMousePoint = QPoint(); +} + +void LinePainter::mouseMoveEvent(QMouseEvent *event) +{ + if (lastMousePoint.isNull()) + return; + + QPoint newMousePoint = event->pos(); + if (lastMousePoint == newMousePoint) + return; + linePoints.append(lastMousePoint); + linePoints.append(newMousePoint); + lastMousePoint = newMousePoint; + update(); +} - QScopedPointer<PixmapPainter> pixmapPainter; - if (parser.isSet(pixmapPainterOption)) { - pixmapPainter.reset(new PixmapPainter); - pixmapPainter->show(); +class CursorTester : public QWidget +{ +public: + CursorTester() + :moveLabel(0), moving(false) + { } - QScopedPointer<Labels> label; - if (parser.isSet(labelOption)) { - label.reset(new Labels); - label->resize(200, 200); - label->show(); + inline QRect getRect(int idx) const + { + int h = height() / 2; + return QRect(10, 10 + h * (idx - 1), width() - 20, h - 20); + } + void paintEvent(QPaintEvent *) + { + QPainter p(this); + QRect r1 = getRect(1); + QRect r2 = getRect(2); + p.fillRect(r1, QColor(200, 200, 250)); + p.drawText(r1, "Drag from here to move a window based on QCursor::pos()"); + p.fillRect(r2, QColor(250, 200, 200)); + p.drawText(r2, "Drag from here to move a window based on mouse event position"); + + if (moving) { + p.setPen(Qt::darkGray); + QFont f = font(); + f.setPointSize(8); + p.setFont(f); + p.drawEllipse(mousePos, 30,60); + QPoint pt = mousePos - QPoint(0, 60); + QPoint pt2 = pt - QPoint(30,10); + QPoint offs(30, 0); + p.drawLine(pt, pt2); + p.drawLine(pt2 - offs, pt2 + offs); + p.drawText(pt2 - offs, "mouse pos"); + + p.setPen(QColor(50,130,70)); + QPoint cursorPos = mapFromGlobal(QCursor::pos()); + pt = cursorPos - QPoint(0, 30); + pt2 = pt + QPoint(60, -20); + p.drawEllipse(cursorPos, 60, 30); + p.drawLine(pt, pt2); + p.drawLine(pt2 - offs, pt2 + offs); + p.drawText(pt2 - offs, "cursor pos"); + } } - QScopedPointer<MainWindow> mainWindow; - if (parser.isSet(mainWindowOption)) { - mainWindow.reset(new MainWindow); - mainWindow->show(); + void mousePressEvent(QMouseEvent *e) + { + if (moving) + return; + QRect r1 = getRect(1); + QRect r2 = getRect(2); + + moving = r1.contains(e->pos()) || r2.contains(e->pos()); + if (!moving) + return; + useCursorPos = r1.contains(e->pos()); + + if (!moveLabel) + moveLabel = new QLabel(this,Qt::BypassWindowManagerHint|Qt::FramelessWindowHint|Qt::Window ); + + if (useCursorPos) + moveLabel->setText("I'm following QCursor::pos()"); + else + moveLabel->setText("I'm following QMouseEvent::globalPos()"); + moveLabel->adjustSize(); + mouseMoveEvent(e); + moveLabel->show(); } - QScopedPointer<StandardIcons> icons; - if (parser.isSet(standardIconsOption)) { - icons.reset(new StandardIcons); - icons->resize(510, 510); - icons->show(); + void mouseReleaseEvent(QMouseEvent *) + { + if (moveLabel) + moveLabel->hide(); + update(); + moving = false; } - QScopedPointer<Caching> caching; - if (parser.isSet(cachingOption)) { - caching.reset(new Caching); - caching->resize(300, 300); - caching->show(); + void mouseMoveEvent(QMouseEvent *e) + { + if (!moving) + return; + QPoint pos = useCursorPos ? QCursor::pos() : e->globalPos(); + pos -= moveLabel->rect().center(); + moveLabel->move(pos); + mousePos = e->pos(); + update(); } - QScopedPointer<Style> style; - if (parser.isSet(styleOption)) { - style.reset(new Style); - style->show(); +private: + QLabel *moveLabel; + bool useCursorPos; + bool moving; + QPoint mousePos; +}; + + +class ScreenDisplayer : public QWidget +{ +public: + ScreenDisplayer() + : QWidget(), moveLabel(0), scaleFactor(1.0) + { } - QScopedPointer<Fonts> fonts; - if (parser.isSet(fontsOption)) { - fonts.reset(new Fonts); - fonts->show(); + void timerEvent(QTimerEvent *) { + update(); } - QScopedPointer<IconDrawing> iconDrawing; - if (parser.isSet(iconDrawingOption)) { - iconDrawing.reset(new IconDrawing); - iconDrawing->show(); + void mousePressEvent(QMouseEvent *) { + if (!moveLabel) + moveLabel = new QLabel(this,Qt::BypassWindowManagerHint|Qt::FramelessWindowHint|Qt::Window ); + moveLabel->setText("Hello, Qt this is a label\nwith some text"); + moveLabel->show(); + } + void mouseMoveEvent(QMouseEvent *e) { + if (!moveLabel) + return; + moveLabel->move(e->pos() / scaleFactor); + QString str; + QDebug dbg(&str); + dbg.setAutoInsertSpaces(false); + dbg << moveLabel->geometry(); + moveLabel->setText(str); + } + void mouseReleaseEvent(QMouseEvent *) { + if (moveLabel) + moveLabel->hide(); } + void showEvent(QShowEvent *) { + refreshTimer.start(300, this); + } + void hideEvent(QHideEvent *) { + refreshTimer.stop(); + } + void paintEvent(QPaintEvent *) { + QPainter p(this); + QRectF total; + QList<QScreen*> screens = qApp->screens(); + foreach (QScreen *screen, screens) { + total |= screen->geometry(); + } + if (total.isEmpty()) + return; + + scaleFactor = qMin(width()/total.width(), height()/total.height()); + + p.fillRect(rect(), Qt::black); + p.scale(scaleFactor, scaleFactor); + p.setPen(QPen(Qt::white, 10)); + p.setBrush(Qt::gray); + QFont f = font(); + f.setPixelSize(height()); + p.setFont(f); + + foreach (QScreen *screen, screens) { + p.drawRect(screen->geometry()); + p.drawText(screen->geometry(), Qt::AlignCenter, screen->name()); + } + p.setBrush(QColor(200,220,255,127)); + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + if (!widget->isHidden()) + p.drawRect(widget->geometry()); + } - QScopedPointer<Buttons> buttons; - if (parser.isSet(buttonsOption)) { - buttons.reset(new Buttons); - buttons->show(); + QPolygon cursorShape; + cursorShape << QPoint(0,0) << QPoint(20, 60) + << QPoint(30, 50) << QPoint(60, 80) + << QPoint(80, 60) << QPoint(50, 30) + << QPoint(60, 20); + cursorShape.translate(QCursor::pos()); + p.drawPolygon(cursorShape); } +private: + QLabel *moveLabel; + QBasicTimer refreshTimer; + qreal scaleFactor; +}; + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QCoreApplication::setApplicationVersion(QT_VERSION_STR); + + int argumentCount = QCoreApplication::arguments().count(); + + QCommandLineParser parser; + parser.setApplicationDescription("High DPI tester. Pass one or more of the options to\n" + "test various high-dpi aspects. \n" + "--interactive is a special option and opens a configuration" + " window."); + parser.addHelpOption(); + parser.addVersionOption(); + QCommandLineOption controllerOption("interactive", "Show configuration window."); + parser.addOption(controllerOption); + + + DemoContainerList demoList; + demoList << new DemoContainer<PixmapPainter>("pixmap", "Test pixmap painter"); + demoList << new DemoContainer<Labels>("label", "Test Labels"); + demoList << new DemoContainer<MainWindow>("mainwindow", "Test QMainWindow"); + demoList << new DemoContainer<StandardIcons>("standard-icons", "Test standard icons"); + demoList << new DemoContainer<Caching>("caching", "Test caching"); + demoList << new DemoContainer<Style>("styles", "Test style"); + demoList << new DemoContainer<Fonts>("fonts", "Test fonts"); + demoList << new DemoContainer<IconDrawing>("icondrawing", "Test icon drawing"); + demoList << new DemoContainer<Buttons>("buttons", "Test buttons"); + demoList << new DemoContainer<LinePainter>("linepainter", "Test line painting"); + demoList << new DemoContainer<DragWidget>("draganddrop", "Test drag and drop"); + demoList << new DemoContainer<CursorTester>("cursorpos", "Test cursor and window positioning"); + demoList << new DemoContainer<ScreenDisplayer>("screens", "Test screen and window positioning"); + + + foreach (DemoContainerBase *demo, demoList) + parser.addOption(demo->option()); + + parser.process(app); + + //controller takes ownership of all demos + DemoController controller(&demoList, &parser); + + if (parser.isSet(controllerOption) || argumentCount <= 1) + controller.show(); if (QApplication::topLevelWidgets().isEmpty()) parser.showHelp(0); return app.exec(); } + +#include "main.moc" |