summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2014-09-01 11:35:12 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-09-01 11:35:53 +0200
commit2dfc786c26663a2d555a8c8152c5ff95a3b0672e (patch)
treefbf4d41dc1836ffa607e70e2348102066a83855c /src
parentd444bbf110e83c72d0657203896ad3c8a4cb5107 (diff)
parent1812bb968c49d50745ab2b10787320205c54f946 (diff)
Merge remote-tracking branch 'origin/5.4' into dev
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/angle/src/common/platform.h1
-rw-r--r--src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp13
-rw-r--r--src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-mutex-private.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-private.hh5
-rw-r--r--src/3rdparty/pcre/patches/pcre-r1495.patch23
-rw-r--r--src/3rdparty/pcre/patches/pcre-r1498.patch45
-rw-r--r--src/3rdparty/pcre/pcre_compile.c27
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java7
-rw-r--r--src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch72
-rw-r--r--src/corelib/animation/qabstractanimation.cpp118
-rw-r--r--src/corelib/animation/qabstractanimation.h2
-rw-r--r--src/corelib/animation/qabstractanimation_p.h10
-rw-r--r--src/corelib/codecs/qtextcodec.cpp2
-rw-r--r--src/corelib/doc/src/objectmodel/properties.qdoc2
-rw-r--r--src/corelib/doc/src/objectmodel/signalsandslots.qdoc2
-rw-r--r--src/corelib/global/qglobal.h7
-rw-r--r--src/corelib/global/qnamespace.h1
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp8
-rw-r--r--src/corelib/io/qsettings_winrt.cpp2
-rw-r--r--src/corelib/io/qstorageinfo.cpp110
-rw-r--r--src/corelib/json/qjsonarray.cpp10
-rw-r--r--src/corelib/json/qjsonarray.h14
-rw-r--r--src/corelib/json/qjsonobject.cpp10
-rw-r--r--src/corelib/json/qjsonobject.h13
-rw-r--r--src/corelib/json/qjsonvalue.h27
-rw-r--r--src/corelib/kernel/qcoreevent.cpp1
-rw-r--r--src/corelib/kernel/qfunctions_winrt.h9
-rw-r--r--src/corelib/kernel/qjni.cpp6
-rw-r--r--src/corelib/kernel/qmetatype.cpp8
-rw-r--r--src/corelib/kernel/qmetatype.h7
-rw-r--r--src/corelib/kernel/qmetatype_p.h1
-rw-r--r--src/corelib/kernel/qobject.cpp12
-rw-r--r--src/corelib/kernel/qvariant.cpp2
-rw-r--r--src/corelib/kernel/qvariant.h10
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp6
-rw-r--r--src/corelib/tools/qlist.h4
-rw-r--r--src/corelib/tools/qstring.cpp88
-rw-r--r--src/corelib/tools/qvector.h10
-rw-r--r--src/gui/image/qicon.cpp10
-rw-r--r--src/gui/image/qiconloader.cpp22
-rw-r--r--src/gui/image/qiconloader_p.h13
-rw-r--r--src/gui/image/qimage.cpp7
-rw-r--r--src/gui/image/qimagereader.cpp19
-rw-r--r--src/gui/image/qpixmap.cpp7
-rw-r--r--src/gui/image/qxpmhandler.cpp2
-rw-r--r--src/gui/kernel/kernel.pri2
-rw-r--r--src/gui/kernel/qevent.cpp13
-rw-r--r--src/gui/kernel/qopenglcontext.cpp4
-rw-r--r--src/gui/kernel/qopenglcontext_p.h1
-rw-r--r--src/gui/kernel/qplatformscreen.cpp9
-rw-r--r--src/gui/kernel/qplatformscreen.h2
-rw-r--r--src/gui/kernel/qplatformscreenpageflipper.cpp121
-rw-r--r--src/gui/kernel/qplatformtheme.cpp6
-rw-r--r--src/gui/kernel/qwindow_p.h3
-rw-r--r--src/gui/opengl/qopenglfunctions.cpp76
-rw-r--r--src/gui/opengl/qopenglshaderprogram.cpp25
-rw-r--r--src/gui/opengl/qopengltextureblitter.cpp14
-rw-r--r--src/gui/opengl/qopengltexturehelper.cpp64
-rw-r--r--src/gui/opengl/qopenglversionfunctions.cpp6
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp4
-rw-r--r--src/gui/painting/qpainter.cpp31
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp3
-rw-r--r--src/gui/painting/qregion.cpp28
-rw-r--r--src/gui/text/qfontengine_ft.cpp2
-rw-r--r--src/gui/text/qplatformfontdatabase.cpp10
-rw-r--r--src/gui/text/qplatformfontdatabase.h1
-rw-r--r--src/network/socket/qabstractsocket.cpp23
-rw-r--r--src/network/socket/qnativesocketengine_winrt.cpp374
-rw-r--r--src/network/socket/qnativesocketengine_winrt_p.h14
-rw-r--r--src/network/ssl/qasn1element.cpp291
-rw-r--r--src/network/ssl/qasn1element_p.h (renamed from src/gui/kernel/qplatformscreenpageflipper.h)86
-rw-r--r--src/network/ssl/qsslcertificate.cpp150
-rw-r--r--src/network/ssl/qsslcertificate_p.h20
-rw-r--r--src/network/ssl/qsslcertificate_qt.cpp266
-rw-r--r--src/network/ssl/qsslcertificate_winrt.cpp205
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp5
-rw-r--r--src/network/ssl/qsslkey_p.cpp41
-rw-r--r--src/network/ssl/qsslkey_p.h23
-rw-r--r--src/network/ssl/qsslkey_qt.cpp184
-rw-r--r--src/network/ssl/qsslkey_winrt.cpp135
-rw-r--r--src/network/ssl/qsslsocket.cpp63
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp59
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h2
-rw-r--r--src/network/ssl/qsslsocket_p.h2
-rw-r--r--src/network/ssl/qsslsocket_winrt.cpp582
-rw-r--r--src/network/ssl/qsslsocket_winrt_p.h48
-rw-r--r--src/network/ssl/ssl.pri10
-rw-r--r--src/opengl/qgl.cpp4
-rw-r--r--src/opengl/qgl_p.h1
-rw-r--r--src/platformheaders/doc/qtplatformheaders.qdocconf63
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp69
-rw-r--r--src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm185
-rw-r--r--src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h11
-rw-r--r--src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp70
-rw-r--r--src/platformsupport/linuxaccessibility/atspiadaptor.cpp57
-rw-r--r--src/platformsupport/linuxaccessibility/atspiadaptor_p.h2
-rw-r--r--src/platformsupport/linuxaccessibility/bridge.cpp4
-rw-r--r--src/platformsupport/linuxaccessibility/linuxaccessibility.pri1
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp8
-rw-r--r--src/plugins/platforms/android/android.pro2
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp6
-rw-r--r--src/plugins/platforms/android/qandroidplatformbackingstore.cpp10
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp4
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.cpp39
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.h3
-rw-r--r--src/plugins/platforms/android/qandroidplatformrasterwindow.cpp83
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp18
-rw-r--r--src/plugins/platforms/android/qandroidplatformservices.cpp9
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.h14
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm19
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemsettings.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemsettings.mm44
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm7
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm50
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp218
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h6
-rw-r--r--src/plugins/platforms/directfb/qdirectfbinput.cpp15
-rw-r--r--src/plugins/platforms/directfb/qdirectfbinput.h1
-rw-r--r--src/plugins/platforms/directfb/qdirectfbintegration.cpp15
-rw-r--r--src/plugins/platforms/directfb/qdirectfbintegration.h9
-rw-r--r--src/plugins/platforms/directfb/qdirectfbwindow.cpp104
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm23
-rw-r--r--src/plugins/platforms/ios/qiosglobal.h4
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm25
-rw-r--r--src/plugins/platforms/ios/qiosplatformaccessibility.mm8
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm19
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm1
-rw-r--r--src/plugins/platforms/ios/quiview_textinput.mm22
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h7
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.cpp38
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.h8
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp17
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp9
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp1
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp27
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp11
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp24
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeimage.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsscaling.cpp (renamed from src/plugins/platforms/android/qandroidplatformrasterwindow.h)51
-rw-r--r--src/plugins/platforms/windows/qwindowsscaling.h114
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp86
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h17
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp12
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp71
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h30
-rw-r--r--src/plugins/platforms/windows/windows.pri6
-rw-r--r--src/plugins/platforms/winrt/qwinrteventdispatcher.cpp1
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp2
-rw-r--r--src/plugins/platforms/winrt/qwinrttheme.cpp1
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp34
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp13
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h12
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp129
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp15
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp9
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp127
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h10
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp127
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h2
-rw-r--r--src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp8
-rw-r--r--src/printsupport/kernel/qprintengine_win.cpp8
-rw-r--r--src/testlib/qbenchmarkvalgrind.cpp2
-rw-r--r--src/tools/qdoc/atom.cpp33
-rw-r--r--src/tools/qdoc/atom.h12
-rw-r--r--src/tools/qdoc/codemarker.cpp2
-rw-r--r--src/tools/qdoc/codemarker.h4
-rw-r--r--src/tools/qdoc/codeparser.cpp3
-rw-r--r--src/tools/qdoc/cppcodemarker.cpp37
-rw-r--r--src/tools/qdoc/cppcodemarker.h4
-rw-r--r--src/tools/qdoc/cppcodeparser.cpp64
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.cpp314
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.h1
-rw-r--r--src/tools/qdoc/doc.cpp12
-rw-r--r--src/tools/qdoc/generator.cpp162
-rw-r--r--src/tools/qdoc/generator.h4
-rw-r--r--src/tools/qdoc/helpprojectwriter.cpp48
-rw-r--r--src/tools/qdoc/helpprojectwriter.h2
-rw-r--r--src/tools/qdoc/htmlgenerator.cpp291
-rw-r--r--src/tools/qdoc/htmlgenerator.h4
-rw-r--r--src/tools/qdoc/main.cpp26
-rw-r--r--src/tools/qdoc/node.cpp266
-rw-r--r--src/tools/qdoc/node.h55
-rw-r--r--src/tools/qdoc/qdocdatabase.cpp176
-rw-r--r--src/tools/qdoc/qdocdatabase.h84
-rw-r--r--src/tools/qdoc/qdocindexfiles.cpp42
-rw-r--r--src/tools/qdoc/qmlvisitor.cpp5
-rw-r--r--src/tools/qdoc/tree.cpp523
-rw-r--r--src/tools/qdoc/tree.h62
-rw-r--r--src/widgets/accessible/complexwidgets.cpp33
-rw-r--r--src/widgets/accessible/qaccessiblewidget.cpp4
-rw-r--r--src/widgets/accessible/qaccessiblewidgetfactory.cpp5
-rw-r--r--src/widgets/accessible/rangecontrols.cpp118
-rw-r--r--src/widgets/accessible/rangecontrols.h38
-rw-r--r--src/widgets/accessible/simplewidgets.cpp23
-rw-r--r--src/widgets/accessible/simplewidgets.h3
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp4
-rw-r--r--src/widgets/dialogs/qfontdialog.cpp9
-rw-r--r--src/widgets/dialogs/qwizard_win.cpp71
-rw-r--r--src/widgets/dialogs/qwizard_win_p.h14
-rw-r--r--src/widgets/itemviews/qabstractitemview.cpp18
-rw-r--r--src/widgets/itemviews/qdatawidgetmapper.cpp43
-rw-r--r--src/widgets/itemviews/qlistview.cpp34
-rw-r--r--src/widgets/kernel/qapplication.cpp20
-rw-r--r--src/widgets/kernel/qwidget.cpp36
-rw-r--r--src/widgets/kernel/qwidgetbackingstore.cpp2
-rw-r--r--src/widgets/styles/qstyle.h3
-rw-r--r--src/widgets/widgets/qabstractspinbox.cpp1
-rw-r--r--src/widgets/widgets/qabstractspinbox.h1
-rw-r--r--src/widgets/widgets/qfontcombobox.cpp9
-rw-r--r--src/widgets/widgets/qwidgetanimator.cpp1
-rw-r--r--src/widgets/widgets/qwidgetlinecontrol.cpp20
-rw-r--r--src/widgets/widgets/qwidgetlinecontrol_p.h23
-rw-r--r--src/winmain/winmain.pro7
222 files changed, 5605 insertions, 3283 deletions
diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h
index e16e7ac0c2..cedc6f2f22 100644
--- a/src/3rdparty/angle/src/common/platform.h
+++ b/src/3rdparty/angle/src/common/platform.h
@@ -56,6 +56,7 @@
# if defined(ANGLE_ENABLE_D3D11)
# include <d3d10_1.h>
+# include <d3d10.h>
# include <d3d11.h>
# include <dxgi.h>
# include <dxgi1_2.h>
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
index 17a13f97d6..651b065ca2 100644
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
@@ -305,6 +305,19 @@ EGLint Renderer11::initialize()
mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples);
}
+#if !defined(ANGLE_PLATFORM_WINRT)
+ static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED");
+ if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1"))
+ {
+ ID3D10Multithread *multithread;
+ result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread));
+ ASSERT(SUCCEEDED(result));
+ result = multithread->SetMultithreadProtected(true);
+ ASSERT(SUCCEEDED(result));
+ multithread->Release();
+ }
+#endif
+
initializeDevice();
return EGL_SUCCESS;
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
index 491c27a6ab..2c8a79f964 100644
--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
@@ -319,6 +319,10 @@ EGLint Renderer9::initialize()
D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
+ static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED");
+ if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1"))
+ behaviorFlags |= D3DCREATE_MULTITHREADED;
+
{
TRACE_EVENT0("gpu", "D3d9_CreateDevice");
result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-mutex-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-mutex-private.hh
index e2ee78b290..40f2e3d152 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-mutex-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-mutex-private.hh
@@ -52,7 +52,13 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
#else
#define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 }
#endif
+
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
+#else
#define hb_mutex_impl_init(M) InitializeCriticalSection (M)
+#endif
+
#define hb_mutex_impl_lock(M) EnterCriticalSection (M)
#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-private.hh
index 58d766c85c..3f70d74c26 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-private.hh
@@ -117,15 +117,16 @@
#endif
// Take from https://github.com/behdad/harfbuzz/commit/26a963b9cb4af3119177f277a2d48a5d537458fb
-#ifdef _WIN32_WCE
+#if defined(_WIN32_WCE)
/* Some things not defined on Windows CE. */
#define MemoryBarrier()
#define getenv(Name) NULL
#define setlocale(Category, Locale) "C"
static int errno = 0; /* Use something better? */
+#elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#define getenv(Name) NULL
#endif
-
/* Basics */
diff --git a/src/3rdparty/pcre/patches/pcre-r1495.patch b/src/3rdparty/pcre/patches/pcre-r1495.patch
new file mode 100644
index 0000000000..d8b4ce097a
--- /dev/null
+++ b/src/3rdparty/pcre/patches/pcre-r1495.patch
@@ -0,0 +1,23 @@
+Index: pcre_compile.c
+===================================================================
+--- pcre_compile.c (revision 1494)
++++ pcre_compile.c (revision 1495)
+@@ -8267,12 +8267,16 @@
+
+ /* If it was a capturing subpattern, check to see if it contained any
+ recursive back references. If so, we must wrap it in atomic brackets.
+- In any event, remove the block from the chain. */
++ Because we are moving code along, we must ensure that any pending recursive
++ references are updated. In any event, remove the block from the chain. */
+
+ if (capnumber > 0)
+ {
+ if (cd->open_caps->flag)
+ {
++ *code = OP_END;
++ adjust_recurse(start_bracket, 1 + LINK_SIZE,
++ (options & PCRE_UTF8) != 0, cd, cd->hwm);
+ memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
+ IN_UCHARS(code - start_bracket));
+ *start_bracket = OP_ONCE;
+
diff --git a/src/3rdparty/pcre/patches/pcre-r1498.patch b/src/3rdparty/pcre/patches/pcre-r1498.patch
new file mode 100644
index 0000000000..8ae48a4336
--- /dev/null
+++ b/src/3rdparty/pcre/patches/pcre-r1498.patch
@@ -0,0 +1,45 @@
+Index: pcre_compile.c
+===================================================================
+--- pcre_compile.c (revision 1497)
++++ pcre_compile.c (revision 1498)
+@@ -2374,6 +2374,7 @@
+ if (c == OP_RECURSE)
+ {
+ const pcre_uchar *scode = cd->start_code + GET(code, 1);
++ const pcre_uchar *endgroup = scode;
+ BOOL empty_branch;
+
+ /* Test for forward reference or uncompleted reference. This is disabled
+@@ -2388,24 +2389,20 @@
+ if (GET(scode, 1) == 0) return TRUE; /* Unclosed */
+ }
+
+- /* If we are scanning a completed pattern, there are no forward references
+- and all groups are complete. We need to detect whether this is a recursive
+- call, as otherwise there will be an infinite loop. If it is a recursion,
+- just skip over it. Simple recursions are easily detected. For mutual
+- recursions we keep a chain on the stack. */
++ /* If the reference is to a completed group, we need to detect whether this
++ is a recursive call, as otherwise there will be an infinite loop. If it is
++ a recursion, just skip over it. Simple recursions are easily detected. For
++ mutual recursions we keep a chain on the stack. */
+
++ do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
++ if (code >= scode && code <= endgroup) continue; /* Simple recursion */
+ else
+- {
++ {
+ recurse_check *r = recurses;
+- const pcre_uchar *endgroup = scode;
+-
+- do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
+- if (code >= scode && code <= endgroup) continue; /* Simple recursion */
+-
+ for (r = recurses; r != NULL; r = r->prev)
+ if (r->group == scode) break;
+ if (r != NULL) continue; /* Mutual recursion */
+- }
++ }
+
+ /* Completed reference; scan the referenced group, remembering it on the
+ stack chain to detect mutual recursions. */
diff --git a/src/3rdparty/pcre/pcre_compile.c b/src/3rdparty/pcre/pcre_compile.c
index 5ce6b73c44..ce365e2915 100644
--- a/src/3rdparty/pcre/pcre_compile.c
+++ b/src/3rdparty/pcre/pcre_compile.c
@@ -2370,6 +2370,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
if (c == OP_RECURSE)
{
const pcre_uchar *scode = cd->start_code + GET(code, 1);
+ const pcre_uchar *endgroup = scode;
BOOL empty_branch;
/* Test for forward reference or uncompleted reference. This is disabled
@@ -2384,24 +2385,20 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
if (GET(scode, 1) == 0) return TRUE; /* Unclosed */
}
- /* If we are scanning a completed pattern, there are no forward references
- and all groups are complete. We need to detect whether this is a recursive
- call, as otherwise there will be an infinite loop. If it is a recursion,
- just skip over it. Simple recursions are easily detected. For mutual
- recursions we keep a chain on the stack. */
+ /* If the reference is to a completed group, we need to detect whether this
+ is a recursive call, as otherwise there will be an infinite loop. If it is
+ a recursion, just skip over it. Simple recursions are easily detected. For
+ mutual recursions we keep a chain on the stack. */
+ do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
+ if (code >= scode && code <= endgroup) continue; /* Simple recursion */
else
- {
+ {
recurse_check *r = recurses;
- const pcre_uchar *endgroup = scode;
-
- do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
- if (code >= scode && code <= endgroup) continue; /* Simple recursion */
-
for (r = recurses; r != NULL; r = r->prev)
if (r->group == scode) break;
if (r != NULL) continue; /* Mutual recursion */
- }
+ }
/* Completed reference; scan the referenced group, remembering it on the
stack chain to detect mutual recursions. */
@@ -8244,12 +8241,16 @@ for (;;)
/* If it was a capturing subpattern, check to see if it contained any
recursive back references. If so, we must wrap it in atomic brackets.
- In any event, remove the block from the chain. */
+ Because we are moving code along, we must ensure that any pending recursive
+ references are updated. In any event, remove the block from the chain. */
if (capnumber > 0)
{
if (cd->open_caps->flag)
{
+ *code = OP_END;
+ adjust_recurse(start_bracket, 1 + LINK_SIZE,
+ (options & PCRE_UTF8) != 0, cd, cd->hwm);
memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
IN_UCHARS(code - start_bracket));
*start_bracket = OP_ONCE;
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 31a99bf910..014023ecb1 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
@@ -108,15 +108,20 @@ public class QtNative
}
}
- public static void openURL(String url)
+ public static boolean openURL(String url)
{
+ boolean ok = true;
+
try {
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
activity().startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
+ ok = false;
}
+
+ return ok;
}
// this method loads full path libs
diff --git a/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch b/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch
new file mode 100644
index 0000000000..1e60f0c54a
--- /dev/null
+++ b/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch
@@ -0,0 +1,72 @@
+From d52fac0c0b5d12cd117ae4b871f0ac6a202755ad Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20Br=C3=BCning?= <michael.bruning@digia.com>
+Date: Wed, 27 Aug 2014 12:42:00 +0200
+Subject: [PATCH] Let ANGLE use multithreaded devices if necessary.
+
+This is needed to prevent lock-ups in application that use ANGLE from
+multiple threads, as e.g. QtWebEngine based applications do.
+
+The environment variable QT_D3DCREATE_MULTITHREADED is used to
+communicate this from the QtWebEngine module.
+
+Change-Id: Ibd5a5c75eb68af567d420d9a35efb3490c93b27c
+---
+ src/3rdparty/angle/src/common/platform.h | 1 +
+ .../angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 13 +++++++++++++
+ .../angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 4 ++++
+ 3 files changed, 18 insertions(+)
+
+diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h
+index e16e7ac..cedc6f2 100644
+--- a/src/3rdparty/angle/src/common/platform.h
++++ b/src/3rdparty/angle/src/common/platform.h
+@@ -56,6 +56,7 @@
+
+ # if defined(ANGLE_ENABLE_D3D11)
+ # include <d3d10_1.h>
++# include <d3d10.h>
+ # include <d3d11.h>
+ # include <dxgi.h>
+ # include <dxgi1_2.h>
+diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+index 17a13f9..651b065 100644
+--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
++++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+@@ -305,6 +305,19 @@ EGLint Renderer11::initialize()
+ mMaxSupportedSamples = std::max(mMaxSupportedSamples, support.maxSupportedSamples);
+ }
+
++#if !defined(ANGLE_PLATFORM_WINRT)
++ static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED");
++ if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1"))
++ {
++ ID3D10Multithread *multithread;
++ result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread));
++ ASSERT(SUCCEEDED(result));
++ result = multithread->SetMultithreadProtected(true);
++ ASSERT(SUCCEEDED(result));
++ multithread->Release();
++ }
++#endif
++
+ initializeDevice();
+
+ return EGL_SUCCESS;
+diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+index 491c27a..2c8a79f 100644
+--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
++++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+@@ -319,6 +319,10 @@ EGLint Renderer9::initialize()
+ D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
+ DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
+
++ static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED");
++ if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1"))
++ behaviorFlags |= D3DCREATE_MULTITHREADED;
++
+ {
+ TRACE_EVENT0("gpu", "D3d9_CreateDevice");
+ result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
+--
+1.8.3.2
+
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index 95d7713cfe..28a09ee2e4 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -222,7 +222,8 @@ QUnifiedTimer::QUnifiedTimer() :
QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
currentAnimationIdx(0), insideTick(false), insideRestart(false), consistentTiming(false), slowMode(false),
startTimersPending(false), stopTimerPending(false),
- slowdownFactor(5.0f), profilerCallback(0)
+ slowdownFactor(5.0f), profilerCallback(0),
+ driverStartTime(0), temporalDrift(0)
{
time.invalidate();
driver = &defaultDriver;
@@ -253,18 +254,56 @@ QUnifiedTimer *QUnifiedTimer::instance()
void QUnifiedTimer::maybeUpdateAnimationsToCurrentTime()
{
- qint64 elapsed = driver->elapsed();
- if (elapsed - lastTick > 50)
- updateAnimationTimers(elapsed);
+ if (elapsed() - lastTick > 50)
+ updateAnimationTimers(-1);
+}
+
+qint64 QUnifiedTimer::elapsed() const
+{
+ if (driver->isRunning())
+ return driverStartTime + driver->elapsed();
+ else if (time.isValid())
+ return time.elapsed() + temporalDrift;
+
+ // Reaching here would normally indicate that the function is called
+ // under the wrong circumstances as neither pauses nor actual animations
+ // are running and there should be no need to query for elapsed().
+ return 0;
}
-void QUnifiedTimer::updateAnimationTimers(qint64 currentTick)
+void QUnifiedTimer::startAnimationDriver()
+{
+ if (driver->isRunning()) {
+ qWarning("QUnifiedTimer::startAnimationDriver: driver is already running...");
+ return;
+ }
+ // Set the start time to the currently elapsed() value before starting.
+ // This means we get the animation system time including the temporal drift
+ // which is what we want.
+ driverStartTime = elapsed();
+ driver->start();
+}
+
+void QUnifiedTimer::stopAnimationDriver()
+{
+ if (!driver->isRunning()) {
+ qWarning("QUnifiedTimer::stopAnimationDriver: driver is not running");
+ return;
+ }
+ // Update temporal drift. Since the driver is running, elapsed() will
+ // return the total animation time in driver-time. Subtract the current
+ // wall time to get the delta.
+ temporalDrift = elapsed() - time.elapsed();
+ driver->stop();
+}
+
+void QUnifiedTimer::updateAnimationTimers(qint64)
{
//setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
if(insideTick)
return;
- qint64 totalElapsed = currentTick >= 0 ? currentTick : driver->elapsed();
+ qint64 totalElapsed = elapsed();
// ignore consistentTiming in case the pause timer is active
qint64 delta = (consistentTiming && !pauseTimer.isActive()) ?
@@ -323,8 +362,7 @@ void QUnifiedTimer::localRestart()
} else if (!driver->isRunning()) {
if (pauseTimer.isActive())
pauseTimer.stop();
- driver->setStartTime(time.isValid() ? time.elapsed() : 0);
- driver->start();
+ startAnimationDriver();
}
}
@@ -345,27 +383,26 @@ void QUnifiedTimer::setTimingInterval(int interval)
if (driver->isRunning() && !pauseTimer.isActive()) {
//we changed the timing interval
- driver->stop();
- driver->setStartTime(time.isValid() ? time.elapsed() : 0);
- driver->start();
+ stopAnimationDriver();
+ startAnimationDriver();
}
}
void QUnifiedTimer::startTimers()
{
startTimersPending = false;
- if (!animationTimers.isEmpty())
- updateAnimationTimers(-1);
//we transfer the waiting animations into the "really running" state
animationTimers += animationTimersToStart;
animationTimersToStart.clear();
if (!animationTimers.isEmpty()) {
- localRestart();
if (!time.isValid()) {
lastTick = 0;
time.start();
+ temporalDrift = 0;
+ driverStartTime = 0;
}
+ localRestart();
}
}
@@ -373,7 +410,7 @@ void QUnifiedTimer::stopTimer()
{
stopTimerPending = false;
if (animationTimers.isEmpty()) {
- driver->stop();
+ stopAnimationDriver();
pauseTimer.stop();
// invalidate the start reference time
time.invalidate();
@@ -483,14 +520,12 @@ void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d)
return;
}
- if (driver->isRunning()) {
- driver->stop();
- d->setStartTime(time.isValid() ? time.elapsed() : 0);
- d->start();
- }
-
+ bool running = driver->isRunning();
+ if (running)
+ stopAnimationDriver();
driver = d;
-
+ if (running)
+ startAnimationDriver();
}
void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d)
@@ -500,13 +535,12 @@ void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d)
return;
}
+ bool running = driver->isRunning();
+ if (running)
+ stopAnimationDriver();
driver = &defaultDriver;
-
- if (d->isRunning()) {
- d->stop();
- driver->setStartTime(time.isValid() ? time.elapsed() : 0);
- driver->start();
- }
+ if (running)
+ startAnimationDriver();
}
/*!
@@ -603,10 +637,12 @@ void QAnimationTimer::restartAnimationTimer()
void QAnimationTimer::startAnimations()
{
+ if (!startAnimationPending)
+ return;
startAnimationPending = false;
+
//force timer to update, which prevents large deltas for our newly added animations
- if (!animations.isEmpty())
- QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
+ QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
//we transfer the waiting animations into the "really running" state
animations += animationsToStart;
@@ -618,7 +654,8 @@ void QAnimationTimer::startAnimations()
void QAnimationTimer::stopTimer()
{
stopTimerPending = false;
- if (animations.isEmpty()) {
+ bool pendingStart = startAnimationPending && animationsToStart.size() > 0;
+ if (animations.isEmpty() && !pendingStart) {
QUnifiedTimer::resumeAnimationTimer(this);
QUnifiedTimer::stopAnimationTimer(this);
// invalidate the start reference time
@@ -749,20 +786,25 @@ QAnimationDriver::~QAnimationDriver()
This is to take into account that pauses can occur in running
animations which will stop the driver, but the time still
increases.
+
+ \obsolete
+
+ This logic is now handled internally in the animation system.
*/
-void QAnimationDriver::setStartTime(qint64 startTime)
+void QAnimationDriver::setStartTime(qint64)
{
- Q_D(QAnimationDriver);
- d->startTime = startTime;
}
/*!
Returns the start time of the animation.
+
+ \obsolete
+
+ This logic is now handled internally in the animation system.
*/
qint64 QAnimationDriver::startTime() const
{
- Q_D(const QAnimationDriver);
- return d->startTime;
+ return 0;
}
@@ -772,6 +814,10 @@ qint64 QAnimationDriver::startTime() const
If \a timeStep is positive, it will be used as the current time in the
calculations; otherwise, the current clock time will be used.
+
+ Since 5.4, the timeStep argument is ignored and elapsed() will be
+ used instead in combination with the internal time offsets of the
+ animation system.
*/
void QAnimationDriver::advanceAnimation(qint64 timeStep)
diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h
index f1aa6c0d78..2d0a88e45f 100644
--- a/src/corelib/animation/qabstractanimation.h
+++ b/src/corelib/animation/qabstractanimation.h
@@ -149,6 +149,7 @@ public:
virtual qint64 elapsed() const;
+ // ### Qt6: Remove these two functions
void setStartTime(qint64 startTime);
qint64 startTime() const;
@@ -157,6 +158,7 @@ Q_SIGNALS:
void stopped();
protected:
+ // ### Qt6: Remove timestep argument
void advanceAnimation(qint64 timeStep = -1);
virtual void start();
virtual void stop();
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
index 39d9cf0fe6..6e71356c4c 100644
--- a/src/corelib/animation/qabstractanimation_p.h
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -132,9 +132,8 @@ private:
class Q_CORE_EXPORT QAnimationDriverPrivate : public QObjectPrivate
{
public:
- QAnimationDriverPrivate() : running(false), startTime(0) {}
+ QAnimationDriverPrivate() : running(false) {}
bool running;
- qint64 startTime;
};
class Q_CORE_EXPORT QAbstractAnimationTimer : public QObject
@@ -193,6 +192,10 @@ public:
int runningAnimationCount();
void registerProfilerCallback(void (*cb)(qint64));
+ void startAnimationDriver();
+ void stopAnimationDriver();
+ qint64 elapsed() const;
+
protected:
void timerEvent(QTimerEvent *);
@@ -233,6 +236,9 @@ private:
int closestPausedAnimationTimerTimeToFinish();
void (*profilerCallback)(qint64);
+
+ qint64 driverStartTime; // The time the animation driver was started
+ qint64 temporalDrift; // The delta between animation driver time and wall time.
};
class QAnimationTimer : public QAbstractAnimationTimer
diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp
index 7e3e629c47..9bce7bf614 100644
--- a/src/corelib/codecs/qtextcodec.cpp
+++ b/src/corelib/codecs/qtextcodec.cpp
@@ -1045,7 +1045,7 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCo
// determine charset
QTextCodec *c = QTextCodec::codecForUtfText(ba, 0);
if (!c) {
- QByteArray header = ba.left(512).toLower();
+ QByteArray header = ba.left(1024).toLower();
int pos = header.indexOf("meta ");
if (pos != -1) {
pos = header.indexOf("charset=", pos);
diff --git a/src/corelib/doc/src/objectmodel/properties.qdoc b/src/corelib/doc/src/objectmodel/properties.qdoc
index 70f0b88e06..1a79a622b3 100644
--- a/src/corelib/doc/src/objectmodel/properties.qdoc
+++ b/src/corelib/doc/src/objectmodel/properties.qdoc
@@ -249,7 +249,7 @@
If the value is \e not compatible with the property's type, the
property is \e not changed, and false is returned. But if the
property with the given name doesn't exist in the QObject (i.e.,
- if it wasn't declared with Q_PROPERTY(), a new property with the
+ if it wasn't declared with Q_PROPERTY()), a new property with the
given name and value is automatically added to the QObject, but
false is still returned. This means that a return of false can't
be used to determine whether a particular property was actually
diff --git a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
index e894d547d0..d290d7dc37 100644
--- a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
+++ b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
@@ -392,7 +392,7 @@
compatible with the slot's arguments. Arguments can also be implicitly
converted by the compiler, if needed.
- You can also connect to functors or C++11 lamdas:
+ You can also connect to functors or C++11 lambdas:
\code
connect(sender, &QObject::destroyed, [=](){ this->m_objects.remove(sender); });
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 673369a012..9176d80f43 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -880,7 +880,12 @@ public:
int control;
};
-# ifdef Q_COMPILER_DECLTYPE
+// We need to use __typeof__ if we don't have decltype or if the compiler
+// hasn't been updated to the fix of Core Language Defect Report 382
+// (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#382).
+// GCC 4.3 and 4.4 have support for decltype, but are affected by DR 382.
+# if defined(Q_COMPILER_DECLTYPE) && \
+ (defined(Q_CC_CLANG) || defined(Q_CC_INTEL) || !defined(Q_CC_GNU) || (__GNUC__ * 100 + __GNUC_MINOR__) >= 405)
# define QT_FOREACH_DECLTYPE(x) typename QtPrivate::remove_reference<decltype(x)>::type
# else
# define QT_FOREACH_DECLTYPE(x) __typeof__((x))
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 485193b071..0da868602c 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -98,6 +98,7 @@ Qt {
#ifndef QT_NO_GESTURES
Q_ENUMS(GestureState)
Q_ENUMS(GestureType)
+ Q_ENUMS(NativeGestureType)
#endif
Q_ENUMS(CursorMoveStyle)
Q_ENUMS(TimerType)
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index 81aed5f7b4..cebca1a56f 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -369,15 +369,15 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen)
if (fileHandle == INVALID_HANDLE_VALUE)
return -1;
- DWORD bytesToRead = DWORD(maxlen); // <- lossy
+ qint64 bytesToRead = maxlen;
// Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when
// the chunks are too large, so we limit the block size to 32MB.
- static const DWORD maxBlockSize = 32 * 1024 * 1024;
+ static const qint64 maxBlockSize = 32 * 1024 * 1024;
qint64 totalRead = 0;
do {
- DWORD blockSize = qMin<DWORD>(bytesToRead, maxBlockSize);
+ DWORD blockSize = DWORD(qMin(bytesToRead, maxBlockSize));
DWORD bytesRead;
if (!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) {
if (totalRead == 0) {
@@ -392,7 +392,7 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen)
totalRead += bytesRead;
bytesToRead -= bytesRead;
} while (totalRead < maxlen);
- return qint64(totalRead);
+ return totalRead;
}
/*
diff --git a/src/corelib/io/qsettings_winrt.cpp b/src/corelib/io/qsettings_winrt.cpp
index 82632bd16d..ad02f050e5 100644
--- a/src/corelib/io/qsettings_winrt.cpp
+++ b/src/corelib/io/qsettings_winrt.cpp
@@ -324,7 +324,7 @@ QWinRTSettingsPrivate::QWinRTSettingsPrivate(QSettings::Scope scope, const QStri
}
QWinRTSettingsPrivate::QWinRTSettingsPrivate(QString rPath)
- : QSettingsPrivate(QSettings::NativeFormat)
+ : QSettingsPrivate(QSettings::NativeFormat, QSettings::UserScope, rPath, QString())
, writeContainer(0)
{
init(QSettings::UserScope);
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
index 205ab3f62c..388b71b39c 100644
--- a/src/corelib/io/qstorageinfo.cpp
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -48,24 +48,24 @@ QT_BEGIN_NAMESPACE
\class QStorageInfo
\inmodule QtCore
\since 5.4
- \brief Provides information about currently mounted storages and drives.
+ \brief Provides information about currently mounted storage and drives.
\ingroup io
\ingroup shared
Allows retrieving information about the volume's space, its mount point,
- label, filesystem name.
+ label, and filesystem name.
You can create an instance of QStorageInfo by passing the path to the
- volume's mount point as the constructor parameter, or you can set it using
- setPath() method. The static mountedVolumes() method can be used to get the
+ volume's mount point as a constructor parameter, or you can set it using
+ the setPath() method. The static mountedVolumes() method can be used to get the
list of all mounted filesystems.
- QStorageInfo always caches the retrieved information but you can call
+ QStorageInfo always caches the retrieved information, but you can call
refresh() to invalidate the cache.
The following example retrieves the most common information about the root
- volume of the system and prints information about it.
+ volume of the system, and prints information about it.
\snippet code/src_corelib_io_qstorageinfo.cpp 2
*/
@@ -73,7 +73,8 @@ QT_BEGIN_NAMESPACE
/*!
Constructs an empty QStorageInfo object.
- This object is not ready for use, invalid and all its parameters are empty.
+ Objects created with the default constructor will be invalid and therefore
+ not ready for use.
\sa setPath(), isReady(), isValid()
*/
@@ -83,15 +84,15 @@ QStorageInfo::QStorageInfo()
}
/*!
- Constructs a new QStorageInfo that gives information about the volume
+ Constructs a new QStorageInfo object that gives information about the volume
mounted at \a path.
If you pass a directory or file, the QStorageInfo object will refer to the
volume where this directory or file is located.
You can check if the created object is correct using the isValid() method.
- The following example shows how to get volume on which application is
- located. It is recommended to always check that volume is ready and valid.
+ The following example shows how to get the volume on which the application is
+ located. It is recommended to always check that the volume is ready and valid.
\snippet code/src_corelib_io_qstorageinfo.cpp 0
@@ -104,8 +105,8 @@ QStorageInfo::QStorageInfo(const QString &path)
}
/*!
- Constructs a new QStorageInfo that gives information about the volume
- that contains the \a dir folder.
+ Constructs a new QStorageInfo object that gives information about the volume
+ containing the \a dir folder.
*/
QStorageInfo::QStorageInfo(const QDir &dir)
: d(new QStorageInfoPrivate)
@@ -114,7 +115,7 @@ QStorageInfo::QStorageInfo(const QDir &dir)
}
/*!
- Constructs a new QStorageInfo that is a copy of the \a other QStorageInfo.
+ Constructs a new QStorageInfo object that is a copy of the \a other QStorageInfo object.
*/
QStorageInfo::QStorageInfo(const QStorageInfo &other)
: d(other.d)
@@ -122,14 +123,14 @@ QStorageInfo::QStorageInfo(const QStorageInfo &other)
}
/*!
- Destroys the QStorageInfo and frees its resources.
+ Destroys the QStorageInfo object and frees its resources.
*/
QStorageInfo::~QStorageInfo()
{
}
/*!
- Makes a copy of \a other QStorageInfo and assigns it to this QStorageInfo.
+ Makes a copy of the QStorageInfo object \a other and assigns it to this QStorageInfo object.
*/
QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other)
{
@@ -140,20 +141,20 @@ QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other)
/*!
\fn QStorageInfo &QStorageInfo::operator=(QStorageInfo &&other)
- Move-assigns \a other to this QStorageInfo instance.
+ Assigns \a other to this QStorageInfo instance.
*/
/*!
\fn void QStorageInfo::swap(QStorageInfo &other)
- Swaps this volume info with the \a other. This function is very fast and
+ Swaps this volume info with \a other. This function is very fast and
never fails.
*/
/*!
- Sets QStorageInfo to the filesystem mounted where \a path is located.
+ Sets this QStorageInfo object to the filesystem mounted where \a path is located.
- Path can either be a root path of the filesystem, or a directory or a file
+ \a path can either be a root path of the filesystem, a directory, or a file
within that filesystem.
\sa rootPath()
@@ -171,12 +172,12 @@ void QStorageInfo::setPath(const QString &path)
Returns the mount point of the filesystem this QStorageInfo object
represents.
- On Windows, returns the volume letter in case the volume is not mounted to
+ On Windows, it returns the volume letter in case the volume is not mounted to
a directory.
Note that the value returned by rootPath() is the real mount point of a
- volume and may not be equal to the value passed to constructor or setPath()
- method. For example, if you have only the root volume in the system and
+ volume, and may not be equal to the value passed to the constructor or setPath()
+ method. For example, if you have only the root volume in the system, and
pass '/directory' to setPath(), then this method will return '/'.
\sa setPath(), device()
@@ -187,10 +188,10 @@ QString QStorageInfo::rootPath() const
}
/*!
- Returns the size (in bytes) available for the current user. If the user is
- the root user or a system administrator returns all available size.
+ Returns the size (in bytes) available for the current user. It returns
+ the total size available if the user is the root user or a system administrator.
- This size can be less than or equal to the free size, returned by
+ This size can be less than or equal to the free size returned by
bytesFree() function.
\sa bytesTotal(), bytesFree()
@@ -201,9 +202,9 @@ qint64 QStorageInfo::bytesAvailable() const
}
/*!
- Returns the number of free bytes on a volume. Note, that if there are some
- kind of quotas on the filesystem, this value can be bigger than
- bytesAvailable().
+ Returns the number of free bytes in a volume. Note that if there are
+ quotas on the filesystem, this value can be larger than the value
+ returned by bytesAvailable().
\sa bytesTotal(), bytesAvailable()
*/
@@ -213,7 +214,7 @@ qint64 QStorageInfo::bytesFree() const
}
/*!
- Returns total volume size in bytes.
+ Returns the total volume size in bytes.
\sa bytesFree(), bytesAvailable()
*/
@@ -227,7 +228,7 @@ qint64 QStorageInfo::bytesTotal() const
This is a platform-dependent function, and filesystem names can vary
between different operating systems. For example, on Windows filesystems
- can be named as 'NTFS' and on Linux as 'ntfs-3g' or 'fuseblk'.
+ they can be named \c NTFS, and on Linux they can be named \c ntfs-3g or \c fuseblk.
\sa name()
*/
@@ -240,8 +241,8 @@ QByteArray QStorageInfo::fileSystemType() const
Returns the device for this volume.
For example, on Unix filesystems (including OS X), this returns the
- devpath like '/dev/sda0' for local storages. On Windows, returns the UNC
- path starting with \\\\?\\ for local storages (i.e. volume GUID).
+ devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC
+ path starting with \c \\\\?\\ for local storages (in other words, the volume GUID).
\sa rootPath()
*/
@@ -251,13 +252,13 @@ QByteArray QStorageInfo::device() const
}
/*!
- Returns the human-readable name of a filesystem, usually called 'label'.
+ Returns the human-readable name of a filesystem, usually called \c label.
- Not all filesystems support this feature, in this case value returned by
+ Not all filesystems support this feature. In this case, the value returned by
this method could be empty. An empty string is returned if the file system
- does not support labels or no label is set.
+ does not support labels, or if no label is set.
- On Linux, retrieving the volume's label requires udev to be present in the
+ On Linux, retrieving the volume's label requires \c udev to be present in the
system.
\sa fileSystemType()
@@ -283,8 +284,8 @@ QString QStorageInfo::displayName() const
Returns true if this QStorageInfo represents the system root volume; false
otherwise.
- On Unix filesystems, the root volume is a volume mounted at "/", on Windows
- the root volume is the volume where OS is installed.
+ On Unix filesystems, the root volume is a volume mounted on \c /. On Windows,
+ the root volume is the volume where the OS is installed.
\sa root()
*/
@@ -299,8 +300,8 @@ bool QStorageInfo::isReadOnly() const
}
/*!
- Returns true if current filesystem is ready to work; false otherwise. For
- example, false is returned if CD volume is not inserted.
+ Returns true if the current filesystem is ready to work; false otherwise. For
+ example, false is returned if the CD volume is not inserted.
Note that fileSystemType(), name(), bytesTotal(), bytesFree(), and
bytesAvailable() will return invalid data until the volume is ready.
@@ -326,9 +327,9 @@ bool QStorageInfo::isValid() const
/*!
Resets QStorageInfo's internal cache.
- QStorageInfo caches information about storages to speed up performance -
- QStorageInfo retrieves information during object construction and/or call
- to setPath() method. You have to manually reset the cache by calling this
+ QStorageInfo caches information about storage to speed up performance.
+ QStorageInfo retrieves information during object construction and/or when calling
+ the setPath() method. You have to manually reset the cache by calling this
function to update storage information.
*/
void QStorageInfo::refresh()
@@ -338,17 +339,16 @@ void QStorageInfo::refresh()
}
/*!
- Returns list of QStorageInfos that corresponds to the list of currently
+ Returns the list of QStorageInfo objects that corresponds to the list of currently
mounted filesystems.
- On Windows, this returns drives presented in 'My Computer' folder. On Unix
- operating systems, returns list of all mounted filesystems (except for
+ On Windows, this returns the drives visible in the \gui{My Computer} folder. On Unix
+ operating systems, it returns the list of all mounted filesystems (except for
pseudo filesystems).
- By default, returns all currently mounted filesystems.
+ Returns all currently mounted filesystems by default.
- The example shows how to retrieve all storages present in the system and
- skip read-only storages.
+ The example shows how to retrieve all available filesystems, skipping read-only ones.
\snippet code/src_corelib_io_qstorageinfo.cpp 1
@@ -364,8 +364,8 @@ Q_GLOBAL_STATIC_WITH_ARGS(QStorageInfo, getRoot, (QStorageInfoPrivate::root()))
/*!
Returns a QStorageInfo object that represents the system root volume.
- On Unix systems this call returns '/' volume, on Windows the volume where
- operating system is installed is returned.
+ On Unix systems this call returns the root ('/') volume; in Windows the volume where
+ the operating system is installed.
\sa isRoot()
*/
@@ -379,8 +379,8 @@ QStorageInfo QStorageInfo::root()
\relates QStorageInfo
- Returns true if \a first QStorageInfo object refers to the same drive or volume
- as the \a second; otherwise returns false.
+ Returns true if the \a first QStorageInfo object refers to the same drive or volume
+ as the \a second; otherwise it returns false.
Note that the result of comparing two invalid QStorageInfo objects is always
positive.
@@ -391,8 +391,8 @@ QStorageInfo QStorageInfo::root()
\relates QStorageInfo
- Returns true if \a first QStorageInfo object refers to a different drive or
- volume than the one specified by \a second; otherwise returns false.
+ Returns true if the \a first QStorageInfo object refers to a different drive or
+ volume than the \a second; otherwise returns false.
*/
QT_END_NAMESPACE
diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp
index c1e831192a..6f3a960f05 100644
--- a/src/corelib/json/qjsonarray.cpp
+++ b/src/corelib/json/qjsonarray.cpp
@@ -746,6 +746,11 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
from which you got the reference.
*/
+/*! \fn QJsonValueRef *QJsonArray::iterator::operator->() const
+
+ Returns a pointer to a modifiable reference to the current item.
+*/
+
/*! \fn QJsonValueRef QJsonArray::iterator::operator[](int j) const
Returns a modifiable reference to the item at offset \a j from the
@@ -971,6 +976,11 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
Returns the current item.
*/
+/*! \fn QJsonValue *QJsonArray::const_iterator::operator->() const
+
+ Returns a pointer to the current item.
+*/
+
/*! \fn QJsonValue QJsonArray::const_iterator::operator[](int j) const
Returns the item at offset \a j from the item pointed to by this iterator (the item at
diff --git a/src/corelib/json/qjsonarray.h b/src/corelib/json/qjsonarray.h
index 4cada7cec1..f3efa3d201 100644
--- a/src/corelib/json/qjsonarray.h
+++ b/src/corelib/json/qjsonarray.h
@@ -112,14 +112,17 @@ public:
typedef std::random_access_iterator_tag iterator_category;
typedef int difference_type;
typedef QJsonValue value_type;
- //typedef T *pointer;
typedef QJsonValueRef reference;
inline iterator() : a(0), i(0) { }
explicit inline iterator(QJsonArray *array, int index) : a(array), i(index) { }
inline QJsonValueRef operator*() const { return QJsonValueRef(a, i); }
- //inline T *operator->() const { return &concrete(i)->value; }
+#ifdef Q_QDOC
+ inline QJsonValueRef* operator->() const;
+#else
+ inline QJsonValueRefPtr operator->() const { return QJsonValueRefPtr(a, i); }
+#endif
inline QJsonValueRef operator[](int j) const { return QJsonValueRef(a, i + j); }
inline bool operator==(const iterator &o) const { return i == o.i; }
@@ -153,7 +156,6 @@ public:
typedef std::random_access_iterator_tag iterator_category;
typedef qptrdiff difference_type;
typedef QJsonValue value_type;
- //typedef const T *pointer;
typedef QJsonValue reference;
inline const_iterator() : a(0), i(0) { }
@@ -162,7 +164,11 @@ public:
inline const_iterator(const iterator &o) : a(o.a), i(o.i) {}
inline QJsonValue operator*() const { return a->at(i); }
- //inline T *operator->() const { return &concrete(i)->value; }
+#ifdef Q_QDOC
+ inline QJsonValue* operator->() const;
+#else
+ inline QJsonValuePtr operator->() const { return QJsonValuePtr(a->at(i)); }
+#endif
inline QJsonValue operator[](int j) const { return a->at(i+j); }
inline bool operator==(const const_iterator &o) const { return i == o.i; }
inline bool operator!=(const const_iterator &o) const { return i != o.i; }
diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp
index cfd797990f..b393701411 100644
--- a/src/corelib/json/qjsonobject.cpp
+++ b/src/corelib/json/qjsonobject.cpp
@@ -710,6 +710,11 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const
\sa key()
*/
+/*! \fn QJsonValueRef *QJsonObject::iterator::operator->() const
+
+ Returns a pointer to a modifiable reference to the current item.
+*/
+
/*!
\fn bool QJsonObject::iterator::operator==(const iterator &other) const
\fn bool QJsonObject::iterator::operator==(const const_iterator &other) const
@@ -893,6 +898,11 @@ QJsonObject::const_iterator QJsonObject::constFind(const QString &key) const
\sa key()
*/
+/*! \fn QJsonValue *QJsonObject::const_iterator::operator->() const
+
+ Returns a pointer to the current item.
+*/
+
/*! \fn bool QJsonObject::const_iterator::operator==(const const_iterator &other) const
\fn bool QJsonObject::const_iterator::operator==(const iterator &other) const
diff --git a/src/corelib/json/qjsonobject.h b/src/corelib/json/qjsonobject.h
index 92dd19af5e..7973b8ab92 100644
--- a/src/corelib/json/qjsonobject.h
+++ b/src/corelib/json/qjsonobject.h
@@ -107,7 +107,6 @@ public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef int difference_type;
typedef QJsonValue value_type;
-// typedef T *pointer;
typedef QJsonValueRef reference;
Q_DECL_CONSTEXPR inline iterator() : o(0), i(0) {}
@@ -116,7 +115,11 @@ public:
inline QString key() const { return o->keyAt(i); }
inline QJsonValueRef value() const { return QJsonValueRef(o, i); }
inline QJsonValueRef operator*() const { return QJsonValueRef(o, i); }
- //inline T *operator->() const { return &concrete(i)->value; }
+#ifdef Q_QDOC
+ inline QJsonValueRef* operator->() const;
+#else
+ inline QJsonValueRefPtr operator->() const { return QJsonValueRefPtr(o, i); }
+#endif
inline bool operator==(const iterator &other) const { return i == other.i; }
inline bool operator!=(const iterator &other) const { return i != other.i; }
@@ -157,7 +160,11 @@ public:
inline QString key() const { return o->keyAt(i); }
inline QJsonValue value() const { return o->valueAt(i); }
inline QJsonValue operator*() const { return o->valueAt(i); }
- //inline const T *operator->() const { return &concrete(i)->value; }
+#ifdef Q_QDOC
+ inline QJsonValue* operator->() const;
+#else
+ inline QJsonValuePtr operator->() const { return QJsonValuePtr(o->valueAt(i)); }
+#endif
inline bool operator==(const const_iterator &other) const { return i == other.i; }
inline bool operator!=(const const_iterator &other) const { return i != other.i; }
diff --git a/src/corelib/json/qjsonvalue.h b/src/corelib/json/qjsonvalue.h
index a00bc0b72f..2d0453f130 100644
--- a/src/corelib/json/qjsonvalue.h
+++ b/src/corelib/json/qjsonvalue.h
@@ -192,6 +192,33 @@ private:
struct UnionHelper;
};
+#ifndef Q_QDOC
+// ### Qt 6: Get rid of these fake pointer classes
+class QJsonValuePtr
+{
+ QJsonValue value;
+public:
+ explicit QJsonValuePtr(const QJsonValue& val)
+ : value(val) {}
+
+ QJsonValue& operator*() { return value; }
+ QJsonValue* operator->() { return &value; }
+};
+
+class QJsonValueRefPtr
+{
+ QJsonValueRef valueRef;
+public:
+ QJsonValueRefPtr(QJsonArray *array, int idx)
+ : valueRef(array, idx) {}
+ QJsonValueRefPtr(QJsonObject *object, int idx)
+ : valueRef(object, idx) {}
+
+ QJsonValueRef& operator*() { return valueRef; }
+ QJsonValueRef* operator->() { return &valueRef; }
+};
+#endif
+
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &);
#endif
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index 8d5a39115a..bc54a2ae74 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -184,6 +184,7 @@ QT_BEGIN_NAMESPACE
\value MouseMove Mouse move (QMouseEvent).
\value MouseTrackingChange The mouse tracking state has changed.
\value Move Widget's position changed (QMoveEvent).
+ \value NativeGesture The system has detected a gesture (QNativeGestureEvent).
\value OrientationChange The screens orientation has changes (QScreenOrientationChangeEvent)
\value Paint Screen update necessary (QPaintEvent).
\value PaletteChange Palette of the widget changed.
diff --git a/src/corelib/kernel/qfunctions_winrt.h b/src/corelib/kernel/qfunctions_winrt.h
index 5f051c3ea6..b585d3c352 100644
--- a/src/corelib/kernel/qfunctions_winrt.h
+++ b/src/corelib/kernel/qfunctions_winrt.h
@@ -44,7 +44,7 @@
#include <QtCore/qglobal.h>
-#ifdef Q_OS_WINRT
+#ifdef Q_OS_WIN
#include <QtCore/QThread>
#include <QtCore/QAbstractEventDispatcher>
@@ -57,6 +57,8 @@ QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
+#ifdef Q_OS_WINRT
+
// Environment ------------------------------------------------------
errno_t qt_winrt_getenv_s(size_t*, char*, size_t, const char*);
errno_t qt_winrt__putenv_s(const char*, const char*);
@@ -122,6 +124,8 @@ generate_inline_return_func2(_putenv_s, errno_t, const char *, const char *)
generate_inline_return_func0(tzset, void)
generate_inline_return_func0(_tzset, void)
+#endif // Q_OS_WINRT
+
// Convenience macros for handling HRESULT values
#define RETURN_IF_FAILED(msg, ret) \
if (FAILED(hr)) { \
@@ -211,5 +215,6 @@ static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results
} // QWinRTFunctions
-#endif // Q_OS_WINRT
+#endif // Q_OS_WIN
+
#endif // QFUNCTIONS_WINRT_H
diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp
index aa9b196e62..4581b70ca7 100644
--- a/src/corelib/kernel/qjni.cpp
+++ b/src/corelib/kernel/qjni.cpp
@@ -721,7 +721,7 @@ jboolean QJNIObjectPrivate::callStaticMethod<jboolean>(jclass clazz,
{
va_list args;
va_start(args, sig);
- jboolean res = callStaticMethod<jboolean>(clazz, methodName, sig);
+ jboolean res = callStaticMethod<jboolean>(clazz, methodName, sig, args);
va_end(args);
return res;
}
@@ -1026,7 +1026,7 @@ jlong QJNIObjectPrivate::callStaticMethod<jlong>(jclass clazz,
{
va_list args;
va_start(args, sig);
- jlong res = callStaticMethod<jlong>(clazz, methodName, sig);
+ jlong res = callStaticMethod<jlong>(clazz, methodName, sig, args);
va_end(args);
return res;
}
@@ -1119,7 +1119,7 @@ jdouble QJNIObjectPrivate::callStaticMethod<jdouble>(const char *className,
{
va_list args;
va_start(args, sig);
- jdouble res = callStaticMethod<jdouble>(className, methodName, sig);
+ jdouble res = callStaticMethod<jdouble>(className, methodName, sig, args);
va_end(args);
return res;
}
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 9980e0d901..0647513221 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -65,6 +65,7 @@
# include "qjsonobject.h"
# include "qjsonarray.h"
# include "qjsondocument.h"
+# include "qbytearraylist.h"
#endif
#ifndef QT_NO_GEOM_VARIANT
@@ -270,6 +271,7 @@ struct DefinedTypesFilter {
\value QJsonDocument QJsonDocument
\value QModelIndex QModelIndex
\value QUuid QUuid
+ \value QByteArrayList QByteArrayList
\value User Base value for user types
\value UnknownType This is an invalid type id. It is returned from QMetaType for types that are not registered
@@ -1191,6 +1193,9 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
case QMetaType::QVariant:
stream << *static_cast<const NS(QVariant)*>(data);
break;
+ case QMetaType::QByteArrayList:
+ stream << *static_cast<const NS(QByteArrayList)*>(data);
+ break;
#endif
case QMetaType::QByteArray:
stream << *static_cast<const NS(QByteArray)*>(data);
@@ -1414,6 +1419,9 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
case QMetaType::QVariant:
stream >> *static_cast< NS(QVariant)*>(data);
break;
+ case QMetaType::QByteArrayList:
+ stream >> *static_cast< NS(QByteArrayList)*>(data);
+ break;
#endif
case QMetaType::QByteArray:
stream >> *static_cast< NS(QByteArray)*>(data);
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 1aa89a03b3..7570a6fb20 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -127,6 +127,7 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId();
F(QVariantMap, 8, QVariantMap) \
F(QVariantList, 9, QVariantList) \
F(QVariantHash, 28, QVariantHash) \
+ F(QByteArrayList, 49, QByteArrayList) \
#define QT_FOR_EACH_STATIC_GUI_CLASS(F)\
F(QFont, 64, QFont) \
@@ -180,6 +181,7 @@ inline Q_DECL_CONSTEXPR int qMetaTypeId();
F(QVariantList, -1, QVariantList, "QList<QVariant>") \
F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
+ F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
#define QT_FOR_EACH_STATIC_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
@@ -393,7 +395,7 @@ public:
QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)
FirstCoreType = Bool,
- LastCoreType = QJsonDocument,
+ LastCoreType = QByteArrayList,
FirstGuiType = QFont,
LastGuiType = QPolygonF,
FirstWidgetsType = QSizePolicy,
@@ -419,7 +421,7 @@ public:
QEasingCurve = 29, QUuid = 30, QVariant = 41, QModelIndex = 42,
QRegularExpression = 44,
QJsonValue = 45, QJsonObject = 46, QJsonArray = 47, QJsonDocument = 48,
- QObjectStar = 39, SChar = 40,
+ QByteArrayList = 49, QObjectStar = 39, SChar = 40,
Void = 43,
QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
QFont = 64, QPixmap = 65, QBrush = 66, QColor = 67, QPalette = 68,
@@ -1763,6 +1765,7 @@ QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
typedef QList<QVariant> QVariantList;
typedef QMap<QString, QVariant> QVariantMap;
typedef QHash<QString, QVariant> QVariantHash;
+typedef QList<QByteArray> QByteArrayList;
#define Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE) \
QT_BEGIN_NAMESPACE \
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index 95b9e2e394..48cb6d6fcc 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -207,6 +207,7 @@ template<> struct TypeDefinition<QJsonObject> { static const bool IsAvailable =
template<> struct TypeDefinition<QJsonValue> { static const bool IsAvailable = false; };
template<> struct TypeDefinition<QModelIndex> { static const bool IsAvailable = false; };
template<> struct TypeDefinition<QUrl> { static const bool IsAvailable = false; };
+template<> struct TypeDefinition<QByteArrayList> { static const bool IsAvailable = false; };
#endif
#ifdef QT_NO_GEOM_VARIANT
template<> struct TypeDefinition<QRect> { static const bool IsAvailable = false; };
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index db2b086ff2..45bf4b62c5 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -4749,10 +4749,14 @@ bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject
int signal_index = -1;
if (signal) {
void *args[] = { &signal_index, signal };
- senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
- if (signal_index < 0 || signal_index >= QMetaObjectPrivate::get(senderMetaObject)->signalCount) {
- qWarning("QObject::disconnect: signal not found in %s", senderMetaObject->className());
- return false;
+ for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
+ senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
+ if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
+ break;
+ }
+ if (!senderMetaObject) {
+ qWarning("QObject::disconnect: signal not found in %s", sender->metaObject()->className());
+ return QMetaObject::Connection(0);
}
signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
}
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 5e8f330a92..29734f902e 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -61,6 +61,7 @@
#include "qjsonobject.h"
#include "qjsonarray.h"
#include "qjsondocument.h"
+#include "qbytearraylist.h"
#endif
#include "private/qvariant_p.h"
#include "qmetatype_p.h"
@@ -2841,6 +2842,7 @@ bool QVariant::canConvert(int targetTypeId) const
if (targetTypeId == QMetaType::QVariantList
&& (d.type == QMetaType::QVariantList
|| d.type == QMetaType::QStringList
+ || d.type == QMetaType::QByteArrayList
|| QMetaType::hasRegisteredConverterFunction(d.type,
qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>()))) {
return true;
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 5ff33cce5f..e141817993 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -51,6 +51,9 @@
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qobject.h>
+#ifndef QT_BOOTSTRAPPED
+#include <QtCore/qbytearraylist.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -713,6 +716,11 @@ namespace QtPrivate {
if (v.userType() == qMetaTypeId<QStringList>()) {
return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QStringList*>(v.constData())));
}
+#ifndef QT_BOOTSTRAPPED
+ if (v.userType() == qMetaTypeId<QByteArrayList>()) {
+ return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QByteArrayList*>(v.constData())));
+ }
+#endif
return QSequentialIterable(v.value<QtMetaTypePrivate::QSequentialIterableImpl>());
}
};
@@ -735,7 +743,7 @@ namespace QtPrivate {
{
static QVariantList invoke(const QVariant &v)
{
- if (v.userType() == qMetaTypeId<QStringList>() || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
+ if (v.userType() == qMetaTypeId<QStringList>() || v.userType() == qMetaTypeId<QByteArrayList>() || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
QSequentialIterable iter = QVariantValueHelperInterface<QSequentialIterable>::invoke(v);
QVariantList l;
l.reserve(iter.size());
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index a147b85eb7..0e6fad48df 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -526,10 +526,6 @@ QList<QAbstractState*> QStateMachinePrivate::computeStatesToEnter(const QList<QA
QAbstractState *s = lst.at(j);
addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
}
- for (int j = src ? 1 : 0; j < lst.size(); ++j) {
- QAbstractState *s = lst.at(j);
- addAncestorStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
- }
if (isParallel(lca)) {
QList<QAbstractState*> lcac = QStatePrivate::get(lca)->childStates();
foreach (QAbstractState* child,lcac) {
@@ -727,6 +723,7 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
return;
}
}
+ addAncestorStatesToEnter(s, root, statesToEnter, statesForDefaultEntry);
}
}
@@ -1095,7 +1092,6 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
if (currentErrorState != 0) {
QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext);
addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
- addAncestorStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
} else {
qWarning("Unrecoverable error detected in running state machine: %s",
qPrintable(errorString));
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 6e0634ac3b..b927bf1ead 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -774,10 +774,10 @@ Q_OUTOFLINE_TEMPLATE QList<T>::~QList()
template <typename T>
Q_OUTOFLINE_TEMPLATE bool QList<T>::operator==(const QList<T> &l) const
{
- if (p.size() != l.p.size())
- return false;
if (d == l.d)
return true;
+ if (p.size() != l.p.size())
+ return false;
Node *i = reinterpret_cast<Node *>(p.end());
Node *b = reinterpret_cast<Node *>(p.begin());
Node *li = reinterpret_cast<Node *>(l.p.end());
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 5454a8fe4d..e7bad15b5d 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -7929,6 +7929,11 @@ QString &QString::setRawData(const QChar *unicode, int size)
Returns the Latin-1 string stored in this object.
*/
+/*! \fn const char *QLatin1String::data() const
+
+ Returns the Latin-1 string stored in this object.
+*/
+
/*! \fn int QLatin1String::size() const
Returns the size of the Latin-1 string stored in this object.
@@ -7959,6 +7964,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
go through QObject::tr(), for example.
*/
+/*!
+ \fn bool QLatin1String::operator==(const QByteArray &other) const
+ \since 5.0
+ \overload
+
+ The \a other byte array is converted to a QString using
+ the QString::fromUtf8() function.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ can be useful if you want to ensure that all user-visible strings
+ go through QObject::tr(), for example.
+*/
+
/*! \fn bool QLatin1String::operator!=(const QString &other) const
Returns \c true if this string is not equal to string \a other;
@@ -7985,6 +8004,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
*/
/*!
+ \fn bool QLatin1String::operator!=(const QByteArray &other) const
+ \since 5.0
+ \overload operator!=()
+
+ The \a other byte array is converted to a QString using
+ the QString::fromUtf8() function.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ can be useful if you want to ensure that all user-visible strings
+ go through QObject::tr(), for example.
+*/
+
+/*!
\fn bool QLatin1String::operator>(const QString &other) const
Returns \c true if this string is lexically greater than string \a
@@ -8011,6 +8044,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
*/
/*!
+ \fn bool QLatin1String::operator>(const QByteArray &other) const
+ \since 5.0
+ \overload
+
+ The \a other const char pointer is converted to a QString using
+ the QString::fromUtf8() function.
+
+ You can disable this operator by defining \c QT_NO_CAST_FROM_ASCII
+ when you compile your applications. This can be useful if you want
+ to ensure that all user-visible strings go through QObject::tr(),
+ for example.
+*/
+
+/*!
\fn bool QLatin1String::operator<(const QString &other) const
Returns \c true if this string is lexically less than the \a other
@@ -8037,6 +8084,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
*/
/*!
+ \fn bool QLatin1String::operator<(const QByteArray &other) const
+ \since 5.0
+ \overload
+
+ The \a other const char pointer is converted to a QString using
+ the QString::fromUtf8() function.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ can be useful if you want to ensure that all user-visible strings
+ go through QObject::tr(), for example.
+*/
+
+/*!
\fn bool QLatin1String::operator>=(const QString &other) const
Returns \c true if this string is lexically greater than or equal
@@ -8062,6 +8123,20 @@ QString &QString::setRawData(const QChar *unicode, int size)
go through QObject::tr(), for example.
*/
+/*!
+ \fn bool QLatin1String::operator>=(const QByteArray &other) const
+ \since 5.0
+ \overload
+
+ The \a other array is converted to a QString using
+ the QString::fromUtf8() function.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ can be useful if you want to ensure that all user-visible strings
+ go through QObject::tr(), for example.
+*/
+
/*! \fn bool QLatin1String::operator<=(const QString &other) const
Returns \c true if this string is lexically less than or equal
@@ -8087,6 +8162,19 @@ QString &QString::setRawData(const QChar *unicode, int size)
go through QObject::tr(), for example.
*/
+/*!
+ \fn bool QLatin1String::operator<=(const QByteArray &other) const
+ \since 5.0
+ \overload
+
+ The \a other array is converted to a QString using
+ the QString::fromUtf8() function.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ can be useful if you want to ensure that all user-visible strings
+ go through QObject::tr(), for example.
+*/
/*! \fn bool operator==(QLatin1String s1, QLatin1String s2)
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index f09f1a3c41..cb4e193ffc 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -256,7 +256,7 @@ public:
static inline QVector<T> fromStdVector(const std::vector<T> &vector)
{ QVector<T> tmp; tmp.reserve(int(vector.size())); std::copy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; }
inline std::vector<T> toStdVector() const
- { std::vector<T> tmp; tmp.reserve(size()); std::copy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; }
+ { return std::vector<T>(d->begin(), d->end()); }
private:
friend class QRegion; // Optimization for QRegion::rects()
@@ -711,10 +711,10 @@ typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
template <typename T>
bool QVector<T>::operator==(const QVector<T> &v) const
{
- if (d->size != v.d->size)
- return false;
if (d == v.d)
return true;
+ if (d->size != v.d->size)
+ return false;
T* b = d->begin();
T* i = b + d->size;
T* j = v.d->end();
@@ -810,7 +810,9 @@ bool QVector<T>::contains(const T &t) const
template <typename T>
int QVector<T>::count(const T &t) const
{
- return int(std::count(cbegin(), cend(), t));
+ const T *b = d->begin();
+ const T *e = d->end();
+ return int(std::count(b, e, t));
}
template <typename T>
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
index ac95222c99..1e4a9ebe8c 100644
--- a/src/gui/image/qicon.cpp
+++ b/src/gui/image/qicon.cpp
@@ -989,10 +989,16 @@ void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
QImageWriter::supportedImageFormats() functions to retrieve a
complete list of the supported file formats.
- Note: When you add a non-empty filename to a QIcon, the icon becomes
+ If a high resolution version of the image exists (identified by
+ the suffix \c @2x on the base name), it is automatically loaded
+ and added with the \e{device pixel ratio} set to a value of 2.
+ This can be disabled by setting the environment variable
+ \c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING (see QImageReader).
+
+ \note When you add a non-empty filename to a QIcon, the icon becomes
non-null, even if the file doesn't exist or points to a corrupt file.
- \sa addPixmap()
+ \sa addPixmap(), QPixmap::devicePixelRatio()
*/
void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
{
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index 9e979023cd..12d9f9f14d 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -176,7 +176,6 @@ QIconTheme::QIconTheme(const QString &themeName)
{
QFile themeIndex;
- QList <QIconDirInfo> keyList;
QStringList iconDirs = QIcon::themeSearchPaths();
for ( int i = 0 ; i < iconDirs.size() ; ++i) {
QDir iconDir(iconDirs[i]);
@@ -269,7 +268,7 @@ QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName,
}
QString contentDir = theme.contentDir() + QLatin1Char('/');
- QList<QIconDirInfo> subDirs = theme.keyList();
+ const QVector<QIconDirInfo> subDirs = theme.keyList();
const QString svgext(QLatin1String(".svg"));
const QString pngext(QLatin1String(".png"));
@@ -333,9 +332,7 @@ QIconLoaderEngine::QIconLoaderEngine(const QString& iconName)
QIconLoaderEngine::~QIconLoaderEngine()
{
- while (!m_entries.isEmpty())
- delete m_entries.takeLast();
- Q_ASSERT(m_entries.size() == 0);
+ qDeleteAll(m_entries);
}
QIconLoaderEngine::QIconLoaderEngine(const QIconLoaderEngine &other)
@@ -371,10 +368,8 @@ void QIconLoaderEngine::ensureLoaded()
{
if (!(QIconLoader::instance()->themeKey() == m_key)) {
- while (!m_entries.isEmpty())
- delete m_entries.takeLast();
+ qDeleteAll(m_entries);
- Q_ASSERT(m_entries.size() == 0);
m_entries = QIconLoader::instance()->loadIcon(m_iconName);
m_key = QIconLoader::instance()->themeKey();
}
@@ -448,8 +443,10 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
// Note that m_entries are sorted so that png-files
// come first
+ const int numEntries = m_entries.size();
+
// Search for exact matches first
- for (int i = 0; i < m_entries.count(); ++i) {
+ for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_entries.at(i);
if (directoryMatchesSize(entry->dir, iconsize)) {
return entry;
@@ -459,7 +456,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
// Find the minimum distance icon
int minimalSize = INT_MAX;
QIconLoaderEngineEntry *closestMatch = 0;
- for (int i = 0; i < m_entries.count(); ++i) {
+ for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_entries.at(i);
int distance = directorySizeDistance(entry->dir, iconsize);
if (distance < minimalSize) {
@@ -564,11 +561,12 @@ void QIconLoaderEngine::virtual_hook(int id, void *data)
{
QIconEngine::AvailableSizesArgument &arg
= *reinterpret_cast<QIconEngine::AvailableSizesArgument*>(data);
- const QList<QIconDirInfo> directoryKey = QIconLoader::instance()->theme().keyList();
arg.sizes.clear();
+ const int N = m_entries.size();
+ arg.sizes.reserve(N);
// Gets all sizes from the DirectoryInfo entries
- for (int i = 0 ; i < m_entries.size() ; ++i) {
+ for (int i = 0; i < N; ++i) {
int size = m_entries.at(i)->dir.size;
arg.sizes.append(QSize(size, size));
}
diff --git a/src/gui/image/qiconloader_p.h b/src/gui/image/qiconloader_p.h
index 419d93d576..2495ff4d50 100644
--- a/src/gui/image/qiconloader_p.h
+++ b/src/gui/image/qiconloader_p.h
@@ -62,6 +62,8 @@
#include <private/qicon_p.h>
#include <private/qfactoryloader_p.h>
#include <QtCore/QHash>
+#include <QtCore/QVector>
+#include <QtCore/QTypeInfo>
QT_BEGIN_NAMESPACE
@@ -84,6 +86,7 @@ struct QIconDirInfo
short threshold;
Type type : 4;
};
+Q_DECLARE_TYPEINFO(QIconDirInfo, Q_MOVABLE_TYPE);
class QIconLoaderEngineEntry
{
@@ -99,13 +102,13 @@ public:
struct ScalableEntry : public QIconLoaderEngineEntry
{
- QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QIcon svgIcon;
};
struct PixmapEntry : public QIconLoaderEngineEntry
{
- QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QPixmap basePixmap;
};
@@ -144,18 +147,18 @@ public:
QIconTheme(const QString &name);
QIconTheme() : m_valid(false) {}
QStringList parents() { return m_parents; }
- QList <QIconDirInfo> keyList() { return m_keyList; }
+ QVector<QIconDirInfo> keyList() { return m_keyList; }
QString contentDir() { return m_contentDir; }
bool isValid() { return m_valid; }
private:
QString m_contentDir;
- QList <QIconDirInfo> m_keyList;
+ QVector<QIconDirInfo> m_keyList;
QStringList m_parents;
bool m_valid;
};
-class Q_GUI_EXPORT QIconLoader : public QObject
+class Q_GUI_EXPORT QIconLoader
{
public:
QIconLoader();
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 16696f611d..c3b4b1444a 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -1391,14 +1391,14 @@ QVector<QRgb> QImage::colorTable() const
/*!
Returns the device pixel ratio for the image. This is the
- ratio between image pixels and device-independent pixels.
+ ratio between \e{device pixels} and \e{device independent pixels}.
Use this function when calculating layout geometry based on
the image size: QSize layoutSize = image.size() / image.devicePixelRatio()
The default value is 1.0.
- \sa setDevicePixelRatio()
+ \sa setDevicePixelRatio(), QImageReader
*/
qreal QImage::devicePixelRatio() const
{
@@ -1423,7 +1423,8 @@ qreal QImage::devicePixelRatio() const
image size will take the ratio into account:
QSize layoutSize = image.size() / image.devicePixelRatio()
The net effect of this is that the image is displayed as
- high-dpi image rather than a large image.
+ high-DPI image rather than a large image
+ (see \l{Drawing High Resolution Versions of Pixmaps and Images}).
\sa devicePixelRatio()
*/
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index a281349aa9..3bf002373c 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -74,17 +74,32 @@
that occurred, or errorString() to get a human readable
description of what went wrong.
+ \section1 Formats
+
Call supportedImageFormats() for a list of formats that
QImageReader can read. QImageReader supports all built-in image
formats, in addition to any image format plugins that support
- reading.
+ reading. Call supportedMimeTypes() to obtain a list of supported MIME
+ types, which for example can be passed to QFileDialog::setMimeTypeFilters().
QImageReader autodetects the image format by default, by looking at the
provided (optional) format string, the file name suffix, and the data
stream contents. You can enable or disable this feature, by calling
setAutoDetectImageFormat().
- \sa QImageWriter, QImageIOHandler, QImageIOPlugin
+ \section1 High Resolution Versions of Images
+
+ It is possible to provide high resolution versions of images should a scaling
+ between \e{device pixels} and \e{device independent pixels} be in effect.
+
+ The high resolution version is marked by the suffix \c @2x on the base name.
+ The image read will have its \e{device pixel ratio} set to a value of 2.
+
+ This can be disabled by setting the environment variable
+ \c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING.
+
+ \sa QImageWriter, QImageIOHandler, QImageIOPlugin, QMimeDatabase
+ \sa QImage::devicePixelRatio(), QPixmap::devicePixelRatio(), QIcon, QPainter::drawPixmap(), QPainter::drawImage(), Qt::AA_UseHighDpiPixmaps
*/
/*!
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index 2d41ca7e24..88ce48f0e8 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -648,14 +648,14 @@ void QPixmap::setMask(const QBitmap &mask)
/*!
Returns the device pixel ratio for the pixmap. This is the
- ratio between pixmap pixels and device-independent pixels.
+ ratio between \e{device pixels} and \e{device independent pixels}.
Use this function when calculating layout geometry based on
the pixmap size: QSize layoutSize = image.size() / image.devicePixelRatio()
The default value is 1.0.
- \sa setDevicePixelRatio()
+ \sa setDevicePixelRatio(), QImageReader
*/
qreal QPixmap::devicePixelRatio() const
{
@@ -680,7 +680,8 @@ qreal QPixmap::devicePixelRatio() const
pixmap size will take the ratio into account:
QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio()
The net effect of this is that the pixmap is displayed as
- high-dpi pixmap rather than a large pixmap.
+ high-DPI pixmap rather than a large pixmap
+ (see \l{Drawing High Resolution Versions of Pixmaps and Images}).
\sa devicePixelRatio()
*/
diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp
index 5edb866b62..ca87951dbb 100644
--- a/src/gui/image/qxpmhandler.cpp
+++ b/src/gui/image/qxpmhandler.cpp
@@ -1094,7 +1094,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const
return false;
QImage image;
- if (sourceImage.format() != QImage::Format_RGB32 || sourceImage.format() != QImage::Format_ARGB32 || sourceImage.format() != QImage::Format_ARGB32_Premultiplied)
+ if (sourceImage.format() != QImage::Format_RGB32 && sourceImage.format() != QImage::Format_ARGB32 && sourceImage.format() != QImage::Format_ARGB32_Premultiplied)
image = sourceImage.convertToFormat(QImage::Format_RGB32);
else
image = sourceImage;
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index c2422ec98b..1169985ea8 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -66,7 +66,6 @@ HEADERS += \
kernel/qplatformsharedgraphicscache.h \
kernel/qplatformdialoghelper.h \
kernel/qplatformservices.h \
- kernel/qplatformscreenpageflipper.h \
kernel/qplatformsystemtrayicon.h \
kernel/qplatformsessionmanager.h \
kernel/qpixelformat.h \
@@ -120,7 +119,6 @@ SOURCES += \
kernel/qplatformsharedgraphicscache.cpp \
kernel/qplatformdialoghelper.cpp \
kernel/qplatformservices.cpp \
- kernel/qplatformscreenpageflipper.cpp \
kernel/qplatformsystemtrayicon.cpp \
kernel/qplatformsessionmanager.cpp \
kernel/qplatformmenu.cpp \
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 1b853411f8..958df48f17 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -3495,11 +3495,13 @@ static const char *eventClassName(QEvent::Type t)
return "QCloseEvent";
case QEvent::FileOpen:
return "QFileOpenEvent";
+#ifndef QT_NO_GESTURES
case QEvent::NativeGesture:
return "QNativeGestureEvent";
case QEvent::Gesture:
case QEvent::GestureOverride:
return "QGestureEvent";
+#endif
case QEvent::HoverEnter:
case QEvent::HoverLeave:
case QEvent::HoverMove:
@@ -3595,6 +3597,14 @@ public:
static const int enumIdx = QObject::staticQtMetaObject.indexOfEnumerator("FocusReason");
return QObject::staticQtMetaObject.enumerator(enumIdx).valueToKey(reason);
}
+
+# ifndef QT_NO_GESTURES
+ static const char *nativeGestureTypeToString(Qt::NativeGestureType type)
+ {
+ static const int enumIdx = QObject::staticQtMetaObject.indexOfEnumerator("NativeGestureType");
+ return QObject::staticQtMetaObject.enumerator(enumIdx).valueToKey(type);
+ }
+# endif // !QT_NO_GESTURES
};
} // namespace
@@ -3775,7 +3785,8 @@ QDebug operator<<(QDebug dbg, const QEvent *e)
# ifndef QT_NO_GESTURES
case QEvent::NativeGesture: {
const QNativeGestureEvent *ne = static_cast<const QNativeGestureEvent *>(e);
- dbg << "QNativeGestureEvent(localPos=" << ne->localPos() << ", value=" << ne->value() << ')';
+ dbg << "QNativeGestureEvent(" << DebugHelper::nativeGestureTypeToString(ne->gestureType())
+ << "localPos=" << ne->localPos() << ", value=" << ne->value() << ')';
}
break;
# endif // !QT_NO_GESTURES
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 71a1d1e074..6b2bb092b1 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -639,6 +639,7 @@ bool QOpenGLContext::create()
*/
void QOpenGLContext::destroy()
{
+ deleteQGLContext();
Q_D(QOpenGLContext);
if (d->platformGLContext)
emit aboutToBeDestroyed();
@@ -1086,6 +1087,9 @@ void *QOpenGLContext::qGLContextHandle() const
}
/*!
+ internal: If the delete function is specified QOpenGLContext "owns"
+ the passed context handle and will use the delete function to destroy it.
+
\internal
*/
void QOpenGLContext::setQGLContextHandle(void *handle,void (*qGLContextDeleteFunction)(void *))
diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h
index 46e1572376..2d27b19ebe 100644
--- a/src/gui/kernel/qopenglcontext_p.h
+++ b/src/gui/kernel/qopenglcontext_p.h
@@ -198,6 +198,7 @@ class Q_GUI_EXPORT QOpenGLContextPrivate : public QObjectPrivate
public:
QOpenGLContextPrivate()
: qGLContextHandle(0)
+ , qGLContextDeleteFunction(0)
, platformGLContext(0)
, shareContext(0)
, shareGroup(0)
diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp
index 05d04ae4ee..0c47005807 100644
--- a/src/gui/kernel/qplatformscreen.cpp
+++ b/src/gui/kernel/qplatformscreen.cpp
@@ -275,15 +275,6 @@ QPlatformScreen * QPlatformScreen::platformScreenForWindow(const QWindow *window
*/
/*!
- Implemented in subclasses to return a page flipper object for the screen, or 0 if the
- hardware does not support page flipping. The default implementation returns 0.
- */
-QPlatformScreenPageFlipper *QPlatformScreen::pageFlipper() const
-{
- return 0;
-}
-
-/*!
Reimplement this function in subclass to return the cursor of the screen.
The default implementation returns 0.
diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h
index 085a147e8d..151a6386d9 100644
--- a/src/gui/kernel/qplatformscreen.h
+++ b/src/gui/kernel/qplatformscreen.h
@@ -71,7 +71,6 @@ class QPlatformOpenGLContext;
class QPlatformScreenPrivate;
class QPlatformWindow;
class QPlatformCursor;
-class QPlatformScreenPageFlipper;
class QScreen;
class QSurfaceFormat;
@@ -115,7 +114,6 @@ public:
virtual QString name() const { return QString(); }
- virtual QPlatformScreenPageFlipper *pageFlipper() const;
virtual QPlatformCursor *cursor() const;
protected:
diff --git a/src/gui/kernel/qplatformscreenpageflipper.cpp b/src/gui/kernel/qplatformscreenpageflipper.cpp
deleted file mode 100644
index 8665adc463..0000000000
--- a/src/gui/kernel/qplatformscreenpageflipper.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 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 "qplatformscreenpageflipper.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QPlatformScreenBuffer
- \since 5.0
- \internal
- \preliminary
- \ingroup qpa
-
- \brief The QPlatformScreenBuffer class provides an abstraction for screen buffers.
- */
-QPlatformScreenBuffer::QPlatformScreenBuffer()
- : m_destroyed(false)
- , m_ready(true)
-{
-
-}
-
-QPlatformScreenBuffer::~QPlatformScreenBuffer()
-{
-
-}
-
-bool QPlatformScreenBuffer::isDestroyed() const
-{
- return m_destroyed;
-}
-
-bool QPlatformScreenBuffer::isReady() const
-{
- return m_ready;
-}
-
-void QPlatformScreenBuffer::aboutToBeDisplayed()
-{
-}
-
-void QPlatformScreenBuffer::displayed()
-{
-}
-
-
-/*!
- \class QPlatformScreenPageFlipper
- \since 5.0
- \internal
- \preliminary
- \ingroup qpa
-
- \brief The QPlatformScreenPageFlipper class provides an abstract interface for display buffer swapping
-
- Implement the displayBuffer() function to initiate a buffer swap. The
- bufferDisplayed() signal should be emitted once the buffer is actually displayed on
- the screen. The bufferReleased() signal should be emitted when the buffer data is no
- longer owned by the display hardware.
-*/
-
-QPlatformScreenPageFlipper::QPlatformScreenPageFlipper(QObject *parent)
- :QObject(parent)
-{
-
-}
-
-/*!
- \fn bool QPlatformScreenPageFlipper::displayBuffer(QPlatformScreenBuffer *buffer)
-
- Implemented in subclasses to display \a buffer directly on the screen. Returns \c true
- if it is possible to display the buffer, and \c false if the buffer cannot be displayed.
-
- If this function returns \c true, the buffer must not be modified or destroyed before the
- bufferReleased() signal is emitted. The signal bufferDisplayed() is emitted when the buffer
- is displayed on the screen. The two signals may be emitted in either order.
-
- This function is allowed to block.
-*/
-
-QT_END_NAMESPACE
-
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index d3d3d3c222..d1b1106b28 100644
--- a/src/gui/kernel/qplatformtheme.cpp
+++ b/src/gui/kernel/qplatformtheme.cpp
@@ -508,7 +508,11 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
case MousePressAndHoldInterval:
return QVariant(800);
case MouseDoubleClickDistance:
- return QVariant(5);
+ {
+ bool ok = false;
+ int dist = qgetenv("QT_DBL_CLICK_DIST").toInt(&ok);
+ return QVariant(ok ? dist : 5);
+ }
}
return QVariant();
}
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index 0c58745735..808181d48c 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -100,6 +100,7 @@ public:
, cursor(Qt::ArrowCursor)
, hasCursor(false)
#endif
+ , compositing(false)
{
isWindow = true;
}
@@ -175,6 +176,8 @@ public:
QCursor cursor;
bool hasCursor;
#endif
+
+ bool compositing;
};
diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp
index 43fff1c65a..23861bd778 100644
--- a/src/gui/opengl/qopenglfunctions.cpp
+++ b/src/gui/opengl/qopenglfunctions.cpp
@@ -47,6 +47,10 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
+#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE_EXT
+#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA
+#endif
+
QT_BEGIN_NAMESPACE
/*!
@@ -360,8 +364,6 @@ static int qt_gl_resolve_extensions()
extensions |= QOpenGLExtensions::BGRATextureFormat;
if (extensionMatcher.match("GL_ARB_texture_rectangle"))
extensions |= QOpenGLExtensions::TextureRectangle;
- if (extensionMatcher.match("GL_SGIS_generate_mipmap"))
- extensions |= QOpenGLExtensions::GenerateMipmap;
if (extensionMatcher.match("GL_ARB_texture_compression"))
extensions |= QOpenGLExtensions::TextureCompression;
if (extensionMatcher.match("GL_EXT_texture_compression_s3tc"))
@@ -385,44 +387,51 @@ static int qt_gl_resolve_extensions()
if (format.majorVersion() >= 2)
extensions |= QOpenGLExtensions::GenerateMipmap;
- if (format.majorVersion() >= 3)
+ if (format.majorVersion() >= 3) {
extensions |= QOpenGLExtensions::PackedDepthStencil
| QOpenGLExtensions::Depth24
| QOpenGLExtensions::ElementIndexUint
- | QOpenGLExtensions::MapBufferRange;
+ | QOpenGLExtensions::MapBufferRange
+ | QOpenGLExtensions::FramebufferBlit
+ | QOpenGLExtensions::FramebufferMultisample;
+ } else {
+ // Recognize features by extension name.
+ if (extensionMatcher.match("GL_OES_packed_depth_stencil"))
+ extensions |= QOpenGLExtensions::PackedDepthStencil;
+ if (extensionMatcher.match("GL_OES_depth24"))
+ extensions |= QOpenGLExtensions::Depth24;
+ if (extensionMatcher.match("GL_ANGLE_framebuffer_blit"))
+ extensions |= QOpenGLExtensions::FramebufferBlit;
+ if (extensionMatcher.match("GL_ANGLE_framebuffer_multisample"))
+ extensions |= QOpenGLExtensions::FramebufferMultisample;
+ if (extensionMatcher.match("GL_NV_framebuffer_blit"))
+ extensions |= QOpenGLExtensions::FramebufferBlit;
+ if (extensionMatcher.match("GL_NV_framebuffer_multisample"))
+ extensions |= QOpenGLExtensions::FramebufferMultisample;
+ }
if (extensionMatcher.match("GL_OES_mapbuffer"))
extensions |= QOpenGLExtensions::MapBuffer;
- if (extensionMatcher.match("GL_OES_packed_depth_stencil"))
- extensions |= QOpenGLExtensions::PackedDepthStencil;
if (extensionMatcher.match("GL_OES_element_index_uint"))
extensions |= QOpenGLExtensions::ElementIndexUint;
- if (extensionMatcher.match("GL_OES_depth24"))
- extensions |= QOpenGLExtensions::Depth24;
- // TODO: Consider matching GL_APPLE_texture_format_BGRA8888 as well, but it needs testing.
+ // We don't match GL_APPLE_texture_format_BGRA8888 here because it has different semantics.
if (extensionMatcher.match("GL_IMG_texture_format_BGRA8888") || extensionMatcher.match("GL_EXT_texture_format_BGRA8888"))
extensions |= QOpenGLExtensions::BGRATextureFormat;
- if (extensionMatcher.match("GL_ANGLE_framebuffer_blit"))
- extensions |= QOpenGLExtensions::FramebufferBlit;
- if (extensionMatcher.match("GL_ANGLE_framebuffer_multisample"))
- extensions |= QOpenGLExtensions::FramebufferMultisample;
- if (extensionMatcher.match("GL_NV_framebuffer_blit"))
- extensions |= QOpenGLExtensions::FramebufferBlit;
- if (extensionMatcher.match("GL_NV_framebuffer_multisample"))
- extensions |= QOpenGLExtensions::FramebufferMultisample;
- if (format.majorVersion() >= 3)
- extensions |= QOpenGLExtensions::FramebufferBlit | QOpenGLExtensions::FramebufferMultisample;
} else {
extensions |= QOpenGLExtensions::ElementIndexUint | QOpenGLExtensions::MapBuffer;
- // Recognize features by extension name.
- if (format.majorVersion() >= 3
- || extensionMatcher.match("GL_ARB_framebuffer_object"))
- {
+ if (format.version() >= qMakePair(1, 2))
+ extensions |= QOpenGLExtensions::BGRATextureFormat;
+
+ if (format.version() >= qMakePair(1, 4) || extensionMatcher.match("GL_SGIS_generate_mipmap"))
+ extensions |= QOpenGLExtensions::GenerateMipmap;
+
+ if (format.majorVersion() >= 3 || extensionMatcher.match("GL_ARB_framebuffer_object")) {
extensions |= QOpenGLExtensions::FramebufferMultisample |
QOpenGLExtensions::FramebufferBlit |
QOpenGLExtensions::PackedDepthStencil;
} else {
+ // Recognize features by extension name.
if (extensionMatcher.match("GL_EXT_framebuffer_multisample"))
extensions |= QOpenGLExtensions::FramebufferMultisample;
if (extensionMatcher.match("GL_EXT_framebuffer_blit"))
@@ -430,21 +439,20 @@ static int qt_gl_resolve_extensions()
if (extensionMatcher.match("GL_EXT_packed_depth_stencil"))
extensions |= QOpenGLExtensions::PackedDepthStencil;
}
+
+ if (format.version() >= qMakePair(3, 2) || extensionMatcher.match("GL_ARB_geometry_shader4"))
+ extensions |= QOpenGLExtensions::GeometryShaders;
+
if (extensionMatcher.match("GL_ARB_map_buffer_range"))
extensions |= QOpenGLExtensions::MapBufferRange;
- }
-
- if (format.renderableType() == QSurfaceFormat::OpenGL && format.version() >= qMakePair(3, 2))
- extensions |= QOpenGLExtensions::GeometryShaders;
-#ifndef QT_OPENGL_ES
- if (extensionMatcher.match("GL_EXT_framebuffer_sRGB")) {
- GLboolean srgbCapableFramebuffers = false;
- ctx->functions()->glGetBooleanv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgbCapableFramebuffers);
- if (srgbCapableFramebuffers)
- extensions |= QOpenGLExtensions::SRGBFrameBuffer;
+ if (extensionMatcher.match("GL_EXT_framebuffer_sRGB")) {
+ GLboolean srgbCapableFramebuffers = false;
+ ctx->functions()->glGetBooleanv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &srgbCapableFramebuffers);
+ if (srgbCapableFramebuffers)
+ extensions |= QOpenGLExtensions::SRGBFrameBuffer;
+ }
}
-#endif
return extensions;
}
diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp
index 6e85e5eb4b..8c0b3997fe 100644
--- a/src/gui/opengl/qopenglshaderprogram.cpp
+++ b/src/gui/opengl/qopenglshaderprogram.cpp
@@ -278,16 +278,27 @@ bool QOpenGLShaderPrivate::compile(QOpenGLShader *q)
"Fragment",
"Vertex",
"Geometry",
+ "Tessellation Control",
+ "Tessellation Evaluation",
+ "Compute",
""
};
- const char *type = types[3];
- if (shaderType == QOpenGLShader::Fragment)
- type = types[0];
- else if (shaderType == QOpenGLShader::Vertex)
- type = types[1];
- else if (shaderType == QOpenGLShader::Geometry)
- type = types[2];
+ const char *type = types[6];
+ switch (shaderType) {
+ case QOpenGLShader::Fragment:
+ type = types[0]; break;
+ case QOpenGLShader::Vertex:
+ type = types[1]; break;
+ case QOpenGLShader::Geometry:
+ type = types[2]; break;
+ case QOpenGLShader::TessellationControl:
+ type = types[3]; break;
+ case QOpenGLShader::TessellationEvaluation:
+ type = types[4]; break;
+ case QOpenGLShader::Compute:
+ type = types[5]; break;
+ }
// Get info and source code lengths
GLint infoLogLength = 0;
diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp
index ef548188c8..ebe0429290 100644
--- a/src/gui/opengl/qopengltextureblitter.cpp
+++ b/src/gui/opengl/qopengltextureblitter.cpp
@@ -248,9 +248,6 @@ bool QOpenGLTextureBlitter::create()
Q_D(QOpenGLTextureBlitter);
- d->vao->create();
- d->vao->bind();
-
if (d->program)
return true;
@@ -273,6 +270,9 @@ bool QOpenGLTextureBlitter::create()
d->program->bind();
+ // Create and bind the VAO, if supported.
+ QOpenGLVertexArrayObject::Binder vaoBinder(d->vao.data());
+
d->vertexBuffer.create();
d->vertexBuffer.bind();
d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data));
@@ -292,8 +292,6 @@ bool QOpenGLTextureBlitter::create()
d->program->setUniformValue(d->swizzleUniformPos,false);
- d->vao->release();
-
return true;
}
@@ -316,7 +314,8 @@ void QOpenGLTextureBlitter::bind()
{
Q_D(QOpenGLTextureBlitter);
- d->vao->bind();
+ if (d->vao->isCreated())
+ d->vao->bind();
d->program->bind();
@@ -335,7 +334,8 @@ void QOpenGLTextureBlitter::release()
{
Q_D(QOpenGLTextureBlitter);
d->program->release();
- d->vao->release();
+ if (d->vao->isCreated())
+ d->vao->release();
}
void QOpenGLTextureBlitter::setSwizzleRB(bool swizzle)
diff --git a/src/gui/opengl/qopengltexturehelper.cpp b/src/gui/opengl/qopengltexturehelper.cpp
index 27aece8eca..9cb5e8798e 100644
--- a/src/gui/opengl/qopengltexturehelper.cpp
+++ b/src/gui/opengl/qopengltexturehelper.cpp
@@ -164,6 +164,60 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context)
TexSubImage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(GetProcAddress(handle, QByteArrayLiteral("glTexSubImage2D")));
TexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLenum , const GLvoid *)>(GetProcAddress(handle, QByteArrayLiteral("glTexSubImage1D")));
+#elif defined(QT_OPENGL_ES_2)
+ // Here we are targeting OpenGL ES 2.0+ only. This is likely using EGL, where,
+ // similarly to WGL, non-extension functions (i.e. any function that is part of the
+ // GLES spec) *may* not be queried via eglGetProcAddress.
+
+ // OpenGL 1.0
+ GetIntegerv = ::glGetIntegerv;
+ GetBooleanv = ::glGetBooleanv;
+ PixelStorei = ::glPixelStorei;
+ GetTexLevelParameteriv = 0;
+ GetTexLevelParameterfv = 0;
+ GetTexParameteriv = ::glGetTexParameteriv;
+ GetTexParameterfv = ::glGetTexParameterfv;
+ GetTexImage = 0;
+ TexImage2D = ::glTexImage2D;
+ TexImage1D = 0;
+ TexParameteriv = ::glTexParameteriv;
+ TexParameteri = ::glTexParameteri;
+ TexParameterfv = ::glTexParameterfv;
+ TexParameterf = ::glTexParameterf;
+
+ // OpenGL 1.1
+ GenTextures = ::glGenTextures;
+ DeleteTextures = ::glDeleteTextures;
+ BindTexture = ::glBindTexture;
+ TexSubImage2D = ::glTexSubImage2D;
+ TexSubImage1D = 0;
+
+ // OpenGL 1.3
+ GetCompressedTexImage = 0;
+ CompressedTexSubImage1D = 0;
+ CompressedTexSubImage2D = ::glCompressedTexSubImage2D;
+ CompressedTexImage1D = 0;
+ CompressedTexImage2D = ::glCompressedTexImage2D;
+ ActiveTexture = ::glActiveTexture;
+
+ // OpenGL 3.0
+ GenerateMipmap = ::glGenerateMipmap;
+
+ // OpenGL 3.2
+ TexImage3DMultisample = 0;
+ TexImage2DMultisample = 0;
+
+ // OpenGL 4.2
+ TexStorage3D = 0;
+ TexStorage2D = 0;
+ TexStorage1D = 0;
+
+ // OpenGL 4.3
+ TexStorage3DMultisample = 0;
+ TexStorage2DMultisample = 0;
+ TexBufferRange = 0;
+ TextureView = 0;
+
#else
// OpenGL 1.0
@@ -196,6 +250,13 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context)
CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3DOES")));
CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3DOES")));
} else {
+#ifdef QT_OPENGL_ES_3
+ // OpenGL ES 3.0+ has glTexImage3D.
+ TexImage3D = ::glTexImage3D;
+ TexSubImage3D = ::glTexSubImage3D;
+ CompressedTexImage3D = ::glCompressedTexImage3D;
+ CompressedTexSubImage3D = ::glCompressedTexSubImage3D;
+#else
// OpenGL 1.2
TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexImage3D")));
TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3D")));
@@ -203,8 +264,10 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context)
// OpenGL 1.3
CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3D")));
CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3D")));
+#endif
}
+#ifndef QT_OPENGL_ES_2
// OpenGL 1.3
GetCompressedTexImage = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glGetCompressedTexImage")));
CompressedTexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage1D")));
@@ -230,6 +293,7 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context)
TexStorage2DMultisample = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLenum , GLsizei , GLsizei , GLboolean )>(context->getProcAddress(QByteArrayLiteral("glTexStorage2DMultisample")));
TexBufferRange = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLenum , GLuint , GLintptr , GLsizeiptr )>(context->getProcAddress(QByteArrayLiteral("glTexBufferRange")));
TextureView = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint , GLenum , GLuint , GLuint , GLuint , GLuint )>(context->getProcAddress(QByteArrayLiteral("glTextureView")));
+#endif
}
void QOpenGLTextureHelper::dsa_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param)
diff --git a/src/gui/opengl/qopenglversionfunctions.cpp b/src/gui/opengl/qopenglversionfunctions.cpp
index 3335a88cbb..f5ce8865a8 100644
--- a/src/gui/opengl/qopenglversionfunctions.cpp
+++ b/src/gui/opengl/qopenglversionfunctions.cpp
@@ -98,8 +98,10 @@ void QAbstractOpenGLFunctionsPrivate::removeFunctionsBackend(QOpenGLContext *con
Qt now provides a family of classes which all inherit from
QAbstractOpenGLFunctions which expose every core OpenGL function by way of a
corresponding member function. There is a class for every valid combination
- of OpenGL version and profile. Each class follows the naming convention
- QOpenGLFunctions_<MAJOR VERSION>_<MINOR VERSION>[_PROFILE].
+ of OpenGL version and profile. Each class follows the naming convention:
+ \badcode
+ QOpenGLFunctions_<MAJOR VERSION>_<MINOR VERSION>[_PROFILE]
+ \endcode
For OpenGL versions 1.0 through to 3.0 there are no profiles, leading to the
classes:
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 2e340219b9..914691375a 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -921,7 +921,7 @@ void QRasterPaintEngine::renderHintsChanged()
bool was_aa = s->flags.antialiased;
bool was_bilinear = s->flags.bilinear;
- s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
+ s->flags.antialiased = bool(s->renderHints & (QPainter::Antialiasing | QPainter::HighQualityAntialiasing));
s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting);
@@ -2726,7 +2726,7 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
scanline += bpl;
}
} else { // 32-bit alpha...
- uint *sl = (uint *) src;
+ uint *sl = (uint *) scanline;
for (int y = y0; y < y1; ++y) {
for (int x = x0; x < x1; ) {
// Skip those with 0 coverage
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 0e03a0194a..5d046caaa4 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -1106,6 +1106,11 @@ void QPainterPrivate::updateState(QPainterState *newState)
\li \inlineimage qpainter-pathstroking.png
\endtable
+ Text drawing is done using drawText(). When you need
+ fine-grained positioning, boundingRect() tells you where a given
+ drawText() command will draw.
+
+ \section1 Drawing Pixmaps and Images
There are functions to draw pixmaps/images, namely drawPixmap(),
drawImage() and drawTiledPixmap(). Both drawPixmap() and drawImage()
@@ -1113,15 +1118,25 @@ void QPainterPrivate::updateState(QPainterState *newState)
on-screen while drawImage() may be faster on a QPrinter or other
devices.
- Text drawing is done using drawText(). When you need
- fine-grained positioning, boundingRect() tells you where a given
- drawText() command will draw.
-
There is a drawPicture() function that draws the contents of an
entire QPicture. The drawPicture() function is the only function
that disregards all the painter's settings as QPicture has its own
settings.
+ \section2 Drawing High Resolution Versions of Pixmaps and Images
+
+ High resolution versions of pixmaps have a \e{device pixel ratio} value larger
+ than 1 (see QImageReader, QPixmap::devicePixelRatio()). Should it match the value
+ of the underlying QPaintDevice, it is drawn directly onto the device with no
+ additional transformation applied.
+
+ This is for example the case when drawing a QPixmap of 64x64 pixels size with
+ a device pixel ratio of 2 onto a high DPI screen which also has
+ a device pixel ratio of 2. Note that the pixmap is then effectively 32x32
+ pixels in \e{user space}. Code paths in Qt that calculate layout geometry
+ based on the pixmap size will use this size. The net effect of this is that
+ the pixmap is displayed as high DPI pixmap rather than a large pixmap.
+
\section1 Rendering Quality
To get the optimal rendering result using QPainter, you should use
@@ -5024,6 +5039,8 @@ static inline QPointF roundInDeviceCoordinates(const QPointF &p, const QTransfor
into the given \a target in the paint device.
\note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
+ \note See \l{Drawing High Resolution Versions of Pixmaps and Images} on how this is affected
+ by QPixmap::devicePixelRatio().
\table 100%
\row
@@ -5038,7 +5055,7 @@ static inline QPointF roundInDeviceCoordinates(const QPointF &p, const QTransfor
transparent. Drawing bitmaps with gradient or texture colors is
not supported.
- \sa drawImage()
+ \sa drawImage(), QPixmap::devicePixelRatio()
*/
void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
{
@@ -7694,6 +7711,8 @@ void QPainterState::init(QPainter *p) {
into the \a target rectangle in the paint device.
\note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
+ \note See \l{Drawing High Resolution Versions of Pixmaps and Images} on how this is affected
+ by QImage::devicePixelRatio().
If the image needs to be modified to fit in a lower-resolution
result (e.g. converting from 32-bit to 8-bit), use the \a flags to
@@ -7705,7 +7724,7 @@ void QPainterState::init(QPainter *p) {
\snippet code/src_gui_painting_qpainter.cpp 20
\endtable
- \sa drawPixmap()
+ \sa drawPixmap(), QImage::devicePixelRatio()
*/
/*!
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index 66a56ac32f..407e032027 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -62,6 +62,7 @@ public:
QPlatformBackingStorePrivate(QWindow *w)
: window(w)
#ifndef QT_NO_OPENGL
+ , textureId(0)
, blitter(0)
#endif
{
@@ -276,7 +277,6 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
if (d_ptr->needsSwizzle)
d_ptr->blitter->setSwizzleRB(false);
}
- funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
for (int i = 0; i < textures->count(); ++i) {
@@ -287,6 +287,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
}
}
+ funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
funcs->glDisable(GL_BLEND);
d_ptr->blitter->release();
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 20c62fdd9d..eb197378ad 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -1072,28 +1072,12 @@ struct QRegionPrivate {
int innerArea;
inline QRegionPrivate() : numRects(0), innerArea(-1) {}
- inline QRegionPrivate(const QRect &r) {
- numRects = 1;
- extents = r;
- innerRect = r;
- innerArea = r.width() * r.height();
- }
-
- inline QRegionPrivate(const QRegionPrivate &r) {
- rects = r.rects;
- numRects = r.numRects;
- extents = r.extents;
- innerRect = r.innerRect;
- innerArea = r.innerArea;
- }
-
- inline QRegionPrivate &operator=(const QRegionPrivate &r) {
- rects = r.rects;
- numRects = r.numRects;
- extents = r.extents;
- innerRect = r.innerRect;
- innerArea = r.innerArea;
- return *this;
+ inline QRegionPrivate(const QRect &r)
+ : numRects(1),
+ extents(r),
+ innerRect(r),
+ innerArea(r.width() * r.height())
+ {
}
void intersect(const QRect &r);
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index eef316b039..cb3cb34d27 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -826,7 +826,7 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
}
if (set && set->outline_drawing)
- load_flags = FT_LOAD_NO_BITMAP;
+ load_flags |= FT_LOAD_NO_BITMAP;
if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing))
load_flags |= FT_LOAD_NO_HINTING;
diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp
index e9ffa68591..5dc81d241d 100644
--- a/src/gui/text/qplatformfontdatabase.cpp
+++ b/src/gui/text/qplatformfontdatabase.cpp
@@ -402,6 +402,16 @@ QString QPlatformFontDatabase::fontDir() const
}
/*!
+ Returns true if the font family is private. For any given family name,
+ the result is platform dependent.
+*/
+bool QPlatformFontDatabase::isPrivateFontFamily(const QString &family) const
+{
+ Q_UNUSED(family);
+ return false;
+}
+
+/*!
Returns the default system font.
\sa QGuiApplication::font()
diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h
index b200cf0e58..46ef5c0f46 100644
--- a/src/gui/text/qplatformfontdatabase.h
+++ b/src/gui/text/qplatformfontdatabase.h
@@ -110,6 +110,7 @@ public:
virtual QString fontDir() const;
virtual QFont defaultFont() const;
+ virtual bool isPrivateFontFamily(const QString &family) const;
virtual QString resolveFontFamilyAlias(const QString &family) const;
virtual bool fontsAlwaysScalable() const;
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index bead45ab83..e572745d51 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -2008,6 +2008,9 @@ static int qt_timeout_value(int msecs, int elapsed)
\note Multiple calls to this functions do not accumulate the time.
If the function times out, the connecting process will be aborted.
+ \note This function may fail randomly on Windows. Consider using the event
+ loop and the connected() signal if your software will run on Windows.
+
\sa connectToHost(), connected()
*/
bool QAbstractSocket::waitForConnected(int msecs)
@@ -2107,6 +2110,9 @@ bool QAbstractSocket::waitForConnected(int msecs)
there is new data available for reading; otherwise it returns \c false
(if an error occurred or the operation timed out).
+ \note This function may fail randomly on Windows. Consider using the event
+ loop and the readyRead() signal if your software will run on Windows.
+
\sa waitForBytesWritten()
*/
bool QAbstractSocket::waitForReadyRead(int msecs)
@@ -2166,6 +2172,20 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
}
/*! \reimp
+
+ This function blocks until at least one byte has been written on the socket
+ and the \l{QIODevice::}{bytesWritten()} signal has been emitted. The
+ function will timeout after \a msecs milliseconds; the default timeout is
+ 30000 milliseconds.
+
+ The function returns \c true if the bytesWritten() signal is emitted;
+ otherwise it returns \c false (if an error occurred or the operation timed
+ out).
+
+ \note This function may fail randomly on Windows. Consider using the event
+ loop and the bytesWritten() signal if your software will run on Windows.
+
+ \sa waitForReadyRead()
*/
bool QAbstractSocket::waitForBytesWritten(int msecs)
{
@@ -2247,6 +2267,9 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
If msecs is -1, this function will not time out.
+ \note This function may fail randomly on Windows. Consider using the event
+ loop and the disconnected() signal if your software will run on Windows.
+
\sa disconnectFromHost(), close()
*/
bool QAbstractSocket::waitForDisconnected(int msecs)
diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp
index ab6c2a6590..2ea6d6e015 100644
--- a/src/network/socket/qnativesocketengine_winrt.cpp
+++ b/src/network/socket/qnativesocketengine_winrt.cpp
@@ -51,8 +51,14 @@
#include <qelapsedtimer.h>
#include <qthread.h>
#include <qabstracteventdispatcher.h>
+#include <qfunctions_winrt.h>
-#include <private/qeventdispatcher_winrt_p.h>
+#include <private/qthread_p.h>
+#include <private/qabstractsocket_p.h>
+
+#ifndef QT_NO_SSL
+#include <QSslSocket>
+#endif
#include <wrl.h>
#include <windows.foundation.collections.h>
@@ -124,6 +130,20 @@ struct SocketHandler
Q_GLOBAL_STATIC(SocketHandler, gSocketHandler)
+struct SocketGlobal
+{
+ SocketGlobal()
+ {
+ HRESULT hr;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ &bufferFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ ComPtr<IBufferFactory> bufferFactory;
+};
+Q_GLOBAL_STATIC(SocketGlobal, g)
+
static inline QString qt_QStringFromHString(const HString &string)
{
UINT32 length;
@@ -131,60 +151,7 @@ static inline QString qt_QStringFromHString(const HString &string)
return QString::fromWCharArray(rawString, length);
}
-#define READ_BUFFER_SIZE 8192
-
-class ByteArrayBuffer : public Microsoft::WRL::RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>,
- IBuffer, Windows::Storage::Streams::IBufferByteAccess>
-{
-public:
- ByteArrayBuffer(int size) : m_bytes(size, Qt::Uninitialized), m_length(0)
- {
- }
-
- ByteArrayBuffer(const char *data, int size) : m_bytes(data, size), m_length(size)
- {
- }
-
- HRESULT __stdcall Buffer(byte **value)
- {
- *value = reinterpret_cast<byte *>(m_bytes.data());
- return S_OK;
- }
-
- HRESULT __stdcall get_Capacity(UINT32 *value)
- {
- *value = m_bytes.size();
- return S_OK;
- }
-
- HRESULT __stdcall get_Length(UINT32 *value)
- {
- *value = m_length;
- return S_OK;
- }
-
- HRESULT __stdcall put_Length(UINT32 value)
- {
- Q_ASSERT(value <= UINT32(m_bytes.size()));
- m_length = value;
- return S_OK;
- }
-
- ComPtr<IInputStream> inputStream() const
- {
- return m_stream;
- }
-
- void setInputStream(ComPtr<IInputStream> stream)
- {
- m_stream = stream;
- }
-
-private:
- QByteArray m_bytes;
- UINT32 m_length;
- ComPtr<IInputStream> m_stream;
-};
+#define READ_BUFFER_SIZE 65536
template <typename T>
static AsyncStatus opStatus(const ComPtr<T> &op)
@@ -207,6 +174,14 @@ static AsyncStatus opStatus(const ComPtr<T> &op)
QNativeSocketEngine::QNativeSocketEngine(QObject *parent)
: QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent)
{
+#ifndef QT_NO_SSL
+ Q_D(QNativeSocketEngine);
+ Q_ASSERT(parent);
+ d->sslSocket = qobject_cast<QSslSocket *>(parent->parent());
+#else
+ d->sslSocket = Q_NULLPTR;
+#endif
+
connect(this, SIGNAL(connectionReady()), SLOT(connectionNotification()), Qt::QueuedConnection);
connect(this, SIGNAL(readReady()), SLOT(readNotification()), Qt::QueuedConnection);
connect(this, SIGNAL(writeReady()), SLOT(writeNotification()), Qt::QueuedConnection);
@@ -239,16 +214,14 @@ bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::
if (isValid())
close();
- d->socketDescriptor = socketDescriptor;
-
// Currently, only TCP sockets are initialized this way.
- SocketHandler *handler = gSocketHandler();
- d->tcp = handler->pendingTcpSockets.take(socketDescriptor);
+ d->socketDescriptor = qintptr(gSocketHandler->pendingTcpSockets.take(socketDescriptor));
d->socketType = QAbstractSocket::TcpSocket;
- if (!d->tcp || !d->fetchConnectionParameters()) {
+ if (!d->socketDescriptor || !d->fetchConnectionParameters()) {
d->setError(QAbstractSocket::UnsupportedSocketOperationError,
d->InvalidSocketErrorString);
+ d->socketDescriptor = -1;
return false;
}
@@ -287,68 +260,23 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
return false;
}
- ComPtr<IAsyncAction> op;
const QString portString = QString::number(port);
HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
HRESULT hr = E_FAIL;
if (d->socketType == QAbstractSocket::TcpSocket)
- hr = d->tcp->ConnectAsync(remoteHost.Get(), portReference.Get(), &op);
+ hr = d->tcpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp);
else if (d->socketType == QAbstractSocket::UdpSocket)
- hr = d->udp->ConnectAsync(remoteHost.Get(), portReference.Get(), &op);
+ hr = d->udpSocket()->ConnectAsync(remoteHost.Get(), portReference.Get(), &d->connectOp);
if (FAILED(hr)) {
qWarning("QNativeSocketEnginePrivate::nativeConnect:: Could not obtain connect action");
return false;
}
-
- hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(
- d, &QNativeSocketEnginePrivate::handleConnectToHost).Get());
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Unable to set host connection callback.");
- return false;
- }
d->socketState = QAbstractSocket::ConnectingState;
- while (opStatus(op) == Started)
- d->eventLoop.processEvents();
-
- AsyncStatus status = opStatus(op);
- if (status == Error || status == Canceled)
- return false;
+ hr = d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
+ d, &QNativeSocketEnginePrivate::handleConnectToHost).Get());
+ Q_ASSERT_SUCCEEDED(hr);
- if (hr == 0x8007274c) { // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
- d->setError(QAbstractSocket::NetworkError, d->ConnectionTimeOutErrorString);
- d->socketState = QAbstractSocket::UnconnectedState;
- return false;
- }
- if (hr == 0x8007274d) { // No connection could be made because the target machine actively refused it.
- d->setError(QAbstractSocket::ConnectionRefusedError, d->ConnectionRefusedErrorString);
- d->socketState = QAbstractSocket::UnconnectedState;
- return false;
- }
- if (FAILED(hr)) {
- d->setError(QAbstractSocket::UnknownSocketError, d->UnknownSocketErrorString);
- d->socketState = QAbstractSocket::UnconnectedState;
- return false;
- }
-
- if (d->socketType == QAbstractSocket::TcpSocket) {
- IInputStream *stream;
- hr = d->tcp->get_InputStream(&stream);
- if (FAILED(hr))
- return false;
- ByteArrayBuffer *buffer = static_cast<ByteArrayBuffer *>(d->readBuffer.Get());
- buffer->setInputStream(stream);
- ComPtr<IAsyncBufferOperation> op;
- hr = stream->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
- if (FAILED(hr))
- return false;
- hr = op->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to set socket read callback.");
- return false;
- }
- }
- d->socketState = QAbstractSocket::ConnectedState;
- return true;
+ return d->socketState == QAbstractSocket::ConnectedState;
}
bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
@@ -385,7 +313,7 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
return false;
}
} else if (d->socketType == QAbstractSocket::UdpSocket) {
- hr = d->udp->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
+ hr = d->udpSocket()->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Unable to bind socket."); // ### Set error message
return false;
@@ -447,13 +375,16 @@ int QNativeSocketEngine::accept()
if (d->socketType == QAbstractSocket::TcpSocket) {
IStreamSocket *socket = d->pendingConnections.takeFirst();
- IInputStream *stream;
- socket->get_InputStream(&stream);
- // TODO: delete buffer and stream on socket close
- ByteArrayBuffer *buffer = static_cast<ByteArrayBuffer *>(d->readBuffer.Get());
- buffer->setInputStream(stream);
+ HRESULT hr;
+ ComPtr<IBuffer> buffer;
+ hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IInputStream> stream;
+ hr = socket->get_InputStream(&stream);
+ Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsyncBufferOperation> op;
- HRESULT hr = stream->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
+ hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Faild to read from the socket buffer.");
return -1;
@@ -476,12 +407,25 @@ int QNativeSocketEngine::accept()
void QNativeSocketEngine::close()
{
Q_D(QNativeSocketEngine);
+
+ if (d->connectOp) {
+ ComPtr<IAsyncInfo> info;
+ d->connectOp.As(&info);
+ if (info) {
+ info->Cancel();
+ info->Close();
+ }
+ }
+
if (d->socketDescriptor != -1) {
ComPtr<IClosable> socket;
- if (d->socketType == QAbstractSocket::TcpSocket && d->tcp)
- d->tcp.As(&socket);
- else if (d->socketType == QAbstractSocket::UdpSocket && d->udp)
- d->udp.As(&socket);
+ if (d->socketType == QAbstractSocket::TcpSocket) {
+ d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
+ d->tcpSocket()->Release();
+ } else if (d->socketType == QAbstractSocket::UdpSocket) {
+ d->udpSocket()->QueryInterface(IID_PPV_ARGS(&socket));
+ d->udpSocket()->Release();
+ }
if (socket) {
d->closingDown = true;
@@ -549,42 +493,40 @@ qint64 QNativeSocketEngine::read(char *data, qint64 maxlen)
qint64 QNativeSocketEngine::write(const char *data, qint64 len)
{
Q_D(QNativeSocketEngine);
+ if (!isValid())
+ return -1;
+
HRESULT hr = E_FAIL;
ComPtr<IOutputStream> stream;
if (d->socketType == QAbstractSocket::TcpSocket)
- hr = d->tcp->get_OutputStream(&stream);
+ hr = d->tcpSocket()->get_OutputStream(&stream);
else if (d->socketType == QAbstractSocket::UdpSocket)
- hr = d->udp->get_OutputStream(&stream);
+ hr = d->udpSocket()->get_OutputStream(&stream);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get output stream to socket.");
return -1;
}
- ComPtr<ByteArrayBuffer> buffer = Make<ByteArrayBuffer>(data, len);
+ ComPtr<IBuffer> buffer;
+ hr = g->bufferFactory->Create(len, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = buffer->put_Length(len);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = buffer.As(&byteArrayAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ byte *bytes;
+ hr = byteArrayAccess->Buffer(&bytes);
+ Q_ASSERT_SUCCEEDED(hr);
+ memcpy(bytes, data, len);
ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
hr = stream->WriteAsync(buffer.Get(), &op);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to write to socket.");
- return -1;
- }
- hr = op->put_Completed(Callback<IAsyncOperationWithProgressCompletedHandler<UINT32, UINT32>>(
- d, &QNativeSocketEnginePrivate::handleWriteCompleted).Get());
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to set socket write callback.");
- return -1;
- }
-
- while (opStatus(op) == Started)
- d->eventLoop.processEvents();
-
- AsyncStatus status = opStatus(op);
- if (status == Error || status == Canceled)
- return -1;
+ RETURN_IF_FAILED("Failed to write to stream", return -1);
UINT32 bytesWritten;
- hr = op->GetResults(&bytesWritten);
+ hr = QWinRTFunctions::await(op, &bytesWritten);
if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get written socket length.");
+ d->setError(QAbstractSocket::SocketAccessError, QNativeSocketEnginePrivate::AccessErrorString);
return -1;
}
@@ -655,7 +597,7 @@ qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QH
ComPtr<IOutputStream> stream;
const QString portString = QString::number(port);
HStringReference portRef(reinterpret_cast<LPCWSTR>(portString.utf16()));
- if (FAILED(d->udp->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation)))
+ if (FAILED(d->udpSocket()->GetOutputStreamAsync(remoteHost.Get(), portRef.Get(), &streamOperation)))
return -1;
HRESULT hr;
while (hr = streamOperation->GetResults(&stream) == E_ILLEGAL_METHOD_CALL)
@@ -825,29 +767,50 @@ void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable)
d->notifyOnException = enable;
}
+void QNativeSocketEngine::establishRead()
+{
+ Q_D(QNativeSocketEngine);
+
+ HRESULT hr;
+ ComPtr<IInputStream> stream;
+ hr = d->tcpSocket()->get_InputStream(&stream);
+ RETURN_VOID_IF_FAILED("Failed to get socket input stream");
+
+ ComPtr<IBuffer> buffer;
+ hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncBufferOperation> op;
+ hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
+ RETURN_VOID_IF_FAILED("Failed to initiate socket read");
+ hr = op->put_Completed(Callback<SocketReadCompletedHandler>(d, &QNativeSocketEnginePrivate::handleReadyRead).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol)
{
Q_UNUSED(socketProtocol);
- SocketHandler *handler = gSocketHandler();
switch (socketType) {
case QAbstractSocket::TcpSocket: {
- HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &tcp);
+ ComPtr<IStreamSocket> socket;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &socket);
if (FAILED(hr)) {
qWarning("Failed to create StreamSocket instance");
return false;
}
- socketDescriptor = ++handler->socketCount;
+ socketDescriptor = qintptr(socket.Detach());
return true;
}
case QAbstractSocket::UdpSocket: {
- HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &udp);
+ ComPtr<IDatagramSocket> socket;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &socket);
if (FAILED(hr)) {
qWarning("Failed to create stream socket");
return false;
}
EventRegistrationToken token;
- udp->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
- socketDescriptor = ++handler->socketCount;
+ udpSocket()->add_MessageReceived(Callback<DatagramReceivedHandler>(this, &QNativeSocketEnginePrivate::handleNewDatagram).Get(), &token);
+ socketDescriptor = qintptr(socket.Detach());
return true;
}
default:
@@ -865,8 +828,6 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate()
, closingDown(false)
, socketDescriptor(-1)
{
- ComPtr<ByteArrayBuffer> buffer = Make<ByteArrayBuffer>(READ_BUFFER_SIZE);
- readBuffer = buffer;
}
QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate()
@@ -980,7 +941,7 @@ int QNativeSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt)
{
ComPtr<IStreamSocketControl> control;
if (socketType == QAbstractSocket::TcpSocket) {
- if (FAILED(tcp->get_Control(&control))) {
+ if (FAILED(tcpSocket()->get_Control(&control))) {
qWarning("QNativeSocketEnginePrivate::option: Could not obtain socket control");
return -1;
}
@@ -1036,7 +997,7 @@ bool QNativeSocketEnginePrivate::setOption(QAbstractSocketEngine::SocketOption o
{
ComPtr<IStreamSocketControl> control;
if (socketType == QAbstractSocket::TcpSocket) {
- if (FAILED(tcp->get_Control(&control))) {
+ if (FAILED(tcpSocket()->get_Control(&control))) {
qWarning("QNativeSocketEnginePrivate::setOption: Could not obtain socket control");
return false;
}
@@ -1100,7 +1061,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
ComPtr<IHostName> hostName;
HString tmpHString;
ComPtr<IStreamSocketInformation> info;
- if (FAILED(tcp->get_Information(&info))) {
+ if (FAILED(tcpSocket()->get_Information(&info))) {
qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket info");
return false;
}
@@ -1129,7 +1090,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
ComPtr<IHostName> hostName;
HString tmpHString;
ComPtr<IDatagramSocketInformation> info;
- if (FAILED(udp->get_Information(&info))) {
+ if (FAILED(udpSocket()->get_Information(&info))) {
qWarning("QNativeSocketEnginePrivate::fetchConnectionParameters: Could not obtain socket information");
return false;
}
@@ -1169,8 +1130,46 @@ HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener
return S_OK;
}
-HRESULT QNativeSocketEnginePrivate::handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus)
+HRESULT QNativeSocketEnginePrivate::handleConnectToHost(IAsyncAction *action, AsyncStatus)
{
+ Q_Q(QNativeSocketEngine);
+
+ HRESULT hr = action->GetResults();
+ if (wasDeleted || !connectOp) // Protect against a late callback
+ return S_OK;
+
+ connectOp.Reset();
+ switch (hr) {
+ case 0x8007274c: // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
+ setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
+ case 0x80072751: // A socket operation was attempted to an unreachable host.
+ setError(QAbstractSocket::HostNotFoundError, HostUnreachableErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
+ case 0x8007274d: // No connection could be made because the target machine actively refused it.
+ setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
+ default:
+ if (FAILED(hr)) {
+ setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString);
+ socketState = QAbstractSocket::UnconnectedState;
+ return S_OK;
+ }
+ break;
+ }
+
+ socketState = QAbstractSocket::ConnectedState;
+ emit q->connectionReady();
+
+ // Delay the reader so that the SSL socket can upgrade
+ if (sslSocket)
+ q->connect(sslSocket, SIGNAL(encrypted()), SLOT(establishRead()));
+ else
+ q->establishRead();
+
return S_OK;
}
@@ -1183,22 +1182,25 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
if (status == Error || status == Canceled)
return S_OK;
- ByteArrayBuffer *buffer = 0;
- HRESULT hr = asyncInfo->GetResults((IBuffer **)&buffer);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get ready read results.");
- return S_OK;
- }
- UINT32 len;
- buffer->get_Length(&len);
- if (!len) {
+ ComPtr<IBuffer> buffer;
+ HRESULT hr = asyncInfo->GetResults(&buffer);
+ RETURN_OK_IF_FAILED("Failed to get read results buffer");
+
+ UINT32 bufferLength;
+ hr = buffer->get_Length(&bufferLength);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (!bufferLength) {
if (q->isReadNotificationEnabled())
emit q->readReady();
return S_OK;
}
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
+ hr = buffer.As(&byteArrayAccess);
+ Q_ASSERT_SUCCEEDED(hr);
byte *data;
- buffer->Buffer(&data);
+ hr = byteArrayAccess->Buffer(&data);
+ Q_ASSERT_SUCCEEDED(hr);
readMutex.lock();
if (readBytes.atEnd()) // Everything has been read; the buffer is safe to reset
@@ -1208,15 +1210,25 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
qint64 readPos = readBytes.pos();
readBytes.seek(readBytes.size());
Q_ASSERT(readBytes.atEnd());
- readBytes.write(reinterpret_cast<const char*>(data), qint64(len));
+ readBytes.write(reinterpret_cast<const char*>(data), qint64(bufferLength));
readBytes.seek(readPos);
readMutex.unlock();
if (q->isReadNotificationEnabled())
emit q->readReady();
+ ComPtr<IInputStream> stream;
+ hr = tcpSocket()->get_InputStream(&stream);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // Reuse the stream buffer
+ hr = buffer->get_Capacity(&bufferLength);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = buffer->put_Length(0);
+ Q_ASSERT_SUCCEEDED(hr);
+
ComPtr<IAsyncBufferOperation> op;
- hr = buffer->inputStream()->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op);
+ hr = stream->ReadAsync(buffer.Get(), bufferLength, InputStreamOptions_Partial, &op);
if (FAILED(hr)) {
qErrnoWarning(hr, "Could not read into socket stream buffer.");
return S_OK;
@@ -1229,28 +1241,6 @@ HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *async
return S_OK;
}
-HRESULT QNativeSocketEnginePrivate::handleWriteCompleted(IAsyncOperationWithProgress<UINT32, UINT32> *op, AsyncStatus status)
-{
- if (status == Error) {
- ComPtr<IAsyncInfo> info;
- HRESULT hr = op->QueryInterface(IID_PPV_ARGS(&info));
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to cast operation.");
- return S_OK;
- }
- HRESULT errorCode;
- hr = info->get_ErrorCode(&errorCode);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get error code.");
- return S_OK;
- }
- qErrnoWarning(errorCode, "A socket error occurred.");
- return S_OK;
- }
-
- return S_OK;
-}
-
HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, IDatagramSocketMessageReceivedEventArgs *args)
{
Q_Q(QNativeSocketEngine);
diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h
index bf23faeb45..1d84c93f0a 100644
--- a/src/network/socket/qnativesocketengine_winrt_p.h
+++ b/src/network/socket/qnativesocketengine_winrt_p.h
@@ -134,6 +134,9 @@ signals:
void readReady();
void writeReady();
+private slots:
+ void establishRead();
+
private:
Q_DECLARE_PRIVATE(QNativeSocketEngine)
Q_DISABLE_COPY(QNativeSocketEngine)
@@ -192,17 +195,21 @@ public:
bool checkProxy(const QHostAddress &address);
bool fetchConnectionParameters();
+
private:
- Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket> tcp;
- Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IDatagramSocket> udp;
+ inline ABI::Windows::Networking::Sockets::IStreamSocket *tcpSocket() const
+ { return reinterpret_cast<ABI::Windows::Networking::Sockets::IStreamSocket *>(socketDescriptor); }
+ inline ABI::Windows::Networking::Sockets::IDatagramSocket *udpSocket() const
+ { return reinterpret_cast<ABI::Windows::Networking::Sockets::IDatagramSocket *>(socketDescriptor); }
Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> tcpListener;
- Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> readBuffer;
+ Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> connectOp;
QBuffer readBytes;
QMutex readMutex;
QList<ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs *> pendingDatagrams;
QList<ABI::Windows::Networking::Sockets::IStreamSocket *> pendingConnections;
QList<ABI::Windows::Networking::Sockets::IStreamSocket *> currentConnections;
QEventLoop eventLoop;
+ QAbstractSocket *sslSocket;
HRESULT handleBindCompleted(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus);
HRESULT handleNewDatagram(ABI::Windows::Networking::Sockets::IDatagramSocket *socket,
@@ -211,7 +218,6 @@ private:
ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args);
HRESULT handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus);
HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32> *asyncInfo, ABI::Windows::Foundation::AsyncStatus);
- HRESULT handleWriteCompleted(ABI::Windows::Foundation::IAsyncOperationWithProgress<UINT32, UINT32> *, ABI::Windows::Foundation::AsyncStatus);
};
QT_END_NAMESPACE
diff --git a/src/network/ssl/qasn1element.cpp b/src/network/ssl/qasn1element.cpp
new file mode 100644
index 0000000000..d282a02827
--- /dev/null
+++ b/src/network/ssl/qasn1element.cpp
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork 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 "qasn1element_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qvector.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+typedef QMap<QByteArray, QByteArray> OidNameMap;
+static OidNameMap createOidMap()
+{
+ OidNameMap oids;
+ // used by unit tests
+ oids.insert(oids.end(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink"));
+ oids.insert(oids.end(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street"));
+ return oids;
+}
+Q_GLOBAL_STATIC_WITH_ARGS(OidNameMap, oidNameMap, (createOidMap()))
+
+QAsn1Element::QAsn1Element(quint8 type, const QByteArray &value)
+ : mType(type)
+ , mValue(value)
+{
+}
+
+bool QAsn1Element::read(QDataStream &stream)
+{
+ // type
+ quint8 tmpType;
+ stream >> tmpType;
+ if (!tmpType)
+ return false;
+
+ // length
+ qint64 length = 0;
+ quint8 first;
+ stream >> first;
+ if (first & 0x80) {
+ // long form
+ const quint8 bytes = (first & 0x7f);
+ if (bytes > 7)
+ return false;
+
+ quint8 b;
+ for (int i = 0; i < bytes; i++) {
+ stream >> b;
+ length = (length << 8) | b;
+ }
+ } else {
+ // short form
+ length = (first & 0x7f);
+ }
+
+ // value
+ QByteArray tmpValue;
+ tmpValue.resize(length);
+ int count = stream.readRawData(tmpValue.data(), tmpValue.size());
+ if (count != length)
+ return false;
+
+ mType = tmpType;
+ mValue.swap(tmpValue);
+ return true;
+}
+
+bool QAsn1Element::read(const QByteArray &data)
+{
+ QDataStream stream(data);
+ return read(stream);
+}
+
+void QAsn1Element::write(QDataStream &stream) const
+{
+ // type
+ stream << mType;
+
+ // length
+ qint64 length = mValue.size();
+ if (length >= 128) {
+ // long form
+ quint8 encodedLength = 0x80;
+ QByteArray ba;
+ while (length) {
+ ba.prepend(quint8((length & 0xff)));
+ length >>= 8;
+ encodedLength += 1;
+ }
+ stream << encodedLength;
+ stream.writeRawData(ba.data(), ba.size());
+ } else {
+ // short form
+ stream << quint8(length);
+ }
+
+ // value
+ stream.writeRawData(mValue.data(), mValue.size());
+}
+
+QAsn1Element QAsn1Element::fromInteger(unsigned int val)
+{
+ QAsn1Element elem(QAsn1Element::IntegerType);
+ while (val > 127) {
+ elem.mValue.prepend(val & 0xff);
+ val >>= 8;
+ }
+ elem.mValue.prepend(val & 0x7f);
+ return elem;
+}
+
+QAsn1Element QAsn1Element::fromVector(const QVector<QAsn1Element> &items)
+{
+ QAsn1Element seq;
+ seq.mType = SequenceType;
+ QDataStream stream(&seq.mValue, QIODevice::WriteOnly);
+ for (QVector<QAsn1Element>::const_iterator it = items.cbegin(), end = items.cend(); it != end; ++it)
+ it->write(stream);
+ return seq;
+}
+
+QAsn1Element QAsn1Element::fromObjectId(const QByteArray &id)
+{
+ QAsn1Element elem;
+ elem.mType = ObjectIdentifierType;
+ QList<QByteArray> bits = id.split('.');
+ Q_ASSERT(bits.size() > 2);
+ elem.mValue += quint8((bits[0].toUInt() * 40 + bits[1].toUInt()));
+ for (int i = 2; i < bits.size(); ++i) {
+ char buffer[std::numeric_limits<unsigned int>::digits / 7 + 2];
+ char *pBuffer = buffer + sizeof(buffer);
+ *--pBuffer = '\0';
+ unsigned int node = bits[i].toUInt();
+ *--pBuffer = quint8((node & 0x7f));
+ node >>= 7;
+ while (node) {
+ *--pBuffer = quint8(((node & 0x7f) | 0x80));
+ node >>= 7;
+ }
+ elem.mValue += pBuffer;
+ }
+ return elem;
+}
+
+QDateTime QAsn1Element::toDateTime() const
+{
+ if (mValue.endsWith('Z')) {
+ if (mType == UtcTimeType && mValue.size() == 13)
+ return QDateTime(QDate(2000 + mValue.mid(0, 2).toInt(),
+ mValue.mid(2, 2).toInt(),
+ mValue.mid(4, 2).toInt()),
+ QTime(mValue.mid(6, 2).toInt(),
+ mValue.mid(8, 2).toInt(),
+ mValue.mid(10, 2).toInt()),
+ Qt::UTC);
+ else if (mType == GeneralizedTimeType && mValue.size() == 15)
+ return QDateTime(QDate(mValue.mid(0, 4).toInt(),
+ mValue.mid(4, 2).toInt(),
+ mValue.mid(6, 2).toInt()),
+ QTime(mValue.mid(8, 2).toInt(),
+ mValue.mid(10, 2).toInt(),
+ mValue.mid(12, 2).toInt()),
+ Qt::UTC);
+ }
+ return QDateTime();
+}
+
+QMultiMap<QByteArray, QString> QAsn1Element::toInfo() const
+{
+ QMultiMap<QByteArray, QString> info;
+ QAsn1Element elem;
+ QDataStream issuerStream(mValue);
+ while (elem.read(issuerStream) && elem.mType == QAsn1Element::SetType) {
+ QAsn1Element issuerElem;
+ QDataStream setStream(elem.mValue);
+ if (issuerElem.read(setStream) && issuerElem.mType == QAsn1Element::SequenceType) {
+ QVector<QAsn1Element> elems = issuerElem.toVector();
+ if (elems.size() == 2) {
+ const QByteArray key = elems.front().toObjectName();
+ if (!key.isEmpty())
+ info.insert(key, elems.back().toString());
+ }
+ }
+ }
+ return info;
+}
+
+QVector<QAsn1Element> QAsn1Element::toVector() const
+{
+ QVector<QAsn1Element> items;
+ if (mType == SequenceType) {
+ QAsn1Element elem;
+ QDataStream stream(mValue);
+ while (elem.read(stream))
+ items << elem;
+ }
+ return items;
+}
+
+QByteArray QAsn1Element::toObjectId() const
+{
+ QByteArray key;
+ if (mType == ObjectIdentifierType && !mValue.isEmpty()) {
+ quint8 b = mValue[0];
+ key += QByteArray::number(b / 40) + '.' + QByteArray::number (b % 40);
+ unsigned int val = 0;
+ for (int i = 1; i < mValue.size(); ++i) {
+ b = mValue[i];
+ val = (val << 7) | (b & 0x7f);
+ if (!(b & 0x80)) {
+ key += '.' + QByteArray::number(val);
+ val = 0;
+ }
+ }
+ }
+ return key;
+}
+
+QByteArray QAsn1Element::toObjectName() const
+{
+ QByteArray key = toObjectId();
+ return oidNameMap->value(key, key);
+}
+
+QString QAsn1Element::toString() const
+{
+ if (mType == PrintableStringType || mType == TeletexStringType)
+ return QString::fromLatin1(mValue, mValue.size());
+ if (mType == Utf8StringType)
+ return QString::fromUtf8(mValue, mValue.size());
+ return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformscreenpageflipper.h b/src/network/ssl/qasn1element_p.h
index 232e37d24a..6b3179ac35 100644
--- a/src/gui/kernel/qplatformscreenpageflipper.h
+++ b/src/network/ssl/qasn1element_p.h
@@ -1,9 +1,9 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,54 +39,78 @@
**
****************************************************************************/
-#ifndef QPLATFORMSCREENPAGEFLIPPER_H
-#define QPLATFORMSCREENPAGEFLIPPER_H
+
+#ifndef QASN1ELEMENT_P_H
+#define QASN1ELEMENT_P_H
//
// W A R N I N G
// -------------
//
-// This file is part of the QPA API and is not meant to be used
-// in applications. Usage of this API may make your code
-// source and binary incompatible with future versions of Qt.
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
//
-#include <QtCore/QObject>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmap.h>
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QPlatformScreenBuffer {
+class Q_AUTOTEST_EXPORT QAsn1Element
+{
public:
- QPlatformScreenBuffer();
- virtual ~QPlatformScreenBuffer();
+ enum ElementType {
+ // universal
+ IntegerType = 0x02,
+ BitStringType = 0x03,
+ OctetStringType = 0x04,
+ NullType = 0x05,
+ ObjectIdentifierType = 0x06,
+ Utf8StringType = 0x0c,
+ PrintableStringType = 0x13,
+ TeletexStringType = 0x14,
+ UtcTimeType = 0x17,
+ GeneralizedTimeType = 0x18,
+ SequenceType = 0x30,
+ SetType = 0x31,
- bool isDestroyed() const;
- bool isReady() const;
+ // application
+ Rfc822NameType = 0x81,
+ DnsNameType = 0x82,
- virtual void aboutToBeDisplayed();
- virtual void displayed();
- virtual void release() = 0;
+ // context specific
+ Context0Type = 0xA0,
+ Context3Type = 0xA3
+ };
- virtual void *handle() const = 0;
+ explicit QAsn1Element(quint8 type = 0, const QByteArray &value = QByteArray());
+ bool read(QDataStream &data);
+ bool read(const QByteArray &data);
+ void write(QDataStream &data) const;
-protected:
- bool m_destroyed;
- bool m_ready;
-};
+ static QAsn1Element fromInteger(unsigned int val);
+ static QAsn1Element fromVector(const QVector<QAsn1Element> &items);
+ static QAsn1Element fromObjectId(const QByteArray &id);
-class Q_GUI_EXPORT QPlatformScreenPageFlipper : public QObject
-{
- Q_OBJECT
-public:
- explicit QPlatformScreenPageFlipper(QObject *parent = 0);
+ QDateTime toDateTime() const;
+ QMultiMap<QByteArray, QString> toInfo() const;
+ QVector<QAsn1Element> toVector() const;
+ QByteArray toObjectId() const;
+ QByteArray toObjectName() const;
+ QString toString() const;
- virtual bool displayBuffer(QPlatformScreenBuffer *) = 0;
+ quint8 type() const { return mType; }
+ QByteArray value() const { return mValue; }
-Q_SIGNALS:
- void bufferDisplayed(QPlatformScreenBuffer *);
- void bufferReleased(QPlatformScreenBuffer *);
+private:
+ quint8 mType;
+ QByteArray mValue;
};
+Q_DECLARE_TYPEINFO(QAsn1Element, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
-#endif // QPLATFORMSCREENPAGEFLIPPER_H
+#endif
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index 47ea3343ea..bae78f4347 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -122,6 +122,7 @@
#include "qsslcertificate.h"
#include "qsslcertificate_p.h"
+#include "qasn1element_p.h"
#include "qsslkey_p.h"
#include <QtCore/qdir.h>
@@ -641,6 +642,155 @@ static const char *certificate_blacklist[] = {
0
};
+bool QSslCertificatePrivate::parse(const QByteArray &data)
+{
+#ifndef QT_NO_OPENSSL
+ Q_UNUSED(data);
+#else
+ QAsn1Element root;
+
+ QDataStream dataStream(data);
+ if (!root.read(dataStream) || root.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QDataStream rootStream(root.value());
+ QAsn1Element cert;
+ if (!cert.read(rootStream) || cert.type() != QAsn1Element::SequenceType)
+ return false;
+
+ // version or serial number
+ QAsn1Element elem;
+ QDataStream certStream(cert.value());
+ if (!elem.read(certStream))
+ return false;
+
+ if (elem.type() == QAsn1Element::Context0Type) {
+ QDataStream versionStream(elem.value());
+ if (!elem.read(versionStream) || elem.type() != QAsn1Element::IntegerType)
+ return false;
+
+ versionString = QByteArray::number(elem.value()[0] + 1);
+ if (!elem.read(certStream))
+ return false;
+ } else {
+ versionString = QByteArray::number(1);
+ }
+
+ // serial number
+ if (elem.type() != QAsn1Element::IntegerType)
+ return false;
+
+ QByteArray hexString;
+ hexString.reserve(elem.value().size() * 3);
+ for (int a = 0; a < elem.value().size(); ++a) {
+ const quint8 b = elem.value().at(a);
+ if (b || !hexString.isEmpty()) { // skip leading zeros
+ hexString += QByteArray::number(b, 16).rightJustified(2, '0');
+ hexString += ':';
+ }
+ }
+ hexString.chop(1);
+ serialNumberString = hexString;
+
+ // algorithm ID
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ //qDebug() << "algorithm ID" << elem.type() << elem.length << elem.value().toHex();
+
+ // issuer info
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QByteArray issuerDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
+ issuerInfo = elem.toInfo();
+
+ // validity period
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QDataStream validityStream(elem.value());
+ if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
+ return false;
+
+ notValidBefore = elem.toDateTime();
+ if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
+ return false;
+
+ notValidAfter = elem.toDateTime();
+
+ // subject name
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QByteArray subjectDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
+ subjectInfo = elem.toInfo();
+ subjectMatchesIssuer = issuerDer == subjectDer;
+
+ // public key
+ qint64 keyStart = certStream.device()->pos();
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ publicKeyDerData.resize(certStream.device()->pos() - keyStart);
+ QDataStream keyStream(elem.value());
+ if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+
+ // key algorithm
+ if (!elem.read(elem.value()) || elem.type() != QAsn1Element::ObjectIdentifierType)
+ return false;
+
+ const QByteArray oid = elem.toObjectId();
+ if (oid == "1.2.840.113549.1.1.1")
+ publicKeyAlgorithm = QSsl::Rsa;
+ else if (oid == "1.2.840.10040.4.1")
+ publicKeyAlgorithm = QSsl::Dsa;
+ else
+ publicKeyAlgorithm = QSsl::Opaque;
+
+ certStream.device()->seek(keyStart);
+ certStream.readRawData(publicKeyDerData.data(), publicKeyDerData.size());
+
+ // extensions
+ while (elem.read(certStream)) {
+ if (elem.type() == QAsn1Element::Context3Type) {
+ if (elem.read(elem.value()) && elem.type() == QAsn1Element::SequenceType) {
+ QDataStream extStream(elem.value());
+ while (elem.read(extStream) && elem.type() == QAsn1Element::SequenceType) {
+ QAsn1Element oidElem, valElem;
+ QDataStream seqStream(elem.value());
+ if (oidElem.read(seqStream) && oidElem.type() == QAsn1Element::ObjectIdentifierType &&
+ valElem.read(seqStream) && valElem.type() == QAsn1Element::OctetStringType) {
+ // alternative name
+ if (oidElem.toObjectId() == QByteArray("2.5.29.17")) {
+ QAsn1Element sanElem;
+ if (sanElem.read(valElem.value()) && sanElem.type() == QAsn1Element::SequenceType) {
+ QDataStream nameStream(sanElem.value());
+ QAsn1Element nameElem;
+ while (nameElem.read(nameStream)) {
+ if (nameElem.type() == QAsn1Element::Rfc822NameType) {
+ subjectAlternativeNames.insert(QSsl::EmailEntry, QString::fromLatin1(nameElem.value(), nameElem.value().size()));
+ } else if (nameElem.type() == QAsn1Element::DnsNameType) {
+ subjectAlternativeNames.insert(QSsl::DnsEntry, QString::fromLatin1(nameElem.value(), nameElem.value().size()));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ derData = data.left(dataStream.device()->pos());
+ null = false;
+
+#endif // QT_NO_OPENSSL
+ return true;
+}
+
bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
{
for (int a = 0; certificate_blacklist[a] != 0; a++) {
diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h
index 4bee9edcb9..472553c30c 100644
--- a/src/network/ssl/qsslcertificate_p.h
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -69,6 +69,11 @@ struct X509_EXTENSION;
struct ASN1_OBJECT;
#endif
+#ifdef Q_OS_WINRT
+#include <wrl.h>
+#include <windows.security.cryptography.certificates.h>
+#endif
+
QT_BEGIN_NAMESPACE
// forward declaration
@@ -99,9 +104,18 @@ public:
QDateTime notValidAfter;
QDateTime notValidBefore;
+#ifdef QT_NO_OPENSSL
+ bool subjectMatchesIssuer;
+ QSsl::KeyAlgorithm publicKeyAlgorithm;
+ QByteArray publicKeyDerData;
+ QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames;
+
+ QByteArray derData;
+#endif
X509 *x509;
void init(const QByteArray &data, QSsl::EncodingFormat format);
+ bool parse(const QByteArray &data);
static QByteArray asn1ObjectId(ASN1_OBJECT *object);
static QByteArray asn1ObjectName(ASN1_OBJECT *object);
@@ -117,6 +131,12 @@ public:
friend class QSslSocketBackendPrivate;
QAtomicInt ref;
+
+#ifdef Q_OS_WINRT
+ Microsoft::WRL::ComPtr<ABI::Windows::Security::Cryptography::Certificates::ICertificate> certificate;
+
+ static QSslCertificate QSslCertificate_from_Certificate(ABI::Windows::Security::Cryptography::Certificates::ICertificate *iCertificate);
+#endif
};
QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificate_qt.cpp b/src/network/ssl/qsslcertificate_qt.cpp
new file mode 100644
index 0000000000..391ee6f7f9
--- /dev/null
+++ b/src/network/ssl/qsslcertificate_qt.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork 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 "qsslcertificate.h"
+#include "qsslcertificate_p.h"
+#include "qsslkey.h"
+#include "qsslkey_p.h"
+#include "qsslcertificateextension.h"
+#include "qsslcertificateextension_p.h"
+
+QT_BEGIN_NAMESPACE
+
+bool QSslCertificate::operator==(const QSslCertificate &other) const
+{
+ if (d == other.d)
+ return true;
+ if (d->null && other.d->null)
+ return true;
+ return d->derData == other.d->derData;
+}
+
+bool QSslCertificate::isNull() const
+{
+ return d->null;
+}
+
+bool QSslCertificate::isSelfSigned() const
+{
+ if (d->null)
+ return false;
+
+ qWarning("QSslCertificate::isSelfSigned: This function does not check, whether the certificate \
+ is actually signed. It just checks whether issuer and subject are identical");
+ return d->subjectMatchesIssuer;
+}
+
+QByteArray QSslCertificate::version() const
+{
+ return d->versionString;
+}
+
+QByteArray QSslCertificate::serialNumber() const
+{
+ return d->serialNumberString;
+}
+
+QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
+{
+ return issuerInfo(QSslCertificatePrivate::subjectInfoToString(info));
+}
+
+QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
+{
+ return d->issuerInfo.values(attribute);
+}
+
+QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
+{
+ return subjectInfo(QSslCertificatePrivate::subjectInfoToString(info));
+}
+
+QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
+{
+ return d->subjectInfo.values(attribute);
+}
+
+QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
+{
+ return d->subjectInfo.uniqueKeys();
+}
+
+QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
+{
+ return d->issuerInfo.uniqueKeys();
+}
+
+QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
+{
+ return d->subjectAlternativeNames;
+}
+
+QDateTime QSslCertificate::effectiveDate() const
+{
+ return d->notValidBefore;
+}
+
+QDateTime QSslCertificate::expiryDate() const
+{
+ return d->notValidAfter;
+}
+
+#ifndef Q_OS_WINRT // implemented in qsslcertificate_winrt.cpp
+Qt::HANDLE QSslCertificate::handle() const
+{
+ Q_UNIMPLEMENTED();
+ return 0;
+}
+#endif
+
+QSslKey QSslCertificate::publicKey() const
+{
+ QSslKey key;
+ key.d->type = QSsl::PublicKey;
+ if (d->publicKeyAlgorithm != QSsl::Opaque) {
+ key.d->algorithm = d->publicKeyAlgorithm;
+ key.d->decodeDer(d->publicKeyDerData);
+ }
+ return key;
+}
+
+QList<QSslCertificateExtension> QSslCertificate::extensions() const
+{
+ Q_UNIMPLEMENTED();
+ return QList<QSslCertificateExtension>();
+}
+
+#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
+#define ENDCERTSTRING "-----END CERTIFICATE-----"
+
+QByteArray QSslCertificate::toPem() const
+{
+ QByteArray array = toDer();
+
+ // Convert to Base64 - wrap at 64 characters.
+ array = array.toBase64();
+ QByteArray tmp;
+ for (int i = 0; i <= array.size() - 64; i += 64) {
+ tmp += QByteArray::fromRawData(array.data() + i, 64);
+ tmp += '\n';
+ }
+ if (int remainder = array.size() % 64) {
+ tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
+ tmp += '\n';
+ }
+
+ return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
+}
+
+QByteArray QSslCertificate::toDer() const
+{
+ return d->derData;
+}
+
+QString QSslCertificate::toText() const
+{
+ Q_UNIMPLEMENTED();
+ return QString();
+}
+
+void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
+{
+ if (!data.isEmpty()) {
+ QList<QSslCertificate> certs = (format == QSsl::Pem)
+ ? certificatesFromPem(data, 1)
+ : certificatesFromDer(data, 1);
+ if (!certs.isEmpty()) {
+ *this = *certs.first().d;
+ }
+ }
+}
+
+static bool matchLineFeed(const QByteArray &pem, int *offset)
+{
+ char ch = 0;
+
+ // ignore extra whitespace at the end of the line
+ while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
+ ++*offset;
+
+ if (ch == '\n') {
+ *offset += 1;
+ return true;
+ }
+ if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
+ *offset += 2;
+ return true;
+ }
+ return false;
+}
+
+QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
+{
+ QList<QSslCertificate> certificates;
+ int offset = 0;
+ while (count == -1 || certificates.size() < count) {
+ int startPos = pem.indexOf(BEGINCERTSTRING, offset);
+ if (startPos == -1)
+ break;
+ startPos += sizeof(BEGINCERTSTRING) - 1;
+ if (!matchLineFeed(pem, &startPos))
+ break;
+
+ int endPos = pem.indexOf(ENDCERTSTRING, startPos);
+ if (endPos == -1)
+ break;
+
+ offset = endPos + sizeof(ENDCERTSTRING) - 1;
+ if (offset < pem.size() && !matchLineFeed(pem, &offset))
+ break;
+
+ QByteArray decoded = QByteArray::fromBase64(
+ QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
+ certificates << certificatesFromDer(decoded, 1);;
+ }
+
+ return certificates;
+}
+
+QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
+{
+ QList<QSslCertificate> certificates;
+
+ QByteArray data = der;
+ while (count == -1 || certificates.size() < count) {
+ QSslCertificate cert;
+ if (!cert.d->parse(data))
+ break;
+
+ certificates << cert;
+ data.remove(0, cert.d->derData.size());
+ }
+
+ return certificates;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificate_winrt.cpp b/src/network/ssl/qsslcertificate_winrt.cpp
index 9c857a6787..6f4bb80cf9 100644
--- a/src/network/ssl/qsslcertificate_winrt.cpp
+++ b/src/network/ssl/qsslcertificate_winrt.cpp
@@ -39,153 +39,76 @@
**
****************************************************************************/
-
-
-#include "qsslcertificate.h"
#include "qsslcertificate_p.h"
-QT_BEGIN_NAMESPACE
-
-bool QSslCertificate::operator==(const QSslCertificate &other) const
-{
- if (d == other.d)
- return true;
- return false;
-}
-
-bool QSslCertificate::isNull() const
-{
- Q_UNIMPLEMENTED();
- return true;
-}
-
-bool QSslCertificate::isSelfSigned() const
-{
- Q_UNIMPLEMENTED();
- return true;
-}
-
-QByteArray QSslCertificate::version() const
-{
- Q_UNIMPLEMENTED();
- return QByteArray();
-}
-
-QByteArray QSslCertificate::serialNumber() const
-{
- Q_UNIMPLEMENTED();
- return QByteArray();
-}
-
-QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
-{
- Q_UNIMPLEMENTED();
- return QStringList();
-}
-
-QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
-{
- Q_UNIMPLEMENTED();
- return QStringList();
-}
-
-QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
-{
- Q_UNIMPLEMENTED();
- return QStringList();
-}
-
-QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
-{
- Q_UNIMPLEMENTED();
- return QStringList();
-}
-
-QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
-{
- Q_UNIMPLEMENTED();
- return QList<QByteArray>();
-}
-
-QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
-{
- Q_UNIMPLEMENTED();
- return QList<QByteArray>();
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
-{
- Q_UNIMPLEMENTED();
- return QMultiMap<QSsl::AlternativeNameEntryType, QString>();
-}
-
-QDateTime QSslCertificate::effectiveDate() const
-{
- Q_UNIMPLEMENTED();
- return QDateTime();
-}
-
-QDateTime QSslCertificate::expiryDate() const
-{
- Q_UNIMPLEMENTED();
- return QDateTime();
+#include <QtCore/qfunctions_winrt.h>
+
+#include <wrl.h>
+#include <windows.storage.streams.h>
+#include <windows.security.cryptography.h>
+#include <robuffer.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Security::Cryptography;
+using namespace ABI::Windows::Security::Cryptography::Certificates;
+using namespace ABI::Windows::Storage::Streams;
+
+QT_USE_NAMESPACE
+
+struct SslCertificateGlobal
+{
+ SslCertificateGlobal() {
+ HRESULT hr;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Certificates_Certificate).Get(),
+ &certificateFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(),
+ &bufferFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ ComPtr<ICertificateFactory> certificateFactory;
+ ComPtr<ICryptographicBufferStatics> bufferFactory;
+};
+Q_GLOBAL_STATIC(SslCertificateGlobal, g)
+
+QSslCertificate QSslCertificatePrivate::QSslCertificate_from_Certificate(ICertificate *iCertificate)
+{
+ Q_ASSERT(iCertificate);
+ ComPtr<IBuffer> buffer;
+ HRESULT hr = iCertificate->GetCertificateBlob(&buffer);
+ RETURN_IF_FAILED("Could not obtain certification blob", return QSslCertificate());
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
+ hr = buffer.As(&byteAccess);
+ RETURN_IF_FAILED("Could not obtain byte access to buffer", return QSslCertificate());
+ char *data;
+ hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
+ RETURN_IF_FAILED("Could not obtain buffer data", return QSslCertificate());
+ UINT32 size;
+ hr = buffer->get_Length(&size);
+ RETURN_IF_FAILED("Could not obtain buffer length ", return QSslCertificate());
+ QByteArray der(data, size);
+
+ QSslCertificate certificate;
+ certificate.d->null = false;
+ certificate.d->certificate = iCertificate;
+
+ return certificatesFromDer(der, 1).at(0);
}
Qt::HANDLE QSslCertificate::handle() const
{
- Q_UNIMPLEMENTED();
- return 0;
-}
-
-QSslKey QSslCertificate::publicKey() const
-{
- Q_UNIMPLEMENTED();
- return QSslKey();
-}
+ if (!d->certificate) {
+ HRESULT hr;
+ ComPtr<IBuffer> buffer;
+ hr = g->bufferFactory->CreateFromByteArray(d->derData.length(), (BYTE *)d->derData.data(), &buffer);
+ RETURN_IF_FAILED("Failed to create the certificate data buffer", return 0);
-QList<QSslCertificateExtension> QSslCertificate::extensions() const
-{
- Q_UNIMPLEMENTED();
- return QList<QSslCertificateExtension>();
-}
+ hr = g->certificateFactory->CreateCertificate(buffer.Get(), &d->certificate);
+ RETURN_IF_FAILED("Failed to create the certificate handle from the data buffer", return 0);
+ }
-QByteArray QSslCertificate::toPem() const
-{
- Q_UNIMPLEMENTED();
- return QByteArray();
+ return d->certificate.Get();
}
-
-QByteArray QSslCertificate::toDer() const
-{
- Q_UNIMPLEMENTED();
- return QByteArray();
-}
-
-QString QSslCertificate::toText() const
-{
- Q_UNIMPLEMENTED();
- return QString();
-}
-
-void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
-{
- Q_UNIMPLEMENTED();
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
-{
- Q_UNIMPLEMENTED();
- Q_UNUSED(pem)
- Q_UNUSED(count)
- return QList<QSslCertificate>();
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
-{
- Q_UNIMPLEMENTED();
- Q_UNUSED(der)
- Q_UNUSED(count)
- return QList<QSslCertificate>();
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
index 14559d6618..7e78ac0fee 100644
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ b/src/network/ssl/qsslkey_openssl.cpp
@@ -109,10 +109,9 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
return false;
}
-void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase,
- bool deepClear)
+void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
{
- decodePem(pemFromDer(der), passPhrase, deepClear);
+ decodePem(pemFromDer(der), QByteArray(), deepClear);
}
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index 37936fad10..2b0dab9933 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -175,8 +175,10 @@ QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem) const
/*!
Constructs a QSslKey by decoding the string in the byte array
\a encoded using a specified \a algorithm and \a encoding format.
- If the encoded key is encrypted, \a passPhrase is used to decrypt
- it. \a type specifies whether the key is public or private.
+ \a type specifies whether the key is public or private.
+
+ If the key is encoded as PEM and encrypted, \a passPhrase is used
+ to decrypt it.
After construction, use isNull() to check if \a encoded contained
a valid key.
@@ -188,7 +190,7 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
d->type = type;
d->algorithm = algorithm;
if (encoding == QSsl::Der)
- d->decodeDer(encoded, passPhrase);
+ d->decodeDer(encoded);
else
d->decodePem(encoded, passPhrase);
}
@@ -196,8 +198,10 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
/*!
Constructs a QSslKey by reading and decoding data from a
\a device using a specified \a algorithm and \a encoding format.
- If the encoded key is encrypted, \a passPhrase is used to decrypt
- it. \a type specifies whether the key is public or private.
+ \a type specifies whether the key is public or private.
+
+ If the key is encoded as PEM and encrypted, \a passPhrase is used
+ to decrypt it.
After construction, use isNull() to check if \a device provided
a valid key.
@@ -211,9 +215,10 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
encoded = device->readAll();
d->type = type;
d->algorithm = algorithm;
- d->decodePem((encoding == QSsl::Der) ?
- d->pemFromDer(encoded) : encoded,
- passPhrase);
+ if (encoding == QSsl::Der)
+ d->decodeDer(encoded);
+ else
+ d->decodePem(encoded, passPhrase);
}
/*!
@@ -228,7 +233,11 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
QSslKey::QSslKey(Qt::HANDLE handle, QSsl::KeyType type)
: d(new QSslKeyPrivate)
{
+#ifndef QT_NO_OPENSSL
d->opaque = reinterpret_cast<EVP_PKEY *>(handle);
+#else
+ d->opaque = handle;
+#endif
d->algorithm = QSsl::Opaque;
d->type = type;
d->isNull = !d->opaque;
@@ -313,17 +322,25 @@ QSsl::KeyAlgorithm QSslKey::algorithm() const
}
/*!
- Returns the key in DER encoding. The result is encrypted with
- \a passPhrase if the key is a private key and \a passPhrase is
- non-empty.
+ Returns the key in DER encoding.
+
+ The \a passPhrase argument should be omitted as DER cannot be
+ encrypted. It will be removed in a future version of Qt.
*/
-// ### autotest failure for non-empty passPhrase and private key
QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
{
if (d->isNull || d->algorithm == QSsl::Opaque)
return QByteArray();
+ // Encrypted DER is nonsense, see QTBUG-41038.
+ if (d->type == QSsl::PrivateKey && !passPhrase.isEmpty())
+ return QByteArray();
+
+#ifndef QT_NO_OPENSSL
return d->derFromPem(toPem(passPhrase));
+#else
+ return d->derData;
+#endif
}
/*!
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index e12bbadc06..9c1476038a 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -61,10 +61,6 @@
#ifndef QT_NO_OPENSSL
#include <openssl/rsa.h>
#include <openssl/dsa.h>
-#else
-struct RSA;
-struct DSA;
-struct EVP_PKEY;
#endif
QT_BEGIN_NAMESPACE
@@ -73,9 +69,11 @@ class QSslKeyPrivate
{
public:
inline QSslKeyPrivate()
- : rsa(0)
+ : opaque(0)
+#ifndef QT_NO_OPENSSL
+ , rsa(0)
, dsa(0)
- , opaque(0)
+#endif
{
clear();
}
@@ -85,9 +83,10 @@ public:
void clear(bool deep = true);
+#ifndef QT_NO_OPENSSL
bool fromEVP_PKEY(EVP_PKEY *pkey);
- void decodeDer(const QByteArray &der, const QByteArray &passPhrase,
- bool deepClear = true);
+#endif
+ void decodeDer(const QByteArray &der, bool deepClear = true);
void decodePem(const QByteArray &pem, const QByteArray &passPhrase,
bool deepClear = true);
QByteArray pemHeader() const;
@@ -102,9 +101,15 @@ public:
bool isNull;
QSsl::KeyType type;
QSsl::KeyAlgorithm algorithm;
+#ifndef QT_NO_OPENSSL
+ EVP_PKEY *opaque;
RSA *rsa;
DSA *dsa;
- EVP_PKEY *opaque;
+#else
+ Qt::HANDLE opaque;
+ QByteArray derData;
+ int keyLength;
+#endif
QAtomicInt ref;
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
new file mode 100644
index 0000000000..feeb7d6f87
--- /dev/null
+++ b/src/network/ssl/qsslkey_qt.cpp
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork 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 "qsslkey.h"
+#include "qsslkey_p.h"
+#include "qasn1element_p.h"
+
+QT_USE_NAMESPACE
+
+static const quint8 bits_table[256] = {
+ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+};
+
+static int numberOfBits(const QByteArray &modulus)
+{
+ int bits = modulus.size() * 8;
+ for (int i = 0; i < modulus.size(); ++i) {
+ quint8 b = modulus[i];
+ bits -= 8;
+ if (b != 0) {
+ bits += bits_table[b];
+ break;
+ }
+ }
+ return bits;
+}
+
+void QSslKeyPrivate::clear(bool deep)
+{
+ Q_UNUSED(deep);
+ isNull = true;
+ derData.clear();
+ keyLength = -1;
+}
+
+void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
+{
+ clear(deepClear);
+
+ if (der.isEmpty())
+ return;
+
+ QAsn1Element elem;
+ if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType)
+ return;
+
+ if (type == QSsl::PublicKey) {
+ // key info
+ QDataStream keyStream(elem.value());
+ if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
+ return;
+ QVector<QAsn1Element> infoItems = elem.toVector();
+ if (infoItems.size() < 2 || infoItems[0].type() != QAsn1Element::ObjectIdentifierType)
+ return;
+ if (algorithm == QSsl::Rsa) {
+ if (infoItems[0].toObjectId() != "1.2.840.113549.1.1.1")
+ return;
+ // key data
+ if (!elem.read(keyStream) || elem.type() != QAsn1Element::BitStringType || elem.value().isEmpty())
+ return;
+ if (!elem.read(elem.value().mid(1)) || elem.type() != QAsn1Element::SequenceType)
+ return;
+ if (!elem.read(elem.value()) || elem.type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(elem.value());
+ } else if (algorithm == QSsl::Dsa) {
+ if (infoItems[0].toObjectId() != "1.2.840.10040.4.1")
+ return;
+ if (infoItems[1].type() != QAsn1Element::SequenceType)
+ return;
+ // key params
+ QVector<QAsn1Element> params = infoItems[1].toVector();
+ if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(params[0].value());
+ }
+
+ } else {
+ QVector<QAsn1Element> items = elem.toVector();
+ if (items.isEmpty())
+ return;
+
+ // version
+ if (items[0].type() != QAsn1Element::IntegerType || items[0].value().toHex() != "00")
+ return;
+
+ if (algorithm == QSsl::Rsa) {
+ if (items.size() != 9 || items[1].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(items[1].value());
+ } else if (algorithm == QSsl::Dsa) {
+ if (items.size() != 6 || items[1].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(items[1].value());
+ }
+ }
+
+ derData = der;
+ isNull = false;
+}
+
+void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
+ bool deepClear)
+{
+ if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
+ Q_UNIMPLEMENTED();
+ return;
+ }
+
+ decodeDer(derFromPem(pem), deepClear);
+}
+
+int QSslKeyPrivate::length() const
+{
+ return keyLength;
+}
+
+QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
+{
+ if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
+ Q_UNIMPLEMENTED();
+ return QByteArray();
+ }
+
+ return pemFromDer(derData);
+}
+
+Qt::HANDLE QSslKeyPrivate::handle() const
+{
+ return opaque;
+}
diff --git a/src/network/ssl/qsslkey_winrt.cpp b/src/network/ssl/qsslkey_winrt.cpp
index 1c625081a4..2c83069694 100644
--- a/src/network/ssl/qsslkey_winrt.cpp
+++ b/src/network/ssl/qsslkey_winrt.cpp
@@ -41,6 +41,7 @@
#include "qsslkey.h"
#include "qsslkey_p.h"
+#include "qsslcertificate_p.h"
#include <QtCore/qfunctions_winrt.h>
@@ -59,136 +60,4 @@ using namespace ABI::Windows::Security::Cryptography::Certificates;
using namespace ABI::Windows::Security::Cryptography::Core;
using namespace ABI::Windows::Storage::Streams;
-QT_BEGIN_NAMESPACE
-
-struct SslKeyGlobal
-{
- SslKeyGlobal()
- {
- HRESULT hr;
- hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(),
- &bufferFactory);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<IAsymmetricKeyAlgorithmProviderStatics> keyProviderFactory;
- hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Core_AsymmetricKeyAlgorithmProvider).Get(),
- &keyProviderFactory);
- Q_ASSERT_SUCCEEDED(hr);
-
- ComPtr<IAsymmetricAlgorithmNamesStatics> algorithmNames;
- hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Core_AsymmetricAlgorithmNames).Get(),
- &algorithmNames);
- Q_ASSERT_SUCCEEDED(hr);
-
- HString algorithmName;
- // The algorithm name doesn't matter for imports, so just use PKCS1
- hr = algorithmNames->get_RsaPkcs1(algorithmName.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- hr = keyProviderFactory->OpenAlgorithm(algorithmName.Get(), &keyProvider);
- Q_ASSERT_SUCCEEDED(hr);
- }
-
- ComPtr<ICryptographicBufferStatics> bufferFactory;
- ComPtr<IAsymmetricKeyAlgorithmProvider> keyProvider;
-};
-Q_GLOBAL_STATIC(SslKeyGlobal, g)
-
-// Use the opaque struct for key storage
-struct EVP_PKEY {
- ComPtr<ICryptographicKey> key;
-};
-
-void QSslKeyPrivate::clear(bool deep)
-{
- isNull = true;
-
- if (opaque) {
- if (deep) {
- delete opaque;
- opaque = 0;
- } else {
- opaque->key.Reset();
- }
- }
-}
-
-void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase,
- bool deepClear)
-{
- Q_UNUSED(passPhrase);
-
- clear(deepClear);
-
- if (der.isEmpty())
- return;
-
- if (type != QSsl::PublicKey) {
- qWarning("The WinRT SSL backend does not support importing private keys.");
- return;
- }
-
- HRESULT hr;
- ComPtr<IBuffer> buffer;
- hr = g->bufferFactory->CreateFromByteArray(der.length(), (BYTE *)der.data(), &buffer);
- Q_ASSERT_SUCCEEDED(hr);
-
- if (!opaque)
- opaque = new EVP_PKEY;
-
- hr = g->keyProvider->ImportDefaultPublicKeyBlob(buffer.Get(), &opaque->key);
- RETURN_VOID_IF_FAILED("Failed to import public key");
-
- isNull = false;
-}
-
-void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
- bool deepClear)
-{
- decodeDer(derFromPem(pem), passPhrase, deepClear);
-}
-
-int QSslKeyPrivate::length() const
-{
- if (isNull)
- return -1;
-
- Q_ASSERT(opaque && opaque->key);
- HRESULT hr;
- UINT32 keySize;
- hr = opaque->key->get_KeySize(&keySize);
- Q_ASSERT_SUCCEEDED(hr);
- return keySize;
-}
-
-QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
-{
- Q_UNUSED(passPhrase);
- QByteArray result;
- if (isNull)
- return result;
-
- Q_ASSERT(opaque && opaque->key);
- HRESULT hr;
- ComPtr<IBuffer> buffer;
- hr = opaque->key->ExportDefaultPublicKeyBlobType(&buffer);
- RETURN_IF_FAILED("Failed to export key", return result);
-
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
- hr = buffer.As(&byteAccess);
- Q_ASSERT_SUCCEEDED(hr);
- char *data;
- hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
- Q_ASSERT_SUCCEEDED(hr);
- UINT32 size;
- hr = buffer->get_Length(&size);
- Q_ASSERT_SUCCEEDED(hr);
- result = pemFromDer(QByteArray::fromRawData(data, size));
- return result;
-}
-
-Qt::HANDLE QSslKeyPrivate::handle() const
-{
- return opaque ? opaque->key.Get() : 0;
-}
-
-QT_END_NAMESPACE
+QT_USE_NAMESPACE
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 5df550b1c8..b092e5e980 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1894,8 +1894,10 @@ void QSslSocket::disconnectFromHost()
emit stateChanged(d->state);
}
- if (!d->writeBuffer.isEmpty())
+ if (!d->writeBuffer.isEmpty()) {
+ d->pendingClose = true;
return;
+ }
if (d->mode == UnencryptedMode) {
d->plainSocket->disconnectFromHost();
@@ -2513,6 +2515,65 @@ QSharedPointer<QSslContext> QSslSocketPrivate::sslContext(QSslSocket *socket)
return (socket) ? socket->d_func()->sslContextPointer : QSharedPointer<QSslContext>();
}
+bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
+{
+ QStringList commonNameList = cert.subjectInfo(QSslCertificate::CommonName);
+
+ foreach (const QString &commonName, commonNameList) {
+ if (isMatchingHostname(commonName.toLower(), peerName.toLower())) {
+ return true;
+ }
+ }
+
+ foreach (const QString &altName, cert.subjectAlternativeNames().values(QSsl::DnsEntry)) {
+ if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
+{
+ int wildcard = cn.indexOf(QLatin1Char('*'));
+
+ // Check this is a wildcard cert, if not then just compare the strings
+ if (wildcard < 0)
+ return cn == hostname;
+
+ int firstCnDot = cn.indexOf(QLatin1Char('.'));
+ int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1);
+
+ // Check at least 3 components
+ if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length()))
+ return false;
+
+ // Check * is last character of 1st component (ie. there's a following .)
+ if (wildcard+1 != firstCnDot)
+ return false;
+
+ // Check only one star
+ if (cn.lastIndexOf(QLatin1Char('*')) != wildcard)
+ return false;
+
+ // Check characters preceding * (if any) match
+ if (wildcard && (hostname.leftRef(wildcard) != cn.leftRef(wildcard)))
+ return false;
+
+ // Check characters following first . match
+ if (hostname.midRef(hostname.indexOf(QLatin1Char('.'))) != cn.midRef(firstCnDot))
+ return false;
+
+ // Check if the hostname is an IP address, if so then wildcards are not allowed
+ QHostAddress addr(hostname);
+ if (!addr.isNull())
+ return false;
+
+ // Ok, I guess this was a wildcard CN and the hostname matches.
+ return true;
+}
+
QT_END_NAMESPACE
#include "moc_qsslsocket.cpp"
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index f869039687..dc08954d6e 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -1552,65 +1552,6 @@ QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates
return certificates;
}
-bool QSslSocketBackendPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
-{
- QStringList commonNameList = cert.subjectInfo(QSslCertificate::CommonName);
-
- foreach (const QString &commonName, commonNameList) {
- if (isMatchingHostname(commonName.toLower(), peerName.toLower())) {
- return true;
- }
- }
-
- foreach (const QString &altName, cert.subjectAlternativeNames().values(QSsl::DnsEntry)) {
- if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
- return true;
- }
- }
-
- return false;
-}
-
-bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
-{
- int wildcard = cn.indexOf(QLatin1Char('*'));
-
- // Check this is a wildcard cert, if not then just compare the strings
- if (wildcard < 0)
- return cn == hostname;
-
- int firstCnDot = cn.indexOf(QLatin1Char('.'));
- int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1);
-
- // Check at least 3 components
- if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length()))
- return false;
-
- // Check * is last character of 1st component (ie. there's a following .)
- if (wildcard+1 != firstCnDot)
- return false;
-
- // Check only one star
- if (cn.lastIndexOf(QLatin1Char('*')) != wildcard)
- return false;
-
- // Check characters preceding * (if any) match
- if (wildcard && (hostname.leftRef(wildcard) != cn.leftRef(wildcard)))
- return false;
-
- // Check characters following first . match
- if (hostname.midRef(hostname.indexOf(QLatin1Char('.'))) != cn.midRef(firstCnDot))
- return false;
-
- // Check if the hostname is an IP address, if so then wildcards are not allowed
- QHostAddress addr(hostname);
- if (!addr.isNull())
- return false;
-
- // Ok, I guess this was a wildcard CN and the hostname matches.
- return true;
-}
-
QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
{
QList<QSslError> errors;
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index f4f2fe842c..3a1df7c420 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -142,8 +142,6 @@ public:
Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher);
static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
- static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
- Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName);
static QString getErrorsFromOpenSsl();
static bool importPKCS12(QIODevice *device,
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index 06e12297a4..bda36d2649 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -150,6 +150,8 @@ public:
QRegExp::PatternSyntax syntax);
static void addDefaultCaCertificate(const QSslCertificate &cert);
static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
+ static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
+ Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
#if defined(Q_OS_MACX)
static PtrSecCertificateCopyData ptrSecCertificateCopyData;
diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp
index da4cf91f49..c9ddd9ec1b 100644
--- a/src/network/ssl/qsslsocket_winrt.cpp
+++ b/src/network/ssl/qsslsocket_winrt.cpp
@@ -39,39 +39,132 @@
**
****************************************************************************/
-/****************************************************************************
-**
-** In addition, as a special exception, the copyright holders listed above give
-** permission to link the code of its release of Qt with the OpenSSL project's
-** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
-** same license as the original version), and distribute the linked executables.
-**
-** You must comply with the GNU General Public License version 2 in all
-** respects for all of the code used other than the "OpenSSL" code. If you
-** modify this file, you may extend this exception to your version of the file,
-** but you are not obligated to do so. If you do not wish to do so, delete
-** this exception statement from your version of this file.
-**
-****************************************************************************/
-
-//#define QSSLSOCKET_DEBUG
-//#define QT_DECRYPT_SSL_TRAFFIC
-
#include "qsslsocket_winrt_p.h"
#include "qsslsocket.h"
#include "qsslcertificate_p.h"
+#include "qsslcipher_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QSysInfo>
+#include <QtCore/qfunctions_winrt.h>
+#include <private/qnativesocketengine_winrt_p.h>
+
+#include <windows.networking.h>
+#include <windows.networking.sockets.h>
+#include <windows.security.cryptography.certificates.h>
+#include <robuffer.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Networking;
+using namespace ABI::Windows::Networking::Sockets;
+using namespace ABI::Windows::Security::Cryptography::Certificates;
+using namespace ABI::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
-bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
+// For QSet<QSslError>
+inline uint qHash(const QSslError &error, uint seed)
+ Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(error)))
+{ return (qHash(error.error()) ^ seed); }
+
+// For QSet<QSslCertificate>
+inline uint qHash(const QSslCertificate &certificate, uint seed)
+ Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(certificate)))
+{ return (qHash(certificate.handle()) ^ seed); }
+
+bool QSslSocketPrivate::s_libraryLoaded = true;
+bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
+bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
+
+struct SslSocketGlobal
+{
+ SslSocketGlobal()
+ {
+ HRESULT hr;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
+ &hostNameFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<ICertificateStoresStatics> certificateStores;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Certificates_CertificateStores).Get(),
+ &certificateStores);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = certificateStores->get_TrustedRootCertificationAuthorities(&rootStore);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncOperation<IVectorView<Certificate *> *>> op;
+ hr = certificateStores->FindAllAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<Certificate *>> certificates;
+ hr = QWinRTFunctions::await(op, certificates.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 size;
+ hr = certificates->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint32 i = 0; i < size; ++i) {
+ ComPtr<ICertificate> certificate;
+ hr = certificates->GetAt(i, &certificate);
+ Q_ASSERT_SUCCEEDED(hr);
+ systemCaCertificates.append(QSslCertificatePrivate::QSslCertificate_from_Certificate(certificate.Get()));
+ }
+ }
+
+ void syncCaCertificates(const QSet<QSslCertificate> &add, const QSet<QSslCertificate> &remove)
+ {
+ QMutexLocker locker(&certificateMutex);
+ foreach (const QSslCertificate &certificate, add) {
+ QHash<QSslCertificate, QAtomicInt>::iterator it = additionalCertificates.find(certificate);
+ if (it != additionalCertificates.end()) {
+ it.value().ref(); // Add a reference
+ } else {
+ // install certificate
+ HRESULT hr;
+ hr = rootStore->Add(static_cast<ICertificate *>(certificate.handle()));
+ Q_ASSERT_SUCCEEDED(hr);
+ additionalCertificates.insert(certificate, 1);
+ }
+ }
+ foreach (const QSslCertificate &certificate, remove) {
+ QHash<QSslCertificate, QAtomicInt>::iterator it = additionalCertificates.find(certificate);
+ if (it != additionalCertificates.end() && !it.value().deref()) {
+ // no more references, remove certificate
+ HRESULT hr;
+ hr = rootStore->Delete(static_cast<ICertificate *>(certificate.handle()));
+ Q_ASSERT_SUCCEEDED(hr);
+ additionalCertificates.erase(it);
+ }
+ }
+ }
+
+ ComPtr<IHostNameFactory> hostNameFactory;
+ QList<QSslCertificate> systemCaCertificates;
+
+private:
+ QMutex certificateMutex;
+ ComPtr<ICertificateStore> rootStore;
+ QHash<QSslCertificate, QAtomicInt> additionalCertificates;
+};
+Q_GLOBAL_STATIC(SslSocketGlobal, g)
+
+// Called on the socket's thread to avoid cross-thread deletion
+void QSslSocketConnectionHelper::disconnectSocketFromHost()
+{
+ if (d->plainSocket)
+ d->plainSocket->disconnectFromHost();
+}
QSslSocketBackendPrivate::QSslSocketBackendPrivate()
+ : connectionHelper(new QSslSocketConnectionHelper(this))
{
- ensureInitialized();
}
QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
{
+ g->syncCaCertificates(QSet<QSslCertificate>(), previousCaCertificates);
}
void QSslSocketPrivate::deinitialize()
@@ -84,31 +177,28 @@ bool QSslSocketPrivate::supportsSsl()
return true;
}
-bool QSslSocketPrivate::ensureLibraryLoaded()
-{
- return true;
-}
-
-void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
-{
- Q_UNIMPLEMENTED();
-}
-
void QSslSocketPrivate::ensureInitialized()
{
+ if (s_loadedCiphersAndCerts)
+ return;
+ s_loadedCiphersAndCerts = true;
+ resetDefaultCiphers();
}
long QSslSocketPrivate::sslLibraryVersionNumber()
{
- Q_UNIMPLEMENTED();
- return 0;
+ return QSysInfo::windowsVersion();
}
-
QString QSslSocketPrivate::sslLibraryVersionString()
{
- Q_UNIMPLEMENTED();
- return QString::number(sslLibraryVersionNumber());
+ switch (QSysInfo::windowsVersion()) {
+ case QSysInfo::WV_WINDOWS8_1:
+ return QStringLiteral("Windows Runtime 8.1 SSL library");
+ default:
+ break;
+ }
+ return QStringLiteral("Windows Runtime SSL library");
}
long QSslSocketPrivate::sslLibraryBuildVersionNumber()
@@ -125,20 +215,68 @@ QString QSslSocketPrivate::sslLibraryBuildVersionString()
void QSslSocketPrivate::resetDefaultCiphers()
{
- Q_UNIMPLEMENTED();
+ setDefaultSupportedCiphers(QSslSocketBackendPrivate::defaultCiphers());
+ setDefaultCiphers(QSslSocketBackendPrivate::defaultCiphers());
+}
+
+
+QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
+{
+ QList<QSslCipher> ciphers;
+ const QString protocolStrings[] = { QStringLiteral("SSLv3"), QStringLiteral("TLSv1"),
+ QStringLiteral("TLSv1.1"), QStringLiteral("TLSv1.2") };
+ const QSsl::SslProtocol protocols[] = { QSsl::SslV3, QSsl::TlsV1_0, QSsl::TlsV1_1, QSsl::TlsV1_2 };
+ for (int i = 0; i < ARRAYSIZE(protocols); ++i) {
+ QSslCipher cipher;
+ cipher.d->isNull = false;
+ cipher.d->name = QStringLiteral("WINRT");
+ cipher.d->protocol = protocols[i];
+ cipher.d->protocolString = protocolStrings[i];
+ ciphers.append(cipher);
+ }
+ return ciphers;
}
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
{
- Q_UNIMPLEMENTED();
- ensureInitialized();
- QList<QSslCertificate> systemCerts;
- return systemCerts;
+ return g->systemCaCertificates;
}
void QSslSocketBackendPrivate::startClientEncryption()
{
- Q_UNIMPLEMENTED();
+ Q_Q(QSslSocket);
+
+ QSsl::SslProtocol protocol = q->protocol();
+ switch (q->protocol()) {
+ case QSsl::AnyProtocol:
+ case QSsl::SslV3:
+ protectionLevel = SocketProtectionLevel_Ssl; // Only use this value if weak cipher support is required
+ break;
+ case QSsl::SecureProtocols:
+ case QSsl::TlsV1SslV3:
+ case QSsl::TlsV1_0:
+ protectionLevel = SocketProtectionLevel_Tls10;
+ break;
+ case QSsl::TlsV1_1:
+ protectionLevel = SocketProtectionLevel_Tls11;
+ break;
+ case QSsl::TlsV1_2:
+ protectionLevel = SocketProtectionLevel_Tls12;
+ break;
+ default:
+ protectionLevel = SocketProtectionLevel_Tls12; // default to highest
+ protocol = QSsl::TlsV1_2;
+ break;
+ }
+
+ // Sync custom certificates
+ const QSet<QSslCertificate> caCertificates = configuration.caCertificates.toSet();
+ const QSet<QSslCertificate> newCertificates = caCertificates - previousCaCertificates;
+ const QSet<QSslCertificate> oldCertificates = previousCaCertificates - caCertificates;
+ g->syncCaCertificates(newCertificates, oldCertificates);
+ previousCaCertificates = caCertificates;
+
+ continueHandshake();
}
void QSslSocketBackendPrivate::startServerEncryption()
@@ -148,33 +286,379 @@ void QSslSocketBackendPrivate::startServerEncryption()
void QSslSocketBackendPrivate::transmit()
{
- Q_UNIMPLEMENTED();
+ Q_Q(QSslSocket);
+
+ if (connectionEncrypted && !writeBuffer.isEmpty()) {
+ qint64 totalBytesWritten = 0;
+ int nextDataBlockSize;
+ while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {
+ int writtenBytes = plainSocket->write(writeBuffer.readPointer(), nextDataBlockSize);
+ writtenBytes = nextDataBlockSize;
+
+ writeBuffer.free(writtenBytes);
+ totalBytesWritten += writtenBytes;
+
+ if (writtenBytes < nextDataBlockSize)
+ break;
+ }
+
+ if (totalBytesWritten > 0) {
+ // Don't emit bytesWritten() recursively.
+ if (!emittedBytesWritten) {
+ emittedBytesWritten = true;
+ emit q->bytesWritten(totalBytesWritten);
+ emittedBytesWritten = false;
+ }
+ }
+ }
+
+ // Check if we've got any data to be read from the socket.
+ int pendingBytes;
+ bool bytesRead = false;
+ while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
+ char *ptr = buffer.reserve(pendingBytes);
+ int readBytes = plainSocket->read(ptr, pendingBytes);
+ buffer.chop(pendingBytes - readBytes);
+ bytesRead = true;
+ }
+
+ if (bytesRead) {
+ if (readyReadEmittedPointer)
+ *readyReadEmittedPointer = true;
+ emit q->readyRead();
+ }
+
+ if (pendingClose) {
+ pendingClose = false;
+ q->disconnectFromHost();
+ }
}
void QSslSocketBackendPrivate::disconnectFromHost()
{
- Q_UNIMPLEMENTED();
+ QMetaObject::invokeMethod(connectionHelper.data(), "disconnectSocketFromHost", Qt::QueuedConnection);
}
void QSslSocketBackendPrivate::disconnected()
{
- Q_UNIMPLEMENTED();
}
QSslCipher QSslSocketBackendPrivate::sessionCipher() const
{
- Q_UNIMPLEMENTED();
- return QSslCipher();
+ return configuration.sessionCipher;
}
QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
{
- Q_UNIMPLEMENTED();
- return QSsl::UnknownProtocol;
+ return configuration.sessionCipher.protocol();
}
+
void QSslSocketBackendPrivate::continueHandshake()
{
- Q_UNIMPLEMENTED();
+ Q_Q(QSslSocket);
+
+ IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
+ if (qintptr(socket) == -1) {
+ q->setErrorString(QStringLiteral("At attempt was made to continue the handshake on an invalid socket."));
+ q->setSocketError(QAbstractSocket::SslInternalError);
+ emit q->error(QAbstractSocket::SslInternalError);
+ return;
+ }
+
+ HRESULT hr;
+ ComPtr<IHostName> hostName;
+ const QString host = verificationPeerName.isEmpty() ? plainSocket->peerName()
+ : verificationPeerName;
+ if (host.isEmpty()) {
+ ComPtr<IStreamSocketInformation> info;
+ hr = socket->get_Information(&info);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = info->get_RemoteAddress(&hostName);
+ } else {
+ HStringReference hostRef(reinterpret_cast<LPCWSTR>(host.utf16()), host.length());
+ hr = g->hostNameFactory->CreateHostName(hostRef.Get(), &hostName);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ if (FAILED(hr)) {
+ q->setErrorString(qt_error_string(hr));
+ q->setSocketError(QAbstractSocket::SslInvalidUserDataError);
+ emit q->error(QAbstractSocket::SslInvalidUserDataError);
+ return;
+ }
+
+ ComPtr<IStreamSocketControl> control;
+ hr = socket->get_Control(&control);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IStreamSocketControl2> control2;
+ hr = control.As(&control2);
+ ComPtr<IVector<ChainValidationResult>> ignoreList;
+ hr = control2->get_IgnorableServerCertificateErrors(&ignoreList);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ QSet<QSslError> ignoreErrors = ignoreErrorsList.toSet();
+ for (int i = ChainValidationResult_Untrusted; i < ChainValidationResult_OtherErrors + 1; ++i) {
+ // Populate the native ignore list - break to add, continue to skip
+ switch (i) {
+ case ChainValidationResult_Revoked:
+ case ChainValidationResult_InvalidSignature:
+ case ChainValidationResult_BasicConstraintsError:
+ case ChainValidationResult_InvalidCertificateAuthorityPolicy:
+ case ChainValidationResult_UnknownCriticalExtension:
+ case ChainValidationResult_OtherErrors:
+ continue; // The above errors can't be ignored in the handshake
+ case ChainValidationResult_Untrusted:
+ if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::CertificateUntrusted))
+ break;
+ continue;
+ case ChainValidationResult_Expired:
+ if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::CertificateExpired))
+ break;
+ continue;
+ case ChainValidationResult_IncompleteChain:
+ if (ignoreAllSslErrors
+ || ignoreErrors.contains(QSslError::InvalidCaCertificate)
+ || ignoreErrors.contains(QSslError::UnableToVerifyFirstCertificate)
+ || ignoreErrors.contains(QSslError::UnableToGetIssuerCertificate)) {
+ break;
+ }
+ continue;
+ case ChainValidationResult_WrongUsage:
+ if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::InvalidPurpose))
+ break;
+ continue;
+ case ChainValidationResult_InvalidName:
+ if (ignoreAllSslErrors
+ || ignoreErrors.contains(QSslError::HostNameMismatch)
+ || ignoreErrors.contains(QSslError::SubjectIssuerMismatch)) {
+ break;
+ }
+ continue;
+ case ChainValidationResult_RevocationInformationMissing:
+ case ChainValidationResult_RevocationFailure:
+ default:
+ if (ignoreAllSslErrors)
+ break;
+ continue;
+ }
+ hr = ignoreList->Append(static_cast<ChainValidationResult>(i));
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ ComPtr<IAsyncAction> op;
+ hr = socket->UpgradeToSslAsync(protectionLevel, hostName.Get(), &op);
+ if (FAILED(hr)) {
+ q->setErrorString(QSslSocket::tr("Error creating SSL session: %1")
+ .arg(qt_error_string(hr)));
+ q->setSocketError(QAbstractSocket::SslInternalError);
+ emit q->error(QAbstractSocket::SslInternalError);
+ return;
+ }
+
+ hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(
+ this, &QSslSocketBackendPrivate::onSslUpgrade).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+HRESULT QSslSocketBackendPrivate::onSslUpgrade(IAsyncAction *action, AsyncStatus)
+{
+ Q_Q(QSslSocket);
+
+ if (wasDeleted) {
+ qWarning("SSL upgrade callback received after the delegate was deleted. "
+ "This may be indicative of an internal bug in the WinRT SSL implementation.");
+ return S_OK;
+ }
+
+ HRESULT hr = action->GetResults();
+ QSet<QSslError> errors;
+ switch (hr) {
+ case SEC_E_INVALID_TOKEN: // Occurs when the server doesn't support the requested protocol
+ q->setErrorString(qt_error_string(hr));
+ q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
+ emit q->error(QAbstractSocket::SslHandshakeFailedError);
+ q->disconnectFromHost();
+ return S_OK;
+ default:
+ if (FAILED(hr))
+ qErrnoWarning(hr, "error"); // Unhandled error; let sslErrors take care of it
+ break;
+ }
+
+ IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
+ if (qintptr(socket) == -1) {
+ qWarning("The underlying TCP socket used by the SSL socket is invalid. "
+ "This may be indicative of an internal bug in the WinRT SSL implementation.");
+ return S_OK;
+ }
+
+ ComPtr<IStreamSocketInformation> info;
+ hr = socket->get_Information(&info);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IStreamSocketInformation2> info2;
+ hr = info.As(&info2);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // Cipher
+ QSsl::SslProtocol protocol;
+ SocketProtectionLevel protectionLevel;
+ hr = info->get_ProtectionLevel(&protectionLevel);
+ switch (protectionLevel) {
+ default:
+ protocol = QSsl::UnknownProtocol;
+ break;
+ case SocketProtectionLevel_Ssl:
+ protocol = QSsl::SslV3;
+ break;
+ case SocketProtectionLevel_Tls10:
+ protocol = QSsl::TlsV1_0;
+ break;
+ case SocketProtectionLevel_Tls11:
+ protocol = QSsl::TlsV1_1;
+ break;
+ case SocketProtectionLevel_Tls12:
+ protocol = QSsl::TlsV1_2;
+ break;
+ }
+ configuration.sessionCipher = QSslCipher(QStringLiteral("WINRT"), protocol); // The actual cipher name is not accessible
+
+ // Certificate & chain
+ ComPtr<ICertificate> certificate;
+ hr = info2->get_ServerCertificate(&certificate);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ QList<QSslCertificate> peerCertificateChain;
+ if (certificate) {
+ ComPtr<IAsyncOperation<CertificateChain *>> op;
+ hr = certificate->BuildChainAsync(Q_NULLPTR, &op);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<ICertificateChain> certificateChain;
+ hr = QWinRTFunctions::await(op, certificateChain.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IVectorView<Certificate *>> certificates;
+ hr = certificateChain->GetCertificates(true, &certificates);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 certificatesLength;
+ hr = certificates->get_Size(&certificatesLength);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint32 i = 0; i < certificatesLength; ++i) {
+ ComPtr<ICertificate> chainCertificate;
+ hr = certificates->GetAt(i, &chainCertificate);
+ Q_ASSERT_SUCCEEDED(hr);
+ peerCertificateChain.append(QSslCertificatePrivate::QSslCertificate_from_Certificate(chainCertificate.Get()));
+ }
+ }
+
+ configuration.peerCertificate = certificate ? QSslCertificatePrivate::QSslCertificate_from_Certificate(certificate.Get())
+ : QSslCertificate();
+ configuration.peerCertificateChain = peerCertificateChain;
+
+ // Errors
+ ComPtr<IVectorView<ChainValidationResult>> chainValidationResults;
+ hr = info2->get_ServerCertificateErrors(&chainValidationResults);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 size;
+ hr = chainValidationResults->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint32 i = 0; i < size; ++i) {
+ ChainValidationResult result;
+ hr = chainValidationResults->GetAt(i, &result);
+ Q_ASSERT_SUCCEEDED(hr);
+ switch (result) {
+ case ChainValidationResult_Success:
+ break;
+ case ChainValidationResult_Untrusted:
+ errors.insert(QSslError::CertificateUntrusted);
+ break;
+ case ChainValidationResult_Revoked:
+ errors.insert(QSslError::CertificateRevoked);
+ break;
+ case ChainValidationResult_Expired:
+ errors.insert(QSslError::CertificateExpired);
+ break;
+ case ChainValidationResult_IncompleteChain:
+ errors.insert(QSslError::UnableToGetIssuerCertificate);
+ break;
+ case ChainValidationResult_InvalidSignature:
+ errors.insert(QSslError::CertificateSignatureFailed);
+ break;
+ case ChainValidationResult_WrongUsage:
+ errors.insert(QSslError::InvalidPurpose);
+ break;
+ case ChainValidationResult_InvalidName:
+ errors.insert(QSslError::HostNameMismatch);
+ break;
+ case ChainValidationResult_InvalidCertificateAuthorityPolicy:
+ errors.insert(QSslError::InvalidCaCertificate);
+ break;
+ default:
+ errors.insert(QSslError::UnspecifiedError);
+ break;
+ }
+ }
+
+ sslErrors = errors.toList();
+
+ // Peer validation
+ if (!configuration.peerCertificate.isNull()) {
+ const QString peerName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
+ if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
+ // No matches in common names or alternate names.
+ const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
+ const int index = sslErrors.indexOf(QSslError::HostNameMismatch);
+ if (index >= 0) // Replace the existing error
+ sslErrors[index] = error;
+ else
+ sslErrors.append(error);
+ emit q->peerVerifyError(error);
+ }
+
+ // Peer validation required, but no certificate is present
+ } else if (configuration.peerVerifyMode == QSslSocket::VerifyPeer
+ || configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer) {
+ QSslError error(QSslError::NoPeerCertificate);
+ sslErrors.append(error);
+ emit q->peerVerifyError(error);
+ }
+
+ // Peer chain validation
+ foreach (const QSslCertificate &certificate, peerCertificateChain) {
+ if (!QSslCertificatePrivate::isBlacklisted(certificate))
+ continue;
+
+ QSslError error(QSslError::CertificateBlacklisted, certificate);
+ sslErrors.append(error);
+ emit q->peerVerifyError(error);
+ }
+
+ if (!sslErrors.isEmpty()) {
+ emit q->sslErrors(sslErrors);
+ q->setErrorString(sslErrors.first().errorString());
+ q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
+ emit q->error(QAbstractSocket::SslHandshakeFailedError);
+
+ // Disconnect if there are any non-ignorable errors
+ foreach (const QSslError &error, sslErrors) {
+ if (ignoreErrorsList.contains(error))
+ continue;
+ q->disconnectFromHost();
+ return S_OK;
+ }
+ }
+
+ if (readBufferMaxSize)
+ plainSocket->setReadBufferSize(readBufferMaxSize);
+
+ connectionEncrypted = true;
+ emit q->encrypted();
+
+ if (pendingClose) {
+ pendingClose = false;
+ q->disconnectFromHost();
+ }
+
+ return S_OK;
}
QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
diff --git a/src/network/ssl/qsslsocket_winrt_p.h b/src/network/ssl/qsslsocket_winrt_p.h
index 791330a6fd..aa31c85d6e 100644
--- a/src/network/ssl/qsslsocket_winrt_p.h
+++ b/src/network/ssl/qsslsocket_winrt_p.h
@@ -39,30 +39,15 @@
**
****************************************************************************/
-/****************************************************************************
-**
-** In addition, as a special exception, the copyright holders listed above give
-** permission to link the code of its release of Qt with the OpenSSL project's
-** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
-** same license as the original version), and distribute the linked executables.
-**
-** You must comply with the GNU General Public License version 2 in all
-** respects for all of the code used other than the "OpenSSL" code. If you
-** modify this file, you may extend this exception to your version of the file,
-** but you are not obligated to do so. If you do not wish to do so, delete
-** this exception statement from your version of this file.
-**
-****************************************************************************/
-
-#ifndef QSSLSOCKET_OPENSSL_P_H
-#define QSSLSOCKET_OPENSSL_P_H
+#ifndef QSSLSOCKET_WINRT_P_H
+#define QSSLSOCKET_WINRT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
-// of the QLibrary class. This header file may change from
+// of the QtNetwork library. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
@@ -70,8 +55,24 @@
#include "qsslsocket_p.h"
+#include <wrl.h>
+#include <windows.networking.sockets.h>
+
QT_BEGIN_NAMESPACE
+class QSslSocketConnectionHelper : public QObject
+{
+ Q_OBJECT
+public:
+ QSslSocketConnectionHelper(QSslSocketBackendPrivate *d)
+ : d(d) { }
+
+ Q_INVOKABLE void disconnectSocketFromHost();
+
+private:
+ QSslSocketBackendPrivate *d;
+};
+
class QSslSocketBackendPrivate : public QSslSocketPrivate
{
Q_DECLARE_PUBLIC(QSslSocket)
@@ -89,13 +90,22 @@ public:
QSsl::SslProtocol sessionProtocol() const Q_DECL_OVERRIDE;
void continueHandshake() Q_DECL_OVERRIDE;
+ static QList<QSslCipher> defaultCiphers();
static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName);
static bool importPKCS12(QIODevice *device,
QSslKey *key, QSslCertificate *cert,
QList<QSslCertificate> *caCertificates,
const QByteArray &passPhrase);
+
+private:
+ HRESULT onSslUpgrade(ABI::Windows::Foundation::IAsyncAction *,
+ ABI::Windows::Foundation::AsyncStatus);
+
+ QScopedPointer<QSslSocketConnectionHelper> connectionHelper;
+ ABI::Windows::Networking::Sockets::SocketProtectionLevel protectionLevel;
+ QSet<QSslCertificate> previousCaCertificates;
};
QT_END_NAMESPACE
-#endif
+#endif // QSSLSOCKET_WINRT_P_H
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
index 0fbeb1d369..384e149241 100644
--- a/src/network/ssl/ssl.pri
+++ b/src/network/ssl/ssl.pri
@@ -1,6 +1,7 @@
# OpenSSL support; compile in QSslSocket.
contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
- HEADERS += ssl/qssl.h \
+ HEADERS += ssl/qasn1element_p.h \
+ ssl/qssl.h \
ssl/qsslcertificate.h \
ssl/qsslcertificate_p.h \
ssl/qsslconfiguration.h \
@@ -14,7 +15,8 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
ssl/qsslsocket_p.h \
ssl/qsslcertificateextension.h \
ssl/qsslcertificateextension_p.h
- SOURCES += ssl/qssl.cpp \
+ SOURCES += ssl/qasn1element.cpp \
+ ssl/qssl.cpp \
ssl/qsslcertificate.cpp \
ssl/qsslconfiguration.cpp \
ssl/qsslcipher.cpp \
@@ -25,7 +27,9 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
winrt {
HEADERS += ssl/qsslsocket_winrt_p.h
- SOURCES += ssl/qsslcertificate_winrt.cpp \
+ SOURCES += ssl/qsslcertificate_qt.cpp \
+ ssl/qsslcertificate_winrt.cpp \
+ ssl/qsslkey_qt.cpp \
ssl/qsslkey_winrt.cpp \
ssl/qsslsocket_winrt.cpp
}
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 10ba8ac2ee..d2c017fcac 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -2126,7 +2126,7 @@ QGLContext::QGLContext(const QGLFormat &format)
d->init(0, format);
}
-void qDeleteQGLContext(void *handle)
+static void qDeleteQGLContext(void *handle)
{
QGLContext *context = static_cast<QGLContext *>(handle);
delete context;
@@ -3475,7 +3475,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
d->valid = d->guiGlContext->create();
if (d->valid)
- d->guiGlContext->setQGLContextHandle(this, qDeleteQGLContext);
+ d->guiGlContext->setQGLContextHandle(this, 0);
d->glFormat = QGLFormat::fromSurfaceFormat(d->guiGlContext->format());
d->setupSharing();
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 6dd939c2de..fb71e60ba9 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -242,6 +242,7 @@ public:
void swapRegion(const QRegion &region);
QOpenGLContext *guiGlContext;
+ // true if QGLContext owns the QOpenGLContext (for who deletes who)
bool ownContext;
void setupSharing();
diff --git a/src/platformheaders/doc/qtplatformheaders.qdocconf b/src/platformheaders/doc/qtplatformheaders.qdocconf
index 65fe660b40..1c09971e23 100644
--- a/src/platformheaders/doc/qtplatformheaders.qdocconf
+++ b/src/platformheaders/doc/qtplatformheaders.qdocconf
@@ -1,53 +1,38 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
-# Name of the project which must match the outputdir. Determines the .index file
-project = QtPlatformHeaders
+project = QtPlatformHeaders
+description = Qt Platform Headers Reference Documentation
+version = $QT_VERSION
-# Directories in which to search for files to document and images.
-# By default set to the root directory of the project for sources
-# and headers and qdoc will therefore generate output for each file.
-# Images should be placed in <rootdir>/dic/images and examples in
-# <rootdir>/examples.
-# Paths are relative to the location of this file.
+examplesinstallpath = qtplatformheaders
-headerdirs += ..
-sourcedirs += ..
-exampledirs += .. \
- snippets
-
-imagedirs += images
-
-depends += qtdoc qtcore qtgui qtwidgets
-
-examplesinstallpath = platformheaders
-
-# The following parameters are for creating a qhp file, the qhelpgenerator
-# program can convert the qhp file into a qch file which can be opened in
-# Qt Assistant and/or Qt Creator.
+qhp.projects = QtPlatformHeaders
-# Defines the name of the project. You cannot use operators (+, =, -) in
-# the name. Properties for this project are set using a qhp.<projectname>.property
-# format.
-qhp.projects = QtPlatformHeaders
+qhp.QtPlatformHeaders.file = qtplatformheaders.qhp
+qhp.QtPlatformHeaders.namespace = org.qt-project.qtplatformheaders.$QT_VERSION_TAG
+qhp.QtPlatformHeaders.virtualFolder = qtplatformheaders
+qhp.QtPlatformHeaders.indexTitle = Qt Platform Headers
+qhp.QtPlatformHeaders.indexRoot =
-# Sets the name of the output qhp file.
-qhp.QtPlatformHeaders.file = qtplatformheaders.qhp
+qhp.QtPlatformHeaders.filterAttributes = qtplatformheaders $QT_VERSION qtrefdoc
+qhp.QtPlatformHeaders.customFilters.Qt.name = QtPlatformHeaders $QT_VERSION
+qhp.QtPlatformHeaders.customFilters.Qt.filterAttributes = qtplatformheaders $QT_VERSION
-# Namespace for the output file. This namespace is used to distinguish between
-# different documentation files in Creator/Assistant.
-qhp.QtPlatformHeaders.namespace = org.qt-project.qtplatformheaders.$QT_VERSION_TAG
-
-# Title for the package, will be the main title for the package in
-# Assistant/Creator.
-qhp.QtPlatformHeaders.indexTitle = Qt Platform Headers
-
-# Only update the name of the project for the next variables.
-qhp.QtPlatformHeaders.virtualFolder = qtplatformheaders
-qhp.QtPlatformHeaders.subprojects = classes
+qhp.QtPlatformHeaders.subprojects = classes
qhp.QtPlatformHeaders.subprojects.classes.title = C++ Classes
qhp.QtPlatformHeaders.subprojects.classes.indexTitle = Qt Platform Headers C++ Classes
qhp.QtPlatformHeaders.subprojects.classes.selectors = class fake:headerfile
qhp.QtPlatformHeaders.subprojects.classes.sortPages = true
+depends += \
+ qtcore \
+ qtgui \
+ qtdoc
+
+headerdirs += ..
+sourcedirs += ..
+exampledirs += snippets
+imagedirs += images
+
navigation.landingpage = "Qt Platform Headers"
navigation.cppclassespage = "Qt Platform Headers C++ Classes"
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
index 7b5f882982..13a4c13099 100644
--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
@@ -516,7 +516,7 @@ QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine,
}
namespace {
-QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match)
+QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool useXftConf)
{
switch (hintingPreference) {
case QFont::PreferNoHinting:
@@ -529,8 +529,7 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin
break;
}
- const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
- if (services && (services->desktopEnvironment() == "GNOME" || services->desktopEnvironment() == "UNITY")) {
+ if (useXftConf) {
void *hintStyleResource =
QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
QGuiApplication::primaryScreen());
@@ -558,8 +557,17 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin
return QFontEngine::HintFull;
}
-QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match)
+QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool useXftConf)
{
+ if (useXftConf) {
+ void *subpixelTypeResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
+ QGuiApplication::primaryScreen());
+ int subpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
+ if (subpixelType > 0)
+ return QFontEngine::SubpixelAntialiasingType(subpixelType - 1);
+ }
+
int subpixel = FC_RGBA_UNKNOWN;
FcPatternGetInteger(match, FC_RGBA, 0, &subpixel);
@@ -596,8 +604,22 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
fid.index = fontfile->indexValue;
bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
+ bool forcedAntialiasSetting = !antialias;
engine = new QFontEngineFT(fontDef);
+ const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
+ bool useXftConf = (services && (services->desktopEnvironment() == "GNOME" || services->desktopEnvironment() == "UNITY"));
+ if (useXftConf) {
+ void *antialiasResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
+ QGuiApplication::primaryScreen());
+ int antialiasingEnabled = int(reinterpret_cast<qintptr>(antialiasResource));
+ if (antialiasingEnabled > 0) {
+ antialias = antialiasingEnabled - 1;
+ forcedAntialiasSetting = true;
+ }
+ }
+
QFontEngine::GlyphFormat format;
// try and get the pattern
FcPattern *pattern = FcPatternCreate();
@@ -622,7 +644,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
FcPattern *match = FcFontMatch(0, pattern, &result);
if (match) {
- engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)f.hintingPreference, match));
+ engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)f.hintingPreference, match, useXftConf));
FcBool fc_autohint;
if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)
@@ -634,18 +656,16 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
engine->lcdFilterType = lcdFilter;
#endif
- if (antialias) {
- // If antialiasing is not fully disabled, fontconfig may still disable it on a font match basis.
+ if (!forcedAntialiasSetting) {
FcBool fc_antialias;
- if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) != FcResultMatch)
- fc_antialias = true;
- antialias = fc_antialias;
+ if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) == FcResultMatch)
+ antialias = fc_antialias;
}
if (antialias) {
QFontEngine::SubpixelAntialiasingType subpixelType = QFontEngine::Subpixel_None;
if (!(f.styleStrategy & QFont::NoSubpixelAntialias))
- subpixelType = subpixelTypeFromMatch(match);
+ subpixelType = subpixelTypeFromMatch(match, useXftConf);
engine->subpixelType = subpixelType;
format = (subpixelType == QFontEngine::Subpixel_None)
@@ -676,6 +696,20 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal p
QFontDef fontDef = engine->fontDef;
+ bool forcedAntialiasSetting = false;
+ const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
+ bool useXftConf = (services && (services->desktopEnvironment() == "GNOME" || services->desktopEnvironment() == "UNITY"));
+ if (useXftConf) {
+ void *antialiasResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
+ QGuiApplication::primaryScreen());
+ int antialiasingEnabled = int(reinterpret_cast<qintptr>(antialiasResource));
+ if (antialiasingEnabled > 0) {
+ engine->antialias = antialiasingEnabled - 1;
+ forcedAntialiasSetting = true;
+ }
+ }
+
QFontEngine::GlyphFormat format;
// try and get the pattern
FcPattern *pattern = FcPatternCreate();
@@ -693,7 +727,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal p
FcPattern *match = FcFontMatch(0, pattern, &result);
if (match) {
- engine->setDefaultHintStyle(defaultHintStyleFromMatch(hintingPreference, match));
+ engine->setDefaultHintStyle(defaultHintStyleFromMatch(hintingPreference, match, useXftConf));
FcBool fc_autohint;
if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)
@@ -705,13 +739,14 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal p
engine->lcdFilterType = lcdFilter;
#endif
- FcBool fc_antialias;
- if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) != FcResultMatch)
- fc_antialias = true;
- engine->antialias = fc_antialias;
+ if (!forcedAntialiasSetting) {
+ FcBool fc_antialias;
+ if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) == FcResultMatch)
+ engine->antialias = fc_antialias;
+ }
if (engine->antialias) {
- QFontEngine::SubpixelAntialiasingType subpixelType = subpixelTypeFromMatch(match);
+ QFontEngine::SubpixelAntialiasingType subpixelType = subpixelTypeFromMatch(match, useXftConf);
engine->subpixelType = subpixelType;
format = subpixelType == QFontEngine::Subpixel_None
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
index 7ae72cc446..8e4c1c07a8 100644
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
@@ -211,6 +211,13 @@ void QCoreTextFontDatabase::populateFontDatabase()
QPlatformFontDatabase::registerAliasToFontFamily(familyName, localizedFamilyName);
#endif
}
+
+ // Force creating the theme fonts to get the descriptors in m_systemFontDescriptors
+ if (m_themeFonts.isEmpty())
+ (void)themeFonts();
+
+ Q_FOREACH (CTFontDescriptorRef fontDesc, m_systemFontDescriptors)
+ populateFromDescriptor(fontDesc);
}
void QCoreTextFontDatabase::populateFamily(const QString &familyName)
@@ -231,67 +238,76 @@ void QCoreTextFontDatabase::populateFamily(const QString &familyName)
populateFromDescriptor(CTFontDescriptorRef(CFArrayGetValueAtIndex(matchingFonts, i)));
}
-void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
+struct FontDescription {
+ QCFString familyName;
+ QCFString styleName;
+ QString foundryName;
+ QFont::Weight weight;
+ QFont::Style style;
+ QFont::Stretch stretch;
+ int pixelSize;
+ bool fixedPitch;
+ QSupportedWritingSystems writingSystems;
+};
+
+static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
{
- QString foundryName = QStringLiteral("CoreText");
- QCFString familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
- QCFString styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
- QFont::Weight weight = QFont::Normal;
- QFont::Style style = QFont::StyleNormal;
- QFont::Stretch stretch = QFont::Unstretched;
- bool fixedPitch = false;
+
+ fd->foundryName = QStringLiteral("CoreText");
+ fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
+ fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
+ fd->weight = QFont::Normal;
+ fd->style = QFont::StyleNormal;
+ fd->stretch = QFont::Unstretched;
+ fd->fixedPitch = false;
if (styles) {
if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) {
- Q_ASSERT(CFNumberIsFloatType(weightValue));
double normalizedWeight;
if (CFNumberGetValue(weightValue, kCFNumberDoubleType, &normalizedWeight)) {
if (normalizedWeight >= 0.62)
- weight = QFont::Black;
+ fd->weight = QFont::Black;
else if (normalizedWeight >= 0.4)
- weight = QFont::Bold;
+ fd->weight = QFont::Bold;
else if (normalizedWeight >= 0.3)
- weight = QFont::DemiBold;
+ fd->weight = QFont::DemiBold;
else if (normalizedWeight == 0.0)
- weight = QFont::Normal;
+ fd->weight = QFont::Normal;
else if (normalizedWeight <= -0.4)
- weight = QFont::Light;
+ fd->weight = QFont::Light;
}
}
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
- Q_ASSERT(CFNumberIsFloatType(italic));
double d;
if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
if (d > 0.0)
- style = QFont::StyleItalic;
+ fd->style = QFont::StyleItalic;
}
}
if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) {
int d;
if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) {
if (d & kCTFontMonoSpaceTrait)
- fixedPitch = true;
+ fd->fixedPitch = true;
if (d & kCTFontExpandedTrait)
- stretch = QFont::Expanded;
+ fd->stretch = QFont::Expanded;
else if (d & kCTFontCondensedTrait)
- stretch = QFont::Condensed;
+ fd->stretch = QFont::Condensed;
}
}
}
- int pixelSize = 0;
if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) {
if (CFNumberIsFloatType(size)) {
double d;
CFNumberGetValue(size, kCFNumberDoubleType, &d);
- pixelSize = d;
+ fd->pixelSize = d;
} else {
- CFNumberGetValue(size, kCFNumberIntType, &pixelSize);
+ CFNumberGetValue(size, kCFNumberIntType, &fd->pixelSize);
}
}
- QSupportedWritingSystems writingSystems;
if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
CFIndex length = CFArrayGetCount(languages);
for (int i = 1; i < LanguageCount; ++i) {
@@ -299,14 +315,24 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
continue;
QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII);
if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang))
- writingSystems.setSupported(QFontDatabase::WritingSystem(i));
+ fd->writingSystems.setSupported(QFontDatabase::WritingSystem(i));
}
}
+}
+void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
+{
+ FontDescription fd;
+ getFontDescription(font, &fd);
+ populateFromFontDescription(font, fd);
+}
+
+void QCoreTextFontDatabase::populateFromFontDescription(CTFontDescriptorRef font, const FontDescription &fd)
+{
CFRetain(font);
- QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch,
+ QPlatformFontDatabase::registerFont(fd.familyName, fd.styleName, fd.foundryName, fd.weight, fd.style, fd.stretch,
true /* antialiased */, true /* scalable */,
- pixelSize, fixedPitch, writingSystems, (void *) font);
+ fd.pixelSize, fd.fixedPitch, fd.writingSystems, (void *) font);
}
void QCoreTextFontDatabase::releaseHandle(void *handle)
@@ -612,6 +638,113 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData
return families;
}
+bool QCoreTextFontDatabase::isPrivateFontFamily(const QString &family) const
+{
+ if (family.startsWith(QLatin1Char('.')))
+ return true;
+
+ return QPlatformFontDatabase::isPrivateFontFamily(family);
+}
+
+static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f)
+{
+ switch (f) {
+ case QPlatformTheme::SystemFont:
+ return kCTFontSystemFontType;
+
+ case QPlatformTheme::MenuFont:
+ case QPlatformTheme::MenuBarFont:
+ case QPlatformTheme::MenuItemFont:
+ return kCTFontMenuItemFontType;
+
+ case QPlatformTheme::MessageBoxFont:
+ return kCTFontEmphasizedSystemFontType;
+
+ case QPlatformTheme::LabelFont:
+ return kCTFontSystemFontType;
+
+ case QPlatformTheme::TipLabelFont:
+ return kCTFontToolTipFontType;
+
+ case QPlatformTheme::StatusBarFont:
+ return kCTFontSystemFontType;
+
+ case QPlatformTheme::TitleBarFont:
+ return kCTFontWindowTitleFontType;
+
+ case QPlatformTheme::MdiSubWindowTitleFont:
+ case QPlatformTheme::DockWidgetTitleFont:
+ return kCTFontSystemFontType;
+
+ case QPlatformTheme::PushButtonFont:
+ return kCTFontPushButtonFontType;
+
+ case QPlatformTheme::CheckBoxFont:
+ case QPlatformTheme::RadioButtonFont:
+ return kCTFontSystemFontType;
+
+ case QPlatformTheme::ToolButtonFont:
+ return kCTFontSmallToolbarFontType;
+
+ case QPlatformTheme::ItemViewFont:
+ return kCTFontSystemFontType;
+
+ case QPlatformTheme::ListViewFont:
+ return kCTFontViewsFontType;
+
+ case QPlatformTheme::HeaderViewFont:
+ return kCTFontSmallSystemFontType;
+
+ case QPlatformTheme::ListBoxFont:
+ return kCTFontViewsFontType;
+
+ case QPlatformTheme::ComboMenuItemFont:
+ return kCTFontSystemFontType;
+
+ case QPlatformTheme::ComboLineEditFont:
+ return kCTFontViewsFontType;
+
+ case QPlatformTheme::SmallFont:
+ return kCTFontSmallSystemFontType;
+
+ case QPlatformTheme::MiniFont:
+ return kCTFontMiniSystemFontType;
+
+ case QPlatformTheme::FixedFont:
+ return kCTFontUserFixedPitchFontType;
+
+ default:
+ return kCTFontSystemFontType;
+ }
+}
+
+const QHash<QPlatformTheme::Font, QFont *> &QCoreTextFontDatabase::themeFonts() const
+{
+ if (m_themeFonts.isEmpty()) {
+ for (long f = QPlatformTheme::SystemFont; f < QPlatformTheme::NFonts; f++) {
+ QPlatformTheme::Font ft = static_cast<QPlatformTheme::Font>(f);
+ m_themeFonts.insert(ft, themeFont(ft));
+ }
+ }
+
+ return m_themeFonts;
+}
+
+QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const
+{
+ CTFontUIFontType fontType = fontTypeFromTheme(f);
+
+ QCFType<CTFontRef> ctFont = CTFontCreateUIFontForLanguage(fontType, 0.0, NULL);
+ CTFontDescriptorRef fontDesc = CTFontCopyFontDescriptor(ctFont);
+
+ FontDescription fd;
+ getFontDescription(fontDesc, &fd);
+ m_systemFontDescriptors.insert(fontDesc);
+
+ QFont *font = new QFont(fd.familyName, fd.pixelSize, fd.weight, fd.style == QFont::StyleItalic);
+ return font;
+}
+
QFont QCoreTextFontDatabase::defaultFont() const
{
if (defaultFontName.isEmpty()) {
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h
index c73f4a32ca..a3da27b28d 100644
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h
@@ -47,6 +47,7 @@
#define HAVE_ATS QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_5, __IPHONE_NA)
#include <qpa/qplatformfontdatabase.h>
+#include <qpa/qplatformtheme.h>
#include <private/qcore_mac_p.h>
#ifndef Q_OS_IOS
@@ -66,6 +67,8 @@ Q_DECLARE_METATYPE(ATSFontContainerRef);
QT_BEGIN_NAMESPACE
+struct FontDescription;
+
class QCoreTextFontDatabase : public QPlatformFontDatabase
{
public:
@@ -79,17 +82,25 @@ public:
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName);
void releaseHandle(void *handle);
+ bool isPrivateFontFamily(const QString &family) const;
QFont defaultFont() const;
QList<int> standardSizes() const;
+ // For iOS and OS X platform themes
+ QFont *themeFont(QPlatformTheme::Font) const;
+ const QHash<QPlatformTheme::Font, QFont *> &themeFonts() const;
+
private:
void populateFromDescriptor(CTFontDescriptorRef font);
+ void populateFromFontDescription(CTFontDescriptorRef font, const FontDescription &fd);
mutable QString defaultFontName;
void removeApplicationFonts();
QVector<QVariant> m_applicationFonts;
+ mutable QSet<CTFontDescriptorRef> m_systemFontDescriptors;
+ mutable QHash<QPlatformTheme::Font, QFont *> m_themeFonts;
};
QT_END_NAMESPACE
diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
index 72de73db7e..9c44283b0e 100644
--- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
+++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
@@ -408,6 +408,53 @@ QEvdevKeyboardHandler::KeycodeAction QEvdevKeyboardHandler::processKeycode(quint
#ifdef QT_QPA_KEYMAP_DEBUG
qWarning("Processing: uni=%04x, qt=%08x, qtmod=%08x", unicode, qtcode & ~modmask, (qtcode & modmask));
#endif
+ //If NumLockOff and keypad key pressed remap event sent
+ if (!m_locks[1] &&
+ (qtcode & Qt::KeypadModifier) &&
+ keycode >= 71 &&
+ keycode <= 83 &&
+ keycode != 74 &&
+ keycode != 78) {
+
+ unicode = 0xffff;
+ int oldMask = (qtcode & modmask);
+ switch (keycode) {
+ case 71: //7 --> Home
+ qtcode = Qt::Key_Home;
+ break;
+ case 72: //8 --> Up
+ qtcode = Qt::Key_Up;
+ break;
+ case 73: //9 --> PgUp
+ qtcode = Qt::Key_PageUp;
+ break;
+ case 75: //4 --> Left
+ qtcode = Qt::Key_Left;
+ break;
+ case 76: //5 --> Clear
+ qtcode = Qt::Key_Clear;
+ break;
+ case 77: //6 --> right
+ qtcode = Qt::Key_Right;
+ break;
+ case 79: //1 --> End
+ qtcode = Qt::Key_End;
+ break;
+ case 80: //2 --> Down
+ qtcode = Qt::Key_Down;
+ break;
+ case 81: //3 --> PgDn
+ qtcode = Qt::Key_PageDown;
+ break;
+ case 82: //0 --> Ins
+ qtcode = Qt::Key_Insert;
+ break;
+ case 83: //, --> Del
+ qtcode = Qt::Key_Delete;
+ break;
+ }
+ qtcode ^= oldMask;
+ }
// send the result to the server
processKeyEvent(keycode, unicode, qtcode & ~modmask, Qt::KeyboardModifiers(qtcode & modmask), pressed, autorepeat);
@@ -437,6 +484,29 @@ void QEvdevKeyboardHandler::unloadKeymap()
memset(m_locks, 0, sizeof(m_locks));
m_composing = 0;
m_dead_unicode = 0xffff;
+
+ //Set locks according to keyboard leds
+ quint16 ledbits[1];
+ memset(ledbits, 0, sizeof(ledbits));
+ if (::ioctl(m_fd, EVIOCGLED(sizeof(ledbits)), ledbits) < 0) {
+ qWarning("Failed to query led states. Settings numlock & capslock off");
+ switchLed(LED_NUML,false);
+ switchLed(LED_CAPSL, false);
+ switchLed(LED_SCROLLL,false);
+ } else {
+ //Capslock
+ if ((ledbits[0]&0x02) > 0)
+ m_locks[0] = 1;
+ //Numlock
+ if ((ledbits[0]&0x01) > 0)
+ m_locks[1] = 1;
+ //Scrollock
+ if ((ledbits[0]&0x04) > 0)
+ m_locks[2] = 1;
+#ifdef QT_QPA_KEYMAP_DEBUG
+ qWarning("numlock=%d , capslock=%d, scrolllock=%d",m_locks[1],m_locks[0],m_locks[2]);
+#endif
+ }
}
bool QEvdevKeyboardHandler::loadKeymap(const QString &file)
diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
index d4454e4b9f..ba62d8a532 100644
--- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
+++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
@@ -52,6 +52,7 @@
#ifndef QT_NO_ACCESSIBILITY
#include "socket_interface.h"
#include "constant_mappings_p.h"
+#include "../accessibility/qaccessiblebridgeutils_p.h"
#include "application_p.h"
/*!
@@ -1486,7 +1487,7 @@ QStringList AtSpiAdaptor::accessibleInterfaces(QAccessibleInterface *interface)
if (interface->role() == QAccessible::Application)
ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_APPLICATION);
- if (interface->actionInterface())
+ if (interface->actionInterface() || interface->valueInterface())
ifaces << QLatin1String(ATSPI_DBUS_INTERFACE_ACTION);
if (interface->textInterface())
@@ -1696,36 +1697,44 @@ QRect AtSpiAdaptor::getExtents(QAccessibleInterface *interface, uint coordType)
// Action interface
bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
{
- QAccessibleActionInterface *actionIface = interface->actionInterface();
- if (!actionIface)
- return false;
-
if (function == QLatin1String("GetNActions")) {
- sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(actionIface->actionNames().count()))));
+ int count = QAccessibleBridgeUtils::effectiveActionNames(interface).count();
+ sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(count))));
} else if (function == QLatin1String("DoAction")) {
int index = message.arguments().at(0).toInt();
- if (index < 0 || index >= actionIface->actionNames().count())
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ if (index < 0 || index >= actionNames.count())
return false;
- interface->actionInterface()->doAction(actionIface->actionNames().at(index));
- sendReply(connection, message, true);
+ const QString actionName = actionNames.at(index);
+ bool success = QAccessibleBridgeUtils::performEffectiveAction(interface, actionName);
+ sendReply(connection, message, success);
} else if (function == QLatin1String("GetActions")) {
- sendReply(connection, message, QVariant::fromValue(getActions(actionIface)));
+ sendReply(connection, message, QVariant::fromValue(getActions(interface)));
} else if (function == QLatin1String("GetName")) {
int index = message.arguments().at(0).toInt();
- if (index < 0 || index >= actionIface->actionNames().count())
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ if (index < 0 || index >= actionNames.count())
return false;
- sendReply(connection, message, actionIface->actionNames().at(index));
+ sendReply(connection, message, actionNames.at(index));
} else if (function == QLatin1String("GetDescription")) {
int index = message.arguments().at(0).toInt();
- if (index < 0 || index >= actionIface->actionNames().count())
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ if (index < 0 || index >= actionNames.count())
return false;
- sendReply(connection, message, actionIface->localizedActionDescription(actionIface->actionNames().at(index)));
+ QString description;
+ if (QAccessibleActionInterface *actionIface = interface->actionInterface())
+ description = actionIface->localizedActionDescription(actionNames.at(index));
+ else
+ description = qAccessibleLocalizedActionDescription(actionNames.at(index));
+ sendReply(connection, message, description);
} else if (function == QLatin1String("GetKeyBinding")) {
int index = message.arguments().at(0).toInt();
- if (index < 0 || index >= actionIface->actionNames().count())
+ const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface);
+ if (index < 0 || index >= actionNames.count())
return false;
QStringList keyBindings;
- keyBindings = actionIface->keyBindingsForAction(actionIface->actionNames().value(index));
+ if (QAccessibleActionInterface *actionIface = interface->actionInterface())
+ keyBindings = actionIface->keyBindingsForAction(actionNames.at(index));
if (keyBindings.isEmpty()) {
QString acc = interface->text(QAccessible::Accelerator);
if (!acc.isEmpty())
@@ -1742,20 +1751,24 @@ bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, const QStrin
return true;
}
-QSpiActionArray AtSpiAdaptor::getActions(QAccessibleActionInterface *actionInterface) const
+QSpiActionArray AtSpiAdaptor::getActions(QAccessibleInterface *interface) const
{
+ QAccessibleActionInterface *actionInterface = interface->actionInterface();
QSpiActionArray actions;
- Q_FOREACH (const QString &actionName, actionInterface->actionNames()) {
+ Q_FOREACH (const QString &actionName, QAccessibleBridgeUtils::effectiveActionNames(interface)) {
QSpiAction action;
QStringList keyBindings;
action.name = actionName;
- action.description = actionInterface->localizedActionDescription(actionName);
-
- keyBindings = actionInterface->keyBindingsForAction(actionName);
+ if (actionInterface) {
+ action.description = actionInterface->localizedActionDescription(actionName);
+ keyBindings = actionInterface->keyBindingsForAction(actionName);
+ } else {
+ action.description = qAccessibleLocalizedActionDescription(actionName);
+ }
if (keyBindings.length() > 0)
- action.keyBinding = keyBindings[0];
+ action.keyBinding = keyBindings[0];
else
action.keyBinding = QString();
diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor_p.h b/src/platformsupport/linuxaccessibility/atspiadaptor_p.h
index d3cd510153..410742b6b6 100644
--- a/src/platformsupport/linuxaccessibility/atspiadaptor_p.h
+++ b/src/platformsupport/linuxaccessibility/atspiadaptor_p.h
@@ -122,7 +122,7 @@ private:
static QRect translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect);
// action helper functions
- QSpiActionArray getActions(QAccessibleActionInterface* interface) const;
+ QSpiActionArray getActions(QAccessibleInterface *interface) const;
// text helper functions
QVariantList getAttributes(QAccessibleInterface *, int offset, bool includeDefaults) const;
diff --git a/src/platformsupport/linuxaccessibility/bridge.cpp b/src/platformsupport/linuxaccessibility/bridge.cpp
index 3665b9cefe..25451b1d62 100644
--- a/src/platformsupport/linuxaccessibility/bridge.cpp
+++ b/src/platformsupport/linuxaccessibility/bridge.cpp
@@ -136,8 +136,8 @@ static RoleMapping map[] = {
{ QAccessible::Caret, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "text caret") },
//: Role of an accessible object
{ QAccessible::AlertMessage, ATSPI_ROLE_ALERT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "alert message") },
- //: Role of an accessible object
- { QAccessible::Window, ATSPI_ROLE_WINDOW, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "window") },
+ //: Role of an accessible object: a window with frame and title
+ { QAccessible::Window, ATSPI_ROLE_FRAME, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "frame") },
//: Role of an accessible object
{ QAccessible::Client, ATSPI_ROLE_FILLER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "filler") },
//: Role of an accessible object
diff --git a/src/platformsupport/linuxaccessibility/linuxaccessibility.pri b/src/platformsupport/linuxaccessibility/linuxaccessibility.pri
index 1b65fb1cad..1d51d2876c 100644
--- a/src/platformsupport/linuxaccessibility/linuxaccessibility.pri
+++ b/src/platformsupport/linuxaccessibility/linuxaccessibility.pri
@@ -2,6 +2,7 @@ contains(QT_CONFIG, accessibility-atspi-bridge) {
QT_FOR_PRIVATE += dbus
include(../../3rdparty/atspi2/atspi2.pri)
+ include(../accessibility/accessibility.pri)
INCLUDEPATH += $$PWD
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
index be90bbecb0..25017bdb30 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
@@ -139,9 +139,11 @@ void QIBusPlatformInputContext::commit()
return;
}
- QInputMethodEvent event;
- event.setCommitString(d->predit);
- QCoreApplication::sendEvent(input, &event);
+ if (!d->predit.isEmpty()) {
+ QInputMethodEvent event;
+ event.setCommitString(d->predit);
+ QCoreApplication::sendEvent(input, &event);
+ }
d->context->Reset();
d->predit = QString();
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro
index 0209379afb..ffbad08c10 100644
--- a/src/plugins/platforms/android/android.pro
+++ b/src/plugins/platforms/android/android.pro
@@ -47,7 +47,6 @@ SOURCES += $$PWD/androidplatformplugin.cpp \
$$PWD/qandroidplatformscreen.cpp \
$$PWD/qandroidplatformwindow.cpp \
$$PWD/qandroidplatformopenglwindow.cpp \
- $$PWD/qandroidplatformrasterwindow.cpp \
$$PWD/qandroidplatformbackingstore.cpp \
$$PWD/qandroidplatformopenglcontext.cpp \
$$PWD/qandroidplatformforeignwindow.cpp \
@@ -76,7 +75,6 @@ HEADERS += $$PWD/qandroidplatformintegration.h \
$$PWD/qandroidplatformscreen.h \
$$PWD/qandroidplatformwindow.h \
$$PWD/qandroidplatformopenglwindow.h \
- $$PWD/qandroidplatformrasterwindow.h \
$$PWD/qandroidplatformbackingstore.h \
$$PWD/qandroidplatformopenglcontext.h \
$$PWD/qandroidplatformforeignwindow.h \
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index f776e43efa..de30fa825a 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -401,10 +401,8 @@ namespace QtAndroid
{
QMutexLocker lock(&m_surfacesMutex);
const auto &it = m_surfaces.find(surfaceId);
- if (it == m_surfaces.end())
- return;
-
- m_surfaces.remove(surfaceId);
+ if (it != m_surfaces.end())
+ m_surfaces.remove(surfaceId);
if (m_surfaces.isEmpty())
m_surfaceId = 1;
diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp
index ff49f59076..2ee556de5c 100644
--- a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp
+++ b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp
@@ -42,7 +42,7 @@
#include "qandroidplatformbackingstore.h"
#include "qandroidplatformscreen.h"
-#include "qandroidplatformrasterwindow.h"
+#include "qandroidplatformwindow.h"
#include <qpa/qplatformscreen.h>
QT_BEGIN_NAMESPACE
@@ -66,7 +66,7 @@ void QAndroidPlatformBackingStore::flush(QWindow *window, const QRegion &region,
if (!m_backingStoreSet)
setBackingStore(window);
- (static_cast<QAndroidPlatformRasterWindow *>(window->handle()))->repaint(region);
+ (static_cast<QAndroidPlatformWindow *>(window->handle()))->repaint(region);
}
void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents)
@@ -79,11 +79,11 @@ void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &stat
void QAndroidPlatformBackingStore::setBackingStore(QWindow *window)
{
- if (window->surfaceType() == QSurface::RasterSurface) {
- (static_cast<QAndroidPlatformRasterWindow *>(window->handle()))->setBackingStore(this);
+ if (window->surfaceType() == QSurface::RasterSurface || window->surfaceType() == QSurface::RasterGLSurface) {
+ (static_cast<QAndroidPlatformWindow *>(window->handle()))->setBackingStore(this);
m_backingStoreSet = true;
} else {
- qWarning("QAndroidPlatformBackingStore does not support GL windows.");
+ qWarning("QAndroidPlatformBackingStore does not support OpenGL-only windows.");
}
}
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 829227f81c..53cb3588f6 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -62,7 +62,6 @@
#include "qandroidplatformfontdatabase.h"
#include "qandroidplatformopenglcontext.h"
#include "qandroidplatformopenglwindow.h"
-#include "qandroidplatformrasterwindow.h"
#include "qandroidplatformscreen.h"
#include "qandroidplatformservices.h"
#include "qandroidplatformtheme.h"
@@ -192,6 +191,7 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
return false;
else
return true;
+ case RasterGLSurface: return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -227,8 +227,6 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind
{
if (window->type() == Qt::ForeignWindow)
return new QAndroidPlatformForeignWindow(window);
- else if (window->surfaceType() == QSurface::RasterSurface)
- return new QAndroidPlatformRasterWindow(window);
else
return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
}
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
index d821145973..73c0a76dd7 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
@@ -42,9 +42,11 @@
#include "qandroidplatformopenglwindow.h"
+#include "qandroidplatformscreen.h"
#include "androidjnimain.h"
#include <QSurfaceFormat>
+#include <QtGui/private/qwindow_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformscreen.h>
@@ -69,25 +71,52 @@ QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
unlockSurface();
}
+void QAndroidPlatformOpenGLWindow::repaint(const QRegion &region)
+{
+ // This is only for real raster top-level windows. Stop in all other cases.
+ if ((window()->surfaceType() == QSurface::RasterGLSurface && qt_window_private(window())->compositing)
+ || window()->surfaceType() == QSurface::OpenGLSurface
+ || QAndroidPlatformWindow::parent())
+ return;
+
+ QRect currentGeometry = geometry();
+
+ QRect dirtyClient = region.boundingRect();
+ QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(),
+ currentGeometry.top() + dirtyClient.top(),
+ dirtyClient.width(),
+ dirtyClient.height());
+ QRect mOldGeometryLocal = m_oldGeometry;
+ m_oldGeometry = currentGeometry;
+ // If this is a move, redraw the previous location
+ if (mOldGeometryLocal != currentGeometry)
+ platformScreen()->setDirty(mOldGeometryLocal);
+ platformScreen()->setDirty(dirtyRegion);
+}
+
void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
{
if (rect == geometry())
return;
- QRect oldGeometry = geometry();
+ m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
- QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
+ if (m_nativeSurfaceId != -1)
+ QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
QRect availableGeometry = screen()->availableGeometry();
- if (oldGeometry.width() == 0
- && oldGeometry.height() == 0
+ if (m_oldGeometry.width() == 0
+ && m_oldGeometry.height() == 0
&& rect.width() > 0
&& rect.height() > 0
&& availableGeometry.width() > 0
&& availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
}
+
+ if (rect.topLeft() != m_oldGeometry.topLeft())
+ repaint(QRegion(rect));
}
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
@@ -162,8 +191,8 @@ QSurfaceFormat QAndroidPlatformOpenGLWindow::format() const
void QAndroidPlatformOpenGLWindow::clearEgl()
{
- eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_eglSurface != EGL_NO_SURFACE) {
+ eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(m_eglDisplay, m_eglSurface);
m_eglSurface = EGL_NO_SURFACE;
}
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
index 713f943bc5..5f7089d5a4 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
@@ -66,6 +66,8 @@ public:
void applicationStateChanged(Qt::ApplicationState);
+ void repaint(const QRegion &region) Q_DECL_OVERRIDE;
+
protected:
virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h);
void createEgl(EGLConfig config);
@@ -80,6 +82,7 @@ private:
QJNIObjectPrivate m_androidSurfaceObject;
QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format;
+ QRect m_oldGeometry;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp b/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp
deleted file mode 100644
index 3fb236793b..0000000000
--- a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the plugins 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 "qandroidplatformrasterwindow.h"
-
-#include "qandroidplatformscreen.h"
-
-QT_BEGIN_NAMESPACE
-
-QAndroidPlatformRasterWindow::QAndroidPlatformRasterWindow(QWindow *window)
- :QAndroidPlatformWindow(window)
-{
-
-}
-
-void QAndroidPlatformRasterWindow::repaint(const QRegion &region)
-{
- if (QAndroidPlatformWindow::parent())
- return;
-
- QRect currentGeometry = geometry();
-
- QRect dirtyClient = region.boundingRect();
- QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(),
- currentGeometry.top() + dirtyClient.top(),
- dirtyClient.width(),
- dirtyClient.height());
- QRect mOldGeometryLocal = m_oldGeometry;
- m_oldGeometry = currentGeometry;
- // If this is a move, redraw the previous location
- if (mOldGeometryLocal != currentGeometry)
- platformScreen()->setDirty(mOldGeometryLocal);
- platformScreen()->setDirty(dirtyRegion);
-}
-
-void QAndroidPlatformRasterWindow::setGeometry(const QRect &rect)
-{
- m_oldGeometry = geometry();
- QAndroidPlatformWindow::setGeometry(rect);
- if (rect.topLeft() != m_oldGeometry.topLeft())
- repaint(QRegion(rect));
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index 433461f628..870d81688c 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -48,9 +48,9 @@
#include "qandroidplatformscreen.h"
#include "qandroidplatformbackingstore.h"
#include "qandroidplatformintegration.h"
+#include "qandroidplatformwindow.h"
#include "androidjnimain.h"
#include "androidjnimenu.h"
-#include "qandroidplatformrasterwindow.h"
#include <android/bitmap.h>
#include <android/native_window_jni.h>
@@ -58,6 +58,7 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
+#include <QtGui/private/qwindow_p.h>
QT_BEGIN_NAMESPACE
@@ -291,6 +292,19 @@ void QAndroidPlatformScreen::doRedraw()
if (m_dirtyRect.isEmpty())
return;
+ // Stop if there no visible raster windows. This is important because if we only have
+ // RasterGLSurface windows that have renderToTexture children (i.e. they need the
+ // OpenGL path) then we must bail out right now.
+ bool hasVisibleRasterWindows = false;
+ foreach (QAndroidPlatformWindow *window, m_windowStack) {
+ if (window->window()->isVisible() && window->isRaster() && !qt_window_private(window->window())->compositing) {
+ hasVisibleRasterWindows = true;
+ break;
+ }
+ }
+ if (!hasVisibleRasterWindows)
+ return;
+
QMutexLocker lock(&m_surfaceMutex);
if (m_id == -1 && m_rasterSurfaces) {
m_id = QtAndroid::createSurface(this, m_availableGeometry, true, m_depth);
@@ -343,7 +357,7 @@ void QAndroidPlatformScreen::doRedraw()
visibleRegion -= targetRect;
QRect windowRect = targetRect.translated(-window->geometry().topLeft());
- QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformRasterWindow *>(window)->backingStore();
+ QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformWindow *>(window)->backingStore();
if (backingStore)
compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect);
}
diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp
index 9c21abe39b..1f2f58f838 100644
--- a/src/plugins/platforms/android/qandroidplatformservices.cpp
+++ b/src/plugins/platforms/android/qandroidplatformservices.cpp
@@ -54,11 +54,10 @@ QAndroidPlatformServices::QAndroidPlatformServices()
bool QAndroidPlatformServices::openUrl(const QUrl &url)
{
QJNIObjectPrivate urlString = QJNIObjectPrivate::fromString(url.toString());
- QJNIObjectPrivate::callStaticMethod<void>(QtAndroid::applicationClass(),
- "openURL",
- "(Ljava/lang/String;)V",
- urlString.object());
- return true;
+ return QJNIObjectPrivate::callStaticMethod<jboolean>(QtAndroid::applicationClass(),
+ "openURL",
+ "(Ljava/lang/String;)Z",
+ urlString.object());
}
bool QAndroidPlatformServices::openDocument(const QUrl &url)
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h
index 91e32fa2ac..1899499d01 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformwindow.h
@@ -49,6 +49,7 @@
QT_BEGIN_NAMESPACE
class QAndroidPlatformScreen;
+class QAndroidPlatformBackingStore;
class QAndroidPlatformWindow: public QPlatformWindow
{
@@ -71,10 +72,19 @@ public:
void propagateSizeHints();
void requestActivateWindow();
void updateStatusBarVisibility();
- inline bool isRaster() const { return window()->surfaceType() == QSurface::RasterSurface; }
+ inline bool isRaster() const {
+ return window()->surfaceType() == QSurface::RasterSurface
+ || window()->surfaceType() == QSurface::RasterGLSurface;
+ }
bool isExposed() const;
virtual void applicationStateChanged(Qt::ApplicationState);
+
+ void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; }
+ QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; }
+
+ virtual void repaint(const QRegion &) { }
+
protected:
void setGeometry(const QRect &rect);
@@ -83,6 +93,8 @@ protected:
Qt::WindowState m_windowState;
WId m_windowId;
+
+ QAndroidPlatformBackingStore *m_backingStore = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
index 5a7cdec83e..8158c244ab 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
@@ -81,6 +81,7 @@ static NSButton *macCreateButton(const char *text, NSView *superview)
NSInteger mResultCode;
BOOL mDialogIsExecuting;
BOOL mResultSet;
+ BOOL mClosingDueToKnownButton;
};
- (void)restoreOriginalContentView;
- (void)relayout;
@@ -103,6 +104,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
mResultCode = NSCancelButton;
mDialogIsExecuting = false;
mResultSet = false;
+ mClosingDueToKnownButton = false;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7)
@@ -114,6 +116,11 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
name:NSColorPanelColorDidChangeNotification
object:mColorPanel];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:mColorPanel];
+
[mColorPanel retain];
return self;
}
@@ -179,6 +186,15 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
emit mHelper->colorSelected(mQtColor);
}
+- (void)windowWillClose:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+ if (mCancelButton && mHelper && !mClosingDueToKnownButton) {
+ mClosingDueToKnownButton = true; // prevent repeating emit
+ emit mHelper->reject();
+ }
+}
+
- (void)restoreOriginalContentView
{
if (mStolenContentView) {
@@ -246,6 +262,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
- (void)onOkClicked
{
+ mClosingDueToKnownButton = true;
[mColorPanel close];
[self updateQtColor];
[self finishOffWithCode:NSOKButton];
@@ -254,6 +271,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
- (void)onCancelClicked
{
if (mOkButton) {
+ mClosingDueToKnownButton = true;
[mColorPanel close];
mQtColor = QColor();
[self finishOffWithCode:NSCancelButton];
@@ -298,6 +316,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
{
mDialogIsExecuting = false;
mResultSet = false;
+ mClosingDueToKnownButton = false;
[mColorPanel makeKeyAndOrderFront:mColorPanel];
}
diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.h b/src/plugins/platforms/cocoa/qcocoasystemsettings.h
index 9ce301f7e7..3861da6230 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemsettings.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.h
@@ -50,7 +50,6 @@ QT_BEGIN_NAMESPACE
QPalette * qt_mac_createSystemPalette();
QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes();
-QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts();
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
index 26aa871998..3ce2f06763 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
@@ -213,48 +213,4 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
return palettes;
}
-QFont *qt_mac_qfontForThemeFont(ThemeFontID themeID)
-{
- CTFontUIFontType ctID = HIThemeGetUIFontType(themeID);
- QCFType<CTFontRef> ctfont = CTFontCreateUIFontForLanguage(ctID, 0, 0);
- QString familyName = QCFString(CTFontCopyFamilyName(ctfont));
- QCFType<CFDictionaryRef> dict = CTFontCopyTraits(ctfont);
- CFNumberRef num = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kCTFontWeightTrait));
- float fW;
- CFNumberGetValue(num, kCFNumberFloat32Type, &fW);
- QFont::Weight wght = fW > 0. ? QFont::Bold : QFont::Normal;
- num = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kCTFontSlantTrait));
- CFNumberGetValue(num, kCFNumberFloatType, &fW);
- bool italic = (fW != 0.0);
- return new QFont(familyName, CTFontGetSize(ctfont), wght, italic);
-}
-
-QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts()
-{
- QHash<QPlatformTheme::Font, QFont *> fonts;
-
- fonts.insert(QPlatformTheme::SystemFont, qt_mac_qfontForThemeFont(kThemeApplicationFont));
- fonts.insert(QPlatformTheme::PushButtonFont, qt_mac_qfontForThemeFont(kThemePushButtonFont));
- fonts.insert(QPlatformTheme::ListViewFont, qt_mac_qfontForThemeFont(kThemeViewsFont));
- fonts.insert(QPlatformTheme::ListBoxFont, qt_mac_qfontForThemeFont(kThemeViewsFont));
- fonts.insert(QPlatformTheme::TitleBarFont, qt_mac_qfontForThemeFont(kThemeWindowTitleFont));
- fonts.insert(QPlatformTheme::MenuFont, qt_mac_qfontForThemeFont(kThemeMenuItemFont));
- fonts.insert(QPlatformTheme::MenuBarFont, qt_mac_qfontForThemeFont(kThemeMenuItemFont));
- fonts.insert(QPlatformTheme::ComboMenuItemFont, qt_mac_qfontForThemeFont(kThemeSystemFont));
- fonts.insert(QPlatformTheme::HeaderViewFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont));
- fonts.insert(QPlatformTheme::TipLabelFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont));
- fonts.insert(QPlatformTheme::LabelFont, qt_mac_qfontForThemeFont(kThemeSystemFont));
- fonts.insert(QPlatformTheme::ToolButtonFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont));
- fonts.insert(QPlatformTheme::MenuItemFont, qt_mac_qfontForThemeFont(kThemeMenuItemFont));
- fonts.insert(QPlatformTheme::ComboLineEditFont, qt_mac_qfontForThemeFont(kThemeViewsFont));
- fonts.insert(QPlatformTheme::SmallFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont));
- fonts.insert(QPlatformTheme::MiniFont, qt_mac_qfontForThemeFont(kThemeMiniSystemFont));
-
- QFont* fixedFont = new QFont(QStringLiteral("Monaco"), fonts[QPlatformTheme::SystemFont]->pointSize());
- fixedFont->setStyleHint(QFont::TypeWriter);
- fonts.insert(QPlatformTheme::FixedFont, fixedFont);
-
- return fonts;
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index dce1671800..ae42fee82c 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -60,6 +60,7 @@
#include <QtCore/qfileinfo.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpainter.h>
+#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformnativeinterface.h>
@@ -134,6 +135,12 @@ const QPalette *QCocoaTheme::palette(Palette type) const
return 0;
}
+QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts()
+{
+ QCoreTextFontDatabase *ctfd = static_cast<QCoreTextFontDatabase *>(QGuiApplicationPrivate::platformIntegration()->fontDatabase());
+ return ctfd->themeFonts();
+}
+
const QFont *QCocoaTheme::font(Font type) const
{
if (m_fonts.isEmpty()) {
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 011a9ba71a..cfcbb8053c 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -66,7 +66,11 @@
#include <accessibilityinspector.h>
#endif
-Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.tabletsupport")
+Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
+#ifndef QT_NO_GESTURES
+Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
+#endif
+Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
static QTouchDevice *touchDevice = 0;
@@ -1120,41 +1124,49 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
}
}
+- (bool) shouldSendSingleTouch
+{
+ // QtWidgets expects single-point touch events, QtDeclarative does not.
+ // Until there is an API we solve this by looking at the window class type.
+ return m_window->inherits("QWidgetWindow");
+}
+
- (void)touchesBeganWithEvent:(NSEvent *)event
{
const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, /*acceptSingleTouch= ### true or false?*/false);
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points;
QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points);
}
- (void)touchesMovedWithEvent:(NSEvent *)event
{
const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, /*acceptSingleTouch= ### true or false?*/false);
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points;
QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points);
}
- (void)touchesEndedWithEvent:(NSEvent *)event
{
const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, /*acceptSingleTouch= ### true or false?*/false);
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points;
QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points);
}
- (void)touchesCancelledWithEvent:(NSEvent *)event
{
const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, /*acceptSingleTouch= ### true or false?*/false);
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points;
QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points);
}
#ifndef QT_NO_GESTURES
-//#define QT_COCOA_ENABLE_GESTURE_DEBUG
- (void)magnifyWithEvent:(NSEvent *)event
{
-#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG
- qDebug() << "magnifyWithEvent" << [event magnification];
-#endif
+ qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -1167,9 +1179,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)smartMagnifyWithEvent:(NSEvent *)event
{
static bool zoomIn = true;
-#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG
- qDebug() << "smartMagnifyWithEvent" << zoomIn;
-#endif
+ qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn;
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -1182,9 +1192,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)rotateWithEvent:(NSEvent *)event
{
-#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG
- qDebug() << "rotateWithEvent" << [event rotation];
-#endif
+ qCDebug(lcQpaGestures) << "rotateWithEvent" << [event rotation];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -1195,9 +1203,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)swipeWithEvent:(NSEvent *)event
{
-#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG
- qDebug() << "swipeWithEvent" << [event deltaX] << [event deltaY];
-#endif
+ qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -1219,22 +1225,18 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)beginGestureWithEvent:(NSEvent *)event
{
-#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG
- qDebug() << "beginGestureWithEvent";
-#endif
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint;
QWindowSystemInterface::handleGestureEvent(m_window, timestamp, Qt::BeginNativeGesture,
windowPoint, screenPoint);
}
- (void)endGestureWithEvent:(NSEvent *)event
{
-#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG
- qDebug() << "endGestureWithEvent";
-#endif
+ qCDebug(lcQpaGestures) << "endGestureWithEvent";
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
index 4c39560cbe..f131419140 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
@@ -48,11 +48,11 @@
#include "qwindowsdirect2ddevicecontext.h"
#include "qwindowsfontengine.h"
-#include "qwindowsfontenginedirectwrite.h"
#include "qwindowsfontdatabase.h"
#include "qwindowsintegration.h"
#include <QtCore/QStack>
+#include <QtCore/QSettings>
#include <QtGui/private/qpaintengine_p.h>
#include <QtGui/private/qtextengine_p.h>
#include <QtGui/private/qfontengine_p.h>
@@ -109,6 +109,13 @@ static inline ID2D1Factory1 *factory()
return QWindowsDirect2DContext::instance()->d2dFactory();
}
+inline static FLOAT pixelSizeToDIP(int pixelSize)
+{
+ FLOAT dpiX, dpiY;
+ QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY);
+ return FLOAT(pixelSize) * 96.0f / dpiY;
+}
+
class Direct2DPathGeometryWriter
{
public:
@@ -243,7 +250,7 @@ public:
QPointF currentBrushOrigin;
- QHash< QFont, ComPtr<IDWriteFontFace> > fontCache;
+ QHash< QFontDef, ComPtr<IDWriteFontFace> > fontCache;
struct {
bool emulate;
@@ -836,6 +843,74 @@ public:
{
dc()->SetAntialiasMode(antialiasMode());
}
+
+ void drawGlyphRun(const D2D1_POINT_2F &pos,
+ IDWriteFontFace *fontFace,
+ const QFontDef &fontDef,
+ int numGlyphs,
+ const UINT16 *glyphIndices,
+ const FLOAT *glyphAdvances,
+ const DWRITE_GLYPH_OFFSET *glyphOffsets,
+ bool rtl)
+ {
+ Q_Q(QWindowsDirect2DPaintEngine);
+
+ DWRITE_GLYPH_RUN glyphRun = {
+ fontFace, // IDWriteFontFace *fontFace;
+ pixelSizeToDIP(fontDef.pixelSize), // FLOAT fontEmSize;
+ numGlyphs, // UINT32 glyphCount;
+ glyphIndices, // const UINT16 *glyphIndices;
+ glyphAdvances, // const FLOAT *glyphAdvances;
+ glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets;
+ FALSE, // BOOL isSideways;
+ rtl ? 1 : 0 // UINT32 bidiLevel;
+ };
+
+ const bool antiAlias = bool((q->state()->renderHints & QPainter::TextAntialiasing)
+ && !(fontDef.styleStrategy & QFont::NoAntialias));
+ dc()->SetTextAntialiasMode(antiAlias ? D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE
+ : D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
+
+ dc()->DrawGlyphRun(pos,
+ &glyphRun,
+ NULL,
+ pen.brush.Get(),
+ DWRITE_MEASURING_MODE_GDI_CLASSIC);
+ }
+
+ ComPtr<IDWriteFontFace> fontFaceFromFontEngine(QFontEngine *fe)
+ {
+ const QFontDef fontDef = fe->fontDef;
+ ComPtr<IDWriteFontFace> fontFace = fontCache.value(fontDef);
+ if (fontFace)
+ return fontFace;
+
+ LOGFONT lf = QWindowsFontDatabase::fontDefToLOGFONT(fontDef);
+
+ // Get substitute name
+ static const char keyC[] = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes";
+ const QString familyName = QString::fromWCharArray(lf.lfFaceName);
+ const QString nameSubstitute = QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString();
+ memcpy(lf.lfFaceName, nameSubstitute.utf16(), sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE));
+
+ ComPtr<IDWriteFont> dwriteFont;
+ HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFromLOGFONT(&lf, &dwriteFont);
+ if (FAILED(hr)) {
+ qDebug("%s: CreateFontFromLOGFONT failed: %#x", __FUNCTION__, hr);
+ return fontFace;
+ }
+
+ hr = dwriteFont->CreateFontFace(&fontFace);
+ if (FAILED(hr)) {
+ qDebug("%s: CreateFontFace failed: %#x", __FUNCTION__, hr);
+ return fontFace;
+ }
+
+ if (fontFace)
+ fontCache.insert(fontDef, fontFace);
+
+ return fontFace;
+ }
};
QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap)
@@ -1411,7 +1486,7 @@ void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticText
return;
}
- ComPtr<IDWriteFontFace> fontFace = fontFaceFromFontEngine(staticTextItem->font, staticTextItem->fontEngine());
+ ComPtr<IDWriteFontFace> fontFace = d->fontFaceFromFontEngine(staticTextItem->fontEngine());
if (!fontFace) {
qWarning("%s: Could not find font - falling back to slow text rendering path.", __FUNCTION__);
QPaintEngineEx::drawStaticTextItem(staticTextItem);
@@ -1432,14 +1507,14 @@ void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticText
glyphOffsets[i].ascenderOffset = staticTextItem->glyphPositions[i].y.toReal() * -1;
}
- drawGlyphRun(D2D1::Point2F(0, 0),
- fontFace.Get(),
- staticTextItem->font,
- staticTextItem->numGlyphs,
- glyphIndices.constData(),
- glyphAdvances.constData(),
- glyphOffsets.constData(),
- false);
+ d->drawGlyphRun(D2D1::Point2F(0, 0),
+ fontFace.Get(),
+ staticTextItem->fontEngine()->fontDef,
+ staticTextItem->numGlyphs,
+ glyphIndices.constData(),
+ glyphAdvances.constData(),
+ glyphOffsets.constData(),
+ false);
}
void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
@@ -1459,7 +1534,7 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem
return;
}
- ComPtr<IDWriteFontFace> fontFace = fontFaceFromFontEngine(*ti.f, ti.fontEngine);
+ ComPtr<IDWriteFontFace> fontFace = d->fontFaceFromFontEngine(ti.fontEngine);
if (!fontFace) {
qWarning("%s: Could not find font - falling back to slow text rendering path.", __FUNCTION__);
QPaintEngine::drawTextItem(p, textItem);
@@ -1482,72 +1557,14 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem
const bool rtl = (ti.flags & QTextItem::RightToLeft);
const QPointF offset(rtl ? ti.width.toReal() : 0, 0);
- drawGlyphRun(to_d2d_point_2f(p + offset),
- fontFace.Get(),
- ti.font(),
- ti.glyphs.numGlyphs,
- glyphIndices.constData(),
- glyphAdvances.constData(),
- glyphOffsets.constData(),
- rtl);
-}
-
-inline static FLOAT pointSizeToDIP(qreal pointSize, FLOAT dpiY)
-{
- return (pointSize + (pointSize / qreal(3.0))) * (dpiY / 96.0f);
-}
-
-inline static FLOAT pixelSizeToDIP(int pixelSize, FLOAT dpiY)
-{
- return FLOAT(pixelSize) * 96.0f / dpiY;
-}
-
-inline static FLOAT fontSizeInDIP(const QFont &font)
-{
- FLOAT dpiX, dpiY;
- QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY);
-
- if (font.pixelSize() == -1) {
- // font size was set as points
- return pointSizeToDIP(font.pointSizeF(), dpiY);
- } else {
- // font size was set as pixels
- return pixelSizeToDIP(font.pixelSize(), dpiY);
- }
-}
-
-void QWindowsDirect2DPaintEngine::drawGlyphRun(const D2D1_POINT_2F &pos,
- IDWriteFontFace *fontFace,
- const QFont &font,
- int numGlyphs,
- const UINT16 *glyphIndices,
- const FLOAT *glyphAdvances,
- const DWRITE_GLYPH_OFFSET *glyphOffsets,
- bool rtl)
-{
- Q_D(QWindowsDirect2DPaintEngine);
-
- DWRITE_GLYPH_RUN glyphRun = {
- fontFace, // IDWriteFontFace *fontFace;
- fontSizeInDIP(font), // FLOAT fontEmSize;
- numGlyphs, // UINT32 glyphCount;
- glyphIndices, // const UINT16 *glyphIndices;
- glyphAdvances, // const FLOAT *glyphAdvances;
- glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets;
- FALSE, // BOOL isSideways;
- rtl ? 1 : 0 // UINT32 bidiLevel;
- };
-
- const bool antiAlias = bool((state()->renderHints & QPainter::TextAntialiasing)
- && !(font.styleStrategy() & QFont::NoAntialias));
- d->dc()->SetTextAntialiasMode(antiAlias ? D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE
- : D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
-
- d->dc()->DrawGlyphRun(pos,
- &glyphRun,
- NULL,
- d->pen.brush.Get(),
- DWRITE_MEASURING_MODE_GDI_CLASSIC);
+ d->drawGlyphRun(to_d2d_point_2f(p + offset),
+ fontFace.Get(),
+ ti.fontEngine->fontDef,
+ ti.glyphs.numGlyphs,
+ glyphIndices.constData(),
+ glyphAdvances.constData(),
+ glyphOffsets.constData(),
+ rtl);
}
void QWindowsDirect2DPaintEngine::ensureBrush()
@@ -1678,49 +1695,4 @@ void QWindowsDirect2DPaintEngine::adjustForAliasing(QPointF *point)
(*point) += adjustment;
}
-Microsoft::WRL::ComPtr<IDWriteFontFace> QWindowsDirect2DPaintEngine::fontFaceFromFontEngine(const QFont &font, QFontEngine *fe)
-{
- Q_D(QWindowsDirect2DPaintEngine);
-
- ComPtr<IDWriteFontFace> fontFace = d->fontCache.value(font);
- if (fontFace)
- return fontFace;
-
- switch (fe->type()) {
- case QFontEngine::Win:
- {
- QWindowsFontEngine *wfe = static_cast<QWindowsFontEngine *>(fe);
- QSharedPointer<QWindowsFontEngineData> wfed = wfe->fontEngineData();
-
- HGDIOBJ oldfont = wfe->selectDesignFont();
- HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFaceFromHdc(wfed->hdc, &fontFace);
- DeleteObject(SelectObject(wfed->hdc, oldfont));
- if (FAILED(hr))
- qWarning("%s: Could not create DirectWrite fontface from HDC: %#x", __FUNCTION__, hr);
-
- }
- break;
-
-#ifndef QT_NO_DIRECTWRITE
-
- case QFontEngine::DirectWrite:
- {
- QWindowsFontEngineDirectWrite *wfedw = static_cast<QWindowsFontEngineDirectWrite *>(fe);
- fontFace = wfedw->directWriteFontFace();
- }
- break;
-
-#endif // QT_NO_DIRECTWRITE
-
- default:
- qWarning("%s: Unknown font engine!", __FUNCTION__);
- break;
- }
-
- if (fontFace)
- d->fontCache.insert(font, fontFace);
-
- return fontFace;
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
index c91a951ebe..1469d32876 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
@@ -105,10 +105,6 @@ public:
void drawTextItem(const QPointF &p, const QTextItem &textItem) Q_DECL_OVERRIDE;
private:
- void drawGlyphRun(const D2D1_POINT_2F &pos, IDWriteFontFace *fontFace, const QFont &font,
- int numGlyphs, const UINT16 *glyphIndices, const FLOAT *glyphAdvances,
- const DWRITE_GLYPH_OFFSET *glyphOffsets, bool rtl);
-
void ensureBrush();
void ensureBrush(const QBrush &brush);
void ensurePen();
@@ -122,8 +118,6 @@ private:
bool antiAliasingEnabled() const;
void adjustForAliasing(QRectF *rect);
void adjustForAliasing(QPointF *point);
-
- Microsoft::WRL::ComPtr<IDWriteFontFace> fontFaceFromFontEngine(const QFont &font, QFontEngine *fe);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/directfb/qdirectfbinput.cpp b/src/plugins/platforms/directfb/qdirectfbinput.cpp
index 49dc45f04a..fd558b9974 100644
--- a/src/plugins/platforms/directfb/qdirectfbinput.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbinput.cpp
@@ -154,7 +154,7 @@ void QDirectFbInput::handleEvents()
void QDirectFbInput::handleMouseEvents(const DFBEvent &event)
{
QPoint p(event.window.x, event.window.y);
- QPoint globalPos = globalPoint(event);
+ QPoint globalPos(event.window.cx, event.window.cy);
Qt::MouseButtons buttons = QDirectFbConvenience::mouseButtons(event.window.buttons);
QDirectFBPointer<IDirectFBDisplayLayer> layer(QDirectFbConvenience::dfbDisplayLayer());
@@ -169,8 +169,8 @@ void QDirectFbInput::handleMouseEvents(const DFBEvent &event)
void QDirectFbInput::handleWheelEvent(const DFBEvent &event)
{
- QPoint p(event.window.cx, event.window.cy);
- QPoint globalPos = globalPoint(event);
+ QPoint p(event.window.x, event.window.y);
+ QPoint globalPos(event.window.cx, event.window.cy);
long timestamp = (event.window.timestamp.tv_sec*1000) + (event.window.timestamp.tv_usec/1000);
QWindow *tlw = m_tlwMap.value(event.window.window_id);
QWindowSystemInterface::handleWheelEvent(tlw, timestamp, p, globalPos,
@@ -227,13 +227,4 @@ void QDirectFbInput::handleGeometryEvent(const DFBEvent &event)
QWindowSystemInterface::handleGeometryChange(tlw, rect);
}
-inline QPoint QDirectFbInput::globalPoint(const DFBEvent &event) const
-{
- QDirectFBPointer<IDirectFBWindow> window;
- m_dfbDisplayLayer->GetWindow(m_dfbDisplayLayer, event.window.window_id, window.outPtr());
- int x,y;
- window->GetPosition(window.data(), &x, &y);
- return QPoint(event.window.cx +x, event.window.cy + y);
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/directfb/qdirectfbinput.h b/src/plugins/platforms/directfb/qdirectfbinput.h
index 0ce45823e1..0d775cdc79 100644
--- a/src/plugins/platforms/directfb/qdirectfbinput.h
+++ b/src/plugins/platforms/directfb/qdirectfbinput.h
@@ -75,7 +75,6 @@ private:
void handleGotFocusEvent(const DFBEvent &event);
void handleCloseEvent(const DFBEvent& event);
void handleGeometryEvent(const DFBEvent& event);
- inline QPoint globalPoint(const DFBEvent &event) const;
IDirectFB *m_dfbInterface;
diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.cpp b/src/plugins/platforms/directfb/qdirectfbintegration.cpp
index 27d070b75d..fe11cbebc4 100644
--- a/src/plugins/platforms/directfb/qdirectfbintegration.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbintegration.cpp
@@ -48,6 +48,7 @@
#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtPlatformSupport/private/qgenericunixservices_p.h>
#include <QtGui/private/qpixmap_blitter_p.h>
#include <QtGui/private/qpixmap_raster_p.h>
@@ -56,11 +57,13 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include <QtCore/QAbstractEventDispatcher>
+#include <qpa/qplatforminputcontextfactory_p.h>
QT_BEGIN_NAMESPACE
QDirectFbIntegration::QDirectFbIntegration()
: m_fontDb(new QGenericUnixFontDatabase())
+ , m_services(new QGenericUnixServices)
{
}
@@ -69,6 +72,8 @@ void QDirectFbIntegration::connectToDirectFb()
initializeDirectFB();
initializeScreen();
initializeInput();
+
+ m_inputContext = QPlatformInputContextFactory::create();
}
bool QDirectFbIntegration::hasCapability(Capability cap) const
@@ -155,4 +160,14 @@ QPlatformFontDatabase *QDirectFbIntegration::fontDatabase() const
return m_fontDb.data();
}
+QPlatformServices *QDirectFbIntegration::services() const
+{
+ return m_services.data();
+}
+
+QPlatformNativeInterface *QDirectFbIntegration::nativeInterface() const
+{
+ return const_cast<QDirectFbIntegration *>(this);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.h b/src/plugins/platforms/directfb/qdirectfbintegration.h
index 8586f33587..eb3ff41961 100644
--- a/src/plugins/platforms/directfb/qdirectfbintegration.h
+++ b/src/plugins/platforms/directfb/qdirectfbintegration.h
@@ -46,6 +46,7 @@
#include "qdirectfbscreen.h"
#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
#include <directfb.h>
#include <directfb_version.h>
@@ -54,7 +55,7 @@ QT_BEGIN_NAMESPACE
class QThread;
class QAbstractEventDispatcher;
-class QDirectFbIntegration : public QPlatformIntegration
+class QDirectFbIntegration : public QPlatformIntegration, public QPlatformNativeInterface
{
public:
QDirectFbIntegration();
@@ -69,6 +70,9 @@ public:
QAbstractEventDispatcher *createEventDispatcher() const;
QPlatformFontDatabase *fontDatabase() const;
+ QPlatformServices *services() const;
+ QPlatformInputContext *inputContext() const { return m_inputContext; }
+ QPlatformNativeInterface *nativeInterface() const;
protected:
virtual void initializeDirectFB();
@@ -81,7 +85,8 @@ protected:
QScopedPointer<QDirectFbInput> m_input;
QScopedPointer<QThread> m_inputRunner;
QScopedPointer<QPlatformFontDatabase> m_fontDb;
-
+ QScopedPointer<QPlatformServices> m_services;
+ QPlatformInputContext *m_inputContext;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/directfb/qdirectfbwindow.cpp b/src/plugins/platforms/directfb/qdirectfbwindow.cpp
index 6bdfc9f161..52ff1a7704 100644
--- a/src/plugins/platforms/directfb/qdirectfbwindow.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbwindow.cpp
@@ -67,27 +67,39 @@ void QDirectFbWindow::createDirectFBWindow()
DFBWindowDescription description;
memset(&description,0,sizeof(DFBWindowDescription));
- description.flags = DFBWindowDescriptionFlags(DWDESC_WIDTH|DWDESC_HEIGHT|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS
- |DWDESC_OPTIONS
- |DWDESC_CAPS);
- description.width = qMax(1, window()->width());
- description.height = qMax(1, window()->height());
- description.posx = window()->x();
- description.posy = window()->y();
-
- if (layerConfig.surface_caps & DSCAPS_PREMULTIPLIED)
- description.surface_caps = DSCAPS_PREMULTIPLIED;
- description.pixelformat = layerConfig.pixelformat;
-
- description.options = DFBWindowOptions(DWOP_ALPHACHANNEL);
- description.caps = DFBWindowCapabilities(DWCAPS_DOUBLEBUFFER|DWCAPS_ALPHACHANNEL);
-
- DFBResult result = layer->CreateWindow(layer, &description, m_dfbWindow.outPtr());
- if (result != DFB_OK)
- DirectFBError("QDirectFbWindow: failed to create window", result);
-
- m_dfbWindow->SetOpacity(m_dfbWindow.data(), 0xff);
- m_inputHandler->addWindow(m_dfbWindow.data(), window());
+
+ if (window()->type() == Qt::Desktop) {
+ QRect fullscreenRect(QPoint(), screen()->availableGeometry().size());
+ window()->setGeometry(fullscreenRect);
+
+ DFBResult result = layer->CreateWindow(layer, &description, m_dfbWindow.outPtr());
+ if (result != DFB_OK)
+ DirectFBError("QDirectFbWindow: failed to create window", result);
+
+ } else {
+ description.flags = DFBWindowDescriptionFlags(DWDESC_WIDTH|DWDESC_HEIGHT|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS
+ |DWDESC_OPTIONS
+ |DWDESC_CAPS);
+ description.width = qMax(1, window()->width());
+ description.height = qMax(1, window()->height());
+ description.posx = window()->x();
+ description.posy = window()->y();
+
+ if (layerConfig.surface_caps & DSCAPS_PREMULTIPLIED)
+ description.surface_caps = DSCAPS_PREMULTIPLIED;
+ description.pixelformat = layerConfig.pixelformat;
+
+ description.options = DFBWindowOptions(DWOP_ALPHACHANNEL);
+ description.caps = DFBWindowCapabilities(DWCAPS_DOUBLEBUFFER|DWCAPS_ALPHACHANNEL);
+
+
+ DFBResult result = layer->CreateWindow(layer, &description, m_dfbWindow.outPtr());
+ if (result != DFB_OK)
+ DirectFBError("QDirectFbWindow: failed to create window", result);
+
+ m_dfbWindow->SetOpacity(m_dfbWindow.data(), 0xff);
+ m_inputHandler->addWindow(m_dfbWindow.data(), window());
+ }
}
QDirectFbWindow::~QDirectFbWindow()
@@ -98,21 +110,9 @@ QDirectFbWindow::~QDirectFbWindow()
void QDirectFbWindow::setGeometry(const QRect &rect)
{
-// bool isMoveOnly = (rect.topLeft() != geometry().topLeft()) && (rect.size() == geometry().size());
-
QPlatformWindow::setGeometry(rect);
- if (window()->isVisible()) {
- m_dfbWindow->SetBounds(m_dfbWindow.data(), rect.x(),rect.y(),
- rect.width(), rect.height());
-// ### TODO port, verify if this is needed
-#if 0
- //Hack. When moving since the WindowSurface of a window becomes invalid when moved
- if (isMoveOnly) { //if resize then windowsurface is updated.
- widget()->windowSurface()->resize(rect.size());
- window()->update();
- }
-#endif
- }
+ m_dfbWindow->SetBounds(m_dfbWindow.data(), rect.x(),rect.y(),
+ rect.width(), rect.height());
}
void QDirectFbWindow::setOpacity(qreal level)
@@ -123,21 +123,23 @@ void QDirectFbWindow::setOpacity(qreal level)
void QDirectFbWindow::setVisible(bool visible)
{
- if (visible) {
- int x = geometry().x();
- int y = geometry().y();
- m_dfbWindow->MoveTo(m_dfbWindow.data(), x, y);
- } else {
- QDirectFBPointer<IDirectFBDisplayLayer> displayLayer;
- QDirectFbConvenience::dfbInterface()->GetDisplayLayer(QDirectFbConvenience::dfbInterface(), DLID_PRIMARY, displayLayer.outPtr());
+ if (window()->type() != Qt::Desktop) {
+ if (visible) {
+ int x = geometry().x();
+ int y = geometry().y();
+ m_dfbWindow->MoveTo(m_dfbWindow.data(), x, y);
+ } else {
+ QDirectFBPointer<IDirectFBDisplayLayer> displayLayer;
+ QDirectFbConvenience::dfbInterface()->GetDisplayLayer(QDirectFbConvenience::dfbInterface(), DLID_PRIMARY, displayLayer.outPtr());
+
+ DFBDisplayLayerConfig config;
+ displayLayer->GetConfiguration(displayLayer.data(), &config);
+ m_dfbWindow->MoveTo(m_dfbWindow.data(), config. width + 1, config.height + 1);
+ }
- DFBDisplayLayerConfig config;
- displayLayer->GetConfiguration(displayLayer.data(), &config);
- m_dfbWindow->MoveTo(m_dfbWindow.data(), config. width + 1, config.height + 1);
+ if (window()->isTopLevel() && visible)
+ QPlatformWindow::setVisible(visible);
}
-
- if (window()->isTopLevel() && visible)
- QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry().size()));
}
void QDirectFbWindow::setWindowFlags(Qt::WindowFlags flags)
@@ -158,12 +160,14 @@ void QDirectFbWindow::setWindowFlags(Qt::WindowFlags flags)
void QDirectFbWindow::raise()
{
- m_dfbWindow->RaiseToTop(m_dfbWindow.data());
+ if (window()->type() != Qt::Desktop)
+ m_dfbWindow->RaiseToTop(m_dfbWindow.data());
}
void QDirectFbWindow::lower()
{
- m_dfbWindow->LowerToBottom(m_dfbWindow.data());
+ if (window()->type() != Qt::Desktop)
+ m_dfbWindow->LowerToBottom(m_dfbWindow.data());
}
WId QDirectFbWindow::winId() const
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 4083c2d5a9..0143b75828 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -53,14 +53,27 @@
QIOSContext::QIOSContext(QOpenGLContext *context)
: QPlatformOpenGLContext()
, m_sharedContext(static_cast<QIOSContext *>(context->shareHandle()))
- , m_eaglContext([[EAGLContext alloc]
- initWithAPI:kEAGLRenderingAPIOpenGLES2
- sharegroup:m_sharedContext ? [m_sharedContext->m_eaglContext sharegroup] : nil])
, m_format(context->format())
{
m_format.setRenderableType(QSurfaceFormat::OpenGLES);
- m_format.setMajorVersion(2);
- m_format.setMinorVersion(0);
+ m_eaglContext = [[EAGLContext alloc]
+ initWithAPI:EAGLRenderingAPI(m_format.majorVersion())
+ sharegroup:m_sharedContext ? [m_sharedContext->m_eaglContext sharegroup] : nil];
+
+ if (m_eaglContext != nil) {
+ EAGLContext *originalContext = [EAGLContext currentContext];
+ [EAGLContext setCurrentContext:m_eaglContext];
+ const GLubyte *s = glGetString(GL_VERSION);
+ if (s) {
+ QByteArray version = QByteArray(reinterpret_cast<const char *>(s));
+ int major, minor;
+ if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) {
+ m_format.setMajorVersion(major);
+ m_format.setMinorVersion(minor);
+ }
+ }
+ [EAGLContext setCurrentContext:originalContext];
+ }
// iOS internally double-buffers its rendering using copy instead of flipping,
// so technically we could report that we are single-buffered so that clients
diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h
index 17184dc21d..20bebb1f3b 100644
--- a/src/plugins/platforms/ios/qiosglobal.h
+++ b/src/plugins/platforms/ios/qiosglobal.h
@@ -65,4 +65,8 @@ int infoPlistValue(NSString* key, int defaultValue);
QT_END_NAMESPACE
+@interface UIResponder (QtFirstResponder)
++(id)currentFirstResponder;
+@end
+
#endif // QIOSGLOBAL_H
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
index 2ce064582e..7ff4950599 100644
--- a/src/plugins/platforms/ios/qiosglobal.mm
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -141,5 +141,30 @@ int infoPlistValue(NSString* key, int defaultValue)
return value ? [value intValue] : defaultValue;
}
+// -------------------------------------------------------------------------
+
+@interface QtFirstResponderEvent : UIEvent
+@property (nonatomic, strong) id firstResponder;
+@end
+
+@implementation QtFirstResponderEvent
+@end
+
+@implementation UIResponder (QtFirstResponder)
+
++(id)currentFirstResponder
+{
+ QtFirstResponderEvent *event = [[[QtFirstResponderEvent alloc] init] autorelease];
+ [[UIApplication sharedApplication] sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event];
+ return event.firstResponder;
+}
+
+- (void)qt_findFirstResponder:(id)sender event:(QtFirstResponderEvent *)event
+{
+ Q_UNUSED(sender);
+ event.firstResponder = self;
+}
+@end
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm
index db579ba559..ad8bd9bdf4 100644
--- a/src/plugins/platforms/ios/qiosplatformaccessibility.mm
+++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm
@@ -64,9 +64,11 @@ void invalidateCache(QAccessibleInterface *iface)
win = parent->window();
parent = parent->parent();
} while (!win && parent);
- Q_ASSERT(win && win->handle());
- QIOSWindow *window = static_cast<QIOSWindow*>(win->handle());
- window->clearAccessibleCache();
+
+ if (win && win->handle()) {
+ QIOSWindow *window = static_cast<QIOSWindow*>(win->handle());
+ window->clearAccessibleCache();
+ }
}
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
index e7093185aa..e51e97bd5a 100644
--- a/src/plugins/platforms/ios/qiostheme.mm
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -46,6 +46,10 @@
#include <QtGui/QFont>
+#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+
#include <UIKit/UIFont.h>
#include <UIKit/UIInterface.h>
@@ -75,19 +79,8 @@ QVariant QIOSTheme::themeHint(ThemeHint hint) const
const QFont *QIOSTheme::font(Font type) const
{
if (m_fonts.isEmpty()) {
- // The real system font on iOS is '.Helvetica Neue UI', as returned by both [UIFont systemFontOfSize]
- // and CTFontCreateUIFontForLanguage(kCTFontSystemFontType, ...), but this font is not included when
- // populating the available fonts in QCoreTextFontDatabase::populateFontDatabase(), since the font
- // is internal to iOS and not supposed to be used by applications. We could potentially add this
- // font to the font-database, but it would then show up when enumerating user fonts from Qt
- // applications since we don't have a flag in Qt to mark a font as a private system font.
- // For now we hard-code the font to Helvetica, which should be very close to the actual
- // system font.
- QLatin1String systemFontFamilyName("Helvetica");
- m_fonts.insert(QPlatformTheme::SystemFont, new QFont(systemFontFamilyName, [UIFont systemFontSize]));
- m_fonts.insert(QPlatformTheme::SmallFont, new QFont(systemFontFamilyName, [UIFont smallSystemFontSize]));
- m_fonts.insert(QPlatformTheme::LabelFont, new QFont(systemFontFamilyName, [UIFont labelFontSize]));
- m_fonts.insert(QPlatformTheme::PushButtonFont, new QFont(systemFontFamilyName, [UIFont buttonFontSize]));
+ QCoreTextFontDatabase *ctfd = static_cast<QCoreTextFontDatabase *>(QGuiApplicationPrivate::platformIntegration()->fontDatabase());
+ m_fonts = ctfd->themeFonts();
}
return m_fonts.value(type, 0);
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 76bd9bb2b5..d8dd875d83 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -85,6 +85,7 @@ QIOSWindow::~QIOSWindow()
// cancellation of all touch events.
[m_view touchesCancelled:0 withEvent:0];
+ clearAccessibleCache();
m_view->m_qioswindow = 0;
[m_view removeFromSuperview];
[m_view release];
diff --git a/src/plugins/platforms/ios/quiview_textinput.mm b/src/plugins/platforms/ios/quiview_textinput.mm
index 861c8151c6..2280b8259a 100644
--- a/src/plugins/platforms/ios/quiview_textinput.mm
+++ b/src/plugins/platforms/ios/quiview_textinput.mm
@@ -177,7 +177,7 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
[super becomeFirstResponder];
}
-- (void)updateUITextInputDelegate:(NSNumber *)intQuery
+- (void)updateUITextInputDelegate:(Qt::InputMethodQueries)query
{
// As documented, we should not report textWillChange/textDidChange unless the text
// was changed externally. That will cause spell checking etc to fail. But we don't
@@ -187,7 +187,6 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
if (m_inSendEventToFocusObject)
return;
- Qt::InputMethodQueries query = Qt::InputMethodQueries([intQuery intValue]);
if (query & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) {
[self.inputDelegate selectionWillChange:id<UITextInput>(self)];
[self.inputDelegate selectionDidChange:id<UITextInput>(self)];
@@ -213,7 +212,7 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
// not be any performance gain by only updating \a query.
staticVariables()->inputMethodQueryEvent = QInputMethodQueryEvent(Qt::ImQueryInput);
QCoreApplication::sendEvent(focusObject, &staticVariables()->inputMethodQueryEvent);
- [self updateUITextInputDelegate:[NSNumber numberWithInt:int(query)]];
+ [self updateUITextInputDelegate:query];
}
- (void)sendEventToFocusObject:(QEvent &)e
@@ -234,20 +233,23 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
{
[self setMarkedText:@"" selectedRange:NSMakeRange(0, 0)];
[self updateInputMethodWithQuery:Qt::ImQueryInput];
+
// Guard agains recursive callbacks by posting calls to UITextInput
- [self performSelectorOnMainThread:@selector(updateKeyboardLayout) withObject:nil waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(updateUITextInputDelegate:)
- withObject:[NSNumber numberWithInt:int(Qt::ImQueryInput)]
- waitUntilDone:NO];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self updateKeyboardLayout];
+ [self updateUITextInputDelegate:Qt::ImQueryInput];
+ });
}
- (void)commit
{
[self unmarkText];
+
// Guard agains recursive callbacks by posting calls to UITextInput
- [self performSelectorOnMainThread:@selector(updateUITextInputDelegate:)
- withObject:[NSNumber numberWithInt:int(Qt::ImSurroundingText)]
- waitUntilDone:NO];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self updateKeyboardLayout];
+ [self updateUITextInputDelegate:Qt::ImSurroundingText];
+ });
}
- (QVariant)imValue:(Qt::InputMethodQuery)query
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 1b2502af10..8c361d72ca 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -77,6 +77,7 @@ enum WindowsEventType // Simplify event types
LeaveEvent = WindowEventFlag + 5,
CloseEvent = WindowEventFlag + 6,
ShowEvent = WindowEventFlag + 7,
+ ShowEventOnParentRestoring = WindowEventFlag + 20,
HideEvent = WindowEventFlag + 8,
DestroyEvent = WindowEventFlag + 9,
MoveEvent = WindowEventFlag + 10,
@@ -128,7 +129,7 @@ enum ProcessDpiAwareness
} // namespace QtWindows
-inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn)
+inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn, LPARAM lParamIn)
{
switch (message) {
case WM_PAINT:
@@ -156,7 +157,9 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
case WM_MOVE:
return QtWindows::MoveEvent;
case WM_SHOWWINDOW:
- return wParamIn ? QtWindows::ShowEvent : QtWindows::HideEvent;
+ if (wParamIn)
+ return lParamIn == SW_PARENTOPENING ? QtWindows::ShowEventOnParentRestoring : QtWindows::ShowEvent;
+ return QtWindows::HideEvent;
case WM_SIZE:
return QtWindows::ResizeEvent;
case WM_NCCALCSIZE:
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
index 34a9c1df5f..40d1108f60 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
@@ -43,6 +43,7 @@
#include "qwindowswindow.h"
#include "qwindowsnativeimage.h"
#include "qwindowscontext.h"
+#include "qwindowsscaling.h"
#include <QtGui/QWindow>
#include <QtGui/QPainter>
@@ -75,12 +76,10 @@ QPaintDevice *QWindowsBackingStore::paintDevice()
return &m_image->image();
}
-void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
- const QPoint &offset)
+void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, 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);
@@ -90,8 +89,9 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
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.
- QRect r = window->frameGeometry();
- QPoint frameOffset(window->frameMargins().left(), window->frameMargins().top());
+ const QMargins marginsDP = rw->frameMarginsDp();
+ const QRect r = rw->geometryDp() + marginsDP;
+ const QPoint frameOffset(marginsDP.left(), marginsDP.top());
QRect dirtyRect = br.translated(offset + frameOffset);
SIZE size = {r.width(), r.height()};
@@ -135,14 +135,15 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
}
}
-void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
+void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion &regionDip)
{
+ 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 << ' ' << region
- << " from: " << (m_image.isNull() ? QSize() : m_image->image().size());
+ << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << sizeDip << ' '
+ << regionDip << " from: " << (m_image.isNull() ? QSize() : m_image->image().size());
}
#endif
const QImage::Format format = window()->format().hasAlpha() ?
@@ -151,10 +152,10 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
QWindowsNativeImage *oldwni = m_image.data();
QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format);
- if (oldwni && !region.isEmpty()) {
+ if (oldwni && !regionDip.isEmpty()) {
const QImage &oldimg(oldwni->image());
QImage &newimg(newwni->image());
- QRegion staticRegion(region);
+ QRegion staticRegion = QWindowsScaling::mapToNative(regionDip);
staticRegion &= QRect(0, 0, oldimg.width(), oldimg.height());
staticRegion &= QRect(0, 0, newimg.width(), newimg.height());
QPainter painter(&newimg);
@@ -163,35 +164,38 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
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 &area, int dx, int dy)
+bool QWindowsBackingStore::scroll(const QRegion &areaDip, int dxDip, int dyDip)
{
if (m_image.isNull() || m_image->image().isNull())
return false;
- const QVector<QRect> rects = area.rects();
+ const QPoint dp = QPoint(dxDip, dyDip) * QWindowsScaling::factor();
+ const QVector<QRect> rects = areaDip.rects();
for (int i = 0; i < rects.size(); ++i)
- qt_scrollRectInImage(m_image->image(), rects.at(i), QPoint(dx, dy));
+ qt_scrollRectInImage(m_image->image(), QWindowsScaling::mapToNative(rects.at(i)), dp);
return true;
}
-void QWindowsBackingStore::beginPaint(const QRegion &region)
+void QWindowsBackingStore::beginPaint(const QRegion &regionDip)
{
if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region;
+ qCDebug(lcQpaBackingStore) <<__FUNCTION__ << regionDip;
if (m_image->image().hasAlphaChannel()) {
QPainter p(&m_image->image());
p.setCompositionMode(QPainter::CompositionMode_Source);
const QColor blank = Qt::transparent;
- foreach (const QRect &r, region.rects())
- p.fillRect(r, blank);
+ foreach (const QRect &r, regionDip.rects())
+ p.fillRect(QWindowsScaling::mapToNative(r), blank);
}
}
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h
index e19b8a4db1..9c9500dabb 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.h
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.h
@@ -43,6 +43,7 @@
#define QWINDOWSBACKINGSTORE_H
#include "qtwindows_additional.h"
+#include "qwindowsscaling.h"
#include <qpa/qplatformbackingstore.h>
#include <QtCore/QScopedPointer>
@@ -60,7 +61,12 @@ public:
~QWindowsBackingStore();
QPaintDevice *paintDevice() Q_DECL_OVERRIDE;
- void flush(QWindow *window, const QRegion &region, const QPoint &offset) Q_DECL_OVERRIDE;
+ void flush(QWindow *window, const QRegion &region, 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 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 dc861c963d..132f224382 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -59,6 +59,7 @@
#endif
#include "qwindowsscreen.h"
#include "qwindowstheme.h"
+#include "qwindowsscaling.h"
#include <QtGui/QWindow>
#include <qpa/qwindowsysteminterface.h>
@@ -88,9 +89,9 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts")
Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl")
Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
-Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.inputmethods")
+Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods")
Q_LOGGING_CATEGORY(lcQpaDialogs, "qt.qpa.dialogs")
-Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.tabletsupport")
+Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
int QWindowsContext::verbose = 0;
@@ -1051,6 +1052,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::FocusOutEvent:
handleFocusEvent(et, platformWindow);
return true;
+ case QtWindows::ShowEventOnParentRestoring: // QTBUG-40696, prevent Windows from re-showing hidden transient children (dialogs).
+ if (!platformWindow->window()->isVisible()) {
+ *result = 0;
+ return true;
+ }
+ break;
case QtWindows::HideEvent:
platformWindow->handleHidden();
return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING)
@@ -1212,7 +1219,9 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
}
}
- QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos,
+ QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered,
+ pos / QWindowsScaling::factor(),
+ globalPos / QWindowsScaling::factor(),
QWindowsKeyMapper::queryKeyboardModifiers());
return true;
}
@@ -1240,7 +1249,7 @@ void QWindowsContext::setAsyncExpose(bool value)
extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result;
- const QtWindows::WindowsEventType et = windowsEventType(message, wParam);
+ const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam);
const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result);
if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) {
if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) {
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index 8352dac0b6..eca8a33215 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -44,6 +44,7 @@
#include "qwindowscontext.h"
#include "qwindowswindow.h"
#include "qwindowsscreen.h"
+#include "qwindowsscaling.h"
#include <QtGui/QBitmap>
#include <QtGui/QImage>
@@ -624,9 +625,15 @@ QWindowsCursor::CursorState QWindowsCursor::cursorState()
return CursorHidden;
}
+QPoint QWindowsCursor::pos() const
+{
+ return mousePosition() / QWindowsScaling::factor();
+}
+
void QWindowsCursor::setPos(const QPoint &pos)
{
- SetCursorPos(pos.x(), pos.y());
+ const QPoint posDp = pos * QWindowsScaling::factor();
+ SetCursorPos(posDp.x() , posDp.y());
}
/*!
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
index 34cb668856..89214156e8 100644
--- a/src/plugins/platforms/windows/qwindowscursor.h
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -102,7 +102,7 @@ public:
QWindowsCursor() {}
void changeCursor(QCursor * widgetCursor, QWindow * widget) Q_DECL_OVERRIDE;
- QPoint pos() const Q_DECL_OVERRIDE { return mousePosition(); }
+ QPoint pos() const Q_DECL_OVERRIDE;
void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
static HCURSOR createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot);
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index f70b5b4e2b..1f930822d8 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -1273,7 +1273,6 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel
{
wchar_t *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16()));
switch (l) {
- break;
case QFileDialogOptions::FileName:
m_fileDialog->SetFileNameLabel(wText);
break;
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 716d892472..e1b4aca0c4 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -41,6 +41,7 @@
#include "qwindowsdrag.h"
#include "qwindowscontext.h"
+#include "qwindowsscaling.h"
#ifndef QT_NO_CLIPBOARD
# include "qwindowsclipboard.h"
#endif
@@ -50,6 +51,7 @@
#include "qwindowswindow.h"
#include "qwindowsmousehandler.h"
#include "qwindowscursor.h"
+#include "qwindowsscaling.h"
#include <QtGui/QMouseEvent>
#include <QtGui/QPixmap>
@@ -295,12 +297,19 @@ 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 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;
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();
+ const QPoint hotSpot = drag->hotSpot() * scaleFactor;
for (int cnum = 0; cnum < actionCount; ++cnum) {
const Qt::DropAction action = actions[cnum];
QPixmap cursorPixmap = drag->dragCursor(action);
@@ -320,15 +329,14 @@ void QWindowsOleDropSource::createCursors()
if (hasPixmap) {
const int x1 = qMin(-hotSpot.x(), 0);
- const int x2 = qMax(pixmap.width() - hotSpot.x(), cursorPixmap.width());
+ const int x2 = qMax(pixmapSizeDp.width() - hotSpot.x(), cursorPixmap.width());
const int y1 = qMin(-hotSpot.y(), 0);
- const int y2 = qMax(pixmap.height() - hotSpot.y(), cursorPixmap.height());
+ const int y2 = qMax(pixmapSizeDp.height() - hotSpot.y(), cursorPixmap.height());
QPixmap newCursor(x2 - x1 + 1, y2 - y1 + 1);
newCursor.fill(Qt::transparent);
QPainter p(&newCursor);
- const QRect srcRect = pixmap.rect();
const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y()));
- p.drawPixmap(pmDest, pixmap, srcRect);
+ p.drawPixmap(pmDest, drawPixmap);
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 +462,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
if (!m_touchDragWindow)
m_touchDragWindow = new QWindowsDragCursorWindow;
m_touchDragWindow->setPixmap(e.pixmap);
- m_touchDragWindow->setFramePosition(QWindowsCursor::mousePosition() - e.hotSpot);
+ m_touchDragWindow->setFramePosition((QWindowsCursor::mousePosition() - e.hotSpot) / QWindowsScaling::factor());
if (!m_touchDragWindow->isVisible())
m_touchDragWindow->show();
break;
@@ -530,7 +538,9 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState,
QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState);
const QPlatformDragQtResponse response =
- QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions);
+ QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(),
+ m_lastPoint / QWindowsScaling::factor(),
+ actions);
m_answerRect = response.answerRect();
const Qt::DropAction action = response.acceptedAction();
@@ -622,7 +632,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
const QPlatformDropQtResponse response =
- QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), m_lastPoint,
+ QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(),
+ m_lastPoint / QWindowsScaling::factor(),
translateToQDragDropActions(*pdwEffect));
if (response.isAccepted()) {
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index d3cbea0b92..35b7f13ea4 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -1345,6 +1345,7 @@ void QWindowsMultiFontEngine::loadEngine(int at)
fontEngine->fontDef.pixelSize,
data);
fedw->fontDef = fontDef;
+ fedw->fontDef.family = fam;
fedw->ref.ref();
engines[at] = fedw;
@@ -1370,6 +1371,7 @@ void QWindowsMultiFontEngine::loadEngine(int at)
engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, data);
engines[at]->ref.ref();
engines[at]->fontDef = fontDef;
+ engines[at]->fontDef.family = fam;
qCDebug(lcQpaFonts) << __FUNCTION__ << at << fam;
// TODO: increase cost in QFontCache for the font engine loaded here
diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
index 8f55e20536..15b14aff1a 100644
--- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
@@ -574,7 +574,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
int size = width * height * 3;
BYTE *alphaValues = new BYTE[size];
- memset(alphaValues, size, 0);
+ memset(alphaValues, 0, size);
hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,
&rect,
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index f8676c30f7..2284c47ed6 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -44,6 +44,7 @@
#include "qwindowswindow.h"
#include "qwindowsintegration.h"
#include "qwindowsmousehandler.h"
+#include "qwindowsscaling.h"
#include <QtCore/QDebug>
#include <QtCore/QObject>
@@ -214,9 +215,10 @@ void QWindowsInputContext::cursorRectChanged()
if (!m_compositionContext.hwnd)
return;
const QInputMethod *inputMethod = QGuiApplication::inputMethod();
- QRect cursorRectangle = inputMethod->cursorRectangle().toRect();
- if (!cursorRectangle.isValid())
+ const QRect cursorRectangleDip = inputMethod->cursorRectangle().toRect();
+ if (!cursorRectangleDip.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 7c50ac69c2..7afda853e8 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -41,6 +41,7 @@
****************************************************************************/
#include "qwindowsintegration.h"
+#include "qwindowsscaling.h"
#include "qwindowswindow.h"
#include "qwindowscontext.h"
#include "qwindowsopenglcontext.h"
@@ -229,6 +230,12 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramL
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();
}
QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()
@@ -289,7 +296,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const
{
QWindowsWindowData requested;
requested.flags = window->flags();
- requested.geometry = window->geometry();
+ requested.geometry = QWindowsScaling::mapToNative(window->geometry());
// Apply custom margins (see QWindowsWindow::setCustomMargins())).
const QVariant customMarginsV = window->property("_q_windowsCustomMargins");
if (customMarginsV.isValid())
@@ -310,7 +317,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, obtained.geometry);
+ QWindowSystemInterface::handleGeometryChange(window, QWindowsScaling::mapFromNative(obtained.geometry));
}
#ifndef QT_NO_OPENGL
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index dc1de047fe..540236bda7 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -43,6 +43,7 @@
#include "qwindowscontext.h"
#include "qwindowswindow.h"
#include "qwindowsguieventdispatcher.h"
+#include "qwindowsscaling.h"
#include <QtGui/QWindow>
#include <qpa/qwindowsysteminterface.h>
@@ -767,11 +768,10 @@ static void showSystemMenu(QWindow* w)
#undef enabled
#undef disabled
#endif // !Q_OS_WINCE
+ const QPoint topLeft = topLevel->geometry().topLeft() * QWindowsScaling::factor();
const int ret = TrackPopupMenuEx(menu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
- topLevel->geometry().x(), topLevel->geometry().y(),
- topLevelHwnd,
- 0);
+ topLeft.x(), topLeft.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 4633378342..2e677102a5 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -191,8 +191,10 @@ 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,
- globalPosition, buttons,
+ QWindowSystemInterface::handleFrameStrutMouseEvent(window,
+ clientPosition / QWindowsScaling::factor(),
+ globalPosition / QWindowsScaling::factor(),
+ buttons,
QWindowsKeyMapper::queryKeyboardModifiers(),
source);
return false; // Allow further event processing (dragging of windows).
@@ -334,7 +336,10 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
m_windowUnderMouse = currentWindowUnderMouse;
}
- QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
+ QWindowSystemInterface::handleMouseEvent(window,
+ winEventPosition / QWindowsScaling::factor(),
+ globalPosition / QWindowsScaling::factor(),
+ buttons,
QWindowsKeyMapper::queryKeyboardModifiers(),
source);
m_previousCaptureWindow = hasCapture ? window : 0;
@@ -388,10 +393,11 @@ bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
}
if (handleEvent) {
+ const QPoint posDip = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos) / QWindowsScaling::factor();
QWindowSystemInterface::handleWheelEvent(receiver,
- QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
- globalPos,
- delta, orientation, mods);
+ posDip, globalPos / QWindowsScaling::factor(),
+ delta / QWindowsScaling::factor(),
+ orientation, mods);
}
return true;
@@ -419,6 +425,7 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, 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);
@@ -432,10 +439,9 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
if (m_lastTouchPositions.contains(id))
touchPoint.normalPosition = m_lastTouchPositions.value(id);
- QPointF screenPos = QPointF(qreal(winTouchInput.x) / qreal(100.), qreal(winTouchInput.y) / qreal(100.));
+ const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) * screenPosFactor;
if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
- touchPoint.area.setSize(QSizeF(qreal(winTouchInput.cxContact) / qreal(100.),
- qreal(winTouchInput.cyContact) / qreal(100.)));
+ touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) * screenPosFactor);
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 399bead323..98b7fc9bc5 100644
--- a/src/plugins/platforms/windows/qwindowsnativeimage.h
+++ b/src/plugins/platforms/windows/qwindowsnativeimage.h
@@ -67,6 +67,8 @@ 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/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
index ce28166e4f..06f9f709c9 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
@@ -64,7 +64,7 @@ enum ResourceType {
static int resourceType(const QByteArray &key)
{
- static const QByteArray names[] = { // match ResourceType
+ static const char *names[] = { // match ResourceType
"renderingcontext",
"eglcontext",
"egldisplay",
@@ -74,8 +74,8 @@ static int resourceType(const QByteArray &key)
"getdc",
"releasedc"
};
- const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
- const QByteArray *result = std::find(names, end, key);
+ const char ** const end = names + sizeof(names) / sizeof(names[0]);
+ const char **result = std::find(names, end, key);
if (result == end)
result = std::find(names, end, key.toLower());
return int(result - names);
diff --git a/src/plugins/platforms/android/qandroidplatformrasterwindow.h b/src/plugins/platforms/windows/qwindowsscaling.cpp
index 50c0d497af..fcc3440b42 100644
--- a/src/plugins/platforms/android/qandroidplatformrasterwindow.h
+++ b/src/plugins/platforms/windows/qwindowsscaling.cpp
@@ -1,7 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@@ -40,31 +39,41 @@
**
****************************************************************************/
-#ifndef QANDROIDPLATFORMRASTERWINDOW_H
-#define QANDROIDPLATFORMRASTERWINDOW_H
+#include "qwindowsscaling.h"
+#include "qwindowsscreen.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QCoreApplication>
-#include "qandroidplatformwindow.h"
QT_BEGIN_NAMESPACE
-class QAndroidPlatformBackingStore;
-class QAndroidPlatformRasterWindow : public QObject, public QAndroidPlatformWindow
-{
- Q_OBJECT
-public:
- QAndroidPlatformRasterWindow(QWindow *window);
+/*!
+ \class QWindowsScaling
+ \brief Windows scaling utilities
- void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; }
- QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; }
- void repaint(const QRegion&region);
+ \internal
+ \ingroup qt-lighthouse-win
+*/
-public slots:
- void setGeometry(const QRect &rect);
+int QWindowsScaling::m_factor = 1;
-private:
- QAndroidPlatformBackingStore *m_backingStore = nullptr;
- QRect m_oldGeometry;
+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 == QByteArrayLiteral("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
-#endif // QANDROIDPLATFORMRASTERWINDOW_H
diff --git a/src/plugins/platforms/windows/qwindowsscaling.h b/src/plugins/platforms/windows/qwindowsscaling.h
new file mode 100644
index 0000000000..99fec7c810
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsscaling.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins 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 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 &regionQt)
+ {
+ 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 &regionDp)
+ {
+ 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 bcdb8a2352..a5a291a8d8 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -101,21 +101,19 @@ static inline QDpi deviceDPI(const QSize &pixels, const QSizeF &physicalSizeMM)
typedef QList<QWindowsScreenData> WindowsScreenDataList;
-// from QDesktopWidget, taking WindowsScreenDataList as LPARAM
-BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p)
+static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
{
MONITORINFOEX info;
memset(&info, 0, sizeof(MONITORINFOEX));
info.cbSize = sizeof(MONITORINFOEX);
if (GetMonitorInfo(hMonitor, &info) == FALSE)
- return TRUE;
+ return false;
- WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p);
- QWindowsScreenData data;
- data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
- data.name = QString::fromWCharArray(info.szDevice);
- if (data.name == QLatin1String("WinDisc")) {
- data.flags |= QWindowsScreenData::LockScreen;
+ data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
+ data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
+ data->name = QString::fromWCharArray(info.szDevice);
+ if (data->name == QLatin1String("WinDisc")) {
+ data->flags |= QWindowsScreenData::LockScreen;
} else {
#ifdef Q_OS_WINCE
//Windows CE, just supports one Display and expects to get only DISPLAY,
@@ -127,40 +125,48 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM
if (hdc) {
#ifndef Q_OS_WINCE
const QDpi dpi = monitorDPI(hMonitor);
- data.dpi = dpi.first ? dpi : deviceDPI(hdc);
+ 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));
+ 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));
const int refreshRate = GetDeviceCaps(hdc, VREFRESH);
if (refreshRate > 1) // 0,1 means hardware default.
- data.refreshRateHz = refreshRate;
+ data->refreshRateHz = refreshRate;
DeleteDC(hdc);
} else {
qWarning("%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.",
__FUNCTION__, qPrintable(QString::fromWCharArray(info.szDevice)),
- data.dpi.first);
+ data->dpi.first);
} // CreateDC() failed
} // not lock screen
- data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
- data.availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
- data.orientation = data.geometry.height() > data.geometry.width() ?
+ data->orientation = data->geometry.height() > data->geometry.width() ?
Qt::PortraitOrientation : Qt::LandscapeOrientation;
// EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only
// virtual desktop screens.
- data.flags |= QWindowsScreenData::VirtualDesktop;
- if (info.dwFlags & MONITORINFOF_PRIMARY) {
- data.flags |= QWindowsScreenData::PrimaryScreen;
+ data->flags |= QWindowsScreenData::VirtualDesktop;
+ if (info.dwFlags & MONITORINFOF_PRIMARY)
+ data->flags |= QWindowsScreenData::PrimaryScreen;
+ return true;
+}
+
+// from QDesktopWidget, taking WindowsScreenDataList as LPARAM
+BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p)
+{
+ QWindowsScreenData data;
+ if (monitorData(hMonitor, &data)) {
+ WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p);
// QPlatformIntegration::screenAdded() documentation specifies that first
// added screen will be the primary screen, so order accordingly.
// Note that the side effect of this policy is that there is no way to change primary
// screen reported by Qt, unless we want to delete all existing screens and add them
// again whenever primary screen changes.
- result->prepend(data);
- } else {
- result->append(data);
+ if (data.flags & QWindowsScreenData::PrimaryScreen)
+ result->prepend(data);
+ else
+ result->append(data);
}
return TRUE;
}
@@ -217,14 +223,36 @@ 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 x, int y, int width, int height) const
+QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) 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;
@@ -248,6 +276,10 @@ QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int heig
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;
}
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index c9d8a5662c..49581db41a 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -43,11 +43,13 @@
#define QWINDOWSSCREEN_H
#include "qwindowscursor.h"
+#include "qwindowsscaling.h"
#ifdef Q_OS_WINCE
# include "qplatformfunctions_wince.h"
#endif
#include <QtCore/QList>
+#include <QtCore/QVector>
#include <QtCore/QPair>
#include <QtCore/QSharedPointer>
#include <qpa/qplatformscreen.h>
@@ -88,24 +90,28 @@ public:
static QWindowsScreen *screenOf(const QWindow *w = 0);
- QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; }
- QRect availableGeometry() const Q_DECL_OVERRIDE { return m_data.availableGeometry; }
+ 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()); }
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 m_data.dpi; }
+ 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(); }
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; }
QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE;
QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE
- { return QWindowsScreen::findTopLevelAt(point, CWP_SKIPINVISIBLE); }
+ { return QWindowsScreen::findTopLevelAt(point * QWindowsScaling::factor() , CWP_SKIPINVISIBLE); }
static QWindow *findTopLevelAt(const QPoint &point, unsigned flags);
static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE);
static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE);
- QPixmap grabWindow(WId window, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
+ QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const Q_DECL_OVERRIDE;
inline void handleChanges(const QWindowsScreenData &newData);
@@ -117,6 +123,7 @@ 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 d1737de907..7d020ff9d6 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qwindowstabletsupport.h"
+#include "qwindowsscaling.h"
#ifndef QT_NO_TABLETEVENT
@@ -275,6 +276,8 @@ static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType)
{
if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902))
return QTabletEvent::Stylus;
+ if (cursorType == 0x4020) // Surface Pro 2 tablet device
+ return QTabletEvent::Stylus;
switch (cursorType & CursorTypeBitMask) {
case 0x0802:
return QTabletEvent::Stylus;
@@ -403,7 +406,8 @@ 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 = QGuiApplication::primaryScreen()->virtualGeometry();
+ const QRect virtualDesktopArea
+ = QWindowsScaling::mapToNative(QGuiApplication::primaryScreen()->virtualGeometry());
qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount
<< "target:" << QGuiApplicationPrivate::tabletPressTarget;
@@ -423,7 +427,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
QPoint globalPos = globalPosF.toPoint();
// Get Mouse Position and compare to tablet info
- const QPoint mouseLocation = QWindowsCursor::mousePosition();
+ QPoint mouseLocation = QWindowsCursor::mousePosition();
// Positions should be almost the same if we are in absolute
// mode. If they are not, use the mouse location.
@@ -479,7 +483,9 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
<< tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation;
}
- QWindowSystemInterface::handleTabletEvent(target, QPointF(localPos), globalPosF,
+ const QPointF localPosDip = QPointF(localPos / QWindowsScaling::factor());
+ const QPointF globalPosDip = globalPosF / qreal(QWindowsScaling::factor());
+ QWindowSystemInterface::handleTabletEvent(target, localPosDip, globalPosDip,
currentDevice, currentPointer,
static_cast<Qt::MouseButtons>(packet.pkButtons),
pressureNew, tiltX, tiltY,
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 3b54feabbf..e6b996c685 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -44,6 +44,7 @@
#include "qwindowscontext.h"
#include "qwindowsdrag.h"
#include "qwindowsscreen.h"
+#include "qwindowsscaling.h"
#ifdef QT_NO_CURSOR
# include "qwindowscursor.h"
#endif
@@ -576,7 +577,9 @@ QWindowsWindowData
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL);
- QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight);
+ 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;
if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
title = topLevel ? qAppName() : w->objectName();
@@ -683,11 +686,9 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe
\ingroup qt-lighthouse-win
*/
-#define QWINDOWSIZE_MAX ((1<<24)-1)
-
QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) :
- minimumSize(w->minimumSize()),
- maximumSize(w->maximumSize()),
+ minimumSize(QWindowsScaling::mapToNativeConstrained(w->minimumSize())),
+ maximumSize(QWindowsScaling::mapToNativeConstrained(w->maximumSize())),
customMargins(cm)
{
}
@@ -930,7 +931,8 @@ void QWindowsWindow::fireExpose(const QRegion &region, bool force)
clearFlag(Exposed);
else
setFlag(Exposed);
- QWindowSystemInterface::handleExposeEvent(window(), region);
+ QWindowSystemInterface::handleExposeEvent(window(),
+ QWindowsScaling::mapFromNative(region));
}
static inline QWindow *findTransientChild(const QWindow *parent)
@@ -1106,7 +1108,7 @@ bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const
return m_data.embedded;
}
-QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const
+QPoint QWindowsWindow::mapToGlobalDp(const QPoint &pos) const
{
if (m_data.hwnd)
return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos);
@@ -1114,7 +1116,7 @@ QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const
return pos;
}
-QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
+QPoint QWindowsWindow::mapFromGlobalDp(const QPoint &pos) const
{
if (m_data.hwnd)
return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos);
@@ -1286,22 +1288,22 @@ static QRect normalFrameGeometry(HWND hwnd)
return QRect();
}
-QRect QWindowsWindow::normalGeometry() const
+QRect QWindowsWindow::normalGeometryDp() 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) : frameMargins();
+ const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMarginsDp();
return frame.isValid() ? frame.marginsRemoved(margins) : frame;
}
-void QWindowsWindow::setGeometry(const QRect &rectIn)
+void QWindowsWindow::setGeometryDp(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 = frameMargins();
+ const QMargins margins = frameMarginsDp();
rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top()));
}
const QSize oldSize = m_data.geometry.size();
@@ -1383,8 +1385,9 @@ void QWindowsWindow::handleGeometryChange()
return;
const QRect previousGeometry = m_data.geometry;
m_data.geometry = geometry_sys();
- QPlatformWindow::setGeometry(m_data.geometry);
- QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
+ const QRect geometryDip = QWindowsScaling::mapFromNative(m_data.geometry);
+ QPlatformWindow::setGeometry(geometryDip);
+ QWindowSystemInterface::handleGeometryChange(window(), geometryDip);
// QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive
// expose events when shrinking, synthesize.
if (!testFlag(OpenGL_ES2) && isExposed()
@@ -1404,7 +1407,7 @@ void QWindowsWindow::handleGeometryChange()
void QWindowsWindow::setGeometry_sys(const QRect &rect) const
{
- const QMargins margins = frameMargins();
+ const QMargins margins = frameMarginsDp();
const QRect frameGeometry = rect + margins;
qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window()
@@ -1441,7 +1444,7 @@ QRect QWindowsWindow::frameGeometry_sys() const
QRect QWindowsWindow::geometry_sys() const
{
- return frameGeometry_sys().marginsRemoved(frameMargins());
+ return frameGeometry_sys().marginsRemoved(frameMarginsDp());
}
/*!
@@ -1514,7 +1517,7 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: "
<< QWindowsWindow::debugWindowFlags(m_data.flags)
<< "\n to: " << QWindowsWindow::debugWindowFlags(flags);
- const QRect oldGeometry = geometry();
+ const QRect oldGeometry = geometryDp();
if (m_data.flags != flags) {
m_data.flags = flags;
if (m_data.hwnd) {
@@ -1602,7 +1605,8 @@ void QWindowsWindow::setWindowState(Qt::WindowState state)
bool QWindowsWindow::isFullScreen_sys() const
{
- return window()->isTopLevel() && geometry_sys() == window()->screen()->geometry();
+ return window()->isTopLevel()
+ && geometry_sys() == QWindowsScaling::mapToNative(window()->screen()->geometry());
}
/*!
@@ -1683,14 +1687,15 @@ 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 r = screen->geometry();
+ const QRect rDip = screen->geometry();
+ const QRect r = QWindowsScaling::mapToNative(rDip);
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(), r);
+ QWindowSystemInterface::handleGeometryChange(window(), rDip);
QWindowSystemInterface::flushWindowSystemEvents();
} else if (newState != Qt::WindowMinimized) {
// Restore saved state.
@@ -1778,7 +1783,7 @@ void QWindowsWindow::propagateSizeHints()
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
}
-QMargins QWindowsWindow::frameMargins() const
+QMargins QWindowsWindow::frameMarginsDp() const
{
// Frames are invalidated by style changes (window state, flags).
// As they are also required for geometry calculations in resize
@@ -1820,17 +1825,17 @@ static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion)
}
}
-static HRGN qRegionToWinRegion(const QRegion &region)
+static HRGN qRegionToWinRegion(const QRegion &regionDip)
{
- const QVector<QRect> rects = region.rects();
+ const QVector<QRect> rects = regionDip.rects();
if (rects.isEmpty())
return NULL;
const int rectCount = rects.size();
if (rectCount == 1)
- return createRectRegion(region.boundingRect());
+ return createRectRegion(QWindowsScaling::mapToNative(regionDip.boundingRect()));
HRGN hRegion = createRectRegion(rects.front());
for (int i = 1; i < rectCount; ++i)
- addRectToWinRegion(rects.at(i), &hRegion);
+ addRectToWinRegion(QWindowsScaling::mapToNative(rects.at(i)), &hRegion);
return hRegion;
}
@@ -1844,7 +1849,7 @@ void QWindowsWindow::setMask(const QRegion &region)
// Mask is in client area coordinates, so offset it in case we have a frame
if (window()->isTopLevel()) {
- const QMargins margins = frameMargins();
+ const QMargins margins = frameMarginsDp();
OffsetRgn(winRegion, margins.left(), margins.top());
}
@@ -1981,23 +1986,23 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
|| (m_data.flags & Qt::FramelessWindowHint)) {
return false;
}
- const QSize minimumSize = w->minimumSize();
+ const QSize minimumSize = QWindowsScaling::mapToNativeConstrained(w->minimumSize());
if (minimumSize.isEmpty())
return false;
- const QSize maximumSize = w->maximumSize();
+ const QSize maximumSize = QWindowsScaling::mapToNativeConstrained(w->maximumSize());
const bool fixedWidth = minimumSize.width() == maximumSize.width();
const bool fixedHeight = minimumSize.height() == maximumSize.height();
if (!fixedWidth && !fixedHeight)
return false;
- const QPoint localPos = w->mapFromGlobal(globalPos);
- const QSize size = w->size();
+ const QPoint localPos = mapFromGlobalDp(globalPos);
+ const QSize size = w->size() * QWindowsScaling::factor();
if (fixedHeight) {
if (localPos.y() >= size.height()) {
*result = HTBORDER; // Unspecified border, no resize cursor.
return true;
}
if (localPos.y() < 0) {
- const QMargins margins = frameMargins();
+ const QMargins margins = frameMarginsDp();
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.
@@ -2249,6 +2254,10 @@ 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 19d2236688..cb9da6fe27 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -46,6 +46,7 @@
#ifdef Q_OS_WINCE
# include "qplatformfunctions_wince.h"
#endif
+#include "qwindowsscaling.h"
#include "qwindowscursor.h"
#include "qwindowsopenglcontext.h"
@@ -152,18 +153,28 @@ public:
~QWindowsWindow();
QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; }
- 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 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 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 mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE;
- QPoint mapFromGlobal(const QPoint &pos) 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(); }
void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE;
void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE;
@@ -179,7 +190,8 @@ public:
void windowEvent(QEvent *event);
void propagateSizeHints() Q_DECL_OVERRIDE;
- QMargins frameMargins() const Q_DECL_OVERRIDE;
+ QMargins frameMarginsDp() const;
+ QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMarginsDp() / QWindowsScaling::factor(); }
void setOpacity(qreal level) Q_DECL_OVERRIDE;
void setMask(const QRegion &region) Q_DECL_OVERRIDE;
@@ -190,7 +202,7 @@ public:
bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE;
inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; }
- bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE;
+ bool startSystemResize(const QPoint &, 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 104d882fba..8e5f35d293 100644
--- a/src/plugins/platforms/windows/windows.pri
+++ b/src/plugins/platforms/windows/windows.pri
@@ -39,7 +39,8 @@ SOURCES += \
$$PWD/qwindowsdialoghelpers.cpp \
$$PWD/qwindowsservices.cpp \
$$PWD/qwindowsnativeimage.cpp \
- $$PWD/qwindowsnativeinterface.cpp
+ $$PWD/qwindowsnativeinterface.cpp \
+ $$PWD/qwindowsscaling.cpp
HEADERS += \
$$PWD/qwindowswindow.h \
@@ -64,7 +65,8 @@ HEADERS += \
$$PWD/qwindowsservices.h \
$$PWD/qplatformfunctions_wince.h \
$$PWD/qwindowsnativeimage.h \
- $$PWD/qwindowsnativeinterface.h
+ $$PWD/qwindowsnativeinterface.h \
+ $$PWD/qwindowsscaling.h
!wince: HEADERS += $$PWD/qwindowsopengltester.h
diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp
index 98eb83f5eb..2bc8e6602f 100644
--- a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp
+++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp
@@ -42,7 +42,6 @@
#include "qwinrteventdispatcher.h"
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformscreen.h>
-#include <qpa/qplatformscreenpageflipper.h>
#include <QtCore/QThread>
#include <QtGui/QGuiApplication>
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index ef99e6da6b..6c905735dd 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -512,8 +512,6 @@ QWinRTScreen::QWinRTScreen()
d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
d->surfaceFormat.setSamples(1);
d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
- d->surfaceFormat.setDepthBufferSize(24);
- d->surfaceFormat.setStencilBufferSize(8);
hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]);
Q_ASSERT_SUCCEEDED(hr);
diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp
index 592a6b1921..7004abf888 100644
--- a/src/plugins/platforms/winrt/qwinrttheme.cpp
+++ b/src/plugins/platforms/winrt/qwinrttheme.cpp
@@ -112,6 +112,7 @@ QWinRTTheme::QWinRTTheme()
Q_ASSERT_SUCCEEDED(hr);
d->palette.setColor(QPalette::ButtonText, fromColor(color));
d->palette.setColor(QPalette::Text, fromColor(color));
+ d->palette.setColor(QPalette::WindowText, fromColor(color));
hr = uiSettings()->UIElementColor(UIElementType_TextMedium, &color);
Q_ASSERT_SUCCEEDED(hr);
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 6258b29fc7..2daadb8649 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -280,13 +280,14 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
{
if (!m_image)
return;
-
- m_image->preparePaint(region);
+ const int dpr = int(m_image->image()->devicePixelRatio());
+ QRegion xRegion = dpr == 1 ? region : QTransform::fromScale(dpr,dpr).map(region);
+ m_image->preparePaint(xRegion);
if (m_image->image()->hasAlphaChannel()) {
QPainter p(m_image->image());
p.setCompositionMode(QPainter::CompositionMode_Source);
- const QVector<QRect> rects = region.rects();
+ const QVector<QRect> rects = xRegion.rects();
const QColor blank = Qt::transparent;
for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
p.fillRect(*it, blank);
@@ -323,9 +324,13 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
return;
}
+ const int dpr = int(window->devicePixelRatio());
+
QVector<QRect> rects = clipped.rects();
- for (int i = 0; i < rects.size(); ++i)
- m_image->put(platformWindow->xcb_window(), rects.at(i).topLeft(), rects.at(i).translated(offset));
+ 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));
+ }
Q_XCB_NOOP(connection());
@@ -355,9 +360,11 @@ void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion &region, c
void QXcbBackingStore::resize(const QSize &size, const QRegion &)
{
- if (m_image && size == m_image->size())
- return;
+ const int dpr = int(window()->devicePixelRatio());
+ const QSize xSize = size * dpr;
+ if (m_image && xSize == m_image->size())
+ return;
Q_XCB_NOOP(connection());
QXcbScreen *screen = static_cast<QXcbScreen *>(window()->screen()->handle());
@@ -369,7 +376,8 @@ void QXcbBackingStore::resize(const QSize &size, const QRegion &)
QXcbWindow* win = static_cast<QXcbWindow *>(pw);
delete m_image;
- m_image = new QXcbShmImage(screen, size, win->depth(), win->imageFormat());
+ m_image = new QXcbShmImage(screen, xSize, win->depth(), win->imageFormat());
+ m_image->image()->setDevicePixelRatio(dpr);
Q_XCB_NOOP(connection());
}
@@ -380,12 +388,14 @@ 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);
- const QVector<QRect> rects = area.rects();
- for (int i = 0; i < rects.size(); ++i)
- qt_scrollRectInImage(*m_image->image(), rects.at(i), QPoint(dx, dy));
-
+ 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);
return true;
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index ff8a6e2d76..ed5fe6d7c0 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -92,6 +92,9 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input")
+Q_LOGGING_CATEGORY(lcQpaXInputDevices, "qt.qpa.input.devices")
+
#ifdef XCB_USE_XLIB
static const char * const xcbConnectionErrors[] = {
"No error", /* Error 0 */
@@ -324,8 +327,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
, has_input_shape(false)
, has_touch_without_mouse_emulation(false)
, has_xkb(false)
- , debug_xinput_devices(false)
- , debug_xinput(false)
, m_buttons(0)
, m_focusWindow(0)
, m_systemTrayTracker(0)
@@ -798,8 +799,7 @@ void QXcbConnection::handleButtonPress(xcb_generic_event_t *ev)
// the rest we need to manage ourselves
m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state);
m_buttons |= translateMouseButton(event->detail);
- if (Q_UNLIKELY(debug_xinput))
- qDebug("xcb: pressed mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons));
+ qCDebug(lcQpaXInput, "xcb: pressed mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons));
}
void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev)
@@ -810,8 +810,7 @@ void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev)
// the rest we need to manage ourselves
m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state);
m_buttons &= ~translateMouseButton(event->detail);
- if (Q_UNLIKELY(debug_xinput))
- qDebug("xcb: released mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons));
+ qCDebug(lcQpaXInput, "xcb: released mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons));
}
#ifndef QT_NO_XKB
@@ -864,7 +863,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handleButtonRelease(event);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
case XCB_MOTION_NOTIFY:
- if (Q_UNLIKELY(debug_xinput)) {
+ if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) {
xcb_motion_notify_event_t *mev = (xcb_motion_notify_event_t *)event;
qDebug("xcb: moved mouse to %4d, %4d; button state %X", mev->event_x, mev->event_y, static_cast<unsigned int>(m_buttons));
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 44ee38e5de..01dd048ea3 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -52,6 +52,7 @@
#include <QVector>
#include <QVarLengthArray>
#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/QLoggingCategory>
// This is needed to make Qt compile together with XKB. xkb.h is using a variable
// which is called 'explicit', this is a reserved keyword in c++
@@ -73,7 +74,7 @@
#define XCB_USE_XINPUT22 // XI 2.2 adds multi-point touch support
#endif
#endif
-struct XInput2DeviceData;
+struct XInput2TouchDeviceData;
#endif
struct xcb_randr_get_output_info_reply_t;
@@ -81,6 +82,9 @@ struct xcb_randr_get_output_info_reply_t;
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaXInput)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaXInputDevices)
+
class QXcbScreen;
class QXcbWindow;
class QXcbDrag;
@@ -504,7 +508,7 @@ private:
void initializeXInput2();
void finalizeXInput2();
void xi2SetupDevices();
- XInput2DeviceData *deviceForId(int id);
+ XInput2TouchDeviceData *touchDeviceForId(int id);
void xi2HandleEvent(xcb_ge_event_t *event);
void xi2HandleHierachyEvent(void *event);
int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
@@ -579,7 +583,7 @@ private:
QXcbEventReader *m_reader;
#if defined(XCB_USE_XINPUT2)
QHash<int, QWindowSystemInterface::TouchPoint> m_touchPoints;
- QHash<int, XInput2DeviceData*> m_touchDevices;
+ QHash<int, XInput2TouchDeviceData*> m_touchDevices;
#endif
#if defined(XCB_USE_EGL)
void *m_egl_display;
@@ -613,8 +617,6 @@ private:
bool has_input_shape;
bool has_touch_without_mouse_emulation;
bool has_xkb;
- bool debug_xinput_devices;
- bool debug_xinput;
Qt::MouseButtons m_buttons;
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 512e574859..84d00d0e09 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -53,8 +53,8 @@
#include <X11/extensions/XI2proto.h>
#define FINGER_MAX_WIDTH_MM 10
-struct XInput2DeviceData {
- XInput2DeviceData()
+struct XInput2TouchDeviceData {
+ XInput2TouchDeviceData()
: xiDeviceInfo(0)
, qtTouchDevice(0)
{
@@ -71,8 +71,11 @@ struct XInput2DeviceData {
void QXcbConnection::initializeXInput2()
{
- debug_xinput = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT");
- debug_xinput_devices = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES");
+ // TODO Qt 6 (or perhaps earlier): remove these redundant env variables
+ if (qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT"))
+ const_cast<QLoggingCategory&>(lcQpaXInput()).setEnabled(QtDebugMsg, true);
+ if (qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES"))
+ const_cast<QLoggingCategory&>(lcQpaXInputDevices()).setEnabled(QtDebugMsg, true);
Display *xDisplay = static_cast<Display *>(m_xlib_display);
if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
int xiMajor = 2;
@@ -87,11 +90,10 @@ void QXcbConnection::initializeXInput2()
} else
m_xi2Enabled = true;
if (m_xi2Enabled) {
- if (Q_UNLIKELY(debug_xinput_devices))
#ifdef XCB_USE_XINPUT22
- qDebug("XInput version %d.%d is available and Qt supports 2.2 or greater", xiMajor, m_xi2Minor);
+ qCDebug(lcQpaXInputDevices, "XInput version %d.%d is available and Qt supports 2.2 or greater", xiMajor, m_xi2Minor);
#else
- qDebug("XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor);
+ qCDebug(lcQpaXInputDevices, "XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor);
#endif
}
@@ -116,8 +118,7 @@ void QXcbConnection::xi2SetupDevices()
// Only non-master pointing devices are relevant here.
if (devices[i].use != XISlavePointer)
continue;
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug() << "input device "<< devices[i].name;
+ qCDebug(lcQpaXInputDevices) << "input device "<< devices[i].name;
#ifndef QT_NO_TABLETEVENT
TabletData tabletData;
#endif
@@ -127,8 +128,7 @@ void QXcbConnection::xi2SetupDevices()
case XIValuatorClass: {
XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]);
const int valuatorAtom = qatom(vci->label);
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
+ qCDebug(lcQpaXInputDevices) << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
#ifndef QT_NO_TABLETEVENT
if (valuatorAtom < QXcbAtom::NAtoms) {
TabletData::ValuatorClassInfo info;
@@ -173,10 +173,18 @@ void QXcbConnection::xi2SetupDevices()
if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight))
scrollingDevice.legacyOrientations |= Qt::Horizontal;
}
+ qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons);
break;
}
#endif
+ case XIKeyClass:
+ qCDebug(lcQpaXInputDevices) << " it's a keyboard";
+ break;
+ case XITouchClass:
+ // will be handled in deviceForId()
+ break;
default:
+ qCDebug(lcQpaXInputDevices) << " has class" << devices[i].classes[c]->type;
break;
}
}
@@ -192,8 +200,7 @@ void QXcbConnection::xi2SetupDevices()
tabletData.pointerType = QTabletEvent::Eraser;
m_tabletData.append(tabletData);
isTablet = true;
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug() << " it's a tablet with pointer type" << tabletData.pointerType;
+ qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << tabletData.pointerType;
}
#endif // QT_NO_TABLETEVENT
@@ -203,23 +210,24 @@ void QXcbConnection::xi2SetupDevices()
// Only use legacy wheel button events when we don't have real scroll valuators.
scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations;
m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug() << " it's a scrolling device";
+ qCDebug(lcQpaXInputDevices) << " it's a scrolling device";
}
#endif
if (!isTablet) {
- XInput2DeviceData *dev = deviceForId(devices[i].deviceid);
- if (Q_UNLIKELY(debug_xinput_devices)) {
- if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen)
- qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d",
- dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
- dev->qtTouchDevice->maximumTouchPoints());
- else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad)
- qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
- dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
- dev->qtTouchDevice->maximumTouchPoints(),
- dev->size.width(), dev->size.height());
+ // touchDeviceForId populates XInput2DeviceData the first time it is called
+ // with a new deviceId. On subsequent calls it will return the cached object.
+ XInput2TouchDeviceData *dev = touchDeviceForId(devices[i].deviceid);
+ if (dev && lcQpaXInputDevices().isDebugEnabled()) {
+ if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen)
+ qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d",
+ dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
+ dev->qtTouchDevice->maximumTouchPoints());
+ else if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad)
+ qCDebug(lcQpaXInputDevices, " it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
+ dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
+ dev->qtTouchDevice->maximumTouchPoints(),
+ dev->size.width(), dev->size.height());
}
}
}
@@ -228,7 +236,7 @@ void QXcbConnection::xi2SetupDevices()
void QXcbConnection::finalizeXInput2()
{
- foreach (XInput2DeviceData *dev, m_touchDevices) {
+ foreach (XInput2TouchDeviceData *dev, m_touchDevices) {
if (dev->xiDeviceInfo)
XIFreeDeviceInfo(dev->xiDeviceInfo);
delete dev;
@@ -324,14 +332,16 @@ void QXcbConnection::xi2Select(xcb_window_t window)
}
}
-XInput2DeviceData *QXcbConnection::deviceForId(int id)
+XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
{
- XInput2DeviceData *dev = m_touchDevices[id];
+ XInput2TouchDeviceData *dev = m_touchDevices[id];
if (!dev) {
- int unused = 0;
+ int nrDevices = 0;
QTouchDevice::Capabilities caps = 0;
- dev = new XInput2DeviceData;
- dev->xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), id, &unused);
+ dev = new XInput2TouchDeviceData;
+ dev->xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), id, &nrDevices);
+ if (nrDevices <= 0)
+ return 0;
int type = -1;
int maxTouchPoints = 1;
bool hasRelativeCoords = false;
@@ -342,8 +352,7 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id)
case XITouchClass: {
XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo);
maxTouchPoints = tci->num_touches;
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug(" has touch class with mode %d", tci->mode);
+ qCDebug(lcQpaXInputDevices, " has touch class with mode %d", tci->mode);
switch (tci->mode) {
case XIDependentTouch:
type = QTouchDevice::TouchPad;
@@ -372,6 +381,8 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id)
}
break;
}
+ default:
+ break;
}
}
if (type < 0 && caps && hasRelativeCoords) {
@@ -444,14 +455,14 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
#ifdef XCB_USE_XINPUT22
if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) {
xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
- if (Q_UNLIKELY(debug_xinput))
- qDebug("XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f",
- event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail,
- fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
- fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) );
+ if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
+ qCDebug(lcQpaXInput, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f",
+ event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail,
+ fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
+ fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) );
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
- XInput2DeviceData *dev = deviceForId(xiDeviceEvent->sourceid);
+ XInput2TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
Q_ASSERT(dev);
const bool firstTouch = m_touchPoints.isEmpty();
if (xiEvent->evtype == XI_TouchBegin) {
@@ -474,9 +485,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
double value;
if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value))
continue;
- if (Q_UNLIKELY(debug_xinput))
- qDebug(" valuator %20s value %lf from range %lf -> %lf",
- atomName(vci->label).constData(), value, vci->min, vci->max );
+ if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
+ qCDebug(lcQpaXInput, " valuator %20s value %lf from range %lf -> %lf",
+ atomName(vci->label).constData(), value, vci->min, vci->max );
if (vci->label == atom(QXcbAtom::RelX)) {
nx = valuatorNormalized(value, vci);
} else if (vci->label == atom(QXcbAtom::RelY)) {
@@ -552,9 +563,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
touchPoint.normalPosition = QPointF(nx, ny);
- if (Q_UNLIKELY(debug_xinput))
- qDebug() << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
- " area " << touchPoint.area << " pressure " << touchPoint.pressure;
+ if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
+ qCDebug(lcQpaXInput) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
+ " area " << touchPoint.area << " pressure " << touchPoint.pressure;
QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiEvent->time, dev->qtTouchDevice, m_touchPoints.values());
if (touchPoint.state == Qt::TouchPointReleased)
// If a touchpoint was released, we can forget it, because the ID won't be reused.
@@ -643,8 +654,9 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
}
}
if (!angleDelta.isNull()) {
- QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
- QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
+ 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);
Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
if (modifiers & Qt::AltModifier) {
std::swap(angleDelta.rx(), angleDelta.ry());
@@ -670,8 +682,9 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
angleDelta.setX(-120);
}
if (!angleDelta.isNull()) {
- QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
- QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
+ 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);
Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
@@ -805,13 +818,11 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
tabletData->pointerType,
tabletData->serialId);
}
- if (Q_UNLIKELY(debug_xinput)) {
- // TODO maybe have a hash of tabletData->deviceId to device data so we can
- // look up the tablet name here, and distinguish multiple tablets
- qDebug("XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d",
- ev->deviceid, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
- ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool);
- }
+ // TODO maybe have a hash of tabletData->deviceId to device data so we can
+ // look up the tablet name here, and distinguish multiple tablets
+ qCDebug(lcQpaXInput, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d",
+ ev->deviceid, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
+ ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool);
}
XFree(data);
}
@@ -872,8 +883,8 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event)
}
}
- if (Q_UNLIKELY(debug_xinput))
- qDebug("XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf",
+ if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
+ qCDebug(lcQpaXInput, "XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf",
ev->deviceid, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail,
fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y),
fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y),
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index 6dbac90e0c..c9adf00673 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -629,16 +629,18 @@ void QXcbCursor::queryPointer(QXcbConnection *c, xcb_window_t *rootWin, QPoint *
QPoint QXcbCursor::pos() const
{
+ const int dpr = int(m_screen->devicePixelRatio());
QPoint p;
queryPointer(connection(), 0, &p);
- return p;
+ return p / dpr;
}
void QXcbCursor::setPos(const QPoint &pos)
{
+ const int dpr = int(m_screen->devicePixelRatio());
xcb_window_t root = 0;
queryPointer(connection(), &root, 0);
- xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y());
+ xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x()*dpr, pos.y()*dpr);
xcb_flush(xcb_connection());
}
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index bd28548cba..fa5ccf58ef 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -300,6 +300,11 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md
void QXcbDrag::move(const QMouseEvent *me)
{
+ // 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();
@@ -336,7 +341,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(), globalPos.y());
+ ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x() * dpr, globalPos.y() * dpr);
if (!translate)
return;
@@ -459,7 +464,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() << 16) + globalPos.y();
+ move.data.data32[2] = (globalPos.x() * dpr << 16) + globalPos.y() * dpr;
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;
@@ -705,7 +710,9 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t
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))
@@ -824,10 +831,12 @@ 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, s);
+ source_sameanswer = QRect(p / dpr, s / dpr);
} else {
source_sameanswer = QRect();
}
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 5673d41811..a00da04c26 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -85,7 +85,8 @@ static int resourceType(const QByteArray &key)
QByteArrayLiteral("appusertime"), QByteArrayLiteral("hintstyle"),
QByteArrayLiteral("startupid"), QByteArrayLiteral("traywindow"),
QByteArrayLiteral("gettimestamp"), QByteArrayLiteral("x11screen"),
- QByteArrayLiteral("rootwindow")
+ QByteArrayLiteral("rootwindow"),
+ QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingEnabled")
};
const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
const QByteArray *result = std::find(names, end, key);
@@ -277,6 +278,12 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resource, Q
case ScreenHintStyle:
result = reinterpret_cast<void *>(xcbScreen->hintStyle() + 1);
break;
+ case ScreenSubpixelType:
+ result = reinterpret_cast<void *>(xcbScreen->subpixelType() + 1);
+ break;
+ case ScreenAntialiasingEnabled:
+ result = reinterpret_cast<void *>(xcbScreen->antialiasingEnabled() + 1);
+ break;
case TrayWindow:
if (QXcbSystemTrayTracker *s = systemTrayTracker(screen))
result = (void *)quintptr(s->trayWindow());
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index c63cdf0254..1cd764914a 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -73,7 +73,9 @@ public:
TrayWindow,
GetTimestamp,
X11Screen,
- RootWindow
+ RootWindow,
+ ScreenSubpixelType,
+ ScreenAntialiasingEnabled
};
QXcbNativeInterface();
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 85f4dfbd43..83ffb02362 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -68,7 +68,10 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
, m_number(number)
, m_refreshRate(60)
, m_forcedDpi(-1)
+ , m_devicePixelRatio(1)
, m_hintStyle(QFontEngine::HintStyle(-1))
+ , m_subpixelType(QFontEngine::SubpixelAntialiasingType(-1))
+ , m_antialiasingEnabled(-1)
, m_xSettings(0)
{
if (connection->hasXRandr())
@@ -76,19 +79,18 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
updateGeometry(output ? output->timestamp : 0);
updateRefreshRate();
-
+ const int dpr = int(devicePixelRatio());
// On VNC, it can be that physical size is unknown while
// virtual size is known (probably back-calculated from DPI and resolution)
if (m_sizeMillimeters.isEmpty())
m_sizeMillimeters = m_virtualSizeMillimeters;
if (m_geometry.isEmpty())
- m_geometry = QRect(QPoint(), m_virtualSize);
+ m_geometry = QRect(QPoint(), m_virtualSize/dpr);
if (m_availableGeometry.isEmpty())
- m_availableGeometry = QRect(QPoint(), m_virtualSize);
+ m_availableGeometry = m_geometry;
readXResources();
-
#ifdef Q_XCB_DEBUG
qDebug();
qDebug("Screen output %s of xcb screen %d:", m_outputName.toUtf8().constData(), m_number);
@@ -99,6 +101,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
qDebug(" virtual height.: %lf", m_virtualSizeMillimeters.height());
qDebug(" virtual geom...: %d x %d", m_virtualSize.width(), m_virtualSize.height());
qDebug(" avail virt geom: %d x %d +%d +%d", m_availableGeometry.width(), m_availableGeometry.height(), m_availableGeometry.x(), m_availableGeometry.y());
+ qDebug(" pixel ratio....: %d", m_devicePixelRatio);
qDebug(" depth..........: %d", screen()->root_depth);
qDebug(" white pixel....: %x", screen()->white_pixel);
qDebug(" black pixel....: %x", screen()->black_pixel);
@@ -220,8 +223,9 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const
{
xcb_window_t root = m_screen->root;
- int x = p.x();
- int y = p.y();
+ int dpr = int(devicePixelRatio());
+ int x = p.x() / dpr;
+ int y = p.y() / dpr;
xcb_window_t parent = root;
xcb_window_t child = root;
@@ -312,11 +316,25 @@ QImage::Format QXcbScreen::format() const
QDpi QXcbScreen::logicalDpi() const
{
+ int dpr = int(devicePixelRatio());
+
if (m_forcedDpi > 0)
- return QDpi(m_forcedDpi, m_forcedDpi);
+ return QDpi(m_forcedDpi/dpr, m_forcedDpi/dpr);
+
+ return QDpi(Q_MM_PER_INCH * m_virtualSize.width() / m_virtualSizeMillimeters.width() / dpr,
+ Q_MM_PER_INCH * m_virtualSize.height() / m_virtualSizeMillimeters.height() / dpr);
+}
+
- return QDpi(Q_MM_PER_INCH * m_virtualSize.width() / m_virtualSizeMillimeters.width(),
- Q_MM_PER_INCH * m_virtualSize.height() / m_virtualSizeMillimeters.height());
+qreal QXcbScreen::devicePixelRatio() const
+{
+ static int override_dpr = qgetenv("QT_DEVICE_PIXEL_RATIO").toInt();
+ 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;
}
QPlatformCursor *QXcbScreen::cursor() const
@@ -394,12 +412,15 @@ void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *chan
void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
{
+ QRect xGeometry;
+ QRect xAvailableGeometry;
+
if (connection()->hasXRandr()) {
xcb_randr_get_crtc_info_reply_t *crtc = xcb_randr_get_crtc_info_reply(xcb_connection(),
xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, timestamp), NULL);
if (crtc) {
- m_geometry = QRect(crtc->x, crtc->y, crtc->width, crtc->height);
- m_availableGeometry = m_geometry;
+ xGeometry = QRect(crtc->x, crtc->y, crtc->width, crtc->height);
+ xAvailableGeometry = xGeometry;
free(crtc);
}
}
@@ -420,10 +441,16 @@ void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
QRect virtualAvailableGeometry(geom[0], geom[1], geom[2], geom[3]);
// Take the intersection of the desktop's available geometry with this screen's geometry
// to get the part of the available geometry which belongs to this screen.
- m_availableGeometry = m_geometry & virtualAvailableGeometry;
+ xAvailableGeometry = xGeometry & virtualAvailableGeometry;
}
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()/dpr, xGeometry.size()/dpr);
+ m_availableGeometry = QRect(xAvailableGeometry.topLeft()/dpr, xAvailableGeometry.size()/dpr);
+
QWindowSystemInterface::handleScreenAvailableGeometryChange(QPlatformScreen::screen(), m_availableGeometry);
}
@@ -547,32 +574,52 @@ QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height)
return result;
}
+static bool parseXftInt(const QByteArray& stringValue, int *value)
+{
+ Q_ASSERT(value != 0);
+ bool ok;
+ *value = stringValue.toInt(&ok);
+ return ok;
+}
+
+static QFontEngine::HintStyle parseXftHintStyle(const QByteArray& stringValue)
+{
+ if (stringValue == "hintfull")
+ return QFontEngine::HintFull;
+ else if (stringValue == "hintnone")
+ return QFontEngine::HintNone;
+ else if (stringValue == "hintmedium")
+ return QFontEngine::HintMedium;
+ else if (stringValue == "hintslight")
+ return QFontEngine::HintLight;
+
+ return QFontEngine::HintStyle(-1);
+}
+
+static QFontEngine::SubpixelAntialiasingType parseXftRgba(const QByteArray& stringValue)
+{
+ if (stringValue == "none")
+ return QFontEngine::Subpixel_None;
+ else if (stringValue == "rgb")
+ return QFontEngine::Subpixel_RGB;
+ else if (stringValue == "bgr")
+ return QFontEngine::Subpixel_BGR;
+ else if (stringValue == "vrgb")
+ return QFontEngine::Subpixel_VRGB;
+ else if (stringValue == "vbgr")
+ return QFontEngine::Subpixel_VBGR;
+
+ return QFontEngine::SubpixelAntialiasingType(-1);
+}
+
bool QXcbScreen::xResource(const QByteArray &identifier,
const QByteArray &expectedIdentifier,
- int *value)
+ QByteArray& stringValue)
{
- Q_ASSERT(value != 0);
if (identifier.startsWith(expectedIdentifier)) {
- QByteArray stringValue = identifier.mid(expectedIdentifier.size());
-
- bool ok;
- *value = stringValue.toInt(&ok);
- if (!ok) {
- if (stringValue == "hintfull")
- *value = QFontEngine::HintFull;
- else if (stringValue == "hintnone")
- *value = QFontEngine::HintNone;
- else if (stringValue == "hintmedium")
- *value = QFontEngine::HintMedium;
- else if (stringValue == "hintslight")
- *value = QFontEngine::HintLight;
-
- return *value != 0;
- }
-
+ stringValue = identifier.mid(expectedIdentifier.size());
return true;
}
-
return false;
}
@@ -604,10 +651,18 @@ void QXcbScreen::readXResources()
for (int i = 0; i < split.size(); ++i) {
const QByteArray &r = split.at(i);
int value;
- if (xResource(r, "Xft.dpi:\t", &value))
- m_forcedDpi = value;
- else if (xResource(r, "Xft.hintstyle:\t", &value))
- m_hintStyle = QFontEngine::HintStyle(value);
+ QByteArray stringValue;
+ if (xResource(r, "Xft.dpi:\t", stringValue)) {
+ if (parseXftInt(stringValue, &value))
+ m_forcedDpi = value;
+ } else if (xResource(r, "Xft.hintstyle:\t", stringValue)) {
+ m_hintStyle = parseXftHintStyle(stringValue);
+ } else if (xResource(r, "Xft.antialias:\t", stringValue)) {
+ if (parseXftInt(stringValue, &value))
+ m_antialiasingEnabled = value;
+ } else if (xResource(r, "Xft.rgba:\t", stringValue)) {
+ m_subpixelType = parseXftRgba(stringValue);
+ }
}
}
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 53ac65bb09..06dc2a32a2 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -75,6 +75,7 @@ public:
QImage::Format format() const;
QSizeF physicalSize() const { return m_sizeMillimeters; }
QDpi logicalDpi() const;
+ qreal devicePixelRatio() const;
QPlatformCursor *cursor() const;
qreal refreshRate() const { return m_refreshRate; }
Qt::ScreenOrientation orientation() const { return m_orientation; }
@@ -104,13 +105,15 @@ public:
void readXResources();
QFontEngine::HintStyle hintStyle() const { return m_hintStyle; }
+ QFontEngine::SubpixelAntialiasingType subpixelType() const { return m_subpixelType; }
+ int antialiasingEnabled() const { return m_antialiasingEnabled; }
QXcbXSettings *xSettings() const;
private:
static bool xResource(const QByteArray &identifier,
- const QByteArray &expectedIdentifier,
- int *value);
+ const QByteArray &expectedIdentifier,
+ QByteArray &stringValue);
void sendStartupMessage(const QByteArray &message) const;
xcb_screen_t *m_screen;
@@ -132,7 +135,10 @@ private:
QXcbCursor *m_cursor;
int m_refreshRate;
int m_forcedDpi;
+ int m_devicePixelRatio;
QFontEngine::HintStyle m_hintStyle;
+ QFontEngine::SubpixelAntialiasingType m_subpixelType;
+ int m_antialiasingEnabled;
QXcbXSettings *m_xSettings;
};
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index cb647e946d..e4feda2c81 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -154,6 +154,30 @@ enum QX11EmbedMessageType {
const quint32 XEMBED_VERSION = 0;
+static inline QRect mapToNative(const QRect &qtRect, int dpr)
+{
+ return QRect(qtRect.x() * dpr, qtRect.y() * dpr, qtRect.width() * dpr, qtRect.height() * dpr);
+}
+
+// When converting native rects 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 QRect mapFromNative(const QRect &xRect, int dpr)
+{
+ return QRect(dpr_floor(xRect.topLeft(), dpr), dpr_ceil(xRect.bottomRight(), dpr));
+}
+
+
// Returns \c true if we should set WM_TRANSIENT_FOR on \a w
static inline bool isTransient(const QWindow *w)
{
@@ -288,11 +312,12 @@ void QXcbWindow::create()
// currently no way to implement it for frame-exclusive geometries.
QRect rect = window()->geometry();
QPlatformWindow::setGeometry(rect);
+ const int dpr = int(devicePixelRatio());
QSize minimumSize = window()->minimumSize();
if (rect.width() > 0 || rect.height() > 0) {
- rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
- rect.setHeight(qBound(1, rect.height(), XCOORD_MAX));
+ rect.setWidth(qBound(1, rect.width(), XCOORD_MAX/dpr));
+ rect.setHeight(qBound(1, rect.height(), XCOORD_MAX/dpr));
} else if (minimumSize.width() > 0 || minimumSize.height() > 0) {
rect.setSize(minimumSize);
} else {
@@ -350,7 +375,9 @@ void QXcbWindow::create()
m_visualId = visualInfo->visualid;
- m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(),
+ const QRect xRect = mapToNative(rect, dpr);
+
+ m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, xRect.x(), xRect.y(), xRect.width(), xRect.height(),
0, visualInfo->depth, InputOutput, visualInfo->visual,
CWBackPixel|CWBorderPixel|CWColormap, &a);
@@ -561,7 +588,9 @@ void QXcbWindow::setGeometry(const QRect &rect)
QPlatformWindow::setGeometry(rect);
propagateSizeHints();
- const QRect wmGeometry = windowToWmGeometry(rect);
+
+ const QRect xRect = mapToNative(rect, int(devicePixelRatio()));
+ const QRect wmGeometry = windowToWmGeometry(xRect);
if (qt_window_private(window())->positionAutomatic) {
const quint32 mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
@@ -1444,23 +1473,26 @@ void QXcbWindow::propagateSizeHints()
xcb_size_hints_t hints;
memset(&hints, 0, sizeof(hints));
- const QRect rect = windowToWmGeometry(geometry());
+ const int dpr = int(devicePixelRatio());
+ const QRect xRect = mapToNative(windowToWmGeometry(geometry()), dpr);
QWindow *win = window();
if (!qt_window_private(win)->positionAutomatic)
- xcb_size_hints_set_position(&hints, true, rect.x(), rect.y());
- if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX)
- xcb_size_hints_set_size(&hints, true, rect.width(), rect.height());
+ xcb_size_hints_set_position(&hints, true, xRect.x(), xRect.y());
+ if (xRect.width() < QWINDOWSIZE_MAX || xRect.height() < QWINDOWSIZE_MAX)
+ xcb_size_hints_set_size(&hints, true, xRect.width(), xRect.height());
xcb_size_hints_set_win_gravity(&hints, m_gravity);
- QSize minimumSize = win->minimumSize();
- QSize maximumSize = win->maximumSize();
- QSize baseSize = win->baseSize();
- QSize sizeIncrement = win->sizeIncrement();
+ QSize minimumSize = win->minimumSize() * dpr;
+ QSize maximumSize = win->maximumSize() * dpr;
+ QSize baseSize = win->baseSize() * dpr;
+ QSize sizeIncrement = win->sizeIncrement() * dpr;
if (minimumSize.width() > 0 || minimumSize.height() > 0)
- xcb_size_hints_set_min_size(&hints, minimumSize.width(), minimumSize.height());
+ xcb_size_hints_set_min_size(&hints,
+ qMin(XCOORD_MAX,minimumSize.width()),
+ qMin(XCOORD_MAX,minimumSize.height()));
if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX)
xcb_size_hints_set_max_size(&hints,
@@ -1664,9 +1696,10 @@ void QXcbWindow::setWmWindowType(QXcbWindowFunctions::WmWindowTypes types)
class ExposeCompressor
{
public:
- ExposeCompressor(xcb_window_t window, QRegion *region)
+ ExposeCompressor(xcb_window_t window, QRegion *region, int devicePixelRatio)
: m_window(window)
, m_region(region)
+ , m_dpr(devicePixelRatio)
, m_pending(true)
{
}
@@ -1682,7 +1715,7 @@ public:
return false;
if (expose->count == 0)
m_pending = false;
- *m_region |= QRect(expose->x, expose->y, expose->width, expose->height);
+ *m_region |= mapFromNative(QRect(expose->x, expose->y, expose->width, expose->height), m_dpr);
return true;
}
@@ -1694,6 +1727,7 @@ public:
private:
xcb_window_t m_window;
QRegion *m_region;
+ int m_dpr;
bool m_pending;
};
@@ -1707,14 +1741,16 @@ bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result)
void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
{
- QRect rect(event->x, event->y, event->width, event->height);
+ const int dpr = int(devicePixelRatio());
+ QRect x_rect(event->x, event->y, event->width, event->height);
+ QRect rect = mapFromNative(x_rect, dpr);
if (m_exposeRegion.isEmpty())
m_exposeRegion = rect;
else
m_exposeRegion |= rect;
- ExposeCompressor compressor(m_window, &m_exposeRegion);
+ ExposeCompressor compressor(m_window, &m_exposeRegion, dpr);
xcb_generic_event_t *filter = 0;
do {
filter = connection()->checkEvent(compressor);
@@ -1808,7 +1844,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
}
}
- QRect rect(pos, QSize(event->width, event->height));
+ QRect rect = mapFromNative(QRect(pos, QSize(event->width, event->height)), int(devicePixelRatio()));
QPlatformWindow::setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(window(), rect);
@@ -1850,15 +1886,16 @@ 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(), m_screen->root(),
- pos.x(), pos.y());
+ pos.x() * dpr, pos.y() * dpr);
xcb_translate_coordinates_reply_t *reply =
xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
if (reply) {
- ret.setX(reply->dst_x);
- ret.setY(reply->dst_y);
+ ret.setX(reply->dst_x / dpr);
+ ret.setY(reply->dst_y / dpr);
free(reply);
}
@@ -1869,15 +1906,17 @@ QPoint QXcbWindow::mapFromGlobal(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(), m_screen->root(), xcb_window(),
- pos.x(), pos.y());
+ pos.x() *dpr, pos.y() * dpr);
xcb_translate_coordinates_reply_t *reply =
xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
if (reply) {
- ret.setX(reply->dst_x);
- ret.setY(reply->dst_y);
+ ret.setX(reply->dst_x / dpr);
+ ret.setY(reply->dst_y / dpr);
free(reply);
}
@@ -1893,7 +1932,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()));
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size() * int(devicePixelRatio())));
}
}
@@ -1924,9 +1963,9 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
}
}
-
- QPoint local(event->event_x, event->event_y);
- QPoint global(event->root_x, event->root_y);
+ const int dpr = int(devicePixelRatio());
+ QPoint local(event->event_x/dpr, event->event_y/dpr);
+ QPoint global(event->root_x/dpr, event->root_y/dpr);
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
@@ -1949,8 +1988,9 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event)
{
- QPoint local(event->event_x, event->event_y);
- QPoint global(event->root_x, event->root_y);
+ const int dpr = int(devicePixelRatio());
+ QPoint local(event->event_x/dpr, event->event_y/dpr);
+ QPoint global(event->root_x/dpr, event->root_y/dpr);
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
if (event->detail >= 4 && event->detail <= 7) {
@@ -1963,8 +2003,9 @@ void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *even
void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
{
- QPoint local(event->event_x, event->event_y);
- QPoint global(event->root_x, event->root_y);
+ const int dpr = int(devicePixelRatio());
+ QPoint local(event->event_x/dpr, event->event_y/dpr);
+ QPoint global(event->root_x/dpr, event->root_y/dpr);
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
handleMouseEvent(event->time, local, global, modifiers);
@@ -2014,9 +2055,9 @@ void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event)
{
return;
}
-
- const QPoint local(event->event_x, event->event_y);
- const QPoint global(event->root_x, event->root_y);
+ const int dpr = int(devicePixelRatio());
+ const QPoint local(event->event_x/dpr, event->event_y/dpr);
+ const QPoint global(event->root_x/dpr, event->root_y/dpr);
QWindowSystemInterface::handleEnterEvent(window(), local, global);
}
@@ -2036,8 +2077,9 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event)
QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0;
if (enterWindow) {
- QPoint local(enter->event_x, enter->event_y);
- QPoint global(enter->root_x, enter->root_y);
+ const int dpr = int(devicePixelRatio());
+ QPoint local(enter->event_x/dpr, enter->event_y/dpr);
+ QPoint global(enter->root_x/dpr, enter->root_y/dpr);
QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global);
} else {
@@ -2190,6 +2232,7 @@ void QXcbWindow::windowEvent(QEvent *event)
bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
{
+ const int dpr = int(devicePixelRatio());
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
if (!connection()->wmSupport()->isSupportedByWM(moveResize))
return false;
@@ -2198,7 +2241,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
xev.type = moveResize;
xev.window = xcb_window();
xev.format = 32;
- const QPoint globalPos = window()->mapToGlobal(pos);
+ const QPoint globalPos = window()->mapToGlobal(pos) * dpr;
xev.data.data32[0] = globalPos.x();
xev.data.data32[1] = globalPos.y();
const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner;
@@ -2316,9 +2359,10 @@ void QXcbWindow::setMask(const QRegion &region)
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(r));
+ rects.push_back(qRectToXCBRectangle(mapToNative(r, dpr)));
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]);
@@ -2352,4 +2396,9 @@ void QXcbWindow::postSyncWindowRequest()
}
}
+qreal QXcbWindow::devicePixelRatio() const
+{
+ return m_screen ? m_screen->devicePixelRatio() : 1.0;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index af9b06a791..4a81fff5b8 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -160,6 +160,8 @@ public:
void postSyncWindowRequest();
void clearSyncWindowRequest() { m_pendingSyncRequest = 0; }
+ qreal devicePixelRatio() const;
+
public Q_SLOTS:
void updateSyncRequestCounter();
diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp
index f85fe0839f..506c29c9cf 100644
--- a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp
+++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp
@@ -308,7 +308,13 @@ QUrl QGtk2FileDialogHelper::directory() const
void QGtk2FileDialogHelper::selectFile(const QUrl &filename)
{
GtkDialog *gtkDialog = d->gtkDialog();
- gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toLocalFile().toUtf8());
+ if (options()->acceptMode() == QFileDialogOptions::AcceptSave) {
+ QFileInfo fi(filename.toLocalFile());
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), fi.path().toUtf8());
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(gtkDialog), fi.fileName().toUtf8());
+ } else {
+ gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toLocalFile().toUtf8());
+ }
}
QList<QUrl> QGtk2FileDialogHelper::selectedFiles() const
diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp
index bf39b9309d..926d36f73f 100644
--- a/src/printsupport/kernel/qprintengine_win.cpp
+++ b/src/printsupport/kernel/qprintengine_win.cpp
@@ -203,7 +203,7 @@ bool QWin32PrintEngine::newPage()
bool transparent = GetBkMode(d->hdc) == TRANSPARENT;
- if (!EndPage(d->hdc)) {
+ if (EndPage(d->hdc) <= 0) {
qErrnoWarning("QWin32PrintEngine::newPage: EndPage failed");
return false;
}
@@ -216,7 +216,7 @@ bool QWin32PrintEngine::newPage()
d->reinit = false;
}
- if (!StartPage(d->hdc)) {
+ if (StartPage(d->hdc) <= 0) {
qErrnoWarning("Win32PrintEngine::newPage: StartPage failed");
return false;
}
@@ -235,7 +235,7 @@ bool QWin32PrintEngine::newPage()
bool success = false;
if (d->hdc && d->state == QPrinter::Active) {
- if (EndPage(d->hdc) != SP_ERROR) {
+ if (EndPage(d->hdc) > 0) {
// reinitialize the DC before StartPage if needed,
// because resetdc is disabled between calls to the StartPage and EndPage functions
// (see StartPage documentation in the Platform SDK:Windows GDI)
@@ -248,7 +248,7 @@ bool QWin32PrintEngine::newPage()
qErrnoWarning("QWin32PrintEngine::newPage(), ResetDC failed (2)");
d->reinit = false;
}
- success = (StartPage(d->hdc) != SP_ERROR);
+ success = (StartPage(d->hdc) > 0);
}
if (!success) {
d->state = QPrinter::Aborted;
diff --git a/src/testlib/qbenchmarkvalgrind.cpp b/src/testlib/qbenchmarkvalgrind.cpp
index 545de3bb65..cd804774e9 100644
--- a/src/testlib/qbenchmarkvalgrind.cpp
+++ b/src/testlib/qbenchmarkvalgrind.cpp
@@ -66,7 +66,7 @@ bool QBenchmarkValgrindUtils::haveValgrind()
if (!process.waitForFinished(-1))
return false;
const QByteArray out = process.readAllStandardOutput();
- QRegExp rx(QLatin1String("^valgrind-([0-9]).([0-9]).[0-9]"));
+ QRegExp rx(QLatin1String("^valgrind-([0-9]+).([0-9]+).[0-9]+"));
if (rx.indexIn(QLatin1String(out.data())) == -1)
return false;
bool ok;
diff --git a/src/tools/qdoc/atom.cpp b/src/tools/qdoc/atom.cpp
index 5c699b0546..de99dc4d5a 100644
--- a/src/tools/qdoc/atom.cpp
+++ b/src/tools/qdoc/atom.cpp
@@ -146,6 +146,8 @@ QT_BEGIN_NAMESPACE
\value UnknownCommand
*/
+QString Atom::noError_ = QString();
+
static const struct {
const char *english;
int no;
@@ -369,12 +371,15 @@ void Atom::dump() const
}
/*!
- The only constructor for LinkAtom. It only create an Atom
- of type Atom::Link with \a p1 being the link text. \a p2
- contains some search parameters.
+ The only constructor for LinkAtom. It creates an Atom of
+ type Atom::Link. \a p1 being the link target. \a p2 is the
+ parameters in square brackets. Normally there is just one
+ word in the square brackets, but there can be up to three
+ words separated by spaces. The constructor splits \a p2 on
+ the space character.
*/
LinkAtom::LinkAtom(const QString& p1, const QString& p2)
- : Atom(p1), genus_(DontCare), goal_(Node::NoType), domain_(0)
+ : Atom(p1), genus_(Node::DontCare), goal_(Node::NoType), domain_(0)
{
QStringList params = p2.toLower().split(QLatin1Char(' '));
foreach (const QString& p, params) {
@@ -388,10 +393,16 @@ LinkAtom::LinkAtom(const QString& p1, const QString& p2)
if (goal_ != Node::NoType)
continue;
}
- if (p == "qml")
- genus_ = QML;
- else if (p == "cpp")
- genus_ = CPP;
+ if (p == "qml") {
+ genus_ = Node::QML;
+ continue;
+ }
+ if (p == "cpp") {
+ genus_ = Node::CPP;
+ continue;
+ }
+ error_ = p2;
+ break;
}
}
@@ -402,7 +413,8 @@ LinkAtom::LinkAtom(const LinkAtom& t)
: Atom(Link, t.string()),
genus_(t.genus_),
goal_(t.goal_),
- domain_(t.domain_)
+ domain_(t.domain_),
+ error_(t.error_)
{
// nothing
}
@@ -416,7 +428,8 @@ LinkAtom::LinkAtom(Atom* previous, const LinkAtom& t)
: Atom(previous, Link, t.string()),
genus_(t.genus_),
goal_(t.goal_),
- domain_(t.domain_)
+ domain_(t.domain_),
+ error_(t.error_)
{
previous->next_ = this;
}
diff --git a/src/tools/qdoc/atom.h b/src/tools/qdoc/atom.h
index 36a7390ae2..e4ef7e06a7 100644
--- a/src/tools/qdoc/atom.h
+++ b/src/tools/qdoc/atom.h
@@ -140,8 +140,6 @@ public:
Last = UnknownCommand
};
- enum NodeGenus { DontCare, CPP, QML };
-
friend class LinkAtom;
Atom(const QString& string)
@@ -201,12 +199,14 @@ public:
const QStringList& strings() const { return strs; }
virtual bool isLinkAtom() const { return false; }
- virtual NodeGenus genus() const { return DontCare; }
+ virtual Node::Genus genus() const { return Node::DontCare; }
virtual bool specifiesDomain() const { return false; }
virtual Tree* domain() const { return 0; }
virtual Node::Type goal() const { return Node::NoType; }
+ virtual const QString& error() { return noError_; }
protected:
+ static QString noError_;
Atom* next_;
Type type_;
QStringList strs;
@@ -221,15 +221,17 @@ class LinkAtom : public Atom
virtual ~LinkAtom() { }
virtual bool isLinkAtom() const { return true; }
- virtual NodeGenus genus() const { return genus_; }
+ virtual Node::Genus genus() const { return genus_; }
virtual bool specifiesDomain() const { return (domain_ != 0); }
virtual Tree* domain() const { return domain_; }
virtual Node::Type goal() const { return goal_; }
+ virtual const QString& error() { return error_; }
protected:
- NodeGenus genus_;
+ Node::Genus genus_;
Node::Type goal_;
Tree* domain_;
+ QString error_;
};
#define ATOM_FORMATTING_BOLD "bold"
diff --git a/src/tools/qdoc/codemarker.cpp b/src/tools/qdoc/codemarker.cpp
index 235b3c3f04..66721c31e7 100644
--- a/src/tools/qdoc/codemarker.cpp
+++ b/src/tools/qdoc/codemarker.cpp
@@ -649,7 +649,7 @@ QString CodeMarker::macName(const Node *node, const QString &name)
/*!
Returns an empty list of documentation sections.
*/
-QList<Section> CodeMarker::qmlSections(QmlClassNode* , SynopsisStyle )
+QList<Section> CodeMarker::qmlSections(QmlClassNode* , SynopsisStyle , Status )
{
return QList<Section>();
}
diff --git a/src/tools/qdoc/codemarker.h b/src/tools/qdoc/codemarker.h
index aa38b82e24..efb2700717 100644
--- a/src/tools/qdoc/codemarker.h
+++ b/src/tools/qdoc/codemarker.h
@@ -154,7 +154,9 @@ public:
virtual QList<Section> sections(const InnerNode *inner,
SynopsisStyle style,
Status status) = 0;
- virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style);
+ virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode,
+ SynopsisStyle style,
+ Status status = Okay);
virtual QStringList macRefsForNode(Node* node);
static void initialize(const Config& config);
diff --git a/src/tools/qdoc/codeparser.cpp b/src/tools/qdoc/codeparser.cpp
index 3b0a650a74..616087ed82 100644
--- a/src/tools/qdoc/codeparser.cpp
+++ b/src/tools/qdoc/codeparser.cpp
@@ -261,8 +261,7 @@ void CodeParser::processCommonMetaCommand(const Location& location,
node->setStatus(Node::Main);
}
else if (command == COMMAND_OBSOLETE) {
- if (node->status() != Node::Compat)
- node->setStatus(Node::Obsolete);
+ node->setStatus(Node::Obsolete);
}
else if (command == COMMAND_NONREENTRANT) {
node->setThreadSafeness(Node::NonReentrant);
diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp
index d3cb111873..715e7daa6e 100644
--- a/src/tools/qdoc/cppcodemarker.cpp
+++ b/src/tools/qdoc/cppcodemarker.cpp
@@ -410,8 +410,7 @@ QString CppCodeMarker::markedUpEnumValue(const QString &enumValue, const Node *r
QString fullName;
while (node->parent()) {
fullName.prepend(markedUpName(node));
- if (node->parent() == relative || node->parent()->name().isEmpty() ||
- node->parent()->isCollisionNode())
+ if (node->parent() == relative || node->parent()->name().isEmpty())
break;
fullName.prepend("<@op>::</@op>");
node = node->parent();
@@ -1094,7 +1093,7 @@ QString CppCodeMarker::addMarkUp(const QString &in,
the list of documentation sections for the children of the
\a qmlClassNode.
*/
-QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style)
+QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style, Status status)
{
QList<Section> sections;
if (qmlClassNode) {
@@ -1144,32 +1143,32 @@ QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisSt
continue;
}
if ((*c)->type() == Node::QmlPropertyGroup) {
- insert(qmlproperties, *c, style, Okay);
+ insert(qmlproperties, *c, style, status);
}
else if ((*c)->type() == Node::QmlProperty) {
const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c);
if (pn->isAttached())
- insert(qmlattachedproperties,*c,style,Okay);
+ insert(qmlattachedproperties,*c,style, status);
else {
- insert(qmlproperties,*c,style,Okay);
+ insert(qmlproperties,*c,style, status);
}
}
else if ((*c)->type() == Node::QmlSignal) {
const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
if (sn->isAttached())
- insert(qmlattachedsignals,*c,style,Okay);
+ insert(qmlattachedsignals,*c,style, status);
else
- insert(qmlsignals,*c,style,Okay);
+ insert(qmlsignals,*c,style, status);
}
else if ((*c)->type() == Node::QmlSignalHandler) {
- insert(qmlsignalhandlers,*c,style,Okay);
+ insert(qmlsignalhandlers,*c,style, status);
}
else if ((*c)->type() == Node::QmlMethod) {
const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
if (mn->isAttached())
- insert(qmlattachedmethods,*c,style,Okay);
+ insert(qmlattachedmethods,*c,style, status);
else
- insert(qmlmethods,*c,style,Okay);
+ insert(qmlmethods,*c,style, status);
}
++c;
}
@@ -1209,31 +1208,31 @@ QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisSt
continue;
}
if ((*c)->type() == Node::QmlPropertyGroup) {
- insert(qmlproperties,*c,style,Okay);
+ insert(qmlproperties,*c,style, status);
}
else if ((*c)->type() == Node::QmlProperty) {
const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c);
if (pn->isAttached())
- insert(qmlattachedproperties,*c,style,Okay);
+ insert(qmlattachedproperties,*c,style, status);
else
- insert(qmlproperties,*c,style,Okay);
+ insert(qmlproperties,*c,style, status);
}
else if ((*c)->type() == Node::QmlSignal) {
const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
if (sn->isAttached())
- insert(qmlattachedsignals,*c,style,Okay);
+ insert(qmlattachedsignals,*c,style, status);
else
- insert(qmlsignals,*c,style,Okay);
+ insert(qmlsignals,*c,style, status);
}
else if ((*c)->type() == Node::QmlSignalHandler) {
- insert(qmlsignalhandlers,*c,style,Okay);
+ insert(qmlsignalhandlers,*c,style, status);
}
else if ((*c)->type() == Node::QmlMethod) {
const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
if (mn->isAttached())
- insert(qmlattachedmethods,*c,style,Okay);
+ insert(qmlattachedmethods,*c,style, status);
else
- insert(qmlmethods,*c,style,Okay);
+ insert(qmlmethods,*c,style, status);
}
++c;
}
diff --git a/src/tools/qdoc/cppcodemarker.h b/src/tools/qdoc/cppcodemarker.h
index 74faf1ca57..0b920a8b39 100644
--- a/src/tools/qdoc/cppcodemarker.h
+++ b/src/tools/qdoc/cppcodemarker.h
@@ -78,7 +78,9 @@ public:
virtual QList<Section> sections(const InnerNode *innerNode,
SynopsisStyle style,
Status status);
- virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style);
+ virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode,
+ SynopsisStyle style,
+ Status status = Okay);
private:
QString addMarkUp(const QString& protectedCode,
diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp
index df11ee5b24..b6de29e57c 100644
--- a/src/tools/qdoc/cppcodeparser.cpp
+++ b/src/tools/qdoc/cppcodeparser.cpp
@@ -497,27 +497,21 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
ptype = Node::DitaMapPage;
}
- /*
- Search for a node with the same name. If there is one,
- then there is a collision, so create a collision node
- and make the existing node a child of the collision
- node, and then create the new Page node and make
- it a child of the collision node as well. Return the
- collision node.
-
- If there is no collision, just create a new Page
- node and return that one.
- */
- NameCollisionNode* ncn = qdb_->checkForCollision(args[0]);
+#if 0
+ const Node* n = qdb_->checkForCollision(args[0]);
+ if (n) {
+ QString other = n->doc().location().fileName();
+ doc.location().warning(tr("Name/title collision detected: '%1' in '\\%2'")
+ .arg(args[0]).arg(command),
+ tr("Also used here: %1").arg(other));
+ }
+#endif
DocNode* dn = 0;
if (ptype == Node::DitaMapPage)
dn = new DitaMapNode(qdb_->primaryTreeRoot(), args[0]);
else
dn = new DocNode(qdb_->primaryTreeRoot(), args[0], Node::Page, ptype);
dn->setLocation(doc.startLocation());
- if (ncn) {
- ncn->addCollision(dn);
- }
return dn;
}
else if (command == COMMAND_DITAMAP) {
@@ -549,40 +543,18 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
classNode = qdb_->findClassNode(names[1].split("::"));
}
- /*
- Search for a node with the same name. If there is one,
- then there is a collision, so create a collision node
- and make the existing node a child of the collision
- node, and then create the new QML class node and make
- it a child of the collision node as well. Return the
- collision node.
-
- If there is no collision, just create a new QML class
- node and return that one.
- */
- NameCollisionNode* ncn = qdb_->checkForCollision(names[0]);
- QmlClassNode* qcn = new QmlClassNode(qdb_->primaryTreeRoot(), names[0]);
- qcn->setClassNode(classNode);
- qcn->setLocation(doc.startLocation());
#if 0
- // to be removed if \qmltype and \instantiates work ok
- if (isParsingCpp() || isParsingQdoc()) {
- qcn->requireCppClass();
- if (names.size() < 2) {
- QString msg = "C++ class name not specified for class documented as "
- "QML type: '\\qmlclass " + arg.first + " <class name>'";
- doc.startLocation().warning(tr(msg.toLatin1().data()));
- }
- else if (!classNode) {
- QString msg = "C++ class not found in any .h file for class documented "
- "as QML type: '\\qmlclass " + arg.first + "'";
- doc.startLocation().warning(tr(msg.toLatin1().data()));
- }
+ const Node* n = qdb_->checkForCollision(names[0]);
+ if (n) {
+ QString other = n->doc().location().fileName();
+ doc.location().warning(tr("Name/title collision detected: '%1' in '\\%2'")
+ .arg(names[0]).arg(command),
+ tr("Also used here: %1").arg(other));
}
#endif
- if (ncn) {
- ncn->addCollision(qcn);
- }
+ QmlClassNode* qcn = new QmlClassNode(qdb_->primaryTreeRoot(), names[0]);
+ qcn->setClassNode(classNode);
+ qcn->setLocation(doc.startLocation());
return qcn;
}
else if (command == COMMAND_QMLBASICTYPE) {
diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp
index c2a5cdb8b8..9cc44d7000 100644
--- a/src/tools/qdoc/ditaxmlgenerator.cpp
+++ b/src/tools/qdoc/ditaxmlgenerator.cpp
@@ -671,10 +671,8 @@ GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName)
*/
void DitaXmlGenerator::generateDocs()
{
- if (!runPrepareOnly()) {
+ if (!runPrepareOnly())
Generator::generateDocs();
- generateCollisionPages();
- }
if (!runGenerateOnly()) {
QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-'));
@@ -2275,10 +2273,6 @@ void DitaXmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
QList<Section>::const_iterator s;
QString fullTitle = dn->fullTitle();
- if (dn->subType() == Node::Collision) {
- fullTitle = "Name Collision: " + fullTitle;
- }
-
generateHeader(dn, fullTitle);
generateBrief(dn, marker); // <shortdesc>
writeProlog(dn);
@@ -2553,9 +2547,6 @@ void DitaXmlGenerator::generateHeader(const Node* node, const QString& name)
case Node::ExternalPage: // not used
outputclass = "externalpage";
break;
- case Node::Collision:
- outputclass = "collision";
- break;
default:
outputclass = "page";
}
@@ -3444,7 +3435,7 @@ void DitaXmlGenerator::writeText(const QString& markedCode, const Node* relative
text.clear();
}
par1 = QStringRef();
- n = qdb_->resolveFunctionTarget(arg.toString(), relative);
+ n = qdb_->findFunctionNode(arg.toString(), relative, Node::DontCare);
addLink(linkForNode(n, relative), arg);
break;
case 1:
@@ -3455,7 +3446,7 @@ void DitaXmlGenerator::writeText(const QString& markedCode, const Node* relative
text.clear();
}
par1 = QStringRef();
- n = qdb_->resolveType(arg.toString(), relative);
+ n = qdb_->findTypeNode(arg.toString(), relative);
if (n && n->isQmlBasicType()) {
if (relative && relative->isQmlType())
addLink(linkForNode(n, relative), arg);
@@ -3733,65 +3724,50 @@ QString DitaXmlGenerator::fileName(const Node* node)
*/
QString DitaXmlGenerator::getLink(const Atom *atom, const Node *relative, const Node** node)
{
- if (atom->string().contains(QLatin1Char(':')) && (atom->string().startsWith("file:") ||
- atom->string().startsWith("http:") ||
- atom->string().startsWith("https:") ||
- atom->string().startsWith("ftp:") ||
- atom->string().startsWith("mailto:"))) {
- return atom->string(); // It's some kind of protocol.
+ const QString& t = atom->string();
+ if (t.at(0) == QChar('h')) {
+ if (t.startsWith("http:") || t.startsWith("https:"))
+ return t;
+ }
+ else if (t.at(0) == QChar('f')) {
+ if (t.startsWith("file:") || t.startsWith("ftp:"))
+ return t;
+ }
+ else if (t.at(0) == QChar('m')) {
+ if (t.startsWith("mailto:"))
+ return t;
}
QString ref;
- QString link;
- QStringList path = atom->string().split("#");
- QString first = path.first().trimmed();
- *node = 0;
- if (first.isEmpty())
- *node = relative; // search for a target on the current page.
- else {
- if (first.endsWith(".html")) { // The target is an html file.
- *node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document);
- }
- else if (first.endsWith("()")) { // The target is a C++ function or QML method.
- *node = qdb_->resolveFunctionTarget(first, relative);
- }
- else {
- *node = qdb_->resolveTarget(first, relative);
- if (!(*node))
- *node = qdb_->findDocNodeByTitle(first);
- if (!(*node)) {
- *node = qdb_->findUnambiguousTarget(first, ref);
- if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
- QString final = (*node)->url() + "#" + ref;
- return final;
- }
- }
- }
- }
+ *node = qdb_->findNodeForAtom(atom, relative, ref);
if (!(*node))
- return link; // empty
-
- if (!(*node)->url().isEmpty())
- return (*node)->url();
+ return QString();
- if (!path.isEmpty()) {
- ref = qdb_->findTarget(path.first(), *node);
+ QString url = (*node)->url();
+ if (!url.isEmpty()) {
if (ref.isEmpty())
- return link; // empty
+ return url;
+ int hashtag = url.lastIndexOf(QChar('#'));
+ if (hashtag != -1)
+ url.truncate(hashtag);
+ return url + "#" + ref;
}
-
/*
Given that *node is not null, we now cconstruct a link
to the page that *node represents, and then if we found
a target on that page, we connect the target to the link
with '#'.
*/
- link = linkForNode(*node, relative);
+ QString link = linkForNode(*node, relative);
if (*node && (*node)->subType() == Node::Image)
link = "images/used-in-examples/" + link;
- if (!ref.isEmpty())
+ if (!ref.isEmpty()) {
+ int hashtag = link.lastIndexOf(QChar('#'));
+ if (hashtag != -1)
+ link.truncate(hashtag);
link += QLatin1Char('#') + ref;
+ }
return link;
}
@@ -3810,31 +3786,20 @@ QString DitaXmlGenerator::getAutoLink(const Atom *atom, const Node *relative, co
{
QString ref;
QString link;
- QString target = atom->string().trimmed();
- *node = 0;
-
- if (target.endsWith("()")) { // The target is a C++ function or QML method.
- *node = qdb_->resolveFunctionTarget(target, relative);
- }
- else {
- *node = qdb_->resolveTarget(target, relative);
- if (!(*node)) {
- *node = qdb_->findDocNodeByTitle(target);
- }
- if (!(*node)) {
- *node = qdb_->findUnambiguousTarget(target, ref);
- if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
- QString final = (*node)->url() + "#" + ref;
- return final;
- }
- }
- }
+ *node = qdb_->findNodeForAtom(atom, relative, ref);
if (!(*node))
- return link; // empty
+ return QString();
- if (!(*node)->url().isEmpty())
- return (*node)->url();
+ QString url = (*node)->url();
+ if (!url.isEmpty()) {
+ if (ref.isEmpty())
+ return url;
+ int hashtag = url.lastIndexOf(QChar('#'));
+ if (hashtag != -1)
+ url.truncate(hashtag);
+ return url + "#" + ref;
+ }
link = linkForNode(*node, relative);
if (!ref.isEmpty())
@@ -3963,40 +3928,7 @@ void DitaXmlGenerator::generateStatus(const Node* node, CodeMarker* marker)
Generator::generateStatus(node, marker);
break;
case Node::Compat:
- if (node->isInnerNode()) {
- text << Atom::ParaLeft
- << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
- << "This "
- << typeString(node)
- << " is part of the Qt 3 support library."
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
- << " It is provided to keep old source code working. "
- << "We strongly advise against "
- << "using it in new code. See ";
-
- const DocNode *docNode = qdb_->findDocNodeByTitle("Porting To Qt 4");
- QString ref;
- if (docNode && node->type() == Node::Class) {
- QString oldName(node->name());
- oldName.remove(QLatin1Char('3'));
- ref = qdb_->findTarget(oldName,docNode);
- }
-
- if (!ref.isEmpty()) {
- QString fn = fileName(docNode);
- QString guid = lookupGuid(fn, ref);
- text << Atom(Atom::GuidLink, fn + QLatin1Char('#') + guid);
- }
- else
- text << Atom(Atom::Link, "Porting to Qt 4");
-
- text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, "Porting to Qt 4")
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
- << " for more information."
- << Atom::ParaRight;
- }
- generateText(text, node, marker);
+ // Porting to Qt 4 no longer supported
break;
default:
Generator::generateStatus(node, marker);
@@ -4652,7 +4584,7 @@ void DitaXmlGenerator::replaceTypesWithLinks(const Node* n, const InnerNode* par
}
i += 2;
if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
- const Node* tn = qdb_->resolveType(arg.toString(), parent);
+ const Node* tn = qdb_->findTypeNode(arg.toString(), parent);
if (tn) {
//Do not generate a link from a C++ function to a QML Basic Type (such as int)
if (n->isFunction() && tn->isQmlBasicType())
@@ -5336,27 +5268,16 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node)
*/
CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
if (node->parent() != 0) {
- /*
- Skip name collision nodes here and process them
- later in generateCollisionPages(). Each one is
- appended to a list for later.
- */
- if (node->isCollisionNode()) {
- NameCollisionNode* ncn = static_cast<NameCollisionNode*>(node);
- collisionNodes.append(const_cast<NameCollisionNode*>(ncn));
- }
- else {
- if (!node->name().endsWith(".ditamap"))
- beginSubPage(node, fileName(node));
- if (node->isNamespace() || node->isClass() || node->isQmlType() || node->isHeaderFile())
- generateClassLikeNode(node, marker);
- else if (node->isDocNode())
- generateDocNode(static_cast<DocNode*>(node), marker);
- else if (node->isQmlBasicType())
- generateQmlBasicTypePage(static_cast<QmlBasicTypeNode*>(node), marker);
- if (!node->name().endsWith(".ditamap"))
- endSubPage();
- }
+ if (!node->name().endsWith(".ditamap"))
+ beginSubPage(node, fileName(node));
+ if (node->isNamespace() || node->isClass() || node->isQmlType() || node->isHeaderFile())
+ generateClassLikeNode(node, marker);
+ else if (node->isDocNode())
+ generateDocNode(static_cast<DocNode*>(node), marker);
+ else if (node->isQmlBasicType())
+ generateQmlBasicTypePage(static_cast<QmlBasicTypeNode*>(node), marker);
+ if (!node->name().endsWith(".ditamap"))
+ endSubPage();
}
NodeList::ConstIterator c = node->childNodes().constBegin();
@@ -5422,13 +5343,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
QString message;
for (int i=0; i<children.size(); ++i) {
Node* child = children[i];
- if (child->isCollisionNode()) {
- const DocNode* fake = static_cast<const DocNode*>(child);
- Node* n = collectNodesByTypeAndSubtype(fake);
- if (n)
- rootPageNode = n;
- continue;
- }
if (!child || child->isInternal() || child->doc().isEmpty() || child->isIndexNode())
continue;
@@ -5487,10 +5401,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
if (!isDuplicate(nodeSubtypeMaps[Node::ExternalPage],child->title(),child))
nodeSubtypeMaps[Node::ExternalPage]->insert(child->title(),child);
break;
- case Node::Collision:
- if (!isDuplicate(nodeSubtypeMaps[Node::Collision],child->title(),child))
- nodeSubtypeMaps[Node::Collision]->insert(child->title(),child);
- break;
default:
break;
}
@@ -6088,122 +5998,4 @@ QString DitaXmlGenerator::stripMarkup(const QString& src) const
return text;
}
-/*!
- We delayed generation of the collision pages until now, after
- all the other pages have been generated. We do this because we might
- encounter a link command that tries to link to a target on a QML
- type page, but the link doesn't specify the module identifer
- for the QML type, and the QML type name without a module
- identifier is ambiguous. When such a link is found, qdoc can't find
- the target, so it appends the target to the NameCollisionNode. After
- the tree has been traversed and all these ambiguous links have been
- added to the name collision nodes, this function is called. The list
- of collision nodes is traversed here, and the collision page for
- each collision is generated. The collision page will not only
- disambiguate links to the QML type pages, but it will also disambiguate
- links to properties, section headers, etc.
- */
-void DitaXmlGenerator::generateCollisionPages()
-{
- if (collisionNodes.isEmpty())
- return;
-
- for (int i=0; i<collisionNodes.size(); ++i) {
- NameCollisionNode* ncn = collisionNodes.at(i);
- if (!ncn)
- continue;
-
- NodeList collisions;
- const NodeList& nl = ncn->childNodes();
- if (!nl.isEmpty()) {
- NodeList::ConstIterator it = nl.constBegin();
- while (it != nl.constEnd()) {
- if (!(*it)->isInternal())
- collisions.append(*it);
- ++it;
- }
- }
- if (collisions.size() <= 1)
- continue;
-
- beginSubPage(ncn, Generator::fileName(ncn));
- QString fullTitle = ncn->fullTitle();
- QString ditaTitle = fullTitle;
- CodeMarker* marker = CodeMarker::markerForFileName(ncn->location().filePath());
- if (ncn->isQmlNode()) {
- // Replace the marker with a QML code marker.
- if (ncn->isQmlNode())
- marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
- }
-
- generateHeader(ncn, ditaTitle);
- writeProlog(ncn);
- writeStartTag(DT_body);
- enterSection(QString(), QString());
-
- NodeMap nm;
- for (int i=0; i<collisions.size(); ++i) {
- Node* n = collisions.at(i);
- QString t;
- if (!n->qmlModuleName().isEmpty())
- t = n->qmlModuleName() + QLatin1Char(' ');
- t += protectEnc(fullTitle);
- nm.insertMulti(t,n);
- }
- generateAnnotatedList(ncn, marker, nm);
-
- QList<QString> targets;
- if (!ncn->linkTargets().isEmpty()) {
- QMap<QString,QString>::ConstIterator t = ncn->linkTargets().constBegin();
- while (t != ncn->linkTargets().constEnd()) {
- int count = 0;
- for (int i=0; i<collisions.size(); ++i) {
- InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- if (n->findChildNode(t.key())) {
- ++count;
- if (count > 1) {
- targets.append(t.key());
- break;
- }
- }
- }
- ++t;
- }
- }
- if (!targets.isEmpty()) {
- QList<QString>::ConstIterator t = targets.constBegin();
- while (t != targets.constEnd()) {
- writeStartTag(DT_p);
- writeGuidAttribute(Doc::canonicalTitle(*t));
- xmlWriter().writeAttribute("outputclass","h2");
- writeCharacters(protectEnc(*t));
- writeEndTag(); // </p>
- writeStartTag(DT_ul);
- for (int i=0; i<collisions.size(); ++i) {
- InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- Node* p = n->findChildNode(*t);
- if (p) {
- QString link = linkForNode(p,0);
- QString label;
- if (!n->qmlModuleName().isEmpty())
- label = n->qmlModuleName() + "::";
- label += n->name() + "::" + p->name();
- writeStartTag(DT_li);
- writeStartTag(DT_xref);
- xmlWriter().writeAttribute("href", link);
- writeCharacters(protectEnc(label));
- writeEndTag(); // </xref>
- writeEndTag(); // </li>
- }
- }
- writeEndTag(); // </ul>
- ++t;
- }
- }
- leaveSection(); // </section>
- writeEndTag(); // </body>
- endSubPage();
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/tools/qdoc/ditaxmlgenerator.h b/src/tools/qdoc/ditaxmlgenerator.h
index d4264d948c..d8d0f9b00e 100644
--- a/src/tools/qdoc/ditaxmlgenerator.h
+++ b/src/tools/qdoc/ditaxmlgenerator.h
@@ -303,7 +303,6 @@ public:
virtual QString format();
virtual bool canHandleFormat(const QString& format);
virtual void generateDocs();
- void generateCollisionPages();
QString protectEnc(const QString& string);
static QString protect(const QString& string, const QString& encoding = "ISO-8859-1");
diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp
index 5745b094d5..752d3075d2 100644
--- a/src/tools/qdoc/doc.cpp
+++ b/src/tools/qdoc/doc.cpp
@@ -649,7 +649,7 @@ void DocParser::parse(const QString& source,
append(Atom::CodeBad,getCode(CMD_BADCODE, marker));
break;
case CMD_BR:
- leavePara();
+ enterPara();
append(Atom::BR);
break;
case CMD_BOLD:
@@ -975,6 +975,11 @@ void DocParser::parse(const QString& source,
if (isLeftBraceAhead()) {
p1 = getArgument();
append(p1, p2);
+ if (!p2.isEmpty() && !(priv->text.lastAtom()->error().isEmpty())) {
+ location().warning(tr("Check parameter in '[ ]' of '\\l' command: '%1', "
+ "possible misspelling, or unrecognized module name")
+ .arg(priv->text.lastAtom()->error()));
+ }
if (isLeftBraceAhead()) {
currentLinkAtom = priv->text.lastAtom();
startFormat(ATOM_FORMATTING_LINK, cmd);
@@ -988,6 +993,11 @@ void DocParser::parse(const QString& source,
else {
p1 = getArgument();
append(p1, p2);
+ if (!p2.isEmpty() && !(priv->text.lastAtom()->error().isEmpty())) {
+ location().warning(tr("Check parameter in '[ ]' of '\\l' command: '%1', "
+ "possible misspelling, or unrecognized module name")
+ .arg(priv->text.lastAtom()->error()));
+ }
append(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
append(Atom::String, cleanLink(p1));
append(Atom::FormattingRight, ATOM_FORMATTING_LINK);
diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp
index 6fdc2a916c..f96ca490f9 100644
--- a/src/tools/qdoc/generator.cpp
+++ b/src/tools/qdoc/generator.cpp
@@ -69,6 +69,7 @@ QStringList Generator::imageFiles;
QMap<QString, QStringList> Generator::imgFileExts;
QString Generator::outDir_;
QString Generator::outSubdir_;
+QStringList Generator::outFileNames_;
QSet<QString> Generator::outputFormats;
QHash<QString, QString> Generator::outputPrefixes;
QString Generator::project;
@@ -244,8 +245,6 @@ void Generator::appendSortedQmlNames(Text& text, const Node* base, const NodeLis
}
}
-QMultiMap<QString,QString> outFileNames;
-
/*!
For debugging qdoc.
*/
@@ -255,10 +254,8 @@ void Generator::writeOutFileNames()
if (!files.open(QFile::WriteOnly))
return;
QTextStream filesout(&files);
- QMultiMap<QString,QString>::ConstIterator i = outFileNames.begin();
- while (i != outFileNames.end()) {
- filesout << i.key() << "\n";
- ++i;
+ foreach (const QString &file, outFileNames_) {
+ filesout << file << "\n";
}
}
@@ -280,7 +277,7 @@ void Generator::beginSubPage(const InnerNode* node, const QString& fileName)
if (!outFile->open(QFile::WriteOnly))
node->location().fatal(tr("Cannot open output file '%1'").arg(outFile->fileName()));
Generator::debug("Writing: " + path);
- outFileNames.insert(fileName,fileName);
+ outFileNames_ << fileName;
QTextStream* out = new QTextStream(outFile);
#ifndef QT_NO_TEXTCODEC
@@ -319,10 +316,7 @@ QString Generator::fileBase(const Node *node) const
QString base;
if (node->isDocNode()) {
base = node->name();
- if (node->subType() == Node::Collision)
- base.prepend("collision-");
- //Was QDOC2_COMPAT, required for index.html
- if (base.endsWith(".html"))
+ if (base.endsWith(".html") && !node->isExampleFile())
base.truncate(base.length() - 5);
if (node->isExample() || node->isExampleFile()) {
@@ -976,10 +970,6 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
\note DitaXmlGenerator overrides this function, but
HtmlGenerator does not.
-
- \note NameCollisionNodes are skipped here and processed
- later. See HtmlGenerator::generateCollisionPages() for
- more on this.
*/
void Generator::generateInnerNode(InnerNode* node)
{
@@ -1010,66 +1000,55 @@ void Generator::generateInnerNode(InnerNode* node)
CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
if (node->parent() != 0) {
- /*
- Skip name collision nodes here and process them
- later in generateCollisionPages(). Each one is
- appended to a list for later.
- */
- if (node->isCollisionNode()) {
- NameCollisionNode* ncn = static_cast<NameCollisionNode*>(node);
- collisionNodes.append(const_cast<NameCollisionNode*>(ncn));
+ if (node->isNamespace() || node->isClass()) {
+ beginSubPage(node, fileName(node));
+ generateClassLikeNode(node, marker);
+ endSubPage();
}
- else {
- if (node->isNamespace() || node->isClass()) {
- beginSubPage(node, fileName(node));
- generateClassLikeNode(node, marker);
- endSubPage();
- }
- if (node->isQmlType()) {
- beginSubPage(node, fileName(node));
- QmlClassNode* qcn = static_cast<QmlClassNode*>(node);
- generateQmlTypePage(qcn, marker);
- endSubPage();
- }
- else if (node->isDocNode()) {
- beginSubPage(node, fileName(node));
- generateDocNode(static_cast<DocNode*>(node), marker);
- endSubPage();
- }
- else if (node->isQmlBasicType()) {
+ if (node->isQmlType()) {
+ beginSubPage(node, fileName(node));
+ QmlClassNode* qcn = static_cast<QmlClassNode*>(node);
+ generateQmlTypePage(qcn, marker);
+ endSubPage();
+ }
+ else if (node->isDocNode()) {
+ beginSubPage(node, fileName(node));
+ generateDocNode(static_cast<DocNode*>(node), marker);
+ endSubPage();
+ }
+ else if (node->isQmlBasicType()) {
+ beginSubPage(node, fileName(node));
+ QmlBasicTypeNode* qbtn = static_cast<QmlBasicTypeNode*>(node);
+ generateQmlBasicTypePage(qbtn, marker);
+ endSubPage();
+ }
+ else if (node->isCollectionNode()) {
+ CollectionNode* cn = static_cast<CollectionNode*>(node);
+ /*
+ A collection node is one of: group, module,
+ or QML module.
+
+ Don't output an HTML page for the collection
+ node unless the \group, \module, or \qmlmodule
+ command was actually seen by qdoc in the qdoc
+ comment for the node.
+
+ A key prerequisite in this case is the call to
+ mergeCollections(cn). We don't know if this
+ collection (group, module, or QML module) has
+ members in other modules. We know at this point
+ that cn's members list contains only members in
+ the current module. Therefore, before outputting
+ the page for cn, we must search for members of
+ cn in the other modules and add them to the
+ members list.
+ */
+ if (cn->wasSeen()) {
+ qdb_->mergeCollections(cn);
beginSubPage(node, fileName(node));
- QmlBasicTypeNode* qbtn = static_cast<QmlBasicTypeNode*>(node);
- generateQmlBasicTypePage(qbtn, marker);
+ generateCollectionNode(cn, marker);
endSubPage();
}
- else if (node->isCollectionNode()) {
- CollectionNode* cn = static_cast<CollectionNode*>(node);
- /*
- A collection node is one of: group, module,
- or QML module.
-
- Don't output an HTML page for the collection
- node unless the \group, \module, or \qmlmodule
- command was actually seen by qdoc in the qdoc
- comment for the node.
-
- A key prerequisite in this case is the call to
- mergeCollections(cn). We don't know if this
- collection (group, module, or QML module) has
- members in other modules. We know at this point
- that cn's members list contains only members in
- the current module. Therefore, before outputting
- the page for cn, we must search for members of
- cn in the other modules and add them to the
- members list.
- */
- if (cn->wasSeen()) {
- qdb_->mergeCollections(cn);
- beginSubPage(node, fileName(node));
- generateCollectionNode(cn, marker);
- endSubPage();
- }
- }
}
}
@@ -1446,47 +1425,6 @@ Generator *Generator::generatorForFormat(const QString& format)
return 0;
}
-#if 0
-/*!
- This function might be useless now with the addition of
- multiple node trees. It is called a few hundred times,
- but it never finds a collision node. The single call has
- been commented out by mws (19/05/2014). If it is no
- longer needed, it will be removed.
-
- This function can be called if getLink() returns an empty
- string. It tests the \a atom string to see if it is a link
- of the form <element> :: <name>, where <element> is a QML
- element or component without a module qualifier. If so, it
- constructs a link to the <name> clause on the disambiguation
- page for <element> and returns that link string. It also
- adds the <name> as a target in the NameCollisionNode for
- <element>. These clauses are then constructed when the
- disambiguation page is actually generated.
- */
-QString Generator::getCollisionLink(const Atom* atom)
-{
- QString link;
- if (!atom->string().contains("::"))
- return link;
- QStringList path = atom->string().split("::");
- NameCollisionNode* ncn = qdb_->findCollisionNode(path[0]);
- if (ncn) {
- QString label;
- if (atom->next() && atom->next()->next()) {
- if (atom->next()->type() == Atom::FormattingLeft &&
- atom->next()->next()->type() == Atom::String)
- label = atom->next()->next()->string();
- }
- ncn->addLinkTarget(path[1],label);
- link = fileName(ncn);
- link += QLatin1Char('#');
- link += Doc::canonicalTitle(path[1]);
- }
- return link;
-}
-#endif
-
/*!
Looks up the tag \a t in the map of metadata values for the
current topic in \a inner. If a value for the tag is found,
diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h
index 81b63ef29a..2ea2715e80 100644
--- a/src/tools/qdoc/generator.h
+++ b/src/tools/qdoc/generator.h
@@ -90,6 +90,7 @@ public:
static const QString& outputDir() { return outDir_; }
static const QString& outputSubdir() { return outSubdir_; }
static void terminate();
+ static const QStringList& outputFileNames() { return outFileNames_; }
static void writeOutFileNames();
static void augmentImageDirs(QSet<QString>& moreImageDirs);
static void debug(const QString& message);
@@ -157,7 +158,6 @@ protected:
void generateSince(const Node *node, CodeMarker *marker);
void generateStatus(const Node *node, CodeMarker *marker);
void generateThreadSafeness(const Node *node, CodeMarker *marker);
- //QString getCollisionLink(const Atom* atom);
QString getMetadataElement(const InnerNode* inner, const QString& t);
QStringList getMetadataElements(const InnerNode* inner, const QString& t);
QString indent(int level, const QString& markedCode);
@@ -175,7 +175,6 @@ protected:
void unknownAtom(const Atom *atom);
void appendSortedQmlNames(Text& text, const Node* base, const NodeList& subs);
- QList<NameCollisionNode*> collisionNodes;
QMap<QString, QStringList> editionGroupMap;
QMap<QString, QStringList> editionModuleMap;
QString naturalLanguage;
@@ -210,6 +209,7 @@ private:
static QString project;
static QString outDir_;
static QString outSubdir_;
+ static QStringList outFileNames_;
static QSet<QString> outputFormats;
static QHash<QString, QString> outputPrefixes;
static QStringList scriptDirs;
diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp
index a1121a95cb..41ab918f5c 100644
--- a/src/tools/qdoc/helpprojectwriter.cpp
+++ b/src/tools/qdoc/helpprojectwriter.cpp
@@ -284,7 +284,6 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
case Node::Class:
project.keywords.append(keywordDetails(node));
- project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
break;
case Node::QmlType:
case Node::QmlBasicType:
@@ -303,12 +302,10 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
}
}
project.keywords.append(keywordDetails(node));
- project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
break;
case Node::Namespace:
project.keywords.append(keywordDetails(node));
- project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
break;
case Node::Enum:
@@ -357,7 +354,6 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
}
}
project.keywords.append(keywordDetails(node));
- project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
}
}
break;
@@ -388,7 +384,6 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
if (node->relates()) {
project.memberStatus[node->relates()].insert(node->status());
- project.files.insert(gen_->fullDocumentLocation(node->relates(),Generator::useOutputSubdirs()));
} else if (node->parent())
project.memberStatus[node->parent()].insert(node->status());
}
@@ -410,8 +405,6 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
case Node::Variable:
{
- QString location = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs());
- project.files.insert(location.left(location.lastIndexOf(QLatin1Char('#'))));
project.keywords.append(keywordDetails(node));
}
break;
@@ -442,7 +435,6 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
}
project.keywords.append(keywordDetails(node));
}
- project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
}
break;
}
@@ -513,8 +505,6 @@ void HelpProjectWriter::generateSections(HelpProject &project,
project.memberStatus[node].insert(childNode->status());
if (childNode->relates()) {
project.memberStatus[childNode->relates()].insert(childNode->status());
- project.files.insert(gen_->fullDocumentLocation(childNode->relates(),
- Generator::useOutputSubdirs()));
}
if (childNode->type() == Node::Function) {
@@ -525,11 +515,6 @@ void HelpProjectWriter::generateSections(HelpProject &project,
childMap[childNode->fullDocumentName()] = childNode;
}
}
- // Insert files for all/compatibility/obsolete members
- addMembers(project, writer, node, false);
- if (node->relates())
- addMembers(project, writer, node->relates(), false);
-
foreach (const Node *child, childMap)
generateSections(project, writer, child);
}
@@ -564,11 +549,10 @@ void HelpProjectWriter::writeSection(QXmlStreamWriter &writer, const QString &pa
}
/*
- Add files for all members, compatibility members and obsolete members
- Also write subsections for these depending on 'writeSections' (default=true).
+ Write subsections for all members, compatibility members and obsolete members.
*/
void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &writer,
- const Node *node, bool writeSections)
+ const Node *node)
{
QString href = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs());
href = href.left(href.size()-5);
@@ -584,21 +568,15 @@ void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &write
if (!node->isNamespace() && !node->isHeaderFile() &&
(derivedClass || node->isQmlType() || !project.memberStatus[node].isEmpty())) {
QString membersPath = href + QStringLiteral("-members.html");
- project.files.insert(membersPath);
- if (writeSections)
- writeSection(writer, membersPath, tr("List of all members"));
+ writeSection(writer, membersPath, tr("List of all members"));
}
if (project.memberStatus[node].contains(Node::Compat)) {
QString compatPath = href + QStringLiteral("-compat.html");
- project.files.insert(compatPath);
- if (writeSections)
- writeSection(writer, compatPath, tr("Compatibility members"));
+ writeSection(writer, compatPath, tr("Compatibility members"));
}
if (project.memberStatus[node].contains(Node::Obsolete)) {
QString obsoletePath = href + QStringLiteral("-obsolete.html");
- project.files.insert(obsoletePath);
- if (writeSections)
- writeSection(writer, obsoletePath, tr("Obsolete members"));
+ writeSection(writer, obsoletePath, tr("Obsolete members"));
}
}
@@ -716,14 +694,12 @@ void HelpProjectWriter::generateProject(HelpProject &project)
if (node == 0)
node = qdb_->findNodeByNameAndType(QStringList("index.html"), Node::Document);
QString indexPath;
- // Never use a collision node as a landing page
- if (node && !node->isCollisionNode())
+ if (node)
indexPath = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs());
else
indexPath = "index.html";
writer.writeAttribute("ref", indexPath);
writer.writeAttribute("title", project.indexTitle);
- project.files.insert(gen_->fullDocumentLocation(rootNode));
generateSections(project, writer, rootNode);
@@ -765,7 +741,6 @@ void HelpProjectWriter::generateProject(HelpProject &project)
Generator::useOutputSubdirs());
writer.writeAttribute("ref", indexPath);
writer.writeAttribute("title", atom->string());
- project.files.insert(indexPath);
sectionStack.top() += 1;
}
@@ -790,7 +765,6 @@ void HelpProjectWriter::generateProject(HelpProject &project)
QString indexPath = gen_->fullDocumentLocation(qdb_->findDocNodeByTitle(subproject.indexTitle),Generator::useOutputSubdirs());
writer.writeAttribute("ref", indexPath);
writer.writeAttribute("title", subproject.title);
- project.files.insert(indexPath);
}
if (subproject.sortPages) {
QStringList titles = subproject.nodes.keys();
@@ -844,12 +818,16 @@ void HelpProjectWriter::generateProject(HelpProject &project)
writer.writeEndElement(); // keywords
writer.writeStartElement("files");
- foreach (const QString &usedFile, project.files) {
+
+ // The list of files to write is the union of generated files and
+ // other files (images and extras) included in the project
+ QSet<QString> files = QSet<QString>::fromList(gen_->outputFileNames());
+ files.unite(project.files);
+ files.unite(project.extraFiles);
+ foreach (const QString &usedFile, files) {
if (!usedFile.isEmpty())
writer.writeTextElement("file", usedFile);
}
- foreach (const QString &usedFile, project.extraFiles)
- writer.writeTextElement("file", usedFile);
writer.writeEndElement(); // files
writer.writeEndElement(); // filterSection
diff --git a/src/tools/qdoc/helpprojectwriter.h b/src/tools/qdoc/helpprojectwriter.h
index 5dfa12cf73..7c4e0f6c72 100644
--- a/src/tools/qdoc/helpprojectwriter.h
+++ b/src/tools/qdoc/helpprojectwriter.h
@@ -106,7 +106,7 @@ private:
void writeNode(HelpProject &project, QXmlStreamWriter &writer, const Node *node);
void readSelectors(SubProject &subproject, const QStringList &selectors);
void addMembers(HelpProject &project, QXmlStreamWriter &writer,
- const Node *node, bool writeSections = true);
+ const Node *node);
void writeSection(QXmlStreamWriter &writer, const QString &path,
const QString &value);
diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp
index dd665ea885..ae8206b8c3 100644
--- a/src/tools/qdoc/htmlgenerator.cpp
+++ b/src/tools/qdoc/htmlgenerator.cpp
@@ -274,10 +274,8 @@ void HtmlGenerator::generateDocs()
Node* qflags = qdb_->findClassNode(QStringList("QFlags"));
if (qflags)
qflagsHref_ = linkForNode(qflags,0);
- if (!runPrepareOnly()) {
+ if (!runPrepareOnly())
Generator::generateDocs();
- generateCollisionPages();
- }
if (!runGenerateOnly()) {
QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-'));
@@ -816,7 +814,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
inObsoleteLink = false;
const Node *node = 0;
QString link = getLink(atom, relative, &node);
- if (link.isEmpty() && !noLinkErrors()) {
+ if (link.isEmpty() && (node != relative) && !noLinkErrors()) {
relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
}
else {
@@ -1352,10 +1350,17 @@ void HtmlGenerator::generateQmlTypePage(QmlClassNode* qcn, CodeMarker* marker)
generateQmlRequisites(qcn, marker);
QString allQmlMembersLink = generateAllQmlMembersFile(qcn, marker);
- if (!allQmlMembersLink.isEmpty()) {
+ QString obsoleteLink = generateQmlMemberFile(qcn, marker, CodeMarker::Obsolete);
+ if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
out() << "<ul>\n";
- out() << "<li><a href=\"" << allQmlMembersLink << "\">"
- << "List of all members, including inherited members</a></li>\n";
+ if (!allQmlMembersLink.isEmpty()) {
+ out() << "<li><a href=\"" << allQmlMembersLink << "\">"
+ << "List of all members, including inherited members</a></li>\n";
+ }
+ if (!obsoleteLink.isEmpty()) {
+ out() << "<li><a href=\"" << obsoleteLink << "\">"
+ << "Obsolete members</a></li>\n";
+ }
out() << "</ul>\n";
}
@@ -1425,117 +1430,6 @@ void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker*
}
/*!
- We delayed generation of the disambiguation pages until now, after
- all the other pages have been generated. We do this because we might
- encounter a link command that tries to link to a target on a QML
- component page, but the link doesn't specify the module identifer
- for the component, and the component name without a module
- identifier is ambiguous. When such a link is found, qdoc can't find
- the target, so it appends the target to the NameCollisionNode. After
- the tree has been traversed and all these ambiguous links have been
- added to the name collision nodes, this function is called. The list
- of collision nodes is traversed here, and the disambiguation page for
- each collision is generated. The disambiguation page will not only
- disambiguate links to the component pages, but it will also disambiguate
- links to properties, section headers, etc.
- */
-void HtmlGenerator::generateCollisionPages()
-{
- if (collisionNodes.isEmpty())
- return;
-
- for (int i=0; i<collisionNodes.size(); ++i) {
- NameCollisionNode* ncn = collisionNodes.at(i);
- if (!ncn)
- continue;
-
- NodeList collisions;
- const NodeList& nl = ncn->childNodes();
- if (!nl.isEmpty()) {
- NodeList::ConstIterator it = nl.constBegin();
- while (it != nl.constEnd()) {
- if (!(*it)->isInternal())
- collisions.append(*it);
- ++it;
- }
- }
- if (collisions.size() <= 1)
- continue;
-
- beginSubPage(ncn, Generator::fileName(ncn));
- QString fullTitle = ncn->fullTitle();
- CodeMarker* marker = CodeMarker::markerForFileName(ncn->location().filePath());
- if (ncn->isQmlNode()) {
- // Replace the marker with a QML code marker.
- if (ncn->isQmlNode())
- marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
- }
-
- generateHeader(fullTitle, ncn, marker);
- if (!fullTitle.isEmpty())
- out() << "<h1 class=\"title\">" << protectEnc(fullTitle) << "</h1>\n";
-
- NodeMap nm;
- for (int i=0; i<collisions.size(); ++i) {
- Node* n = collisions.at(i);
- QString t;
- if (!n->qmlModuleName().isEmpty())
- t = n->qmlModuleName() + "::";
- t += protectEnc(fullTitle);
- nm.insertMulti(t,n);
- }
- generateAnnotatedList(ncn, marker, nm);
-
- QList<QString> targets;
- if (!ncn->linkTargets().isEmpty()) {
- QMap<QString,QString>::ConstIterator t = ncn->linkTargets().constBegin();
- while (t != ncn->linkTargets().constEnd()) {
- int count = 0;
- for (int i=0; i<collisions.size(); ++i) {
- InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- if (n->findChildNode(t.key())) {
- ++count;
- if (count > 1) {
- targets.append(t.key());
- break;
- }
- }
- }
- ++t;
- }
- }
- if (!targets.isEmpty()) {
- QList<QString>::ConstIterator t = targets.constBegin();
- while (t != targets.constEnd()) {
- out() << "<a name=\"" << Doc::canonicalTitle(*t) << "\"></a>";
- out() << "<h2 class=\"title\">" << protectEnc(*t) << "</h2>\n";
- out() << "<ul>\n";
- for (int i=0; i<collisions.size(); ++i) {
- InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- Node* p = n->findChildNode(*t);
- if (p) {
- QString link = linkForNode(p,0);
- QString label;
- if (!n->qmlModuleName().isEmpty())
- label = n->qmlModuleName() + "::";
- label += n->name() + "::" + p->name();
- out() << "<li>";
- out() << "<a href=\"" << link << "\">";
- out() << protectEnc(label) << "</a>";
- out() << "</li>\n";
- }
- }
- out() << "</ul>\n";
- ++t;
- }
- }
-
- generateFooter(ncn);
- endSubPage();
- }
-}
-
-/*!
Generate the HTML page for an entity that doesn't map
to any underlying parsable C++ class or QML component.
*/
@@ -1562,8 +1456,7 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
Generate the TOC for the new doc format.
Don't generate a TOC for the home page.
*/
- if ((dn->subType() != Node::Collision) &&
- (dn->name() != QString("index.html")) &&
+ if ((dn->name() != QString("index.html")) &&
(dn->name() != QString("qtexamplesandtutorials.html")))
generateTableOfContents(dn,marker,0);
@@ -1787,13 +1680,12 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
<< Atom(Atom::ListItemRight);
}
- else if (node->isDocNode()) {
- const DocNode *dn = static_cast<const DocNode *>(node);
- if (dn && dn->isExampleFile()) {
+ else {
+ if (node->isExampleFile()) {
navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::Link, dn->parent()->name())
+ << Atom(Atom::Link, node->parent()->name())
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, dn->parent()->title())
+ << Atom(Atom::String, node->parent()->title())
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
<< Atom(Atom::ListItemRight);
@@ -2572,6 +2464,84 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner,
return fileName;
}
+/*!
+ Generates a separate file where certain members of the QML
+ type \a qcn are listed. The \a marker is used to generate
+ the section lists, which are then traversed and output here.
+
+ Note that this function currently only handles correctly the
+ case where \a status is \c {CodeMarker::Obsolete}.
+ */
+QString HtmlGenerator::generateQmlMemberFile(QmlClassNode* qcn,
+ CodeMarker *marker,
+ CodeMarker::Status status)
+{
+ QList<Section> sections = marker->qmlSections(qcn, CodeMarker::Summary, status);
+ QMutableListIterator<Section> j(sections);
+ while (j.hasNext()) {
+ if (j.next().members.size() == 0)
+ j.remove();
+ }
+ if (sections.isEmpty())
+ return QString();
+
+ QString title = "Obsolete Members for " + qcn->name();
+ QString fileName = fileBase(qcn) + "-obsolete." + fileExtension();
+
+ if (status == CodeMarker::Obsolete) {
+ QString link;
+ if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty())
+ link = QString("../" + Generator::outputSubdir() + QLatin1Char('/'));
+ link += fileName;
+ qcn->setObsoleteLink(link);
+ }
+
+ beginSubPage(qcn, fileName);
+ generateHeader(title, qcn, marker);
+ generateTitle(title, Text(), SmallSubTitle, qcn, marker);
+
+ out() << "<p><b>The following members of QML type "
+ << "<a href=\"" << linkForNode(qcn, 0) << "\">"
+ << protectEnc(qcn->name()) << "</a>"
+ << " are obsolete.</b> "
+ << "They are provided to keep old source code working. "
+ << "We strongly advise against using them in new code.</p>\n";
+
+ QList<Section>::const_iterator s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ out() << "<a name=\"" << registerRef((*s).name.toLower())
+ << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ generateQmlSummary(*s, qcn, marker);
+ ++s;
+ }
+
+ sections = marker->qmlSections(qcn, CodeMarker::Detailed, status);
+ QMutableListIterator<Section> k(sections);
+ while (k.hasNext()) {
+ if (k.next().members.size() == 0)
+ k.remove();
+ }
+ if (sections.isEmpty())
+ return QString();
+
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ NodeList::ConstIterator m = (*s).members.constBegin();
+ while (m != (*s).members.constEnd()) {
+ generateDetailedQmlMember(*m, qcn, marker);
+ out() << "<br/>\n";
+ ++m;
+ }
+ ++s;
+ }
+
+ generateFooter();
+ endSubPage();
+ return fileName;
+}
+
void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classMap)
{
if (classMap.isEmpty())
@@ -3287,7 +3257,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
- const Node* n = qdb_->resolveFunctionTarget(par1.toString(), relative);
+ const Node* n = qdb_->findFunctionNode(par1.toString(), relative, Node::DontCare);
QString link = linkForNode(n, relative);
addLink(link, arg, &html);
par1 = QStringRef();
@@ -3312,7 +3282,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
bool handled = false;
if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
- const Node* n = qdb_->resolveType(arg.toString(), relative);
+ const Node* n = qdb_->findTypeNode(arg.toString(), relative);
html += QLatin1String("<span class=\"type\">");
if (n && n->isQmlBasicType()) {
if (relative && relative->isQmlType())
@@ -3330,9 +3300,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
if (arg.at(0) == QChar('&'))
html += arg;
else {
- // zzz resolveClassTarget()
- const Node* n = qdb_->resolveTarget(arg.toString(), relative);
- if (n)
+ const Node* n = qdb_->findNodeForInclude(QStringList(arg.toString()));
+ if (n && n != relative)
addLink(linkForNode(n,relative), arg, &html);
else
html += arg;
@@ -3659,8 +3628,6 @@ QString HtmlGenerator::refForNode(const Node *node)
return registerRef(ref);
}
-#define DEBUG_ABSTRACT 0
-
/*!
This function is called for links, i.e. for words that
are marked with the qdoc link command. For autolinks
@@ -3691,7 +3658,7 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
QString ref;
- *node = qdb_->findNode(atom, relative, ref);
+ *node = qdb_->findNodeForAtom(atom, relative, ref);
if (!(*node))
return QString();
@@ -3734,31 +3701,20 @@ QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const
{
QString ref;
QString link;
- QString target = atom->string().trimmed();
- *node = 0;
-
- if (target.endsWith("()")) { // The target is a C++ function or QML method.
- *node = qdb_->resolveFunctionTarget(target, relative);
- }
- else {
- *node = qdb_->resolveTarget(target, relative);
- if (!(*node)) {
- *node = qdb_->findDocNodeByTitle(target);
- }
- if (!(*node)) {
- *node = qdb_->findUnambiguousTarget(target, ref);
- if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
- QString final = (*node)->url() + "#" + ref;
- return final;
- }
- }
- }
+ *node = qdb_->findNodeForAtom(atom, relative, ref);
if (!(*node))
- return link; // empty
+ return QString();
- if (!(*node)->url().isEmpty())
- return (*node)->url();
+ QString url = (*node)->url();
+ if (!url.isEmpty()) {
+ if (ref.isEmpty())
+ return url;
+ int hashtag = url.lastIndexOf(QChar('#'));
+ if (hashtag != -1)
+ url.truncate(hashtag);
+ return url + "#" + ref;
+ }
link = linkForNode(*node, relative);
if (!ref.isEmpty())
@@ -3776,7 +3732,7 @@ QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const
*/
QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
{
- if (node == 0 || node == relative)
+ if (node == 0)
return QString();
if (!node->url().isEmpty())
return node->url();
@@ -3977,26 +3933,7 @@ void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker)
Generator::generateStatus(node, marker);
break;
case Node::Compat:
- if (node->isInnerNode()) {
- text << Atom::ParaLeft
- << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
- << "This "
- << typeString(node)
- << " is part of the Qt 3 support library."
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
- << " It is provided to keep old source code working. "
- << "We strongly advise against "
- << "using it in new code. See ";
-
- text << Atom(Atom::Link, "Porting to Qt 4");
-
- text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, "Porting to Qt 4")
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
- << " for more information."
- << Atom::ParaRight;
- }
- generateText(text, node, marker);
+ // Porting to Qt 4 no longer supported
break;
default:
Generator::generateStatus(node, marker);
@@ -4648,8 +4585,6 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent)
break;
case Node::ExternalPage:
break;
- case Node::Collision:
- break;
default:
break;
}
diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h
index ef569b38ce..1dbdaa9a24 100644
--- a/src/tools/qdoc/htmlgenerator.h
+++ b/src/tools/qdoc/htmlgenerator.h
@@ -89,7 +89,6 @@ public:
virtual void terminateGenerator();
virtual QString format();
virtual void generateDocs();
- void generateCollisionPages();
void generateManifestFiles();
QString protectEnc(const QString &string);
@@ -159,6 +158,9 @@ private:
QString generateLowStatusMemberFile(InnerNode *inner,
CodeMarker *marker,
CodeMarker::Status status);
+ QString generateQmlMemberFile(QmlClassNode* qcn,
+ CodeMarker *marker,
+ CodeMarker::Status status);
void generateClassHierarchy(const Node *relative, NodeMap &classMap);
void generateAnnotatedList(const Node* relative, CodeMarker* marker, const NodeMap& nodeMap);
void generateAnnotatedList(const Node* relative, CodeMarker* marker, const NodeList& nodes);
diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp
index 758918e2b6..083f54104d 100644
--- a/src/tools/qdoc/main.cpp
+++ b/src/tools/qdoc/main.cpp
@@ -49,6 +49,7 @@
#include "ditaxmlgenerator.h"
#include "doc.h"
#include "htmlgenerator.h"
+#include "location.h"
#include "plaincodemarker.h"
#include "puredocparser.h"
#include "tokenizer.h"
@@ -101,8 +102,8 @@ static void loadIndexFiles(Config& config)
QFileInfo fi(index);
if (fi.exists() && fi.isFile())
indexFiles << index;
- else if (Generator::runGenerateOnly())
- qDebug() << "warning: Index file not found:" << index;
+ else
+ Location::null.warning(QString("Index file not found: %1").arg(index));
}
dependModules += config.getStringList(CONFIG_DEPENDS);
@@ -165,11 +166,14 @@ static void loadIndexFiles(Config& config)
multiple index files for a module, since the last modified file has the
highest UNIX timestamp.
*/
- qDebug() << "Multiple indices found for dependency:" << dependModules[i] << "\nFound:";
+ QStringList indexPaths;
for (int k = 0; k < foundIndices.size(); k++)
- qDebug() << foundIndices[k].absoluteFilePath();
- qDebug() << "Using" << foundIndices[foundIndices.size() - 1].absoluteFilePath()
- << "as index for" << dependModules[i];
+ indexPaths << foundIndices[k].absoluteFilePath();
+ Location::null.warning(QString("Multiple index files found for dependency \"%1\":\n%2").arg(
+ dependModules[i], indexPaths.join('\n')));
+ Location::null.warning(QString("Using %1 as index file for dependency \"%2\"").arg(
+ foundIndices[foundIndices.size() - 1].absoluteFilePath(),
+ dependModules[i]));
indexToAdd = foundIndices[foundIndices.size() - 1].absoluteFilePath();
}
else if (foundIndices.size() == 1) {
@@ -179,16 +183,14 @@ static void loadIndexFiles(Config& config)
if (!indexFiles.contains(indexToAdd))
indexFiles << indexToAdd;
}
- else if (Generator::runGenerateOnly()) {
- qDebug() << "warning:" << config.getString(CONFIG_PROJECT)
- << "Cannot locate index file for dependency"
- << dependModules[i];
+ else {
+ Location::null.warning(QString("\"%1\" Cannot locate index file for dependency \"%2\"").arg(
+ config.getString(CONFIG_PROJECT), dependModules[i]));
}
}
}
else {
- qDebug() << "Dependent modules specified, but no index directories were set."
- << "There will probably be errors for missing links.";
+ Location::null.warning(QLatin1String("Dependent modules specified, but no index directories were set. There will probably be errors for missing links."));
}
}
qdb->readIndexes(indexFiles);
diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp
index 87a055ae0f..b65c531149 100644
--- a/src/tools/qdoc/node.cpp
+++ b/src/tools/qdoc/node.cpp
@@ -46,6 +46,7 @@
#include <quuid.h>
#include "qdocdatabase.h"
#include <qdebug.h>
+#include "generator.h"
QT_BEGIN_NAMESPACE
@@ -143,8 +144,7 @@ QString Node::plainFullName(const Node* relative) const
const Node* node = this;
while (node) {
fullName.prepend(node->plainName());
- if (node->parent() == relative || node->parent()->subType() == Node::Collision ||
- node->parent()->name().isEmpty())
+ if (node->parent() == relative || node->parent()->name().isEmpty())
break;
fullName.prepend(QLatin1String("::"));
node = node->parent();
@@ -153,18 +153,12 @@ QString Node::plainFullName(const Node* relative) const
}
/*!
- Constructs and returns this node's full name. The \a relative
- node is either null or is a collision node.
+ Constructs and returns this node's full name.
*/
QString Node::fullName(const Node* relative) const
{
- if (isDocNode() || isCollectionNode()) {
- const DocNode* dn = static_cast<const DocNode*>(this);
- // Only print modulename::type on collision pages.
- if (!dn->qmlModuleName().isEmpty() && relative != 0 && relative->isCollisionNode())
- return dn->qmlModuleName() + "::" + dn->title();
- return dn->title();
- }
+ if (isDocNode())
+ return title();
else if (isClass()) {
const ClassNode* cn = static_cast<const ClassNode*>(this);
if (!cn->serviceName().isEmpty())
@@ -414,8 +408,6 @@ QString Node::nodeSubtypeString(unsigned t)
return "external page";
case DitaMap:
return "ditamap";
- case Collision:
- return "collision";
case NoSubType:
default:
break;
@@ -436,8 +428,8 @@ void Node::setPageType(const QString& t)
pageType_ = OverviewPage;
else if (t == "tutorial")
pageType_ = TutorialPage;
- else if (t == "howto")
- pageType_ = HowToPage;
+ else if (t == "faq")
+ pageType_ = FAQPage;
else if (t == "article")
pageType_ = ArticlePage;
else if (t == "example")
@@ -717,22 +709,38 @@ InnerNode::~InnerNode()
}
/*!
- Find the node in this node's children that has the
- given \a name. If this node is a QML class node, be
- sure to also look in the children of its property
- group nodes. Return the matching node or 0.
+ If \a genus is \c{Node::DontCare}, find the first node in
+ this node's child list that has the given \a name. If this
+ node is a QML type, be sure to also look in the children
+ of its property group nodes. Return the matching node or 0.
+
+ If \a genus is either \c{Node::CPP} or \c {Node::QML}, then
+ find all this node's children that have the given \a name,
+ and return the one that satisfies the \a genus requirement.
*/
-Node *InnerNode::findChildNode(const QString& name) const
+Node *InnerNode::findChildNode(const QString& name, Node::Genus genus) const
{
- Node *node = childMap.value(name);
- if (node && !node->isQmlPropertyGroup())
- return node;
- if (isQmlType()) {
- for (int i=0; i<children_.size(); ++i) {
- Node* n = children_.at(i);
- if (n->isQmlPropertyGroup()) {
- node = static_cast<InnerNode*>(n)->findChildNode(name);
- if (node)
+ if (genus == Node::DontCare) {
+ Node *node = childMap.value(name);
+ if (node && !node->isQmlPropertyGroup()) // mws asks: Why not property group?
+ return node;
+ if (isQmlType()) {
+ for (int i=0; i<children_.size(); ++i) {
+ Node* n = children_.at(i);
+ if (n->isQmlPropertyGroup()) {
+ node = static_cast<InnerNode*>(n)->findChildNode(name, genus);
+ if (node)
+ return node;
+ }
+ }
+ }
+ }
+ else {
+ NodeList nodes = childMap.values(name);
+ if (!nodes.isEmpty()) {
+ for (int i=0; i<nodes.size(); ++i) {
+ Node* node = nodes.at(i);
+ if (genus == node->genus() || genus == Node::DontCare)
return node;
}
}
@@ -741,6 +749,39 @@ Node *InnerNode::findChildNode(const QString& name) const
}
/*!
+ Find all the child nodes of this node that are named
+ \a name and return them in \a nodes.
+ */
+void InnerNode::findChildren(const QString& name, NodeList& nodes) const
+{
+ nodes = childMap.values(name);
+ Node* n = primaryFunctionMap.value(name);
+ if (n) {
+ nodes.append(n);
+ NodeList t = secondaryFunctionMap.value(name);
+ if (!t.isEmpty())
+ nodes.append(t);
+ }
+ if (!nodes.isEmpty() || !isQmlNode())
+ return;
+ int i = name.indexOf(QChar('.'));
+ if (i < 0)
+ return;
+ QString qmlPropGroup = name.left(i);
+ NodeList t = childMap.values(qmlPropGroup);
+ if (t.isEmpty())
+ return;
+ foreach (Node* n, t) {
+ if (n->isQmlPropertyGroup()) {
+ n->findChildren(name, nodes);
+ if (!nodes.isEmpty())
+ break;
+ }
+ }
+}
+
+#if 0
+/*!
Find the node in this node's children that has the given \a name. If
this node is a QML class node, be sure to also look in the children
of its property group nodes. Return the matching node or 0. This is
@@ -752,7 +793,7 @@ Node *InnerNode::findChildNode(const QString& name) const
*/
Node* InnerNode::findChildNode(const QString& name, bool qml) const
{
- QList<Node*> nodes = childMap.values(name);
+ NodeList nodes = childMap.values(name);
if (!nodes.isEmpty()) {
for (int i=0; i<nodes.size(); ++i) {
Node* node = nodes.at(i);
@@ -776,24 +817,19 @@ Node* InnerNode::findChildNode(const QString& name, bool qml) const
}
return primaryFunctionMap.value(name);
}
+#endif
/*!
This function is like findChildNode(), but if a node
with the specified \a name is found but it is not of the
specified \a type, 0 is returned.
-
- This function is not recursive and therefore can't handle
- collisions. If it finds a collision node named \a name, it
- will return that node. But it might not find the collision
- node because it looks up \a name in the child map, not the
- list.
*/
Node* InnerNode::findChildNode(const QString& name, Type type)
{
if (type == Function)
return primaryFunctionMap.value(name);
else {
- QList<Node*> nodes = childMap.values(name);
+ NodeList nodes = childMap.values(name);
for (int i=0; i<nodes.size(); ++i) {
Node* node = nodes.at(i);
if (node->type() == type)
@@ -803,13 +839,14 @@ Node* InnerNode::findChildNode(const QString& name, Type type)
return 0;
}
+#if 0
/*!
*/
-void InnerNode::findNodes(const QString& name, QList<Node*>& n)
+void InnerNode::findNodes(const QString& name, NodeList& n)
{
n.clear();
Node* node = 0;
- QList<Node*> nodes = childMap.values(name);
+ NodeList nodes = childMap.values(name);
/*
<sigh> If this node's child map contains no nodes named
name, then if this node is a QML class, search each of its
@@ -857,6 +894,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
if (node)
n.append(node);
}
+#endif
/*!
Find a function node that is a child of this nose, such
@@ -954,18 +992,13 @@ void InnerNode::setOverload(const FunctionNode *func, bool overlode)
Mark all child nodes that have no documentation as having
private access and internal status. qdoc will then ignore
them for documentation purposes.
-
- \note Exception: Name collision nodes are not marked
- private/internal.
*/
void InnerNode::makeUndocumentedChildrenInternal()
{
foreach (Node *child, childNodes()) {
if (child->doc().isEmpty()) {
- if (child->subType() != Node::Collision) {
- child->setAccess(Node::Private);
- child->setStatus(Node::Internal);
- }
+ child->setAccess(Node::Private);
+ child->setStatus(Node::Internal);
}
}
}
@@ -1636,9 +1669,6 @@ DocNode::DocNode(InnerNode* parent, const QString& name, SubType subtype, Node::
case Example:
setPageType(ExamplePage);
break;
- case Collision:
- setPageType(ptype);
- break;
default:
break;
}
@@ -1682,9 +1712,6 @@ QString DocNode::fullTitle() const
else
return name() + " - " + title();
}
- else if (nodeSubtype_ == Collision) {
- return title();
- }
else {
return title();
}
@@ -2412,137 +2439,6 @@ QString QmlPropertyNode::element() const
return parent()->name();
}
-/*! \class NameCollisionNode
-
- An instance of this node is inserted in the tree
- whenever qdoc discovers that two nodes have the
- same name.
- */
-
-/*!
- Constructs a name collision node containing \a child
- as its first child. The parent of \a child becomes
- this node's parent.
- */
-NameCollisionNode::NameCollisionNode(InnerNode* child)
- : DocNode(child->parent(), child->name(), Collision, Node::NoPageType)
-{
- setTitle("Name Collision: " + child->name());
- addCollision(child);
-}
-
-/*!
- Add a collision to this collision node. \a child has
- the same name as the other children in this collision
- node. \a child becomes the current child.
- */
-void NameCollisionNode::addCollision(InnerNode* child)
-{
- if (child) {
- if (child->parent())
- child->parent()->removeChild(child);
- child->setParent((InnerNode*)this);
- children_.append(child);
- }
-}
-
-/*!
- The destructor does nothing.
- */
-NameCollisionNode::~NameCollisionNode()
-{
- // nothing.
-}
-
-/*!
- Returns \c true if this collision node's current node is a QML node.
- */
-bool NameCollisionNode::isQmlNode() const
-{
- return false;
-}
-
-/*!
- Find any of this collision node's children that has type \a t
- and subtype \a st and return a pointer to it.
-*/
-InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st)
-{
- const NodeList& cn = childNodes();
- NodeList::ConstIterator i = cn.constBegin();
- while (i != cn.constEnd()) {
- if ((*i)->type() == t && (*i)->subType() == st)
- return static_cast<InnerNode*>(*i);
- ++i;
- }
- return 0;
-}
-
-/*!
- This node is a name collision node. Find a child of this node
- such that the child's QML module name matches origin's QML module
- Name. Return the matching node, or return this node if there is
- no matching node.
- */
-const Node* NameCollisionNode::applyModuleName(const Node* origin) const
-{
- if (origin && !origin->qmlModuleName().isEmpty()) {
- const NodeList& cn = childNodes();
- NodeList::ConstIterator i = cn.constBegin();
- while (i != cn.constEnd()) {
- if ((*i)->isQmlType()) {
- if (origin->qmlModuleName() == (*i)->qmlModuleName())
- return (*i);
- }
- ++i;
- }
- }
- return this;
-}
-
-/*!
- First, find all the colliding nodes that have the correct
- type \a t and subtype \a st. If there is only one node
- having the correct type and subtype, return that one.
- If there is more than one node having the correct type
- and subtype, then, in that subset, if there is only one
- non-index node, return that one. If there are multiple
- non-index nodes, return this collision node because we
- can't disambiguate. Otherwise, if there are multiple
- nodes having the correct type and subtype, return this
- collision node because, again, we can't disambiguate.
- But if there are no nodes at all that have the correct
- type and subtype, return 0.
- */
-Node* NameCollisionNode::disambiguate(Type t, SubType st)
-{
- NodeList nl;
- const NodeList& cn = childNodes();
- NodeList::ConstIterator i = cn.constBegin();
- while (i != cn.constEnd()) {
- if ((*i)->type() == t) {
- if ((st == NoSubType) || ((*i)->subType() == st))
- nl.append((*i));
- }
- ++i;
- }
- Node* n = 0;
- if (!nl.isEmpty()) {
- i = nl.constBegin();
- if (nl.size() == 1)
- return (*i);
- while (i != nl.constEnd()) {
- if (!(*i)->isIndexNode()) {
- if (n)
- return this;
- n = (*i);
- }
- ++i;
- }
- }
- return n;
-}
-
/*!
Construct the full document name for this node and return it.
*/
@@ -2796,10 +2692,6 @@ QString Node::idForNode() const
str = name();
str.replace(QLatin1Char('/'), QLatin1Char('-'));
break;
- case Node::Collision:
- str = title();
- str.replace(": ","-");
- break;
default:
qDebug() << "ERROR: A case was not handled in Node::idForNode():"
<< "subType():" << subType() << "type():" << type();
diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h
index 37fbe482b0..1b2fb77749 100644
--- a/src/tools/qdoc/node.h
+++ b/src/tools/qdoc/node.h
@@ -66,7 +66,6 @@ class PropertyNode;
class QmlModuleNode;
class CollectionNode;
class QmlPropertyNode;
-class NameCollisionNode;
typedef QList<Node*> NodeList;
typedef QMap<QString, Node*> NodeMap;
@@ -113,10 +112,11 @@ public:
Page,
ExternalPage,
DitaMap,
- Collision,
LastSubtype
};
+ enum Genus { DontCare, CPP, QML };
+
enum Access { Public, Protected, Private };
enum Status {
@@ -217,10 +217,10 @@ public:
virtual bool isNamespace() const { return false; }
virtual bool isClass() const { return false; }
virtual bool isQmlNode() const { return false; }
+ virtual bool isCppNode() const { return false; }
virtual bool isQtQuickNode() const { return false; }
virtual bool isAbstract() const { return false; }
virtual bool isQmlPropertyGroup() const { return false; }
- virtual bool isCollisionNode() const { return false; }
virtual bool isAttached() const { return false; }
virtual bool isAlias() const { return false; }
virtual bool isWrapper() const;
@@ -233,6 +233,7 @@ public:
virtual bool hasClasses() const { return false; }
virtual void setAbstract(bool ) { }
virtual void setWrapper() { }
+ virtual Node::Genus genus() const { return DontCare; }
virtual QString title() const { return name(); }
virtual QString fullTitle() const { return name(); }
virtual QString subTitle() const { return QString(); }
@@ -250,6 +251,7 @@ public:
virtual void appendGroupName(const QString& ) { }
virtual QString element() const { return QString(); }
virtual Tree* tree() const;
+ virtual void findChildren(const QString& , NodeList& nodes) const { nodes.clear(); }
bool isIndexNode() const { return indexNodeFlag_; }
Type type() const { return nodeType_; }
virtual SubType subType() const { return NoSubType; }
@@ -271,6 +273,7 @@ public:
void setLink(LinkType linkType, const QString &link, const QString &desc);
Access access() const { return access_; }
+ bool isPrivate() const { return access_ == Private; }
QString accessString() const;
const Location& location() const { return loc_; }
const Doc& doc() const { return doc_; }
@@ -360,10 +363,11 @@ class InnerNode : public Node
public:
virtual ~InnerNode();
- Node* findChildNode(const QString& name) const;
- Node* findChildNode(const QString& name, bool qml) const;
+ Node* findChildNode(const QString& name, Node::Genus genus) const;
+ //Node* findChildNode(const QString& name, bool qml) const;
Node* findChildNode(const QString& name, Type type);
- void findNodes(const QString& name, QList<Node*>& n);
+ //void findNodes(const QString& name, NodeList& n);
+ virtual void findChildren(const QString& name, NodeList& nodes) const;
FunctionNode* findFunctionNode(const QString& name) const;
FunctionNode* findFunctionNode(const FunctionNode* clone);
void addInclude(const QString &include);
@@ -403,7 +407,6 @@ protected:
private:
friend class Node;
- friend class NameCollisionNode;
static bool isSameSignature(const FunctionNode* f1, const FunctionNode* f2);
void addChild(Node* child);
@@ -443,6 +446,8 @@ public:
virtual ~NamespaceNode() { }
virtual bool isNamespace() const { return true; }
virtual Tree* tree() const { return (parent() ? parent()->tree() : tree_); }
+ virtual bool isCppNode() const { return true; }
+ virtual Node::Genus genus() const { return Node::CPP; }
void setTree(Tree* t) { tree_ = t; }
private:
@@ -473,7 +478,9 @@ public:
ClassNode(InnerNode* parent, const QString& name);
virtual ~ClassNode() { }
virtual bool isClass() const { return true; }
+ virtual bool isCppNode() const { return true; }
virtual bool isWrapper() const { return wrapper_; }
+ virtual Node::Genus genus() const { return Node::CPP; }
virtual QString obsoleteLink() const { return obsoleteLink_; }
virtual void setObsoleteLink(const QString& t) { obsoleteLink_ = t; }
virtual void setWrapper() { wrapper_ = true; }
@@ -544,24 +551,6 @@ protected:
QString subtitle_;
};
-class NameCollisionNode : public DocNode
-{
-public:
- NameCollisionNode(InnerNode* child);
- ~NameCollisionNode();
- virtual bool isQmlNode() const;
- virtual bool isCollisionNode() const { return true; }
- virtual const Node* applyModuleName(const Node* origin) const;
- virtual Node* disambiguate(Type t, SubType st);
- InnerNode* findAny(Node::Type t, Node::SubType st);
- void addCollision(InnerNode* child);
- const QMap<QString,QString>& linkTargets() const { return targets; }
- void addLinkTarget(const QString& t, const QString& v) { targets.insert(t,v); }
-
-private:
- QMap<QString,QString> targets;
-};
-
class ExampleNode : public DocNode
{
public:
@@ -618,6 +607,7 @@ public:
virtual QString qmlModuleIdentifier() const;
virtual QmlModuleNode* qmlModule() const { return qmlModule_; }
virtual void setQmlModule(QmlModuleNode* t) { qmlModule_ = t; }
+ virtual Node::Genus genus() const { return Node::QML; }
const ImportList& importList() const { return importList_; }
void setImportList(const ImportList& il) { importList_ = il; }
const QString& qmlBaseName() const { return qmlBaseName_; }
@@ -655,6 +645,7 @@ public:
virtual ~QmlBasicTypeNode() { }
virtual bool isQmlNode() const { return true; }
virtual bool isQmlBasicType() const { return true; }
+ virtual Node::Genus genus() const { return Node::QML; }
};
class QmlPropertyGroupNode : public InnerNode
@@ -670,6 +661,7 @@ public:
virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); }
virtual QString idNumber();
virtual bool isQmlPropertyGroup() const { return true; }
+ virtual Node::Genus genus() const { return Node::QML; }
virtual QString element() const { return parent()->name(); }
@@ -688,6 +680,7 @@ public:
bool attached);
virtual ~QmlPropertyNode() { }
+ virtual Node::Genus genus() const { return Node::QML; }
virtual void setDataType(const QString& dataType) { type_ = dataType; }
void setStored(bool stored) { stored_ = toFlagValue(stored); }
void setDesignable(bool designable) { designable_ = toFlagValue(designable); }
@@ -746,6 +739,8 @@ public:
EnumNode(InnerNode* parent, const QString& name);
virtual ~EnumNode() { }
+ virtual Node::Genus genus() const { return Node::CPP; }
+ virtual bool isCppNode() const { return true; }
void addItem(const EnumItem& item);
void setFlagsType(TypedefNode* typedeff);
bool hasItem(const QString &name) const { return names.contains(name); }
@@ -767,6 +762,8 @@ public:
TypedefNode(InnerNode* parent, const QString& name);
virtual ~TypedefNode() { }
+ virtual Node::Genus genus() const { return Node::CPP; }
+ virtual bool isCppNode() const { return true; }
const EnumNode* associatedEnum() const { return ae; }
private:
@@ -873,6 +870,8 @@ public:
(type() == QmlMethod) ||
(type() == QmlSignalHandler));
}
+ virtual bool isCppNode() const { return !isQmlNode(); }
+ virtual Node::Genus genus() const { return (isQmlNode() ? Node::QML : Node::CPP); }
virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); }
virtual QString qmlTypeName() const { return parent()->qmlTypeName(); }
virtual QString qmlModuleName() const { return parent()->qmlModuleName(); }
@@ -911,6 +910,8 @@ public:
PropertyNode(InnerNode* parent, const QString& name);
virtual ~PropertyNode() { }
+ virtual Node::Genus genus() const { return Node::CPP; }
+ virtual bool isCppNode() const { return true; }
virtual void setDataType(const QString& dataType) { type_ = dataType; }
void addFunction(FunctionNode* function, FunctionRole role);
void addSignal(FunctionNode* function, FunctionRole role);
@@ -998,6 +999,8 @@ public:
VariableNode(InnerNode* parent, const QString &name);
virtual ~VariableNode() { }
+ virtual Node::Genus genus() const { return Node::CPP; }
+ virtual bool isCppNode() const { return true; }
void setLeftType(const QString &leftType) { lt = leftType; }
void setRightType(const QString &rightType) { rt = rightType; }
void setStatic(bool statique) { sta = statique; }
@@ -1084,6 +1087,7 @@ class ModuleNode : public CollectionNode
virtual ~ModuleNode() { }
virtual bool isModule() const { return true; }
+ virtual bool isCppNode() const { return true; }
virtual void setQtVariable(const QString& v) { qtVariable_ = v; }
virtual QString qtVariable() const { return qtVariable_; }
@@ -1098,6 +1102,7 @@ class QmlModuleNode : public CollectionNode
: CollectionNode(Node::QmlModule, parent, name) { }
virtual ~QmlModuleNode() { }
+ virtual bool isQmlNode() const { return true; }
virtual bool isQmlModule() const { return true; }
virtual QString qmlModuleName() const { return qmlModuleName_; }
virtual QString qmlModuleVersion() const {
diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp
index d43fdf4970..d06cb659c4 100644
--- a/src/tools/qdoc/qdocdatabase.cpp
+++ b/src/tools/qdoc/qdocdatabase.cpp
@@ -379,20 +379,34 @@ void QDocForest::newPrimaryTree(const QString& module)
}
/*!
- Searches the trees for a node named \a target and returns
- a pointer to it if found. The \a relative node is the starting
- point, but it only makes sense in the primary tree, which is
- searched first. After the primary tree is searched, \a relative
- is set to 0 for searching the index trees. When relative is 0,
- the root nodes of the index trees are the starting points.
- */
-const Node* QDocForest::resolveTarget(const QString& target, const Node* relative)
+ Searches through the forest for a node named \a targetPath
+ and returns a pointer to it if found. The \a relative node
+ is the starting point. It only makes sense for the primary
+ tree, which is searched first. After the primary tree has
+ been searched, \a relative is set to 0 for searching the
+ other trees, which are all index trees. With relative set
+ to 0, the starting point for each index tree is the root
+ of the index tree.
+ */
+const Node* QDocForest::findNodeForTarget(QStringList& targetPath,
+ const Node* relative,
+ Node::Genus genus,
+ QString& ref)
{
- QStringList path = target.split("::");
- int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
+ int flags = SearchBaseClasses | SearchEnumValues;
+
+ QString entity = targetPath.at(0);
+ targetPath.removeFirst();
+ QStringList entityPath = entity.split("::");
+
+ QString target;
+ if (!targetPath.isEmpty()) {
+ target = targetPath.at(0);
+ targetPath.removeFirst();
+ }
foreach (Tree* t, searchOrder()) {
- const Node* n = t->findNode(path, relative, flags);
+ const Node* n = t->findNodeForTarget(entityPath, target, relative, flags, genus, ref);
if (n)
return n;
relative = 0;
@@ -401,20 +415,6 @@ const Node* QDocForest::resolveTarget(const QString& target, const Node* relativ
}
/*!
- Searches the Tree \a t for a type node named by the \a path
- and returns a pointer to it if found. The \a relative node
- is the starting point, but it only makes sense when searching
- the primary tree. Therefore, when this function is called with
- \a t being an index tree, \a relative is 0. When relative is 0,
- the root node of \a t is the starting point.
- */
-const Node* QDocForest::resolveTypeHelper(const QStringList& path, const Node* relative, Tree* t)
-{
- int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
- return t->findNode(path, relative, flags);
-}
-
-/*!
This function merges all the collection maps for collection
nodes of node type \a t into the collection multimap \a cnmm,
which is cleared before starting.
@@ -785,15 +785,8 @@ QmlClassNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name
QStringList path(name);
Node* n = forest_.findNodeByNameAndType(path, Node::QmlType);
- if (n) {
- if (n->isQmlType())
- return static_cast<QmlClassNode*>(n);
- else if (n->isCollisionNode()) {
- NameCollisionNode* ncn;
- ncn = static_cast<NameCollisionNode*>(n);
- return static_cast<QmlClassNode*>(ncn->findAny(Node::QmlType, Node::NoSubType));
- }
- }
+ if (n && n->isQmlType())
+ return static_cast<QmlClassNode*>(n);
return 0;
}
@@ -1343,7 +1336,7 @@ void QDocDatabase::resolveIssues() {
When searching the index trees, the search begins at the
root.
*/
-const Node* QDocDatabase::resolveType(const QString& type, const Node* relative)
+const Node* QDocDatabase::findTypeNode(const QString& type, const Node* relative)
{
QStringList path = type.split("::");
if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString("T"))) {
@@ -1351,7 +1344,7 @@ const Node* QDocDatabase::resolveType(const QString& type, const Node* relative)
if (i != typeNodeMap_.end())
return i.value();
}
- return forest_.resolveType(path, relative);
+ return forest_.findTypeNode(path, relative);
}
/*!
@@ -1365,13 +1358,18 @@ const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* r
const Node* node = 0;
if (target.isEmpty())
node = relative;
- else if (target.endsWith(".html")) {
+ else if (target.endsWith(".html"))
node = findNodeByNameAndType(QStringList(target), Node::Document);
- }
else {
- node = resolveTarget(target, relative);
- if (!node)
- node = findDocNodeByTitle(target);
+ QStringList path = target.split("::");
+ int flags = SearchBaseClasses | SearchEnumValues; // | NonFunction;
+ foreach (Tree* t, searchOrder()) {
+ const Node* n = t->findNode(path, relative, flags, Node::DontCare);
+ if (n)
+ return n;
+ relative = 0;
+ }
+ node = findDocNodeByTitle(target);
}
return node;
}
@@ -1578,27 +1576,6 @@ void QDocDatabase::mergeCollections(CollectionNode* cn)
}
}
-
-/*!
- This function is called when the \a{atom} might be a link
- atom. It handles the optional, square bracket parameters
- for the link command.
- */
-Node* QDocDatabase::findNode(const Atom* atom)
-{
- QStringList path(atom->string());
- if (atom->specifiesDomain()) {
- return atom->domain()->findNodeByNameAndType(path, atom->goal());
- }
- qDebug() << "FINDNODE:" << path << atom->goal();
- return forest_.findNodeByNameAndType(path, atom->goal());
-}
-
-const DocNode* QDocDatabase::findDocNodeByTitle(const Atom* atom)
-{
- return forest_.findDocNodeByTitle(atom->string());
-}
-
/*!
Searches for the node that matches the path in \a atom. The
\a relative node is used if the first leg of the path is
@@ -1608,51 +1585,68 @@ const DocNode* QDocDatabase::findDocNodeByTitle(const Atom* atom)
\a ref. If the returned node pointer is null, \a ref is not
valid.
*/
-const Node* QDocDatabase::findNode(const Atom* atom, const Node* relative, QString& ref)
+const Node* QDocDatabase::findNodeForAtom(const Atom* atom, const Node* relative, QString& ref)
{
const Node* node = 0;
- QStringList path = atom->string().split("#");
- QString first = path.first().trimmed();
- path.removeFirst();
+
+ QStringList targetPath = atom->string().split("#");
+ QString first = targetPath.first().trimmed();
+
+ Tree* domain = 0;
+ Node::Genus genus = Node::DontCare;
+ // Reserved for future use
+ //Node::Type goal = Node::NoType;
+
+ if (atom->isLinkAtom()) {
+ domain = atom->domain();
+ genus = atom->genus();
+ // Reserved for future use
+ //goal = atom->goal();
+ }
if (first.isEmpty())
node = relative; // search for a target on the current page.
- else if (atom->specifiesDomain()) {
- qDebug() << "Processing LinkAtom";
- if (first.endsWith(".html")) { // The target is an html file.
- node = atom->domain()->findNodeByNameAndType(QStringList(first), Node::Document);
- }
- else if (first.endsWith("()")) { // The target is a C++ function or QML method.
- node = atom->domain()->resolveFunctionTarget(first, 0); //relative);
- }
+ else if (domain) {
+ if (first.endsWith(".html"))
+ node = domain->findNodeByNameAndType(QStringList(first), Node::Document);
+ else if (first.endsWith("()"))
+ node = domain->findFunctionNode(first, 0, genus);
else {
- node = atom->domain()->resolveTarget(first, 0); // relative);
- if (!node)
- node = atom->domain()->findUnambiguousTarget(first, ref); // ref
- if (!node && path.isEmpty())
- node = atom->domain()->findDocNodeByTitle(first);
+ int flags = SearchBaseClasses | SearchEnumValues;
+ QStringList nodePath = first.split("::");
+ QString target;
+ targetPath.removeFirst();
+ if (!targetPath.isEmpty()) {
+ target = targetPath.at(0);
+ targetPath.removeFirst();
+ }
+ if (relative && relative->tree()->moduleName() != domain->moduleName())
+ relative = 0;
+ node = domain->findNodeForTarget(nodePath, target, relative, flags, genus, ref);
+ return node;
}
}
else {
- if (first.endsWith(".html")) { // The target is an html file.
- node = findNodeByNameAndType(QStringList(first), Node::Document); // ref
- }
- else if (first.endsWith("()")) { // The target is a C++ function or QML method.
- node = resolveFunctionTarget(first, relative);
+ if (first.endsWith(".html")) {
+ node = findNodeByNameAndType(QStringList(first), Node::Document);
+ // the path may also refer to an example file with .html extension
+ if (!node && first.contains("/"))
+ return findNodeForTarget(targetPath, relative, genus, ref);
}
+ else if (first.endsWith("()"))
+ node = findFunctionNode(first, relative, genus);
else {
- node = resolveTarget(first, relative); // ref
- if (!node)
- node = findUnambiguousTarget(first, ref); // ref
- if (!node && path.isEmpty())
- node = findDocNodeByTitle(first);
+ node = findNodeForTarget(targetPath, relative, genus, ref);
+ return node;
}
}
+
if (node && ref.isEmpty()) {
if (!node->url().isEmpty())
return node;
- if (!path.isEmpty()) {
- ref = findTarget(path.first(), node);
+ targetPath.removeFirst();
+ if (!targetPath.isEmpty()) {
+ ref = node->root()->tree()->getRef(targetPath.first(), node);
if (ref.isEmpty())
node = 0;
}
diff --git a/src/tools/qdoc/qdocdatabase.h b/src/tools/qdoc/qdocdatabase.h
index 99d1c46ca2..495db11511 100644
--- a/src/tools/qdoc/qdocdatabase.h
+++ b/src/tools/qdoc/qdocdatabase.h
@@ -88,9 +88,12 @@ class QDocForest
const QVector<Tree*>& indexSearchOrder();
void setSearchOrder();
- const Node* findNode(const QStringList& path, const Node* relative, int findFlags) {
+ const Node* findNode(const QStringList& path,
+ const Node* relative,
+ int findFlags,
+ Node::Genus genus) {
foreach (Tree* t, searchOrder()) {
- const Node* n = t->findNode(path, relative, findFlags);
+ const Node* n = t->findNode(path, relative, findFlags, genus);
if (n)
return n;
relative = 0;
@@ -116,43 +119,48 @@ class QDocForest
return 0;
}
- InnerNode* findRelatesNode(const QStringList& path) {
+ Node* findNodeForInclude(const QStringList& path) {
foreach (Tree* t, searchOrder()) {
- InnerNode* n = t->findRelatesNode(path);
+ Node* n = t->findNodeForInclude(path);
if (n)
return n;
}
return 0;
}
- const Node* resolveFunctionTarget(const QString& target, const Node* relative) {
+ InnerNode* findRelatesNode(const QStringList& path) {
foreach (Tree* t, searchOrder()) {
- const Node* n = t->resolveFunctionTarget(target, relative);
+ InnerNode* n = t->findRelatesNode(path);
if (n)
return n;
- relative = 0;
}
return 0;
}
- const Node* resolveTarget(const QString& target, const Node* relative);
- const Node* resolveType(const QStringList& path, const Node* relative)
- {
+ const Node* findFunctionNode(const QString& target,
+ const Node* relative,
+ Node::Genus genus) {
foreach (Tree* t, searchOrder()) {
- const Node* n = resolveTypeHelper(path, relative, t);
+ const Node* n = t->findFunctionNode(target, relative, genus);
if (n)
return n;
relative = 0;
}
return 0;
}
+ const Node* findNodeForTarget(QStringList& targetPath,
+ const Node* relative,
+ Node::Genus genus,
+ QString& ref);
- const Node* findUnambiguousTarget(const QString& target, QString& ref)
+ const Node* findTypeNode(const QStringList& path, const Node* relative)
{
foreach (Tree* t, searchOrder()) {
- const Node* n = t->findUnambiguousTarget(target, ref);
+ int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
+ const Node* n = t->findNode(path, relative, flags, Node::DontCare);
if (n)
return n;
+ relative = 0;
}
return 0;
}
@@ -189,7 +197,6 @@ class QDocForest
private:
void newPrimaryTree(const QString& module);
NamespaceNode* newIndexTree(const QString& module);
- const Node* resolveTypeHelper(const QStringList& path, const Node* relative, Tree* t);
private:
QDocDatabase* qdb_;
@@ -281,8 +288,12 @@ class QDocDatabase
void resolveTargets() {
primaryTree()->resolveTargets(primaryTreeRoot());
}
- void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority) {
- primaryTree()->insertTarget(name, type, node, priority);
+ void insertTarget(const QString& name,
+ const QString& title,
+ TargetRec::Type type,
+ Node* node,
+ int priority) {
+ primaryTree()->insertTarget(name, title, type, node, priority);
}
/*******************************************************************
@@ -293,10 +304,7 @@ class QDocDatabase
}
FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone);
Node* findNodeInOpenNamespace(QStringList& path, Node::Type type);
- NameCollisionNode* findCollisionNode(const QString& name) {
- return primaryTree()->findCollisionNode(name);
- }
- NameCollisionNode* checkForCollision(const QString& name) {
+ const Node* checkForCollision(const QString& name) {
return primaryTree()->checkForCollision(name);
}
/*******************************************************************/
@@ -304,38 +312,37 @@ class QDocDatabase
/*******************************************************************
The functions declared below handle the parameters in '[' ']'.
********************************************************************/
- Node* findNode(const Atom* atom);
- const Node* findNode(const Atom* atom, const Node* relative, QString& ref);
- const DocNode* findDocNodeByTitle(const Atom* atom);
+ const Node* findNodeForAtom(const Atom* atom, const Node* relative, QString& ref);
/*******************************************************************/
/*******************************************************************
The functions declared below are called for all trees.
********************************************************************/
ClassNode* findClassNode(const QStringList& path) { return forest_.findClassNode(path); }
+ Node* findNodeForInclude(const QStringList& path) { return forest_.findNodeForInclude(path); }
InnerNode* findRelatesNode(const QStringList& path) { return forest_.findRelatesNode(path); }
- const Node* resolveTarget(const QString& target, const Node* relative) {
- return forest_.resolveTarget(target, relative);
+ const Node* findFunctionNode(const QString& target, const Node* relative, Node::Genus genus) {
+ return forest_.findFunctionNode(target, relative, genus);
}
- const Node* resolveFunctionTarget(const QString& target, const Node* relative) {
- return forest_.resolveFunctionTarget(target, relative);
- }
- const Node* resolveType(const QString& type, const Node* relative);
+ const Node* findTypeNode(const QString& type, const Node* relative);
const Node* findNodeForTarget(const QString& target, const Node* relative);
const DocNode* findDocNodeByTitle(const QString& title) {
return forest_.findDocNodeByTitle(title);
}
- const Node* findUnambiguousTarget(const QString& target, QString& ref) {
- return forest_.findUnambiguousTarget(target, ref);
- }
Node* findNodeByNameAndType(const QStringList& path, Node::Type type) {
return forest_.findNodeByNameAndType(path, type);
}
- /*******************************************************************/
- QString findTarget(const QString& target, const Node* node) {
- return node->root()->tree()->findTarget(target, node);
+ private:
+ const Node* findNodeForTarget(QStringList& targetPath,
+ const Node* relative,
+ Node::Genus genus,
+ QString& ref) {
+ return forest_.findNodeForTarget(targetPath, relative, genus, ref);
}
+
+ /*******************************************************************/
+ public:
void addPropertyFunction(PropertyNode* property,
const QString& funcName,
PropertyNode::FunctionRole funcRole) {
@@ -371,8 +378,11 @@ class QDocDatabase
friend class QDocIndexFiles;
friend class QDocTagFiles;
- const Node* findNode(const QStringList& path, const Node* relative, int findFlags) {
- return forest_.findNode(path, relative, findFlags);
+ const Node* findNode(const QStringList& path,
+ const Node* relative,
+ int findFlags,
+ Node::Genus genus) {
+ return forest_.findNode(path, relative, findFlags, genus);
}
void processForest(void (QDocDatabase::*) (InnerNode*));
static void initializeDB();
diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp
index 4531ce8eea..33f848b306 100644
--- a/src/tools/qdoc/qdocindexfiles.cpp
+++ b/src/tools/qdoc/qdocindexfiles.cpp
@@ -471,15 +471,18 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
location = Location(parent->name().toLower() + ".html");
}
else if (element.nodeName() == "keyword") {
- qdb_->insertTarget(name, TargetRec::Keyword, current, 1);
+ QString title = element.attribute("title");
+ qdb_->insertTarget(name, title, TargetRec::Keyword, current, 1);
return;
}
else if (element.nodeName() == "target") {
- qdb_->insertTarget(name, TargetRec::Target, current, 2);
+ QString title = element.attribute("title");
+ qdb_->insertTarget(name, title, TargetRec::Target, current, 2);
return;
}
else if (element.nodeName() == "contents") {
- qdb_->insertTarget(name, TargetRec::Contents, current, 3);
+ QString title = element.attribute("title");
+ qdb_->insertTarget(name, title, TargetRec::Contents, current, 3);
return;
}
else
@@ -1202,18 +1205,26 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
external = true;
}
foreach (const Atom* target, node->doc().targets()) {
- QString targetName = target->string();
- if (!external)
- targetName = Doc::canonicalTitle(targetName);
+ QString title = target->string();
+ QString name = Doc::canonicalTitle(title);
writer.writeStartElement("target");
- writer.writeAttribute("name", targetName);
+ if (!external)
+ writer.writeAttribute("name", name);
+ else
+ writer.writeAttribute("name", title);
+ if (name != title)
+ writer.writeAttribute("title", title);
writer.writeEndElement(); // target
}
}
if (node->doc().hasKeywords()) {
foreach (const Atom* keyword, node->doc().keywords()) {
+ QString title = keyword->string();
+ QString name = Doc::canonicalTitle(title);
writer.writeStartElement("keyword");
- writer.writeAttribute("name", Doc::canonicalTitle(keyword->string()));
+ writer.writeAttribute("name", name);
+ if (name != title)
+ writer.writeAttribute("title", title);
writer.writeEndElement(); // keyword
}
}
@@ -1326,20 +1337,7 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
std::sort(cnodes.begin(), cnodes.end(), compareNodes);
foreach (Node* child, cnodes) {
- /*
- Don't generate anything for a collision node. We want
- children of collision nodes in the index, but leaving
- out the parent collision page will make searching for
- nodes easier.
- */
- if (child->subType() == Node::Collision) {
- const InnerNode* pgn = static_cast<const InnerNode*>(child);
- foreach (Node* c, pgn->childNodes()) {
- generateIndexSections(writer, c, generateInternalNodes);
- }
- }
- else
- generateIndexSections(writer, child, generateInternalNodes);
+ generateIndexSections(writer, child, generateInternalNodes);
}
}
diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp
index fbe4940c19..3f4384dfd6 100644
--- a/src/tools/qdoc/qmlvisitor.cpp
+++ b/src/tools/qdoc/qmlvisitor.cpp
@@ -249,7 +249,7 @@ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Nod
nodes.append(node);
if (topicsUsed.size() > 0) {
for (int i=0; i<topicsUsed.size(); ++i) {
- if (topicsUsed.at(i).topic == QString("qmlpropertygroup")) {
+ if (topicsUsed.at(i).topic == COMMAND_QMLPROPERTYGROUP) {
qDebug() << "PROPERTY GROUP COMMAND SEEN:" << topicsUsed.at(i).args << filePath_;
break;
}
@@ -407,8 +407,7 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
node->setStatus(Node::Internal);
}
else if (command == COMMAND_OBSOLETE) {
- if (node->status() != Node::Compat)
- node->setStatus(Node::Obsolete);
+ node->setStatus(Node::Obsolete);
}
else if (command == COMMAND_PAGEKEYWORDS) {
// Not done yet. Do we need this?
diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp
index e689227bf1..6bd6a649fd 100644
--- a/src/tools/qdoc/tree.cpp
+++ b/src/tools/qdoc/tree.cpp
@@ -86,21 +86,48 @@ Tree::Tree(const QString& module, QDocDatabase* qdb)
destructor of each child node is called, and these
destructors are recursive. Thus the entire tree is
destroyed.
+
+ There are two maps of targets, keywords, and contents.
+ One map is indexed by ref, the other by title. The ref
+ is just the canonical form of the title. Both maps
+ use the same set of TargetRec objects as the values,
+ so the destructor only deletes the values from one of
+ the maps. Then it clears both maps.
*/
Tree::~Tree()
{
- // nothing
+ TargetMap::iterator i = nodesByTargetRef_.begin();
+ while (i != nodesByTargetRef_.end()) {
+ delete i.value();
+ ++i;
+ }
+ nodesByTargetRef_.clear();
+ nodesByTargetTitle_.clear();
}
/* API members */
/*!
+ Calls findClassNode() first with \a path and \a start. If
+ it finds a node, the node is returned. If not, it calls
+ findNamespaceNode() with the same parameters. The result
+ is returned.
+ */
+Node* Tree::findNodeForInclude(const QStringList& path) const
+{
+ Node* n = findClassNode(path);
+ if (!n)
+ n = findNamespaceNode(path);
+ return n;
+}
+
+/*!
Find the C++ class node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
at the root of the tree. Only a C++ class node named \a path is
acceptible. If one is not found, 0 is returned.
*/
-ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const
+ClassNode* Tree::findClassNode(const QStringList& path, const Node* start) const
{
if (!start)
start = const_cast<NamespaceNode*>(root());
@@ -125,8 +152,9 @@ NamespaceNode* Tree::findNamespaceNode(const QStringList& path) const
matches the \a clone node. If it finds a node that is just
like the \a clone, it returns a pointer to the found node.
- There should be a way to avoid creating the clone in the
- first place. Investigate when time allows.
+ Apparently the search order is important here. Don't change
+ it unless you know what you are doing, or you will introduce
+ qdoc warnings.
*/
FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, const FunctionNode* clone)
{
@@ -134,7 +162,7 @@ FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, const Functi
if (parent == 0)
parent = findClassNode(parentPath, 0);
if (parent == 0)
- parent = findNode(parentPath);
+ parent = findNode(parentPath, 0, 0, Node::DontCare);
if (parent == 0 || !parent->isInnerNode())
return 0;
return ((InnerNode*)parent)->findFunctionNode(clone);
@@ -166,47 +194,6 @@ QmlClassNode* Tree::findQmlTypeNode(const QStringList& path)
}
/*!
- First, search for a node with the specified \a name. If a matching
- node is found, if it is a collision node, another collision with
- this name has been found, so return the collision node. If the
- matching node is not a collision node, the first collision for this
- name has been found, so create a NameCollisionNode with the matching
- node as its first child, and return a pointer to the new
- NameCollisionNode. Otherwise return 0.
- */
-NameCollisionNode* Tree::checkForCollision(const QString& name)
-{
- Node* n = const_cast<Node*>(findNode(QStringList(name)));
- if (n) {
- if (n->subType() == Node::Collision) {
- NameCollisionNode* ncn = static_cast<NameCollisionNode*>(n);
- return ncn;
- }
- if (n->isInnerNode())
- return new NameCollisionNode(static_cast<InnerNode*>(n));
- }
- return 0;
-}
-
-/*!
- This function is like checkForCollision() in that it searches
- for a collision node with the specified \a name. But it doesn't
- create anything. If it finds a match, it returns the pointer.
- Otherwise it returns 0.
- */
-NameCollisionNode* Tree::findCollisionNode(const QString& name) const
-{
- Node* n = const_cast<Node*>(findNode(QStringList(name)));
- if (n) {
- if (n->subType() == Node::Collision) {
- NameCollisionNode* ncn = static_cast<NameCollisionNode*>(n);
- return ncn;
- }
- }
- return 0;
-}
-
-/*!
This function begins searching the tree at \a relative for
the \l {FunctionNode} {function node} identified by \a path.
The \a findFlags are used to restrict the search. If a node
@@ -216,30 +203,28 @@ NameCollisionNode* Tree::findCollisionNode(const QString& name) const
*/
const FunctionNode* Tree::findFunctionNode(const QStringList& path,
const Node* relative,
- int findFlags) const
+ int findFlags,
+ Node::Genus genus) const
{
- if (!relative)
- relative = root();
-
- if (path.size() == 3 && !path[0].isEmpty()) {
+ if (path.size() == 3 && !path[0].isEmpty() && (genus != Node::CPP)) {
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (!qcn) {
QStringList p(path[1]);
Node* n = findNodeByNameAndType(p, Node::QmlType);
- if (n) {
- if (n->isQmlType())
- qcn = static_cast<QmlClassNode*>(n);
- else if (n->subType() == Node::Collision) {
- NameCollisionNode* ncn;
- ncn = static_cast<NameCollisionNode*>(n);
- qcn = static_cast<QmlClassNode*>(ncn->findAny(Node::QmlType, Node::NoSubType));
- }
- }
+ if (n && n->isQmlType())
+ qcn = static_cast<QmlClassNode*>(n);
}
if (qcn)
return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2]));
}
+ if (!relative)
+ relative = root();
+ else if (genus != Node::DontCare) {
+ if (genus != relative->genus())
+ relative = root();
+ }
+
do {
const Node* node = relative;
int i;
@@ -252,7 +237,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (i == path.size() - 1)
next = ((InnerNode*) node)->findFunctionNode(path.at(i));
else
- next = ((InnerNode*) node)->findChildNode(path.at(i));
+ next = ((InnerNode*) node)->findChildNode(path.at(i), genus);
if (!next && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
@@ -260,7 +245,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (i == path.size() - 1)
next = static_cast<const InnerNode*>(baseClass)->findFunctionNode(path.at(i));
else
- next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i));
+ next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i), genus);
if (next)
break;
@@ -670,44 +655,197 @@ Node* Tree::findNodeRecursive(const QStringList& path,
}
/*!
- Searches the tree for a node that matches the \a path. The
- search begins at \a start but can move up the parent chain
- recursively if no match is found.
+ Searches the tree for a node that matches the \a path plus
+ the \a target. The search begins at \a start and moves up
+ the parent chain from there, or, if \a start is 0, the search
+ begins at the root.
- This findNode() callse the other findNode(), which is not
- called anywhere else.
+ The \a flags can indicate whether to search base classes and/or
+ the enum values in enum types. \a genus can be a further restriction
+ on what kind of node is an acceptible match, i.e. CPP or QML.
+
+ If a matching node is found, \a ref is an output parameter that
+ is set to the HTML reference to use for the link.
*/
-const Node* Tree::findNode(const QStringList& path, const Node* start, int findFlags) const
+const Node* Tree::findNodeForTarget(const QStringList& path,
+ const QString& target,
+ const Node* start,
+ int flags,
+ Node::Genus genus,
+ QString& ref) const
{
+ const Node* node = 0;
+ QString p;
+ if (path.size() > 1)
+ p = path.join(QString("::"));
+ else {
+ p = path.at(0);
+ node = findDocNodeByTitle(p);
+ if (node) {
+ if (!target.isEmpty()) {
+ ref = getRef(target, node);
+ if (ref.isEmpty())
+ node = 0;
+ }
+ if (node)
+ return node;
+ }
+ }
+ node = findUnambiguousTarget(p, ref);
+ if (node) {
+ if (!target.isEmpty()) {
+ ref = getRef(target, node);
+ if (ref.isEmpty())
+ node = 0;
+ }
+ if (node)
+ return node;
+ }
+
const Node* current = start;
if (!current)
current = root();
/*
- First, search for a node assuming we don't want a QML node.
- If that search fails, search again assuming we do want a
- QML node.
+ If the path contains one or two double colons ("::"),
+ check first to see if the first two path strings refer
+ to a QML element. If they do, path[0] will be the QML
+ module identifier, and path[1] will be the QML type.
+ If the answer is yes, the reference identifies a QML
+ type node.
+ */
+ int path_idx = 0;
+ if ((genus != Node::CPP) && (path.size() >= 2) && !path[0].isEmpty()) {
+ QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
+ if (qcn) {
+ current = qcn;
+ if (path.size() == 2) {
+ if (!target.isEmpty()) {
+ ref = getRef(target, current);
+ if (!ref.isEmpty())
+ return current;
+ else if (genus == Node::QML)
+ return 0;
+ }
+ else
+ return current;
+ }
+ path_idx = 2;
+ }
+ }
+
+ while (current) {
+ if (current->isInnerNode()) {
+ const Node* node = matchPathAndTarget(path, path_idx, target, current, flags, genus, ref);
+ if (node)
+ return node;
+ }
+ current = current->parent();
+ path_idx = 0;
+ }
+ return 0;
+}
+
+/*!
+ First, the \a path is used to find a node. The \a path
+ matches some part of the node's fully quallified name.
+ If the \a target is not empty, it must match a target
+ in the matching node. If the matching of the \a path
+ and the \a target (if present) is successful, \a ref
+ is set from the \a target, and the pointer to the
+ matching node is returned. \a idx is the index into the
+ \a path where to begin the matching. The function is
+ recursive with idx being incremented for each recursive
+ call.
+
+ The matching node must be of the correct \a genus, i.e.
+ either QML or C++, but \a genus can be set to \c DontCare.
+ \a flags indicates whether to search base classes and
+ whether to search for an enum value. \a node points to
+ the node where the search should begin, assuming the
+ \a path is a not a fully-qualified name. \a node is
+ most often the root of this Tree.
+ */
+const Node* Tree::matchPathAndTarget(const QStringList& path,
+ int idx,
+ const QString& target,
+ const Node* node,
+ int flags,
+ Node::Genus genus,
+ QString& ref) const
+{
+ /*
+ If the path has been matched, then if there is a target,
+ try to match the target. If there is a target, but you
+ can't match it at the end of the path, give up; return 0.
*/
- const Node* n = findNode(path, current, findFlags, false);
- if (n)
- return n;
- return findNode(path, current, findFlags, true);
+ if (idx == path.size()) {
+ if (!target.isEmpty()) {
+ ref = getRef(target, node);
+ if (ref.isEmpty())
+ return 0;
+ }
+ if (node->isFunction() && node->name() == node->parent()->name())
+ node = node->parent();
+ return node;
+ }
+
+ const Node* t = 0;
+ QString name = path.at(idx);
+ QList<Node*> nodes;
+ node->findChildren(name, nodes);
+
+ foreach (const Node* n, nodes) {
+ if (genus != Node::DontCare) {
+ if (n->genus() != genus)
+ continue;
+ }
+ t = matchPathAndTarget(path, idx+1, target, n, flags, genus, ref);
+ if (t && !t->isPrivate())
+ return t;
+ }
+ if (target.isEmpty()) {
+ if ((idx) == (path.size()-1) && node->isInnerNode() && (flags & SearchEnumValues)) {
+ t = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(idx));
+ if (t)
+ return t;
+ }
+ }
+ if ((genus != Node::QML) && node->isClass() && (flags & SearchBaseClasses)) {
+ NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
+ foreach (const Node* bc, baseClasses) {
+ t = matchPathAndTarget(path, idx, target, bc, flags, genus, ref);
+ if (t && ! t->isPrivate())
+ return t;
+ if (target.isEmpty()) {
+ if ((idx) == (path.size()-1) && (flags & SearchEnumValues)) {
+ t = static_cast<const InnerNode*>(bc)->findEnumNodeForValue(path.at(idx));
+ if (t)
+ return t;
+ }
+ }
+ }
+ }
+ return 0;
}
/*!
- This overload function was extracted from the one above that has the
- same signature without the last bool parameter, \a qml. This version
- is called only by that other one. It is therefore private. It can
- be called a second time by that other version, if the first call
- returns null. If \a qml is false, the search will only match a node
- that is not a QML node. If \a qml is true, the search will only
- match a node that is a QML node.
-
- This findNode() is only called by the other findNode().
-*/
-const Node* Tree::findNode(const QStringList& path, const Node* start, int findFlags, bool qml) const
+ Searches the tree for a node that matches the \a path. The
+ search begins at \a start but can move up the parent chain
+ recursively if no match is found.
+
+ This findNode() callse the other findNode(), which is not
+ called anywhere else.
+ */
+const Node* Tree::findNode(const QStringList& path,
+ const Node* start,
+ int findFlags,
+ Node::Genus genus) const
{
const Node* current = start;
+ if (!current)
+ current = root();
+
do {
const Node* node = current;
int i;
@@ -718,10 +856,10 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
check first to see if the first two path strings refer
to a QML element. If they do, path[0] will be the QML
module identifier, and path[1] will be the QML type.
- If the anser is yes, the reference identifies a QML
- class node.
+ If the answer is yes, the reference identifies a QML
+ type node.
*/
- if (qml && path.size() >= 2 && !path[0].isEmpty()) {
+ if ((genus != Node::CPP) && (path.size() >= 2) && !path[0].isEmpty()) {
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (qcn) {
node = qcn;
@@ -735,14 +873,14 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
if (node == 0 || !node->isInnerNode())
break;
- const Node* next = static_cast<const InnerNode*>(node)->findChildNode(path.at(i), qml);
+ const Node* next = static_cast<const InnerNode*>(node)->findChildNode(path.at(i), genus);
if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) {
next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i));
}
- if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
+ if (!next && (genus != Node::QML) && node->isClass() && (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const Node* baseClass, baseClasses) {
- next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i));
+ next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i), genus);
if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1)
next = static_cast<const InnerNode*>(baseClass)->findEnumNodeForValue(path.at(i));
if (next) {
@@ -752,13 +890,8 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
}
node = next;
}
- if (node && i == path.size()
- && (!(findFlags & NonFunction) || node->type() != Node::Function
- || ((FunctionNode*)node)->metaness() == FunctionNode::MacroWithoutParams)) {
- if (node->isCollisionNode())
- node = node->applyModuleName(start);
- return node;
- }
+ if (node && i == path.size())
+ return node;
current = current->parent();
} while (current);
@@ -771,16 +904,24 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
it returns the ref from that node. Otherwise it returns an
empty string.
*/
-QString Tree::findTarget(const QString& target, const Node* node) const
+QString Tree::getRef(const QString& target, const Node* node) const
{
+ TargetMap::const_iterator i = nodesByTargetTitle_.constFind(target);
+ if (i != nodesByTargetTitle_.constEnd()) {
+ do {
+ if (i.value()->node_ == node)
+ return i.value()->ref_;
+ ++i;
+ } while (i != nodesByTargetTitle_.constEnd() && i.key() == target);
+ }
QString key = Doc::canonicalTitle(target);
- TargetMap::const_iterator i = nodesByTarget_.constFind(key);
- if (i != nodesByTarget_.constEnd()) {
+ i = nodesByTargetRef_.constFind(key);
+ if (i != nodesByTargetRef_.constEnd()) {
do {
- if (i.value().node_ == node)
- return i.value().ref_;
+ if (i.value()->node_ == node)
+ return i.value()->ref_;
++i;
- } while (i != nodesByTarget_.constEnd() && i.key() == key);
+ } while (i != nodesByTargetRef_.constEnd() && i.key() == key);
}
return QString();
}
@@ -791,31 +932,15 @@ QString Tree::findTarget(const QString& target, const Node* node) const
the \a node, the \a priority. and a canonicalized form of
the \a name, which is later used.
*/
-void Tree::insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority)
-{
- TargetRec target;
- target.type_ = type;
- target.node_ = node;
- target.priority_ = priority;
- target.ref_ = Doc::canonicalTitle(name);
- nodesByTarget_.insert(name, target);
-}
-
-/*!
- Searches this tree for a node named \a target and returns
- a pointer to it if found. The \a start node is the starting
- point, but it only makes sense if \a start is in this tree.
- If \a start is not in this tree, \a start is set to 0 before
- beginning the search to ensure that the search starts at the
- root.
- */
-const Node* Tree::resolveTarget(const QString& target, const Node* start)
+void Tree::insertTarget(const QString& name,
+ const QString& title,
+ TargetRec::Type type,
+ Node* node,
+ int priority)
{
- QStringList path = target.split("::");
- int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
- if (start && start->tree() != this)
- start = 0;
- return findNode(path, start, flags);
+ TargetRec* target = new TargetRec(name, title, type, node, priority);
+ nodesByTargetRef_.insert(name, target);
+ nodesByTargetTitle_.insert(title, target);
}
/*!
@@ -826,8 +951,10 @@ void Tree::resolveTargets(InnerNode* root)
foreach (Node* child, root->childNodes()) {
if (child->type() == Node::Document) {
DocNode* node = static_cast<DocNode*>(child);
- if (!node->title().isEmpty()) {
- QString key = Doc::canonicalTitle(node->title());
+ QString key = node->title();
+ if (!key.isEmpty()) {
+ if (key.contains(QChar(' ')))
+ key = Doc::canonicalTitle(key);
QList<DocNode*> nodes = docNodesByTitle_.values(key);
bool alreadyThere = false;
if (!nodes.empty()) {
@@ -840,52 +967,48 @@ void Tree::resolveTargets(InnerNode* root)
}
}
}
- if (!alreadyThere) {
+ if (!alreadyThere)
docNodesByTitle_.insert(key, node);
- }
- }
- if (node->subType() == Node::Collision) {
- resolveTargets(node);
}
}
if (child->doc().hasTableOfContents()) {
const QList<Atom*>& toc = child->doc().tableOfContents();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 3;
-
for (int i = 0; i < toc.size(); ++i) {
- target.ref_ = refForAtom(toc.at(i));
+ QString ref = refForAtom(toc.at(i));
QString title = Text::sectionHeading(toc.at(i)).toString();
- if (!title.isEmpty()) {
+ if (!ref.isEmpty() && !title.isEmpty()) {
QString key = Doc::canonicalTitle(title);
- nodesByTarget_.insert(key, target);
+ TargetRec* target = new TargetRec(ref, title, TargetRec::Contents, child, 3);
+ nodesByTargetRef_.insert(key, target);
+ nodesByTargetTitle_.insert(title, target);
}
}
}
if (child->doc().hasKeywords()) {
const QList<Atom*>& keywords = child->doc().keywords();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 1;
-
for (int i = 0; i < keywords.size(); ++i) {
- target.ref_ = refForAtom(keywords.at(i));
- QString key = Doc::canonicalTitle(keywords.at(i)->string());
- nodesByTarget_.insert(key, target);
+ QString ref = refForAtom(keywords.at(i));
+ QString title = keywords.at(i)->string();
+ if (!ref.isEmpty() && !title.isEmpty()) {
+ QString key = Doc::canonicalTitle(title);
+ TargetRec* target = new TargetRec(ref, title, TargetRec::Keyword, child, 1);
+ nodesByTargetRef_.insert(key, target);
+ nodesByTargetTitle_.insert(title, target);
+ }
}
}
if (child->doc().hasTargets()) {
- const QList<Atom*>& toc = child->doc().targets();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 2;
-
- for (int i = 0; i < toc.size(); ++i) {
- target.ref_ = refForAtom(toc.at(i));
- QString key = Doc::canonicalTitle(toc.at(i)->string());
- nodesByTarget_.insert(key, target);
+ const QList<Atom*>& targets = child->doc().targets();
+ for (int i = 0; i < targets.size(); ++i) {
+ QString ref = refForAtom(targets.at(i));
+ QString title = targets.at(i)->string();
+ if (!ref.isEmpty() && !title.isEmpty()) {
+ QString key = Doc::canonicalTitle(title);
+ TargetRec* target = new TargetRec(ref, title, TargetRec::Target, child, 2);
+ nodesByTargetRef_.insert(key, target);
+ nodesByTargetTitle_.insert(title, target);
+ }
}
}
}
@@ -896,46 +1019,58 @@ void Tree::resolveTargets(InnerNode* root)
finds one, it sets \a ref and returns the found node.
*/
const Node*
-Tree::findUnambiguousTarget(const QString& target, QString& ref)
+Tree::findUnambiguousTarget(const QString& target, QString& ref) const
{
- TargetRec bestTarget;
int numBestTargets = 0;
- QList<TargetRec> bestTargetList;
+ TargetRec* bestTarget = 0;
+ QList<TargetRec*> bestTargetList;
- QString key = Doc::canonicalTitle(target);
- TargetMap::iterator i = nodesByTarget_.find(key);
- while (i != nodesByTarget_.end()) {
+ QString key = target;
+ TargetMap::const_iterator i = nodesByTargetTitle_.find(key);
+ while (i != nodesByTargetTitle_.constEnd()) {
if (i.key() != key)
break;
- const TargetRec& candidate = i.value();
- if (candidate.priority_ < bestTarget.priority_) {
+ TargetRec* candidate = i.value();
+ if (!bestTarget || (candidate->priority_ < bestTarget->priority_)) {
bestTarget = candidate;
bestTargetList.clear();
bestTargetList.append(candidate);
numBestTargets = 1;
- } else if (candidate.priority_ == bestTarget.priority_) {
+ } else if (candidate->priority_ == bestTarget->priority_) {
bestTargetList.append(candidate);
++numBestTargets;
}
++i;
}
- if (numBestTargets > 0) {
- if (numBestTargets == 1) {
- ref = bestTarget.ref_;
- return bestTarget.node_;
- }
- else if (bestTargetList.size() > 1) {
-#if 0
- qDebug() << "TARGET:" << target << numBestTargets;
- for (int i=0; i<bestTargetList.size(); ++i) {
- const Node* n = bestTargetList.at(i).node_;
- qDebug() << " " << n->name() << n->title();
- }
-#endif
- ref = bestTargetList.at(0).ref_;
- return bestTargetList.at(0).node_;
+ if (bestTarget) {
+ ref = bestTarget->ref_;
+ return bestTarget->node_;
+ }
+
+ numBestTargets = 0;
+ bestTarget = 0;
+ key = Doc::canonicalTitle(target);
+ i = nodesByTargetRef_.find(key);
+ while (i != nodesByTargetRef_.constEnd()) {
+ if (i.key() != key)
+ break;
+ TargetRec* candidate = i.value();
+ if (!bestTarget || (candidate->priority_ < bestTarget->priority_)) {
+ bestTarget = candidate;
+ bestTargetList.clear();
+ bestTargetList.append(candidate);
+ numBestTargets = 1;
+ } else if (candidate->priority_ == bestTarget->priority_) {
+ bestTargetList.append(candidate);
+ ++numBestTargets;
}
+ ++i;
}
+ if (bestTarget) {
+ ref = bestTarget->ref_;
+ return bestTarget->node_;
+ }
+
ref.clear();
return 0;
}
@@ -945,8 +1080,11 @@ Tree::findUnambiguousTarget(const QString& target, QString& ref)
*/
const DocNode* Tree::findDocNodeByTitle(const QString& title) const
{
- QString key = Doc::canonicalTitle(title);
- DocNodeMultiMap::const_iterator i = docNodesByTitle_.constFind(key);
+ DocNodeMultiMap::const_iterator i;
+ if (title.contains(QChar(' ')))
+ i = docNodesByTitle_.constFind(Doc::canonicalTitle(title));
+ else
+ i = docNodesByTitle_.constFind(title);
if (i != docNodesByTitle_.constEnd()) {
/*
Reporting all these duplicate section titles is probably
@@ -1241,16 +1379,27 @@ void Tree::insertQmlType(const QString& key, QmlClassNode* n)
/*!
Split \a target on "::" and find the function node with that
path.
+
+ Called in HtmlGenerator, DitaXmlGenerator, and QdocDatabase.
*/
-const Node* Tree::resolveFunctionTarget(const QString& target, const Node* relative)
+const Node* Tree::findFunctionNode(const QString& target, const Node* relative, Node::Genus genus)
{
QString t = target;
t.chop(2);
QStringList path = t.split("::");
- const FunctionNode* fn = findFunctionNode(path, relative, SearchBaseClasses);
+ const FunctionNode* fn = findFunctionNode(path, relative, SearchBaseClasses, genus);
if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
return fn;
return 0;
}
+/*!
+ Search for a node that is identified by \a name.
+ Return a pointer to a matching node, or 0.
+*/
+const Node* Tree::checkForCollision(const QString& name)
+{
+ return findNode(QStringList(name), 0, 0, Node::DontCare);
+}
+
QT_END_NAMESPACE
diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h
index a953751968..c6d6e1f4bb 100644
--- a/src/tools/qdoc/tree.h
+++ b/src/tools/qdoc/tree.h
@@ -58,15 +58,24 @@ struct TargetRec
{
public:
enum Type { Unknown, Target, Keyword, Contents, Class, Function, Page, Subtitle };
- TargetRec() : node_(0), priority_(INT_MAX), type_(Unknown) { }
+
+ TargetRec(const QString& name,
+ const QString& title,
+ TargetRec::Type type,
+ Node* node,
+ int priority)
+ : node_(node), ref_(name), title_(title), priority_(priority), type_(type) { }
+
bool isEmpty() const { return ref_.isEmpty(); }
+
Node* node_;
QString ref_;
+ QString title_;
int priority_;
Type type_;
};
-typedef QMultiMap<QString, TargetRec> TargetMap;
+typedef QMultiMap<QString, TargetRec*> TargetMap;
typedef QMultiMap<QString, DocNode*> DocNodeMultiMap;
typedef QMap<QString, QmlClassNode*> QmlTypeMap;
typedef QMultiMap<QString, const ExampleNode*> ExampleNodeMap;
@@ -83,10 +92,11 @@ class Tree
Tree(const QString& module, QDocDatabase* qdb);
~Tree();
- ClassNode* findClassNode(const QStringList& path, Node* start = 0) const;
+ Node* findNodeForInclude(const QStringList& path) const;
+ ClassNode* findClassNode(const QStringList& path, const Node* start = 0) const;
NamespaceNode* findNamespaceNode(const QStringList& path) const;
FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone);
- const Node* resolveFunctionTarget(const QString& target, const Node* relative);
+ const Node* findFunctionNode(const QString& target, const Node* relative, Node::Genus genus);
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
@@ -97,26 +107,37 @@ class Tree
Node* start,
const NodeTypeList& types) const;
- const Node* findNode(const QStringList &path,
- const Node* relative = 0,
- int findFlags = 0) const;
+ const Node* findNodeForTarget(const QStringList& path,
+ const QString& target,
+ const Node* node,
+ int flags,
+ Node::Genus genus,
+ QString& ref) const;
+ const Node* matchPathAndTarget(const QStringList& path,
+ int idx,
+ const QString& target,
+ const Node* node,
+ int flags,
+ Node::Genus genus,
+ QString& ref) const;
- const Node* findNode(const QStringList& path,
- const Node* start,
- int findFlags,
- bool qml) const;
+ const Node* findNode(const QStringList &path,
+ const Node* relative, // = 0,
+ int findFlags, // = 0,
+ Node::Genus genus) const; // = Node::DontCare) const;
QmlClassNode* findQmlTypeNode(const QStringList& path);
Node* findNodeByNameAndType(const QStringList& path, Node::Type type) const;
InnerNode* findRelatesNode(const QStringList& path);
- NameCollisionNode* checkForCollision(const QString& name);
- NameCollisionNode* findCollisionNode(const QString& name) const;
- QString findTarget(const QString& target, const Node* node) const;
- void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority);
- const Node* resolveTarget(const QString& target, const Node* start);
+ QString getRef(const QString& target, const Node* node) const;
+ void insertTarget(const QString& name,
+ const QString& title,
+ TargetRec::Type type,
+ Node* node,
+ int priority);
void resolveTargets(InnerNode* root);
- const Node* findUnambiguousTarget(const QString& target, QString& ref);
+ const Node* findUnambiguousTarget(const QString& target, QString& ref) const;
const DocNode* findDocNodeByTitle(const QString& title) const;
void addPropertyFunction(PropertyNode *property,
@@ -131,7 +152,8 @@ class Tree
const FunctionNode *findFunctionNode(const QStringList &path,
const Node *relative = 0,
- int findFlags = 0) const;
+ int findFlags = 0,
+ Node::Genus genus = Node::DontCare) const;
const NamespaceNode *root() const { return &root_; }
FunctionNode *findVirtualFunctionInBaseClasses(ClassNode *classe,
@@ -172,6 +194,7 @@ class Tree
void insertQmlType(const QString& key, QmlClassNode* n);
void addExampleNode(ExampleNode* n) { exampleNodeMap_.insert(n->title(), n); }
ExampleNodeMap& exampleNodeMap() { return exampleNodeMap_; }
+ const Node* checkForCollision(const QString& name);
public:
const QString& moduleName() const { return module_; }
@@ -182,7 +205,8 @@ private:
NamespaceNode root_;
PropertyMap unresolvedPropertyMap;
DocNodeMultiMap docNodesByTitle_;
- TargetMap nodesByTarget_;
+ TargetMap nodesByTargetRef_;
+ TargetMap nodesByTargetTitle_;
CNMap groups_;
CNMap modules_;
CNMap qmlModules_;
diff --git a/src/widgets/accessible/complexwidgets.cpp b/src/widgets/accessible/complexwidgets.cpp
index f7c2ac0cf1..e45be30338 100644
--- a/src/widgets/accessible/complexwidgets.cpp
+++ b/src/widgets/accessible/complexwidgets.cpp
@@ -67,6 +67,7 @@
QT_BEGIN_NAMESPACE
QString qt_accStripAmp(const QString &text);
+QString qt_accHotKey(const QString &text);
#ifndef QT_NO_TABBAR
/*!
@@ -94,9 +95,12 @@ public:
QObject *object() const { return 0; }
QAccessible::Role role() const { return QAccessible::PageTab; }
QAccessible::State state() const {
- QAccessibleInterface *parentInterface = parent();
- QAccessible::State state = parentInterface->state();
- return state;
+ if (!isValid()) {
+ QAccessible::State s;
+ s.invalid = true;
+ return s;
+ }
+ return parent()->state();
}
QRect rect() const {
if (!isValid())
@@ -108,7 +112,7 @@ public:
return rec;
}
- bool isValid() const { return true; }// (!m_parent.isNull()) && m_parent->count() > m_index; }
+ bool isValid() const { return m_parent.data() && m_parent->count() > m_index; }
QAccessibleInterface *childAt(int, int) const { return 0; }
int childCount() const { return 0; }
@@ -116,21 +120,30 @@ public:
QString text(QAccessible::Text t) const
{
- if (t == QAccessible::Name)
+ if (!isValid())
+ return QString();
+ switch (t) {
+ case QAccessible::Name:
return qt_accStripAmp(m_parent->tabText(m_index));
- else if (t == QAccessible::Description)
+ case QAccessible::Accelerator:
+ return qt_accHotKey(m_parent->tabText(m_index));
+ case QAccessible::Description:
return m_parent->tabToolTip(m_index);
- else if (t == QAccessible::Help)
+ case QAccessible::Help:
return m_parent->tabWhatsThis(m_index);
+ default:
+ break;
+ }
return QString();
}
void setText(QAccessible::Text, const QString &) {}
QAccessibleInterface *parent() const {
- return QAccessible::queryAccessibleInterface(m_parent);
+ return QAccessible::queryAccessibleInterface(m_parent.data());
}
QAccessibleInterface *child(int) const { return 0; }
+
// action interface
QStringList actionNames() const
{
@@ -139,7 +152,7 @@ public:
void doAction(const QString &actionName)
{
- if (actionName == pressAction())
+ if (isValid() && actionName == pressAction())
m_parent->setCurrentIndex(m_index);
}
@@ -227,6 +240,8 @@ QString QAccessibleTabBar::text(QAccessible::Text t) const
{
if (t == QAccessible::Name) {
return qt_accStripAmp(tabBar()->tabText(tabBar()->currentIndex()));
+ } else if (t == QAccessible::Accelerator) {
+ return qt_accHotKey(tabBar()->tabText(tabBar()->currentIndex()));
}
return QString();
}
diff --git a/src/widgets/accessible/qaccessiblewidget.cpp b/src/widgets/accessible/qaccessiblewidget.cpp
index 48f99f4d35..29fbc4df97 100644
--- a/src/widgets/accessible/qaccessiblewidget.cpp
+++ b/src/widgets/accessible/qaccessiblewidget.cpp
@@ -70,7 +70,8 @@ static QList<QWidget*> childWidgets(const QWidget *widget)
#if !defined(QT_NO_MENU)
&& !qobject_cast<QMenu*>(w)
#endif
- && w->objectName() != QLatin1String("qt_rubberband"))
+ && w->objectName() != QLatin1String("qt_rubberband")
+ && w->objectName() != QLatin1String("qt_spinbox_lineedit"))
widgets.append(w);
}
return widgets;
@@ -111,7 +112,6 @@ static int qt_accAmpIndex(const QString &text)
return -1;
int fa = 0;
- QChar ac;
while ((fa = text.indexOf(QLatin1Char('&'), fa)) != -1) {
++fa;
if (fa < text.length()) {
diff --git a/src/widgets/accessible/qaccessiblewidgetfactory.cpp b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
index 3d123cc9ab..fb81a4aaeb 100644
--- a/src/widgets/accessible/qaccessiblewidgetfactory.cpp
+++ b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
@@ -66,7 +66,10 @@ QAccessibleInterface *qAccessibleFactory(const QString &classname, QObject *obje
if (false) {
#ifndef QT_NO_LINEEDIT
} else if (classname == QLatin1String("QLineEdit")) {
- iface = new QAccessibleLineEdit(widget);
+ if (widget->objectName() == QLatin1String("qt_spinbox_lineedit"))
+ iface = 0;
+ else
+ iface = new QAccessibleLineEdit(widget);
#endif
#ifndef QT_NO_COMBOBOX
} else if (classname == QLatin1String("QComboBox")) {
diff --git a/src/widgets/accessible/rangecontrols.cpp b/src/widgets/accessible/rangecontrols.cpp
index d4dc74ea69..e16b99c25e 100644
--- a/src/widgets/accessible/rangecontrols.cpp
+++ b/src/widgets/accessible/rangecontrols.cpp
@@ -51,20 +51,28 @@
#include <qglobal.h>
#include <QDoubleSpinBox>
#include <QDial>
+#include <QtWidgets/qlineedit.h>
#include <qmath.h>
#include <private/qmath_p.h>
+#include "simplewidgets.h" // let spinbox use line edit's interface
+
QT_BEGIN_NAMESPACE
#ifndef QT_NO_ACCESSIBILITY
#ifndef QT_NO_SPINBOX
QAccessibleAbstractSpinBox::QAccessibleAbstractSpinBox(QWidget *w)
-: QAccessibleWidget(w, QAccessible::SpinBox)
+: QAccessibleWidget(w, QAccessible::SpinBox), lineEdit(Q_NULLPTR)
{
Q_ASSERT(abstractSpinBox());
}
+QAccessibleAbstractSpinBox::~QAccessibleAbstractSpinBox()
+{
+ delete lineEdit;
+}
+
/*!
Returns the underlying QAbstractSpinBox.
*/
@@ -73,6 +81,14 @@ QAbstractSpinBox *QAccessibleAbstractSpinBox::abstractSpinBox() const
return qobject_cast<QAbstractSpinBox*>(object());
}
+QAccessibleInterface *QAccessibleAbstractSpinBox::lineEditIface() const
+{
+ // QAccessibleLineEdit is only used to forward the text functions
+ if (!lineEdit)
+ lineEdit = new QAccessibleLineEdit(abstractSpinBox()->lineEdit());
+ return lineEdit;
+}
+
QString QAccessibleAbstractSpinBox::text(QAccessible::Text t) const
{
if (t == QAccessible::Value)
@@ -84,6 +100,10 @@ void *QAccessibleAbstractSpinBox::interface_cast(QAccessible::InterfaceType t)
{
if (t == QAccessible::ValueInterface)
return static_cast<QAccessibleValueInterface*>(this);
+ if (t == QAccessible::TextInterface)
+ return static_cast<QAccessibleTextInterface*>(this);
+ if (t == QAccessible::EditableTextInterface)
+ return static_cast<QAccessibleEditableTextInterface*>(this);
return QAccessibleWidget::interface_cast(t);
}
@@ -112,6 +132,102 @@ QVariant QAccessibleAbstractSpinBox::minimumStepSize() const
return abstractSpinBox()->property("stepSize");
}
+void QAccessibleAbstractSpinBox::addSelection(int startOffset, int endOffset)
+{
+ lineEditIface()->textInterface()->addSelection(startOffset, endOffset);
+}
+
+QString QAccessibleAbstractSpinBox::attributes(int offset, int *startOffset, int *endOffset) const
+{
+ return lineEditIface()->textInterface()->attributes(offset, startOffset, endOffset);
+}
+
+int QAccessibleAbstractSpinBox::cursorPosition() const
+{
+ return lineEditIface()->textInterface()->cursorPosition();
+}
+
+QRect QAccessibleAbstractSpinBox::characterRect(int offset) const
+{
+ return lineEditIface()->textInterface()->characterRect(offset);
+}
+
+int QAccessibleAbstractSpinBox::selectionCount() const
+{
+ return lineEditIface()->textInterface()->selectionCount();
+}
+
+int QAccessibleAbstractSpinBox::offsetAtPoint(const QPoint &point) const
+{
+ return lineEditIface()->textInterface()->offsetAtPoint(point);
+}
+
+void QAccessibleAbstractSpinBox::selection(int selectionIndex, int *startOffset, int *endOffset) const
+{
+ lineEditIface()->textInterface()->selection(selectionIndex, startOffset, endOffset);
+}
+
+QString QAccessibleAbstractSpinBox::text(int startOffset, int endOffset) const
+{
+ return lineEditIface()->textInterface()->text(startOffset, endOffset);
+}
+
+QString QAccessibleAbstractSpinBox::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const
+{
+ return lineEditIface()->textInterface()->textBeforeOffset(offset, boundaryType, startOffset, endOffset);
+}
+
+QString QAccessibleAbstractSpinBox::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const
+{
+ return lineEditIface()->textInterface()->textAfterOffset(offset, boundaryType, startOffset, endOffset);
+}
+
+QString QAccessibleAbstractSpinBox::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const
+{
+ return lineEditIface()->textInterface()->textAtOffset(offset, boundaryType, startOffset, endOffset);
+}
+
+void QAccessibleAbstractSpinBox::removeSelection(int selectionIndex)
+{
+ lineEditIface()->textInterface()->removeSelection(selectionIndex);
+}
+
+void QAccessibleAbstractSpinBox::setCursorPosition(int position)
+{
+ lineEditIface()->textInterface()->setCursorPosition(position);
+}
+
+void QAccessibleAbstractSpinBox::setSelection(int selectionIndex, int startOffset, int endOffset)
+{
+ lineEditIface()->textInterface()->setSelection(selectionIndex, startOffset, endOffset);
+}
+
+int QAccessibleAbstractSpinBox::characterCount() const
+{
+ return lineEditIface()->textInterface()->characterCount();
+}
+
+void QAccessibleAbstractSpinBox::scrollToSubstring(int startIndex, int endIndex)
+{
+ lineEditIface()->textInterface()->scrollToSubstring(startIndex, endIndex);
+}
+
+void QAccessibleAbstractSpinBox::deleteText(int startOffset, int endOffset)
+{
+ lineEditIface()->editableTextInterface()->deleteText(startOffset, endOffset);
+}
+
+void QAccessibleAbstractSpinBox::insertText(int offset, const QString &text)
+{
+ lineEditIface()->editableTextInterface()->insertText(offset, text);
+}
+
+void QAccessibleAbstractSpinBox::replaceText(int startOffset, int endOffset, const QString &text)
+{
+ lineEditIface()->editableTextInterface()->replaceText(startOffset, endOffset, text);
+}
+
+
/*!
\class QAccessibleSpinBox
\brief The QAccessibleSpinBox class implements the QAccessibleInterface for spinbox widgets.
diff --git a/src/widgets/accessible/rangecontrols.h b/src/widgets/accessible/rangecontrols.h
index 98cef46c5c..158e1cfcc0 100644
--- a/src/widgets/accessible/rangecontrols.h
+++ b/src/widgets/accessible/rangecontrols.h
@@ -55,12 +55,18 @@ class QSlider;
class QSpinBox;
class QDoubleSpinBox;
class QDial;
+class QAccessibleLineEdit;
#ifndef QT_NO_SPINBOX
-class QAccessibleAbstractSpinBox: public QAccessibleWidget, public QAccessibleValueInterface // TODO, public QAccessibleActionInterface
+class QAccessibleAbstractSpinBox:
+ public QAccessibleWidget,
+ public QAccessibleValueInterface,
+ public QAccessibleTextInterface,
+ public QAccessibleEditableTextInterface
{
public:
explicit QAccessibleAbstractSpinBox(QWidget *w);
+ virtual ~QAccessibleAbstractSpinBox();
QString text(QAccessible::Text t) const Q_DECL_OVERRIDE;
void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE;
@@ -72,10 +78,37 @@ public:
QVariant minimumValue() const Q_DECL_OVERRIDE;
QVariant minimumStepSize() const Q_DECL_OVERRIDE;
- // FIXME Action interface
+ // QAccessibleTextInterface
+ void addSelection(int startOffset, int endOffset) Q_DECL_OVERRIDE;
+ QString attributes(int offset, int *startOffset, int *endOffset) const Q_DECL_OVERRIDE;
+ int cursorPosition() const Q_DECL_OVERRIDE;
+ QRect characterRect(int offset) const Q_DECL_OVERRIDE;
+ int selectionCount() const Q_DECL_OVERRIDE;
+ int offsetAtPoint(const QPoint &point) const Q_DECL_OVERRIDE;
+ void selection(int selectionIndex, int *startOffset, int *endOffset) const Q_DECL_OVERRIDE;
+ QString text(int startOffset, int endOffset) const Q_DECL_OVERRIDE;
+ QString textBeforeOffset (int offset, QAccessible::TextBoundaryType boundaryType,
+ int *endOffset, int *startOffset) const Q_DECL_OVERRIDE;
+ QString textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType,
+ int *startOffset, int *endOffset) const Q_DECL_OVERRIDE;
+ QString textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
+ int *startOffset, int *endOffset) const Q_DECL_OVERRIDE;
+ void removeSelection(int selectionIndex) Q_DECL_OVERRIDE;
+ void setCursorPosition(int position) Q_DECL_OVERRIDE;
+ void setSelection(int selectionIndex, int startOffset, int endOffset) Q_DECL_OVERRIDE;
+ int characterCount() const Q_DECL_OVERRIDE;
+ void scrollToSubstring(int startIndex, int endIndex) Q_DECL_OVERRIDE;
+
+ // QAccessibleEditableTextInterface
+ void deleteText(int startOffset, int endOffset) Q_DECL_OVERRIDE;
+ void insertText(int offset, const QString &text) Q_DECL_OVERRIDE;
+ void replaceText(int startOffset, int endOffset, const QString &text) Q_DECL_OVERRIDE;
protected:
QAbstractSpinBox *abstractSpinBox() const;
+ QAccessibleInterface *lineEditIface() const;
+private:
+ mutable QAccessibleLineEdit *lineEdit;
};
class QAccessibleSpinBox : public QAccessibleAbstractSpinBox
@@ -94,6 +127,7 @@ public:
QString text(QAccessible::Text t) const Q_DECL_OVERRIDE;
+ using QAccessibleAbstractSpinBox::text;
protected:
QDoubleSpinBox *doubleSpinBox() const;
};
diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp
index 6fd249f372..e8827f4537 100644
--- a/src/widgets/accessible/simplewidgets.cpp
+++ b/src/widgets/accessible/simplewidgets.cpp
@@ -298,29 +298,6 @@ QAccessibleInterface *QAccessibleToolButton::child(int index) const
return 0;
}
-/*!
- \internal
-
- Returns the button's text label, depending on the text \a t, and
- the \a child.
-*/
-QString QAccessibleToolButton::text(QAccessible::Text t) const
-{
- QString str;
- switch (t) {
- case QAccessible::Name:
- str = toolButton()->accessibleName();
- if (str.isEmpty())
- str = toolButton()->text();
- break;
- default:
- break;
- }
- if (str.isEmpty())
- str = QAccessibleButton::text(t);
- return qt_accStripAmp(str);
-}
-
/*
The three different tool button types can have the following actions:
| DelayedPopup | ShowMenuAction + (PressedAction || CheckedAction) |
diff --git a/src/widgets/accessible/simplewidgets.h b/src/widgets/accessible/simplewidgets.h
index e4ce6150e2..c46ea9b6be 100644
--- a/src/widgets/accessible/simplewidgets.h
+++ b/src/widgets/accessible/simplewidgets.h
@@ -84,8 +84,6 @@ public:
int childCount() const Q_DECL_OVERRIDE;
QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE;
- QString text(QAccessible::Text t) const Q_DECL_OVERRIDE;
-
// QAccessibleActionInterface
QStringList actionNames() const Q_DECL_OVERRIDE;
void doAction(const QString &actionName) Q_DECL_OVERRIDE;
@@ -174,6 +172,7 @@ public:
void replaceText(int startOffset, int endOffset, const QString &text) Q_DECL_OVERRIDE;
protected:
QLineEdit *lineEdit() const;
+ friend class QAccessibleAbstractSpinBox;
};
#endif // QT_NO_LINEEDIT
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index d202884416..77b94c02a4 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -91,9 +91,7 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
The QFileDialog class enables a user to traverse the file system in
order to select one or many files or a directory.
- The easiest way to create a QFileDialog is to use the static
- functions. On Windows, Mac OS X, KDE and GNOME, these static functions will
- call the native file dialog when possible.
+ The easiest way to create a QFileDialog is to use the static functions.
\snippet code/src_gui_dialogs_qfiledialog.cpp 0
diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp
index 5a68bfbc66..fc9f36f0c2 100644
--- a/src/widgets/dialogs/qfontdialog.cpp
+++ b/src/widgets/dialogs/qfontdialog.cpp
@@ -65,6 +65,10 @@
#include <private/qdialog_p.h>
#include <private/qfont_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformfontdatabase.h>
+
QT_BEGIN_NAMESPACE
class QFontListView : public QListView
@@ -485,8 +489,13 @@ void QFontDialogPrivate::updateFamilies()
const QFontDialog::FontDialogOptions spacingMask = (QFontDialog::ProportionalFonts | QFontDialog::MonospacedFonts);
const QFontDialog::FontDialogOptions options = q->options();
+ QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
+
QStringList familyNames;
foreach (const QString &family, fdb.families(writingSystem)) {
+ if (pfdb->isPrivateFontFamily(family))
+ continue;
+
if ((options & scalableMask) && (options & scalableMask) != scalableMask) {
if (bool(options & QFontDialog::ScalableFonts) != fdb.isSmoothlyScalable(family))
continue;
diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp
index 747115984d..84781b4099 100644
--- a/src/widgets/dialogs/qwizard_win.cpp
+++ b/src/widgets/dialogs/qwizard_win.cpp
@@ -172,6 +172,7 @@ static PtrGetThemePartSize pGetThemePartSize = 0;
static PtrGetThemeColor pGetThemeColor = 0;
int QVistaHelper::instanceCount = 0;
+int QVistaHelper::m_devicePixelRatio = 1;
bool QVistaHelper::is_vista = false;
QVistaHelper::VistaState QVistaHelper::cachedVistaState = QVistaHelper::Dirty;
@@ -228,11 +229,15 @@ void QVistaBackButton::paintEvent(QPaintEvent *)
RECT clipRect;
int xoffset = origin.x() + QWidget::mapToParent(r.topLeft()).x() - 1;
int yoffset = origin.y() + QWidget::mapToParent(r.topLeft()).y() - 1;
+ const int dpr = devicePixelRatio();
+ const QRect rDp = QRect(r.topLeft() * dpr, r.size() * dpr);
+ const int xoffsetDp = xoffset * dpr;
+ const int yoffsetDp = yoffset * dpr;
- clipRect.top = r.top() + yoffset;
- clipRect.bottom = r.bottom() + yoffset;
- clipRect.left = r.left() + xoffset;
- clipRect.right = r.right() + xoffset;
+ clipRect.top = rDp.top() + yoffsetDp;
+ clipRect.bottom = rDp.bottom() + yoffsetDp;
+ clipRect.left = rDp.left() + xoffsetDp;
+ clipRect.right = rDp.right() + xoffsetDp;
int state = WIZ_NAV_BB_NORMAL;
if (!isEnabled())
@@ -259,6 +264,7 @@ QVistaHelper::QVistaHelper(QWizard *wizard)
, wizard(wizard)
, backButton_(0)
{
+ QVistaHelper::m_devicePixelRatio = wizard->devicePixelRatio();
is_vista = resolveSymbols();
if (instanceCount++ == 0)
cachedVistaState = Dirty;
@@ -281,10 +287,12 @@ QVistaHelper::~QVistaHelper()
void QVistaHelper::updateCustomMargins(bool vistaMargins)
{
if (QWindow *window = wizard->windowHandle()) {
- // Reduce top frame to zero since we paint it ourselves.
- const QMargins customMargins = vistaMargins ?
- QMargins(0, -titleBarSize(), 0, 0) : QMargins();
- const QVariant customMarginsV = qVariantFromValue(customMargins);
+ // Reduce top frame to zero since we paint it ourselves. Use
+ // device pixel to avoid rounding errors.
+ const QMargins customMarginsDp = vistaMargins
+ ? QMargins(0, -titleBarSizeDp(), 0, 0)
+ : QMargins();
+ const QVariant customMarginsV = qVariantFromValue(customMarginsDp);
// The dynamic property takes effect when creating the platform window.
window->setProperty("_q_windowsCustomMargins", customMarginsV);
// If a platform window exists, change via native interface.
@@ -351,7 +359,7 @@ bool QVistaHelper::setDWMTitleBar(TitleBarChangeType type)
if (type == NormalTitleBar)
mar.cyTopHeight = 0;
else
- mar.cyTopHeight = titleBarSize() + topOffset();
+ mar.cyTopHeight = (titleBarSize() + topOffset()) * QVistaHelper::m_devicePixelRatio;
if (const HWND wizardHandle = wizardHWND())
if (SUCCEEDED(pDwmExtendFrameIntoClientArea(wizardHandle, &mar)))
value = true;
@@ -371,6 +379,8 @@ void QVistaHelper::drawTitleBar(QPainter *painter)
if (vistaState() == VistaAero && isWindow)
drawBlackRect(QRect(0, 0, wizard->width(),
titleBarSize() + topOffset()), hdc);
+ // The button is positioned in QWizardPrivate::handleAeroStyleChange(),
+ // all calculation is relative to it.
const int btnTop = backButton_->mapToParent(QPoint()).y();
const int btnHeight = backButton_->size().height();
const int verticalCenter = (btnTop + btnHeight / 2) - 1;
@@ -405,14 +415,15 @@ void QVistaHelper::drawTitleBar(QPainter *painter)
const QIcon windowIcon = wizard->windowIcon();
if (!windowIcon.isNull()) {
+ const int size = QVistaHelper::iconSize();
const int iconLeft = (wizard->layoutDirection() == Qt::LeftToRight
? leftMargin()
- : wizard->width() - leftMargin() - iconSize());
+ : wizard->width() - leftMargin() - size);
- const QRect rect(origin.x() + iconLeft,
- origin.y() + verticalCenter - iconSize() / 2, iconSize(), iconSize());
- const HICON hIcon = qt_pixmapToWinHICON(windowIcon.pixmap(iconSize()));
- DrawIconEx(hdc, rect.left(), rect.top(), hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
+ const QPoint pos(origin.x() + iconLeft, origin.y() + verticalCenter - size / 2);
+ const QPoint posDp = pos * QVistaHelper::m_devicePixelRatio;
+ const HICON hIcon = qt_pixmapToWinHICON(windowIcon.pixmap(size * QVistaHelper::m_devicePixelRatio));
+ DrawIconEx(hdc, posDp.x(), posDp.y(), hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
DestroyIcon(hIcon);
}
}
@@ -691,6 +702,8 @@ bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const Q
{
bool value = false;
if (vistaState() == VistaAero) {
+ const QRect rectDp = QRect(rect.topLeft() * QVistaHelper::m_devicePixelRatio,
+ rect.size() * QVistaHelper::m_devicePixelRatio);
HWND handle = QApplicationPrivate::getHWNDForWidget(QApplication::desktop());
HANDLE hTheme = pOpenThemeData(handle, L"WINDOW");
if (!hTheme) return false;
@@ -702,8 +715,8 @@ bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const Q
dcMem = CreateCompatibleDC(hdc);
dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- dib.bmiHeader.biWidth = rect.width();
- dib.bmiHeader.biHeight = -rect.height();
+ dib.bmiHeader.biWidth = rectDp.width();
+ dib.bmiHeader.biHeight = -rectDp.height();
dib.bmiHeader.biPlanes = 1;
dib.bmiHeader.biBitCount = 32;
dib.bmiHeader.biCompression = BI_RGB;
@@ -719,13 +732,13 @@ bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const Q
WIZ_DTTOPTS dto;
dto.dwSize = sizeof(WIZ_DTTOPTS);
const UINT uFormat = WIZ_DT_SINGLELINE|WIZ_DT_CENTER|WIZ_DT_VCENTER|WIZ_DT_NOPREFIX;
- RECT rctext ={0,0, rect.width(), rect.height()};
+ RECT rctext ={0,0, rectDp.width(), rectDp.height()};
dto.dwFlags = WIZ_DTT_COMPOSITED|WIZ_DTT_GLOWSIZE;
dto.iGlowSize = glowSize();
pDrawThemeTextEx(hTheme, dcMem, 0, 0, (LPCWSTR)text.utf16(), -1, uFormat, &rctext, &dto );
- BitBlt(hdc, rect.left(), rect.top(), rect.width(), rect.height(), dcMem, 0, 0, SRCCOPY);
+ BitBlt(hdc, rectDp.left(), rectDp.top(), rectDp.width(), rectDp.height(), dcMem, 0, 0, SRCCOPY);
SelectObject(dcMem, (HGDIOBJ) hOldBmp);
SelectObject(dcMem, (HGDIOBJ) hOldFont);
DeleteObject(bmp);
@@ -743,6 +756,8 @@ bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc)
bool value = false;
if (vistaState() == VistaAero) {
// Set up a memory DC and bitmap that we'll draw into
+ const QRect rectDp = QRect(rect.topLeft() * QVistaHelper::m_devicePixelRatio,
+ rect.size() * QVistaHelper::m_devicePixelRatio);
HDC dcMem;
HBITMAP bmp;
BITMAPINFO dib;
@@ -750,8 +765,8 @@ bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc)
dcMem = CreateCompatibleDC(hdc);
dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- dib.bmiHeader.biWidth = rect.width();
- dib.bmiHeader.biHeight = -rect.height();
+ dib.bmiHeader.biWidth = rectDp.width();
+ dib.bmiHeader.biHeight = -rectDp.height();
dib.bmiHeader.biPlanes = 1;
dib.bmiHeader.biBitCount = 32;
dib.bmiHeader.biCompression = BI_RGB;
@@ -759,7 +774,7 @@ bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc)
bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp);
- BitBlt(hdc, rect.left(), rect.top(), rect.width(), rect.height(), dcMem, 0, 0, SRCCOPY);
+ BitBlt(hdc, rectDp.left(), rectDp.top(), rectDp.width(), rectDp.height(), dcMem, 0, 0, SRCCOPY);
SelectObject(dcMem, (HGDIOBJ) hOldBmp);
DeleteObject(bmp);
@@ -785,12 +800,12 @@ static inline int getWindowBottomMargin()
}
#endif // _MSC_VER >= 1700
-int QVistaHelper::frameSize()
+int QVistaHelper::frameSizeDp()
{
return getWindowBottomMargin();
}
-int QVistaHelper::captionSize()
+int QVistaHelper::captionSizeDp()
{
return GetSystemMetrics(SM_CYCAPTION);
}
@@ -846,6 +861,16 @@ int QVistaHelper::titleOffset()
return leftMargin() + iconOffset;
}
+int QVistaHelper::iconSize()
+{
+ return QStyleHelper::dpiScaled(16); // Standard Aero
+}
+
+int QVistaHelper::glowSize()
+{
+ return QStyleHelper::dpiScaled(10);
+}
+
int QVistaHelper::topOffset()
{
if (vistaState() != VistaAero)
diff --git a/src/widgets/dialogs/qwizard_win_p.h b/src/widgets/dialogs/qwizard_win_p.h
index 81514a8950..ac58e76a45 100644
--- a/src/widgets/dialogs/qwizard_win_p.h
+++ b/src/widgets/dialogs/qwizard_win_p.h
@@ -102,7 +102,8 @@ public:
QColor basicWindowFrameColor();
enum VistaState { VistaAero, VistaBasic, Classic, Dirty };
static VistaState vistaState();
- static int titleBarSize() { return frameSize() + captionSize(); }
+ static int titleBarSize() { return QVistaHelper::titleBarSizeDp() / QVistaHelper::m_devicePixelRatio; }
+ static int titleBarSizeDp() { return QVistaHelper::frameSizeDp() + QVistaHelper::captionSizeDp(); }
static int topPadding() { // padding under text
return int(QStyleHelper::dpiScaled(
QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS7 ? 4 : 6));
@@ -117,12 +118,14 @@ private:
bool drawTitleText(QPainter *painter, const QString &text, const QRect &rect, HDC hdc);
static bool drawBlackRect(const QRect &rect, HDC hdc);
- static int frameSize();
- static int captionSize();
+ static int frameSize() { return QVistaHelper::frameSizeDp() / QVistaHelper::m_devicePixelRatio; }
+ static int frameSizeDp();
+ static int captionSize() { return QVistaHelper::captionSizeDp() / QVistaHelper::m_devicePixelRatio; }
+ static int captionSizeDp();
static int backButtonSize() { return int(QStyleHelper::dpiScaled(30)); }
- static int iconSize() { return 16; } // Standard Aero
- static int glowSize() { return 10; }
+ static int iconSize();
+ static int glowSize();
int leftMargin() { return backButton_->isVisible() ? backButtonSize() + iconSpacing : 0; }
int titleOffset();
@@ -152,6 +155,7 @@ private:
int titleBarOffset; // Extra spacing above the text
int iconSpacing; // Space between button and icon
int textSpacing; // Space between icon and text
+ static int m_devicePixelRatio;
};
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp
index 4b59e72545..37dcede6e3 100644
--- a/src/widgets/itemviews/qabstractitemview.cpp
+++ b/src/widgets/itemviews/qabstractitemview.cpp
@@ -1370,6 +1370,15 @@ bool QAbstractItemView::tabKeyNavigation() const
return d->tabKeyNavigation;
}
+/*!
+ \since 5.2
+ \reimp
+*/
+QSize QAbstractItemView::viewportSizeHint() const
+{
+ return QAbstractScrollArea::viewportSizeHint();
+}
+
#ifndef QT_NO_DRAGANDDROP
/*!
\property QAbstractItemView::showDropIndicator
@@ -1391,15 +1400,6 @@ bool QAbstractItemView::showDropIndicator() const
}
/*!
- \since 5.2
- \reimp
-*/
-QSize QAbstractItemView::viewportSizeHint() const
-{
- return QAbstractScrollArea::viewportSizeHint();
-}
-
-/*!
\property QAbstractItemView::dragEnabled
\brief whether the view supports dragging of its own items
diff --git a/src/widgets/itemviews/qdatawidgetmapper.cpp b/src/widgets/itemviews/qdatawidgetmapper.cpp
index 76d01dbb2b..4158e00dfc 100644
--- a/src/widgets/itemviews/qdatawidgetmapper.cpp
+++ b/src/widgets/itemviews/qdatawidgetmapper.cpp
@@ -50,6 +50,8 @@
#include "private/qobject_p.h"
#include "private/qabstractitemmodel_p.h"
+#include <iterator>
+
QT_BEGIN_NAMESPACE
class QDataWidgetMapperPrivate: public QObjectPrivate
@@ -92,8 +94,8 @@ public:
inline void flipEventFilters(QAbstractItemDelegate *oldDelegate,
QAbstractItemDelegate *newDelegate)
{
- for (int i = 0; i < widgetMap.count(); ++i) {
- QWidget *w = widgetMap.at(i).widget;
+ for (QList<WidgetMapper>::const_iterator it = widgetMap.cbegin(), end = widgetMap.cend(); it != end; ++it) {
+ QWidget *w = it->widget;
if (!w)
continue;
w->removeEventFilter(oldDelegate);
@@ -132,9 +134,9 @@ public:
int QDataWidgetMapperPrivate::findWidget(QWidget *w) const
{
- for (int i = 0; i < widgetMap.count(); ++i) {
- if (widgetMap.at(i).widget == w)
- return i;
+ for (QList<WidgetMapper>::const_iterator it = widgetMap.cbegin(), end = widgetMap.cend(); it != end; ++it) {
+ if (it->widget == w)
+ return int(std::distance(widgetMap.cbegin(), it));
}
return -1;
}
@@ -171,8 +173,8 @@ void QDataWidgetMapperPrivate::populate(WidgetMapper &m)
void QDataWidgetMapperPrivate::populate()
{
- for (int i = 0; i < widgetMap.count(); ++i)
- populate(widgetMap[i]);
+ for (QList<WidgetMapper>::iterator it = widgetMap.begin(), end = widgetMap.end(); it != end; ++it)
+ populate(*it);
}
static bool qContainsIndex(const QModelIndex &idx, const QModelIndex &topLeft,
@@ -187,10 +189,9 @@ void QDataWidgetMapperPrivate::_q_dataChanged(const QModelIndex &topLeft, const
if (topLeft.parent() != rootIndex)
return; // not in our hierarchy
- for (int i = 0; i < widgetMap.count(); ++i) {
- WidgetMapper &m = widgetMap[i];
- if (qContainsIndex(m.currentIndex, topLeft, bottomRight))
- populate(m);
+ for (QList<WidgetMapper>::iterator it = widgetMap.begin(), end = widgetMap.end(); it != end; ++it) {
+ if (qContainsIndex(it->currentIndex, topLeft, bottomRight))
+ populate(*it);
}
}
@@ -582,9 +583,9 @@ QWidget *QDataWidgetMapper::mappedWidgetAt(int section) const
{
Q_D(const QDataWidgetMapper);
- for (int i = 0; i < d->widgetMap.count(); ++i) {
- if (d->widgetMap.at(i).section == section)
- return d->widgetMap.at(i).widget;
+ for (QList<QDataWidgetMapperPrivate::WidgetMapper>::const_iterator it = d->widgetMap.cbegin(), end = d->widgetMap.cend(); it != end; ++it) {
+ if (it->section == section)
+ return it->widget;
}
return 0;
@@ -621,9 +622,8 @@ bool QDataWidgetMapper::submit()
{
Q_D(QDataWidgetMapper);
- for (int i = 0; i < d->widgetMap.count(); ++i) {
- const QDataWidgetMapperPrivate::WidgetMapper &m = d->widgetMap.at(i);
- if (!d->commit(m))
+ for (QList<QDataWidgetMapperPrivate::WidgetMapper>::const_iterator it = d->widgetMap.cbegin(), end = d->widgetMap.cend(); it != end; ++it) {
+ if (!d->commit(*it))
return false;
}
@@ -762,10 +762,11 @@ void QDataWidgetMapper::clearMapping()
{
Q_D(QDataWidgetMapper);
- while (!d->widgetMap.isEmpty()) {
- QWidget *w = d->widgetMap.takeLast().widget;
- if (w)
- w->removeEventFilter(d->delegate);
+ QList<QDataWidgetMapperPrivate::WidgetMapper> copy;
+ d->widgetMap.swap(copy); // a C++98 move
+ for (std::reverse_iterator<QList<QDataWidgetMapperPrivate::WidgetMapper>::const_iterator> it(copy.cend()), end(copy.cbegin()); it != end; ++it) {
+ if (it->widget)
+ it->widget->removeEventFilter(d->delegate);
}
}
diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp
index 135f89d4ac..5706be4b6d 100644
--- a/src/widgets/itemviews/qlistview.cpp
+++ b/src/widgets/itemviews/qlistview.cpp
@@ -1846,14 +1846,44 @@ void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step)
{
horizontalScrollBar()->setSingleStep(step.width() + spacing());
horizontalScrollBar()->setPageStep(viewport()->width());
- horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
+
+ // If both scroll bars are set to auto, we might end up in a situation with enough space
+ // for the actual content. But still one of the scroll bars will become enabled due to
+ // the other one using the space. The other one will become invisible in the same cycle.
+ // -> Infinite loop, QTBUG-39902
+ const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
+ qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
+
+ if (bothScrollBarsAuto && contentsSize.width() - qq->verticalScrollBar()->width() <= viewport()->width()
+ && contentsSize.height() - qq->horizontalScrollBar()->height() <= viewport()->height()) {
+ // break the infinite loop described above by setting the range to 0, 0.
+ // QAbstractScrollArea will then hide the scroll bar for us
+ horizontalScrollBar()->setRange(0, 0);
+ } else {
+ horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
+ }
}
void QCommonListViewBase::updateVerticalScrollBar(const QSize &step)
{
verticalScrollBar()->setSingleStep(step.height() + spacing());
verticalScrollBar()->setPageStep(viewport()->height());
- verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
+
+ // If both scroll bars are set to auto, we might end up in a situation with enough space
+ // for the actual content. But still one of the scroll bars will become enabled due to
+ // the other one using the space. The other one will become invisible in the same cycle.
+ // -> Infinite loop, QTBUG-39902
+ const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded &&
+ qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded;
+
+ if (bothScrollBarsAuto && contentsSize.width() - qq->verticalScrollBar()->width() <= viewport()->width()
+ && contentsSize.height() - qq->horizontalScrollBar()->height() <= viewport()->height()) {
+ // break the infinite loop described above by setting the range to 0, 0.
+ // QAbstractScrollArea will then hide the scroll bar for us
+ verticalScrollBar()->setRange(0, 0);
+ } else {
+ verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
+ }
}
void QCommonListViewBase::scrollContentsBy(int dx, int dy, bool /*scrollElasticBand*/)
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 4818dd7eaa..f438f60e47 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -3326,6 +3326,15 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
{
QWidget* w = static_cast<QWidget *>(receiver);
QWheelEvent* wheel = static_cast<QWheelEvent*>(e);
+
+ // QTBUG-40656, combo and other popups should close when the main window gets a wheel event.
+ while (QWidget *popup = QApplication::activePopupWidget()) {
+ if (w->window() != popup)
+ popup->close();
+ else
+ break;
+ }
+
QPoint relpos = wheel->pos();
bool eventAccepted = wheel->isAccepted();
@@ -4343,7 +4352,16 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window,
}
Q_ASSERT(target.data() != 0);
- StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[static_cast<QWidget *>(target.data())];
+ QWidget *targetWidget = static_cast<QWidget *>(target.data());
+
+#ifdef Q_OS_OSX
+ // Single-touch events are normally not sent unless WA_TouchPadAcceptSingleTouchEvents is set.
+ // In Qt 4 this check was in OS X-only coode. That behavior is preserved here by the #ifdef.
+ if (touchPoints.count() == 1 && !targetWidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents))
+ continue;
+#endif
+
+ StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[targetWidget];
maskAndPoints.first |= touchPoint.state();
maskAndPoints.second.append(touchPoint);
}
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 57169edb9d..34adea866e 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -6569,6 +6569,11 @@ void QWidget::clearFocus()
QAccessible::updateAccessibility(&event);
#endif
}
+
+ if (QTLWExtra *extra = window()->d_func()->maybeTopData()) {
+ if (extra->window)
+ emit extra->window->focusObjectChanged(extra->window->focusObject());
+ }
}
}
@@ -7198,8 +7203,12 @@ QByteArray QWidget::saveGeometry() const
QDataStream stream(&array, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_4_0);
const quint32 magicNumber = 0x1D9D0CB;
+ // Version history:
+ // - Qt 4.2 - 4.8.6, 5.0 - 5.3 : Version 1.0
+ // - Qt 4.8.6 - today, 5.4 - today: Version 1.1, save screen width in addition to check for high DPI scaling.
quint16 majorVersion = 1;
- quint16 minorVersion = 0;
+ quint16 minorVersion = 1;
+ const int screenNumber = QApplication::desktop()->screenNumber(this);
stream << magicNumber
<< majorVersion
<< minorVersion
@@ -7210,9 +7219,10 @@ QByteArray QWidget::saveGeometry() const
<< frameGeometry()
<< normalGeometry()
#endif // Q_WS_MAC
- << qint32(QApplication::desktop()->screenNumber(this))
+ << qint32(screenNumber)
<< quint8(windowState() & Qt::WindowMaximized)
- << quint8(windowState() & Qt::WindowFullScreen);
+ << quint8(windowState() & Qt::WindowFullScreen)
+ << qint32(QApplication::desktop()->screenGeometry(screenNumber).width()); // 1.1 onwards
return array;
}
@@ -7267,6 +7277,7 @@ bool QWidget::restoreGeometry(const QByteArray &geometry)
qint32 restoredScreenNumber;
quint8 maximized;
quint8 fullScreen;
+ qint32 restoredScreenWidth = 0;
stream >> restoredFrameGeometry
>> restoredNormalGeometry
@@ -7274,6 +7285,24 @@ bool QWidget::restoreGeometry(const QByteArray &geometry)
>> maximized
>> fullScreen;
+ if (majorVersion > 1 || minorVersion >= 1)
+ stream >> restoredScreenWidth;
+
+ const QDesktopWidget * const desktop = QApplication::desktop();
+ const qreal screenWidthF = qreal(desktop->screenGeometry(restoredScreenNumber).width());
+ // Sanity check bailing out when large variations of screen sizes occur due to
+ // high DPI scaling or different levels of DPI awareness.
+ if (restoredScreenWidth) {
+ const qreal factor = qreal(restoredScreenWidth) / screenWidthF;
+ if (factor < 0.8 || factor > 1.25)
+ return false;
+ } else {
+ // Saved by Qt 5.3 and earlier, try to prevent too large windows
+ // unless the size will be adapted by maximized or fullscreen.
+ if (!maximized && !fullScreen && qreal(restoredFrameGeometry.width()) / screenWidthF > 1.5)
+ return false;
+ }
+
const int frameHeight = 20;
if (!restoredFrameGeometry.isValid())
restoredFrameGeometry = QRect(QPoint(0,0), sizeHint());
@@ -7287,7 +7316,6 @@ bool QWidget::restoreGeometry(const QByteArray &geometry)
.expandedTo(d_func()->adjustedSize()));
}
- const QDesktopWidget * const desktop = QApplication::desktop();
if (restoredScreenNumber >= desktop->numScreens())
restoredScreenNumber = desktop->primaryScreen();
diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp
index bb4518ec5e..2a968939e4 100644
--- a/src/widgets/kernel/qwidgetbackingstore.cpp
+++ b/src/widgets/kernel/qwidgetbackingstore.cpp
@@ -56,6 +56,7 @@
#include <private/qapplication_p.h>
#include <private/qpaintengine_raster_p.h>
#include <private/qgraphicseffect_p.h>
+#include <QtGui/private/qwindow_p.h>
#include <qpa/qplatformbackingstore.h>
@@ -1132,6 +1133,7 @@ void QWidgetBackingStore::doSync()
widgetTextures = new QPlatformTextureList;
findTextureWidgetsRecursively(tlw, tlw, widgetTextures);
}
+ qt_window_private(tlw->windowHandle())->compositing = widgetTextures && !widgetTextures->isEmpty();
fullUpdatePending = false;
#endif
diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h
index 87fd7656ea..a2de839404 100644
--- a/src/widgets/styles/qstyle.h
+++ b/src/widgets/styles/qstyle.h
@@ -66,6 +66,9 @@ class Q_WIDGETS_EXPORT QStyle : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QStyle)
+ Q_ENUMS(StateFlag PrimitiveElement ControlElement SubElement ComplexControl)
+ Q_ENUMS(SubControl PixelMetric ContentsType RequestSoftwareInputPanel StyleHint)
+ Q_ENUMS(StandardPixmap)
protected:
QStyle(QStylePrivate &dd);
diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp
index 43f5d6fd31..4aed153932 100644
--- a/src/widgets/widgets/qabstractspinbox.cpp
+++ b/src/widgets/widgets/qabstractspinbox.cpp
@@ -699,6 +699,7 @@ void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit)
}
d->updateEditFieldGeometry();
d->edit->setContextMenuPolicy(Qt::NoContextMenu);
+ d->edit->d_func()->control->setAccessibleObject(this);
if (isVisible())
d->edit->show();
diff --git a/src/widgets/widgets/qabstractspinbox.h b/src/widgets/widgets/qabstractspinbox.h
index 7989000cc8..5009e4151f 100644
--- a/src/widgets/widgets/qabstractspinbox.h
+++ b/src/widgets/widgets/qabstractspinbox.h
@@ -170,6 +170,7 @@ private:
Q_DECLARE_PRIVATE(QAbstractSpinBox)
Q_DISABLE_COPY(QAbstractSpinBox)
+ friend class QAccessibleAbstractSpinBox;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractSpinBox::StepEnabled)
diff --git a/src/widgets/widgets/qfontcombobox.cpp b/src/widgets/widgets/qfontcombobox.cpp
index db01543629..bdf5092d9e 100644
--- a/src/widgets/widgets/qfontcombobox.cpp
+++ b/src/widgets/widgets/qfontcombobox.cpp
@@ -53,6 +53,10 @@
#include <QDesktopWidget>
#include <qdebug.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformfontdatabase.h>
+
QT_BEGIN_NAMESPACE
static QFontDatabase::WritingSystem writingSystemFromScript(QLocale::Script script)
@@ -328,7 +332,12 @@ void QFontComboBoxPrivate::_q_updateModel()
int offset = 0;
QFontInfo fi(currentFont);
+ QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
+
for (int i = 0; i < list.size(); ++i) {
+ if (pfdb->isPrivateFontFamily(list.at(i)))
+ continue;
+
if ((filters & scalableMask) && (filters & scalableMask) != scalableMask) {
if (bool(filters & QFontComboBox::ScalableFonts) != fdb.isSmoothlyScalable(list.at(i)))
continue;
diff --git a/src/widgets/widgets/qwidgetanimator.cpp b/src/widgets/widgets/qwidgetanimator.cpp
index 1209ade536..a2d950c12b 100644
--- a/src/widgets/widgets/qwidgetanimator.cpp
+++ b/src/widgets/widgets/qwidgetanimator.cpp
@@ -41,6 +41,7 @@
#include <QtCore/qpropertyanimation.h>
#include <QtWidgets/qwidget.h>
+#include <QtWidgets/qstyle.h>
#include <private/qmainwindowlayout_p.h>
#include "qwidgetanimator_p.h"
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
index b927004773..569308f5c8 100644
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
@@ -737,15 +737,15 @@ void QWidgetLineControl::internalSetText(const QString &txt, int pos, bool edite
#ifndef QT_NO_ACCESSIBILITY
if (changed) {
if (oldText.isEmpty()) {
- QAccessibleTextInsertEvent event(parent(), 0, txt);
+ QAccessibleTextInsertEvent event(accessibleObject(), 0, txt);
event.setCursorPosition(m_cursor);
QAccessible::updateAccessibility(&event);
} else if (txt.isEmpty()) {
- QAccessibleTextRemoveEvent event(parent(), 0, oldText);
+ QAccessibleTextRemoveEvent event(accessibleObject(), 0, oldText);
event.setCursorPosition(m_cursor);
QAccessible::updateAccessibility(&event);
} else {
- QAccessibleTextUpdateEvent event(parent(), 0, oldText, txt);
+ QAccessibleTextUpdateEvent event(accessibleObject(), 0, oldText, txt);
event.setCursorPosition(m_cursor);
QAccessible::updateAccessibility(&event);
}
@@ -803,7 +803,7 @@ void QWidgetLineControl::internalInsert(const QString &s)
if (m_maskData) {
QString ms = maskString(m_cursor, s);
#ifndef QT_NO_ACCESSIBILITY
- QAccessibleTextInsertEvent insertEvent(parent(), m_cursor, ms);
+ QAccessibleTextInsertEvent insertEvent(accessibleObject(), m_cursor, ms);
QAccessible::updateAccessibility(&insertEvent);
#endif
for (int i = 0; i < (int) ms.length(); ++i) {
@@ -815,14 +815,14 @@ void QWidgetLineControl::internalInsert(const QString &s)
m_cursor = nextMaskBlank(m_cursor);
m_textDirty = true;
#ifndef QT_NO_ACCESSIBILITY
- QAccessibleTextCursorEvent event(parent(), m_cursor);
+ QAccessibleTextCursorEvent event(accessibleObject(), m_cursor);
QAccessible::updateAccessibility(&event);
#endif
} else {
int remaining = m_maxLength - m_text.length();
if (remaining != 0) {
#ifndef QT_NO_ACCESSIBILITY
- QAccessibleTextInsertEvent insertEvent(parent(), m_cursor, s);
+ QAccessibleTextInsertEvent insertEvent(accessibleObject(), m_cursor, s);
QAccessible::updateAccessibility(&insertEvent);
#endif
m_text.insert(m_cursor, s.left(remaining));
@@ -853,7 +853,7 @@ void QWidgetLineControl::internalDelete(bool wasBackspace)
addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
m_cursor, m_text.at(m_cursor), -1, -1));
#ifndef QT_NO_ACCESSIBILITY
- QAccessibleTextRemoveEvent event(parent(), m_cursor, m_text.at(m_cursor));
+ QAccessibleTextRemoveEvent event(accessibleObject(), m_cursor, m_text.at(m_cursor));
QAccessible::updateAccessibility(&event);
#endif
if (m_maskData) {
@@ -894,7 +894,7 @@ void QWidgetLineControl::removeSelectedText()
addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
}
#ifndef QT_NO_ACCESSIBILITY
- QAccessibleTextRemoveEvent event(parent(), m_selstart, m_text.mid(m_selstart, m_selend - m_selstart));
+ QAccessibleTextRemoveEvent event(accessibleObject(), m_selstart, m_text.mid(m_selstart, m_selend - m_selstart));
QAccessible::updateAccessibility(&event);
#endif
if (m_maskData) {
@@ -1384,7 +1384,7 @@ void QWidgetLineControl::emitCursorPositionChanged()
#ifndef QT_NO_ACCESSIBILITY
// otherwise we send a selection update which includes the cursor
if (!hasSelectedText()) {
- QAccessibleTextCursorEvent event(parent(), m_cursor);
+ QAccessibleTextCursorEvent event(accessibleObject(), m_cursor);
QAccessible::updateAccessibility(&event);
}
#endif
@@ -1678,7 +1678,7 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
}
}
else if (event == QKeySequence::Cut) {
- if (!isReadOnly()) {
+ if (!isReadOnly() && hasSelectedText()) {
copy();
del();
}
diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h
index ba73e9e25e..85eb1a0f8e 100644
--- a/src/widgets/widgets/qwidgetlinecontrol_p.h
+++ b/src/widgets/widgets/qwidgetlinecontrol_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QWidgetLineControl_P_H
-#define QWidgetLineControl_P_H
+#ifndef QWIDGETLINECONTROL_P_H
+#define QWIDGETLINECONTROL_P_H
//
// W A R N I N G
@@ -99,6 +99,7 @@ public:
, m_passwordMaskDelayOverride(-1)
#endif
, m_keyboardScheme(0)
+ , m_accessibleObject(0)
{
init(txt);
}
@@ -108,6 +109,19 @@ public:
delete [] m_maskData;
}
+ void setAccessibleObject(QObject *object)
+ {
+ Q_ASSERT(object);
+ m_accessibleObject = object;
+ }
+
+ QObject *accessibleObject()
+ {
+ if (m_accessibleObject)
+ return m_accessibleObject;
+ return parent();
+ }
+
int nextMaskBlank(int pos)
{
int c = findInMask(pos, true, false);
@@ -532,10 +546,13 @@ private Q_SLOTS:
private:
int m_keyboardScheme;
+
+ // accessibility events are sent for this object
+ QObject *m_accessibleObject;
};
QT_END_NAMESPACE
#endif // QT_NO_LINEEDIT
-#endif // QWidgetLineControl_P_H
+#endif // QWIDGETLINECONTROL_P_H
diff --git a/src/winmain/winmain.pro b/src/winmain/winmain.pro
index 284f2a2201..b891e4bce0 100644
--- a/src/winmain/winmain.pro
+++ b/src/winmain/winmain.pro
@@ -29,10 +29,7 @@ load(qt_installs)
TARGET = $$qtLibraryTarget($$TARGET$$QT_LIBINFIX) #do this towards the end
load(qt_targets)
+load(qt_build_paths)
+load(qt_common)
wince*:QMAKE_POST_LINK =
-
-lib_replace.match = $$[QT_INSTALL_LIBS/get]
-lib_replace.replace = $$[QT_INSTALL_LIBS/raw]
-lib_replace.CONFIG = path
-QMAKE_PRL_INSTALL_REPLACE += lib_replace