summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/generic/evdevkeyboard/CMakeLists.txt2
-rw-r--r--src/plugins/generic/evdevmouse/CMakeLists.txt2
-rw-r--r--src/plugins/generic/evdevtablet/CMakeLists.txt2
-rw-r--r--src/plugins/generic/evdevtouch/CMakeLists.txt2
-rw-r--r--src/plugins/generic/libinput/CMakeLists.txt2
-rw-r--r--src/plugins/generic/tslib/CMakeLists.txt2
-rw-r--r--src/plugins/generic/tuiotouch/CMakeLists.txt2
-rw-r--r--src/plugins/imageformats/gif/CMakeLists.txt2
-rw-r--r--src/plugins/imageformats/ico/CMakeLists.txt2
-rw-r--r--src/plugins/imageformats/jpeg/CMakeLists.txt4
-rw-r--r--src/plugins/networkinformation/android/CMakeLists.txt4
-rw-r--r--src/plugins/networkinformation/networklistmanager/CMakeLists.txt8
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp7
-rw-r--r--src/plugins/networkinformation/networkmanager/CMakeLists.txt6
-rw-r--r--src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt6
-rw-r--r--src/plugins/platforminputcontexts/compose/CMakeLists.txt2
-rw-r--r--src/plugins/platforminputcontexts/ibus/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/android/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/android/extract-dummy.cpp8
-rw-r--r--src/plugins/platforms/android/extract.cpp21
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp13
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.h1
-rw-r--r--src/plugins/platforms/android/qandroidplatformservices.cpp37
-rw-r--r--src/plugins/platforms/android/qandroidplatformservices.h14
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.cpp10
-rw-r--r--src/plugins/platforms/android/qandroidsystemlocale.cpp12
-rw-r--r--src/plugins/platforms/cocoa/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h42
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm46
-rw-r--r--src/plugins/platforms/cocoa/qcocoainputcontext.h11
-rw-r--r--src/plugins/platforms/cocoa/qcocoainputcontext.mm68
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h8
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm39
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm23
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm9
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm115
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm106
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h1
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm42
-rw-r--r--src/plugins/platforms/cocoa/qnsview_complextext.mm666
-rw-r--r--src/plugins/platforms/cocoa/qnsview_keys.mm305
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm181
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm50
-rw-r--r--src/plugins/platforms/direct2d/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/directfb/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/eglfs/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/ios/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt7
-rw-r--r--src/plugins/platforms/ios/qiosservices.mm10
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.mm5
-rw-r--r--src/plugins/platforms/ios/quiview.mm7
-rw-r--r--src/plugins/platforms/ios/uistrings.cpp51
-rw-r--r--src/plugins/platforms/ios/uistrings_p.h66
-rw-r--r--src/plugins/platforms/linuxfb/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/minimal/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/minimalegl/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/offscreen/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.cpp38
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.h9
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp212
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.h15
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp14
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_x11.h2
-rw-r--r--src/plugins/platforms/qnx/CMakeLists.txt10
-rw-r--r--src/plugins/platforms/vkkhrdisplay/CMakeLists.txt6
-rw-r--r--src/plugins/platforms/vnc/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt37
-rw-r--r--src/plugins/platforms/wasm/qtloader.js75
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.cpp25
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.cpp10
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.cpp22
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.h2
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp24
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h1
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp8
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.h4
-rw-r--r--src/plugins/platforms/wasm/qwasmstring.cpp4
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp5
-rw-r--r--src/plugins/platforms/windows/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp108
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h4
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp5
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h3
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp45
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp17
-rw-r--r--src/plugins/platforms/xcb/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp42
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h11
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_basic.cpp5
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_basic.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_screens.cpp392
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp1
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp15
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h11
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp137
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h19
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp115
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h16
-rw-r--r--src/plugins/platformthemes/gtk3/CMakeLists.txt2
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt2
-rw-r--r--src/plugins/printsupport/cups/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/.cmake.conf2
-rw-r--r--src/plugins/sqldrivers/db2/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/ibase/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/mysql/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/mysql/qsql_mysql.cpp132
-rw-r--r--src/plugins/sqldrivers/oci/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/oci/qsql_oci.cpp126
-rw-r--r--src/plugins/sqldrivers/odbc/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/psql/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/sqlite/CMakeLists.txt9
-rw-r--r--src/plugins/styles/android/CMakeLists.txt2
-rw-r--r--src/plugins/styles/mac/CMakeLists.txt2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm130
-rw-r--r--src/plugins/styles/windowsvista/CMakeLists.txt2
-rw-r--r--src/plugins/styles/windowsvista/qwindowsvistastyle.cpp19
-rw-r--r--src/plugins/styles/windowsvista/qwindowsxpstyle.cpp8
-rw-r--r--src/plugins/tls/certonly/CMakeLists.txt6
-rw-r--r--src/plugins/tls/certonly/qtlsbackend_cert.cpp2
-rw-r--r--src/plugins/tls/openssl/CMakeLists.txt9
-rw-r--r--src/plugins/tls/openssl/qdtls_openssl.cpp9
-rw-r--r--src/plugins/tls/openssl/qdtls_openssl_p.h2
-rw-r--r--src/plugins/tls/openssl/qsslcontext_openssl.cpp50
-rw-r--r--src/plugins/tls/openssl/qsslcontext_openssl_p.h7
-rw-r--r--src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp51
-rw-r--r--src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp196
-rw-r--r--src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h126
-rw-r--r--src/plugins/tls/openssl/qtls_openssl.cpp29
-rw-r--r--src/plugins/tls/openssl/qtls_openssl_p.h6
-rw-r--r--src/plugins/tls/openssl/qtlsbackend_openssl.cpp67
-rw-r--r--src/plugins/tls/openssl/qtlsbackend_openssl_p.h2
-rw-r--r--src/plugins/tls/openssl/qtlskey_openssl.cpp144
-rw-r--r--src/plugins/tls/openssl/qtlskey_openssl_p.h9
-rw-r--r--src/plugins/tls/openssl/qx509_openssl.cpp65
-rw-r--r--src/plugins/tls/schannel/CMakeLists.txt9
-rw-r--r--src/plugins/tls/schannel/qtls_schannel.cpp117
-rw-r--r--src/plugins/tls/schannel/qtlsbackend_schannel_p.h2
-rw-r--r--src/plugins/tls/schannel/qtlskey_schannel.cpp11
-rw-r--r--src/plugins/tls/securetransport/CMakeLists.txt7
-rw-r--r--src/plugins/tls/securetransport/qtls_st.cpp97
-rw-r--r--src/plugins/tls/securetransport/qtlsbackend_st.cpp5
-rw-r--r--src/plugins/tls/securetransport/qtlsbackend_st_p.h2
-rw-r--r--src/plugins/tls/shared/qdtls_base.cpp3
-rw-r--r--src/plugins/tls/shared/qsslsocket_mac_shared.cpp10
-rw-r--r--src/plugins/tls/shared/qsslsocket_qt.cpp8
-rw-r--r--src/plugins/tls/shared/qtlskey_generic.cpp4
-rw-r--r--src/plugins/tls/shared/qx509_generic.cpp2
169 files changed, 3294 insertions, 1852 deletions
diff --git a/src/plugins/generic/evdevkeyboard/CMakeLists.txt b/src/plugins/generic/evdevkeyboard/CMakeLists.txt
index 7134a2d858..1568ac82cb 100644
--- a/src/plugins/generic/evdevkeyboard/CMakeLists.txt
+++ b/src/plugins/generic/evdevkeyboard/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEvdevKeyboardPlugin
OUTPUT_NAME qevdevkeyboardplugin
- TYPE generic
+ PLUGIN_TYPE generic
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/generic/evdevmouse/CMakeLists.txt b/src/plugins/generic/evdevmouse/CMakeLists.txt
index 78cf80f588..f467f631f5 100644
--- a/src/plugins/generic/evdevmouse/CMakeLists.txt
+++ b/src/plugins/generic/evdevmouse/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEvdevMousePlugin
OUTPUT_NAME qevdevmouseplugin
- TYPE generic
+ PLUGIN_TYPE generic
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/generic/evdevtablet/CMakeLists.txt b/src/plugins/generic/evdevtablet/CMakeLists.txt
index 880090dd02..4f39c1be87 100644
--- a/src/plugins/generic/evdevtablet/CMakeLists.txt
+++ b/src/plugins/generic/evdevtablet/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEvdevTabletPlugin
OUTPUT_NAME qevdevtabletplugin
- TYPE generic
+ PLUGIN_TYPE generic
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/generic/evdevtouch/CMakeLists.txt b/src/plugins/generic/evdevtouch/CMakeLists.txt
index d15367c6c2..4b90efbd69 100644
--- a/src/plugins/generic/evdevtouch/CMakeLists.txt
+++ b/src/plugins/generic/evdevtouch/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEvdevTouchScreenPlugin
OUTPUT_NAME qevdevtouchplugin
- TYPE generic
+ PLUGIN_TYPE generic
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/generic/libinput/CMakeLists.txt b/src/plugins/generic/libinput/CMakeLists.txt
index 79da268510..bf423c601d 100644
--- a/src/plugins/generic/libinput/CMakeLists.txt
+++ b/src/plugins/generic/libinput/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QLibInputPlugin
OUTPUT_NAME qlibinputplugin
- TYPE generic
+ PLUGIN_TYPE generic
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/generic/tslib/CMakeLists.txt b/src/plugins/generic/tslib/CMakeLists.txt
index 9a6e368825..42d6f59b13 100644
--- a/src/plugins/generic/tslib/CMakeLists.txt
+++ b/src/plugins/generic/tslib/CMakeLists.txt
@@ -8,7 +8,7 @@ qt_find_package(Tslib) # special case
qt_internal_add_plugin(QTsLibPlugin
OUTPUT_NAME qtslibplugin
- TYPE generic
+ PLUGIN_TYPE generic
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/generic/tuiotouch/CMakeLists.txt b/src/plugins/generic/tuiotouch/CMakeLists.txt
index b572b140b4..8271216182 100644
--- a/src/plugins/generic/tuiotouch/CMakeLists.txt
+++ b/src/plugins/generic/tuiotouch/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QTuioTouchPlugin
OUTPUT_NAME qtuiotouchplugin
- TYPE generic
+ PLUGIN_TYPE generic
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/imageformats/gif/CMakeLists.txt b/src/plugins/imageformats/gif/CMakeLists.txt
index 1ffd702f85..fc9d013e75 100644
--- a/src/plugins/imageformats/gif/CMakeLists.txt
+++ b/src/plugins/imageformats/gif/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QGifPlugin
OUTPUT_NAME qgif
- TYPE imageformats
+ PLUGIN_TYPE imageformats
SOURCES
main.cpp main.h
qgifhandler.cpp qgifhandler_p.h
diff --git a/src/plugins/imageformats/ico/CMakeLists.txt b/src/plugins/imageformats/ico/CMakeLists.txt
index 2d1dc38e17..4d6f765e5a 100644
--- a/src/plugins/imageformats/ico/CMakeLists.txt
+++ b/src/plugins/imageformats/ico/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QICOPlugin
OUTPUT_NAME qico
- TYPE imageformats
+ PLUGIN_TYPE imageformats
SOURCES
main.cpp main.h
qicohandler.cpp qicohandler.h
diff --git a/src/plugins/imageformats/jpeg/CMakeLists.txt b/src/plugins/imageformats/jpeg/CMakeLists.txt
index f0f910d9fd..54c6441a14 100644
--- a/src/plugins/imageformats/jpeg/CMakeLists.txt
+++ b/src/plugins/imageformats/jpeg/CMakeLists.txt
@@ -8,7 +8,7 @@ qt_find_package(JPEG) # special case
qt_internal_add_plugin(QJpegPlugin
OUTPUT_NAME qjpeg
- TYPE imageformats
+ PLUGIN_TYPE imageformats
SOURCES
main.cpp main.h
qjpeghandler.cpp qjpeghandler_p.h
@@ -33,7 +33,7 @@ endif()
#####################################################################
qt_internal_extend_target(QJpegPlugin CONDITION QT_FEATURE_system_jpeg
- PUBLIC_LIBRARIES
+ LIBRARIES
JPEG::JPEG
)
diff --git a/src/plugins/networkinformation/android/CMakeLists.txt b/src/plugins/networkinformation/android/CMakeLists.txt
index f1d260547a..0883ec74e2 100644
--- a/src/plugins/networkinformation/android/CMakeLists.txt
+++ b/src/plugins/networkinformation/android/CMakeLists.txt
@@ -15,9 +15,9 @@ install_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetworkInformationBackend
)
qt_internal_add_plugin(QAndroidNetworkInformationPlugin
- OUTPUT_NAME androidnetworkinformation
+ OUTPUT_NAME qandroidnetworkinformation
CLASS_NAME QAndroidNetworkInformationBackendFactory
- TYPE networkinformation
+ PLUGIN_TYPE networkinformation
DEFAULT_IF ANDROID
SOURCES
qandroidnetworkinformationbackend.cpp
diff --git a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
index 52f19aefa9..170bce0f7b 100644
--- a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
+++ b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
@@ -1,10 +1,10 @@
qt_internal_add_plugin(QNLMNIPlugin
- OUTPUT_NAME networklistmanager
+ OUTPUT_NAME qnetworklistmanager
CLASS_NAME QNetworkListManagerNetworkInformationBackendFactory
- TYPE networkinformation
- DEFAULT_IF WINDOWS AND QT_FEATURE_networklistmanager
+ PLUGIN_TYPE networkinformation
+ DEFAULT_IF WIN32 AND QT_FEATURE_networklistmanager
SOURCES qnetworklistmanagernetworkinformationbackend.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::NetworkPrivate
)
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
index d37f83832b..5157b778b9 100644
--- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
@@ -252,7 +252,7 @@ QNetworkListManagerEvents::ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
{
// This function is run on a different thread than 'monitor' is created on, so we need to run
// it on that thread
- connectivityChanged(newConnectivity);
+ emit connectivityChanged(newConnectivity);
return S_OK;
}
@@ -272,11 +272,10 @@ bool QNetworkListManagerEvents::start()
// Update connectivity since it might have changed since this class was constructed
NLM_CONNECTIVITY connectivity;
hr = networkListManager->GetConnectivity(&connectivity);
- if (FAILED(hr)) {
+ if (FAILED(hr))
qCWarning(lcNetInfoNLM) << "Could not get connectivity:" << errorStringFromHResult(hr);
- } else {
+ else
emit connectivityChanged(connectivity);
- }
return true;
}
diff --git a/src/plugins/networkinformation/networkmanager/CMakeLists.txt b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
index 900364c32f..5fc69f2d55 100644
--- a/src/plugins/networkinformation/networkmanager/CMakeLists.txt
+++ b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
@@ -1,13 +1,13 @@
qt_internal_add_plugin(QNetworkManagerNetworkInformationPlugin
- OUTPUT_NAME networkmanager
+ OUTPUT_NAME qnetworkmanager
CLASS_NAME QNetworkManagerNetworkInformationBackendFactory
- TYPE networkinformation
+ PLUGIN_TYPE networkinformation
DEFAULT_IF LINUX
SOURCES
qnetworkmanagernetworkinformationbackend.cpp
qnetworkmanagerservice.h
qnetworkmanagerservice.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::DBus
Qt::NetworkPrivate
)
diff --git a/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
index 87ca1f0a6d..c9ee7d9a42 100644
--- a/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
+++ b/src/plugins/networkinformation/scnetworkreachability/CMakeLists.txt
@@ -1,11 +1,11 @@
qt_internal_add_plugin(QSCNetworkReachabilityNetworkInformationPlugin
- OUTPUT_NAME scnetworkreachability
+ OUTPUT_NAME qscnetworkreachability
CLASS_NAME QSCNetworkReachabilityNetworkInformationBackendFactory
- TYPE networkinformation
+ PLUGIN_TYPE networkinformation
DEFAULT_IF APPLE
SOURCES
qscnetworkreachabilitynetworkinformationbackend.mm
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::NetworkPrivate
${FWSystemConfiguration}
)
diff --git a/src/plugins/platforminputcontexts/compose/CMakeLists.txt b/src/plugins/platforminputcontexts/compose/CMakeLists.txt
index fe14de36f4..e3fbf913b9 100644
--- a/src/plugins/platforminputcontexts/compose/CMakeLists.txt
+++ b/src/plugins/platforminputcontexts/compose/CMakeLists.txt
@@ -9,7 +9,7 @@ pkg_get_variable(PKG_X11_PREFIX x11 prefix) # special case
qt_internal_add_plugin(QComposePlatformInputContextPlugin
OUTPUT_NAME composeplatforminputcontextplugin
- TYPE platforminputcontexts
+ PLUGIN_TYPE platforminputcontexts
DEFAULT_IF FALSE
SOURCES
qcomposeplatforminputcontext.cpp qcomposeplatforminputcontext.h
diff --git a/src/plugins/platforminputcontexts/ibus/CMakeLists.txt b/src/plugins/platforminputcontexts/ibus/CMakeLists.txt
index 6d6de4fe8b..7ccc627eb1 100644
--- a/src/plugins/platforminputcontexts/ibus/CMakeLists.txt
+++ b/src/plugins/platforminputcontexts/ibus/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QIbusPlatformInputContextPlugin
OUTPUT_NAME ibusplatforminputcontextplugin
- TYPE platforminputcontexts
+ PLUGIN_TYPE platforminputcontexts
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/platforms/CMakeLists.txt b/src/plugins/platforms/CMakeLists.txt
index 8081f0a82e..ba64b6b0f5 100644
--- a/src/plugins/platforms/CMakeLists.txt
+++ b/src/plugins/platforms/CMakeLists.txt
@@ -1,6 +1,6 @@
# Generated from platforms.pro.
-if(ANDROID AND NOT ANDROID_EMBEDDED)
+if(ANDROID)
add_subdirectory(android)
endif()
if(NOT ANDROID AND NOT WASM)
diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt
index af9b7429b6..416e25c28a 100644
--- a/src/plugins/platforms/android/CMakeLists.txt
+++ b/src/plugins/platforms/android/CMakeLists.txt
@@ -7,7 +7,7 @@ qt_find_package(EGL) # special case
qt_internal_add_plugin(QAndroidIntegrationPlugin
OUTPUT_NAME qtforandroid
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES android # special case
SOURCES
androidcontentfileengine.cpp androidcontentfileengine.h
@@ -45,7 +45,7 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin
QT_USE_QSTRINGBUILDER
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
- ${QT_SOURCE_TREE}/src/3rdparty/android
+ ${QtBase_SOURCE_DIR}/src/3rdparty/android
LIBRARIES
EGL::EGL
Qt::Core
diff --git a/src/plugins/platforms/android/extract-dummy.cpp b/src/plugins/platforms/android/extract-dummy.cpp
index bfc0dafd04..43c03792d4 100644
--- a/src/plugins/platforms/android/extract-dummy.cpp
+++ b/src/plugins/platforms/android/extract-dummy.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -45,9 +45,3 @@ Java_org_qtproject_qt_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv *, jo
{
return 0;
}
-
-extern "C" JNIEXPORT jintArray JNICALL
-Java_org_qtproject_qt_android_ExtractStyle_extractChunkInfo20(JNIEnv *, jobject, jbyteArray)
-{
- return 0;
-}
diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp
index cad54d580b..4566d2ac69 100644
--- a/src/plugins/platforms/android/extract.cpp
+++ b/src/plugins/platforms/android/extract.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
** Contact: https://www.qt.io/licensing/
**
@@ -126,26 +127,6 @@ Java_org_qtproject_qt_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv *env,
return result;
}
-extern "C" JNIEXPORT jintArray JNICALL
-Java_org_qtproject_qt_android_ExtractStyle_extractChunkInfo20(JNIEnv *env, jobject obj,
- jbyteArray chunkObj)
-{
- size_t chunkSize = env->GetArrayLength(chunkObj);
- void* storage = alloca(chunkSize);
- env->GetByteArrayRegion(chunkObj, 0, chunkSize,
- reinterpret_cast<jbyte*>(storage));
-
- if (QJniEnvironment::checkAndClearExceptions(env))
- return 0;
-
- jintArray res = Java_org_qtproject_qt_android_ExtractStyle_extractNativeChunkInfo20(env, obj,
- long(storage));
- if (QJniEnvironment::checkAndClearExceptions(env))
- res = nullptr;
-
- return res;
-}
-
static inline void fill9patchOffsets(Res_png_9patch20* patch) {
patch->xDivsOffset = sizeof(Res_png_9patch20);
patch->yDivsOffset = patch->xDivsOffset + (patch->numXDivs * sizeof(int32_t));
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 7b4102fac6..c9ef977816 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -143,6 +143,19 @@ void *QAndroidPlatformNativeInterface::nativeResourceForWindow(const QByteArray
return nullptr;
}
+void *QAndroidPlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
+{
+ if (QEGLPlatformContext *platformContext = static_cast<QEGLPlatformContext *>(context->handle())) {
+ if (resource == "eglcontext")
+ return platformContext->eglContext();
+ else if (resource == "eglconfig")
+ return platformContext->eglConfig();
+ else if (resource == "egldisplay")
+ return platformContext->eglDisplay();
+ }
+ return nullptr;
+}
+
void QAndroidPlatformNativeInterface::customEvent(QEvent *event)
{
if (event->type() != QEvent::User)
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h
index d579bc29ae..52442e87af 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.h
+++ b/src/plugins/platforms/android/qandroidplatformintegration.h
@@ -65,6 +65,7 @@ class QAndroidPlatformNativeInterface: public QPlatformNativeInterface
public:
void *nativeResourceForIntegration(const QByteArray &resource) override;
void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
+ void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override;
std::shared_ptr<AndroidStyle> m_androidStyle;
protected:
diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp
index 36e1aef609..8c2af5fff4 100644
--- a/src/plugins/platforms/android/qandroidplatformservices.cpp
+++ b/src/plugins/platforms/android/qandroidplatformservices.cpp
@@ -41,16 +41,32 @@
#include "qandroidplatformservices.h"
#include <QDebug>
+#include <QDesktopServices>
#include <QFile>
#include <QMimeDatabase>
-#include <QUrl>
#include <QtCore/QJniObject>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qscopedvaluerollback.h>
QT_BEGIN_NAMESPACE
QAndroidPlatformServices::QAndroidPlatformServices()
{
+ m_actionView = QJniObject::getStaticObjectField("android/content/Intent", "ACTION_VIEW",
+ "Ljava/lang/String;")
+ .toString();
+
+ QtAndroidPrivate::registerNewIntentListener(this);
+
+ QMetaObject::invokeMethod(
+ this,
+ [this] {
+ QJniObject context = QJniObject(QtAndroidPrivate::context());
+ QJniObject intent =
+ context.callObjectMethod("getIntent", "()Landroid/content/Intent;");
+ handleNewIntent(nullptr, intent.object());
+ },
+ Qt::QueuedConnection);
}
bool QAndroidPlatformServices::openUrl(const QUrl &theUrl)
@@ -58,6 +74,10 @@ bool QAndroidPlatformServices::openUrl(const QUrl &theUrl)
QString mime;
QUrl url(theUrl);
+ // avoid recursing back into self
+ if (url == m_handlingUrl)
+ return false;
+
// if the file is local, we need to pass the MIME type, otherwise Android
// does not start an Intent to view this file
QLatin1String fileScheme("file");
@@ -87,4 +107,19 @@ QByteArray QAndroidPlatformServices::desktopEnvironment() const
return QByteArray("Android");
}
+bool QAndroidPlatformServices::handleNewIntent(JNIEnv *env, jobject intent)
+{
+ Q_UNUSED(env);
+
+ const QJniObject jniIntent(intent);
+
+ const QString action = jniIntent.callObjectMethod<jstring>("getAction").toString();
+ if (action != m_actionView)
+ return false;
+
+ const QString url = jniIntent.callObjectMethod<jstring>("getDataString").toString();
+ QScopedValueRollback<QUrl> rollback(m_handlingUrl, url);
+ return QDesktopServices::openUrl(url);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformservices.h b/src/plugins/platforms/android/qandroidplatformservices.h
index 6f2f0a394f..dff132d56d 100644
--- a/src/plugins/platforms/android/qandroidplatformservices.h
+++ b/src/plugins/platforms/android/qandroidplatformservices.h
@@ -42,16 +42,28 @@
#include <qpa/qplatformservices.h>
#include "androidjnimain.h"
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qobject.h>
+#include <QUrl>
QT_BEGIN_NAMESPACE
-class QAndroidPlatformServices: public QPlatformServices
+class QAndroidPlatformServices : public QObject,
+ public QPlatformServices,
+ public QtAndroidPrivate::NewIntentListener
{
public:
QAndroidPlatformServices();
+
bool openUrl(const QUrl &url) override;
bool openDocument(const QUrl &url) override;
QByteArray desktopEnvironment() const override;
+
+ bool handleNewIntent(JNIEnv *env, jobject intent) override;
+
+private:
+ QUrl m_handlingUrl;
+ QString m_actionView;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp
index 30a967cc26..c79b1836bc 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.cpp
+++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp
@@ -187,21 +187,17 @@ static void setPaletteColor(const QVariantMap &object,
QJsonObject AndroidStyle::loadStyleData()
{
- QString stylePath(QLatin1String(qgetenv("MINISTRO_ANDROID_STYLE_PATH")));
+ QString stylePath(QLatin1String(qgetenv("ANDROID_STYLE_PATH")));
const QLatin1Char slashChar('/');
if (!stylePath.isEmpty() && !stylePath.endsWith(slashChar))
stylePath += slashChar;
+ Q_ASSERT(!stylePath.isEmpty());
+
QString androidTheme = QLatin1String(qgetenv("QT_ANDROID_THEME"));
if (!androidTheme.isEmpty() && !androidTheme.endsWith(slashChar))
androidTheme += slashChar;
- if (stylePath.isEmpty()) {
- stylePath = QLatin1String("/data/data/org.kde.necessitas.ministro/files/dl/style/")
- + QLatin1String(qgetenv("QT_ANDROID_THEME_DISPLAY_DPI")) + slashChar;
- }
- Q_ASSERT(!stylePath.isEmpty());
-
if (!androidTheme.isEmpty() && QFileInfo::exists(stylePath + androidTheme + QLatin1String("style.json")))
stylePath += androidTheme;
diff --git a/src/plugins/platforms/android/qandroidsystemlocale.cpp b/src/plugins/platforms/android/qandroidsystemlocale.cpp
index 351274a560..74a549454d 100644
--- a/src/plugins/platforms/android/qandroidsystemlocale.cpp
+++ b/src/plugins/platforms/android/qandroidsystemlocale.cpp
@@ -105,14 +105,26 @@ QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const
return m_locale.dayName(in.toInt(), QLocale::LongFormat);
case DayNameShort:
return m_locale.dayName(in.toInt(), QLocale::ShortFormat);
+ case DayNameNarrow:
+ return m_locale.dayName(in.toInt(), QLocale::NarrowFormat);
+ case StandaloneDayNameLong:
+ return m_locale.standaloneDayName(in.toInt(), QLocale::LongFormat);
+ case StandaloneDayNameShort:
+ return m_locale.standaloneDayName(in.toInt(), QLocale::ShortFormat);
+ case StandaloneDayNameNarrow:
+ return m_locale.standaloneDayName(in.toInt(), QLocale::NarrowFormat);
case MonthNameLong:
return m_locale.monthName(in.toInt(), QLocale::LongFormat);
case MonthNameShort:
return m_locale.monthName(in.toInt(), QLocale::ShortFormat);
+ case MonthNameNarrow:
+ return m_locale.monthName(in.toInt(), QLocale::NarrowFormat);
case StandaloneMonthNameLong:
return m_locale.standaloneMonthName(in.toInt(), QLocale::LongFormat);
case StandaloneMonthNameShort:
return m_locale.standaloneMonthName(in.toInt(), QLocale::ShortFormat);
+ case StandaloneMonthNameNarrow:
+ return m_locale.standaloneMonthName(in.toInt(), QLocale::NarrowFormat);
case DateToStringLong:
return m_locale.toString(in.toDate(), QLocale::LongFormat);
case DateToStringShort:
diff --git a/src/plugins/platforms/cocoa/CMakeLists.txt b/src/plugins/platforms/cocoa/CMakeLists.txt
index 62eaad8e02..21f87dae83 100644
--- a/src/plugins/platforms/cocoa/CMakeLists.txt
+++ b/src/plugins/platforms/cocoa/CMakeLists.txt
@@ -9,7 +9,7 @@
qt_internal_add_plugin(QCocoaIntegrationPlugin
OUTPUT_NAME qcocoa
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES cocoa # special case
- TYPE platforms
+ PLUGIN_TYPE platforms
SOURCES
main.mm
qcocoaapplication.h qcocoaapplication.mm
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 82ebc65880..9e26f93b9d 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -247,7 +247,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return iface->text(QAccessible::Name).toNSString();
}
-- (BOOL) accessibilityEnabledAttribute {
+- (BOOL) isAccessibilityEnabled {
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (!iface || !iface->isValid())
return false;
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index e25eff740f..0fa868c73f 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -71,9 +71,12 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow)
Q_DECLARE_LOGGING_CATEGORY(lcQpaDrawing)
Q_DECLARE_LOGGING_CATEGORY(lcQpaMouse)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaKeys)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods)
Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
Q_DECLARE_LOGGING_CATEGORY(lcQpaApplication)
Q_DECLARE_LOGGING_CATEGORY(lcQpaClipboard)
+Q_DECLARE_LOGGING_CATEGORY(lcInputDevices)
class QPixmap;
class QString;
@@ -357,6 +360,45 @@ QSendSuperHelper<Args...> qt_objcDynamicSuperHelper(id receiver, SEL selector, A
// Same as calling super, but the super_class field resolved at runtime instead of compile time
#define qt_objcDynamicSuper(...) qt_objcDynamicSuperHelper(self, _cmd, ##__VA_ARGS__)
+// -------------------------------------------------------------------------
+
+struct InputMethodQueryResult : public QHash<Qt::InputMethodQuery, QVariant>
+{
+ operator bool() { return !isEmpty(); }
+};
+
+InputMethodQueryResult queryInputMethod(QObject *object, Qt::InputMethodQueries queries = Qt::ImEnabled);
+
+// -------------------------------------------------------------------------
+
+struct KeyEvent
+{
+ ulong timestamp = 0;
+ QEvent::Type type = QEvent::None;
+
+ Qt::Key key = Qt::Key_unknown;
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+ QString text;
+ bool isRepeat = false;
+
+ // Scan codes are hardware dependent codes for each key. There is no way to get these
+ // from Carbon or Cocoa, so leave it 0, as documented in QKeyEvent::nativeScanCode().
+ static const quint32 nativeScanCode = 0;
+
+ quint32 nativeVirtualKey = 0;
+ NSEventModifierFlags nativeModifiers = 0;
+
+ KeyEvent(NSEvent *nsevent);
+ bool sendWindowSystemEvent(QWindow *window) const;
+};
+
+QDebug operator<<(QDebug debug, const KeyEvent &e);
+
+// -------------------------------------------------------------------------
+
+QDebug operator<<(QDebug, const NSRange &);
+QDebug operator<<(QDebug, SEL);
+
#endif // __OBJC__
#endif //QCOCOAHELPERS_H
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index a3535b25f3..deede36ac0 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -58,9 +58,12 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
Q_LOGGING_CATEGORY(lcQpaDrawing, "qt.qpa.drawing");
Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse", QtCriticalMsg);
+Q_LOGGING_CATEGORY(lcQpaKeys, "qt.qpa.input.keys", QtCriticalMsg);
+Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods")
Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen", QtCriticalMsg);
Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application");
Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard")
+Q_LOGGING_CATEGORY(lcInputDevices, "qt.qpa.input.devices")
//
// Conversion Functions
@@ -492,6 +495,8 @@ QT_END_NAMESPACE
[super layout];
}
+@end // QNSPanelContentsWrapper
+
// -------------------------------------------------------------------------
io_object_t q_IOObjectRetain(io_object_t obj)
@@ -507,4 +512,43 @@ void q_IOObjectRelease(io_object_t obj)
Q_ASSERT(!ret);
}
-@end
+// -------------------------------------------------------------------------
+
+InputMethodQueryResult queryInputMethod(QObject *object, Qt::InputMethodQueries queries)
+{
+ if (object) {
+ QInputMethodQueryEvent queryEvent(queries | Qt::ImEnabled);
+ if (QCoreApplication::sendEvent(object, &queryEvent)) {
+ if (queryEvent.value(Qt::ImEnabled).toBool()) {
+ InputMethodQueryResult result;
+ static QMetaEnum queryEnum = QMetaEnum::fromType<Qt::InputMethodQuery>();
+ for (int i = 0; i < queryEnum.keyCount(); ++i) {
+ auto query = Qt::InputMethodQuery(queryEnum.value(i));
+ if (queries & query)
+ result.insert(query, queryEvent.value(query));
+ }
+ return result;
+ }
+ }
+ }
+ return {};
+}
+
+// -------------------------------------------------------------------------
+
+QDebug operator<<(QDebug debug, const NSRange &range)
+{
+ if (range.location == NSNotFound) {
+ QDebugStateSaver saver(debug);
+ debug.nospace() << "{NSNotFound, " << range.length << "}";
+ } else {
+ debug << NSStringFromRange(range);
+ }
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, SEL selector)
+{
+ debug << NSStringFromSelector(selector);
+ return debug;
+}
diff --git a/src/plugins/platforms/cocoa/qcocoainputcontext.h b/src/plugins/platforms/cocoa/qcocoainputcontext.h
index 7190ba0de8..2b97ab6a82 100644
--- a/src/plugins/platforms/cocoa/qcocoainputcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoainputcontext.h
@@ -44,6 +44,8 @@
#include <QtCore/QLocale>
#include <QtCore/QPointer>
+#include <QtCore/private/qcore_mac_p.h>
+
QT_BEGIN_NAMESPACE
class QCocoaInputContext : public QPlatformInputContext
@@ -55,18 +57,17 @@ public:
bool isValid() const override { return true; }
+ void setFocusObject(QObject *object) override;
+
void reset() override;
QLocale locale() const override { return m_locale; }
void updateLocale();
-private Q_SLOTS:
- void connectSignals();
- void focusObjectChanged(QObject *focusObject);
-
private:
- QPointer<QWindow> mWindow;
+ QPointer<QWindow> m_focusWindow;
QLocale m_locale;
+ QMacNotificationObserver m_inputSourceObserver;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoainputcontext.mm b/src/plugins/platforms/cocoa/qcocoainputcontext.mm
index 49c622e83b..d7fd6e8998 100644
--- a/src/plugins/platforms/cocoa/qcocoainputcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoainputcontext.mm
@@ -57,8 +57,8 @@ QT_BEGIN_NAMESPACE
\class QCocoaInputContext
\brief Cocoa Input context implementation
- Handles input of foreign characters (particularly East Asian)
- languages.
+ Handles input of languages that support character composition,
+ for example East Asian languages.
\section1 Testing
@@ -74,17 +74,20 @@ QT_BEGIN_NAMESPACE
\section1 Interaction
- Input method support in Cocoa uses NSTextInput protorol. Therefore
- almost all functionality is implemented in QNSView.
+ Input method support in Cocoa is based on the NSTextInputClient protocol,
+ therefore almost all functionality is in QNSView (qnsview_complextext.mm).
*/
-
-
QCocoaInputContext::QCocoaInputContext()
: QPlatformInputContext()
- , mWindow(QGuiApplication::focusWindow())
+ , m_focusWindow(QGuiApplication::focusWindow())
{
- QMetaObject::invokeMethod(this, "connectSignals", Qt::QueuedConnection);
+ m_inputSourceObserver = QMacNotificationObserver(nil,
+ NSTextInputContextKeyboardSelectionDidChangeNotification, [&]() {
+ qCDebug(lcQpaInputMethods) << "Text input source changed";
+ updateLocale();
+ });
+
updateLocale();
}
@@ -95,15 +98,16 @@ QCocoaInputContext::~QCocoaInputContext()
/*!
\brief Cancels a composition.
*/
-
void QCocoaInputContext::reset()
{
+ qCDebug(lcQpaInputMethods) << "Resetting input method";
+
QPlatformInputContext::reset();
- if (!mWindow)
+ if (!m_focusWindow)
return;
- QCocoaWindow *window = static_cast<QCocoaWindow *>(mWindow->handle());
+ QCocoaWindow *window = static_cast<QCocoaWindow *>(m_focusWindow->handle());
QNSView *view = qnsview_cast(window->view());
if (!view)
return;
@@ -115,20 +119,15 @@ void QCocoaInputContext::reset()
}
}
-void QCocoaInputContext::connectSignals()
+void QCocoaInputContext::setFocusObject(QObject *focusObject)
{
- connect(qApp, SIGNAL(focusObjectChanged(QObject*)), this, SLOT(focusObjectChanged(QObject*)));
- focusObjectChanged(qApp->focusObject());
-}
+ qCDebug(lcQpaInputMethods) << "Focus object changed to" << focusObject;
-void QCocoaInputContext::focusObjectChanged(QObject *focusObject)
-{
- Q_UNUSED(focusObject);
- if (mWindow == QGuiApplication::focusWindow()) {
- if (!mWindow)
+ if (m_focusWindow == QGuiApplication::focusWindow()) {
+ if (!m_focusWindow)
return;
- QCocoaWindow *window = static_cast<QCocoaWindow *>(mWindow->handle());
+ QCocoaWindow *window = static_cast<QCocoaWindow *>(m_focusWindow->handle());
if (!window)
return;
QNSView *view = qnsview_cast(window->view());
@@ -140,24 +139,27 @@ void QCocoaInputContext::focusObjectChanged(QObject *focusObject)
[view cancelComposingText];
}
} else {
- mWindow = QGuiApplication::focusWindow();
+ m_focusWindow = QGuiApplication::focusWindow();
}
}
void QCocoaInputContext::updateLocale()
{
- TISInputSourceRef source = TISCopyCurrentKeyboardInputSource();
- CFArrayRef languages = (CFArrayRef) TISGetInputSourceProperty(source, kTISPropertyInputSourceLanguages);
- if (CFArrayGetCount(languages) > 0) {
- CFStringRef langRef = (CFStringRef)CFArrayGetValueAtIndex(languages, 0);
- QString name = QString::fromCFString(langRef);
- QLocale locale(name);
- if (m_locale != locale) {
- m_locale = locale;
- emitLocaleChanged();
- }
+ QCFType<TISInputSourceRef> source = TISCopyCurrentKeyboardInputSource();
+ NSArray *languages = static_cast<NSArray*>(TISGetInputSourceProperty(source,
+ kTISPropertyInputSourceLanguages));
+
+ qCDebug(lcQpaInputMethods) << "Input source supports" << languages;
+ if (!languages.count)
+ return;
+
+ QString language = QString::fromNSString(languages.firstObject);
+ QLocale locale(language);
+ if (m_locale != locale) {
+ qCDebug(lcQpaInputMethods) << "Reporting new locale" << locale;
+ m_locale = locale;
+ emitLocaleChanged();
}
- CFRelease(source);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index caf47e38d3..fc9580b1b8 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -124,18 +124,11 @@ public:
NSToolbar *toolbar(QWindow *window) const;
void clearToolbars();
- void pushPopupWindow(QCocoaWindow *window);
- QCocoaWindow *popPopupWindow();
- QCocoaWindow *activePopupWindow() const;
- QList<QCocoaWindow *> *popupWindowStack();
-
void setApplicationIcon(const QIcon &icon) const override;
void beep() const override;
void quit() const override;
- void closePopups(QWindow *forWindow = nullptr);
-
private Q_SLOTS:
void focusWindowChanged(QWindow *);
@@ -162,7 +155,6 @@ private:
mutable QCocoaVulkanInstance *mCocoaVulkanInstance = nullptr;
#endif
QHash<QWindow *, NSToolbar *> mToolbars;
- QList<QCocoaWindow *> m_popupWindowStack;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QCocoaIntegration::Options)
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 1ab30df7e8..b5d9d48a8a 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -412,6 +412,8 @@ QVariant QCocoaIntegration::styleHint(StyleHint hint) const
return QCoreTextFontEngine::fontSmoothingGamma();
case ShowShortcutsInContextMenus:
return QVariant(false);
+ case ReplayMousePressOutsidePopup:
+ return QVariant(false);
default: break;
}
@@ -452,30 +454,6 @@ void QCocoaIntegration::clearToolbars()
mToolbars.clear();
}
-void QCocoaIntegration::pushPopupWindow(QCocoaWindow *window)
-{
- m_popupWindowStack.append(window);
-}
-
-QCocoaWindow *QCocoaIntegration::popPopupWindow()
-{
- if (m_popupWindowStack.isEmpty())
- return nullptr;
- return m_popupWindowStack.takeLast();
-}
-
-QCocoaWindow *QCocoaIntegration::activePopupWindow() const
-{
- if (m_popupWindowStack.isEmpty())
- return nullptr;
- return m_popupWindowStack.front();
-}
-
-QList<QCocoaWindow *> *QCocoaIntegration::popupWindowStack()
-{
- return &m_popupWindowStack;
-}
-
void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const
{
// Fall back to a size that looks good on the highest resolution screen available
@@ -494,19 +472,6 @@ void QCocoaIntegration::quit() const
[NSApp terminate:nil];
}
-void QCocoaIntegration::closePopups(QWindow *forWindow)
-{
- for (auto it = m_popupWindowStack.begin(); it != m_popupWindowStack.end();) {
- auto *popup = *it;
- if (!forWindow || popup->window()->transientParent() == forWindow) {
- it = m_popupWindowStack.erase(it);
- QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(popup->window());
- } else {
- ++it;
- }
- }
-}
-
void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
{
// Don't revert icon just because we lost focus
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index e22f619a6e..d6af2a5523 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -299,31 +299,26 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable)
QMacAutoReleasePool pool;
if (enable) {
bool previousIsSeparator = true; // setting to true kills all the separators placed at the top.
- NSMenuItem *previousItem = nil;
+ NSMenuItem *lastVisibleItem = nil;
for (NSMenuItem *item in m_nativeMenu.itemArray) {
if (item.separatorItem) {
// hide item if previous was a separator, or if it's explicitly hidden
- bool itemVisible = !previousIsSeparator;
- if (auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem) {
- cocoaItem->setVisible(!previousIsSeparator && cocoaItem->isVisible());
- itemVisible = cocoaItem->isVisible();
- }
- item.hidden = !itemVisible;
+ bool hideItem = previousIsSeparator;
+ if (auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem)
+ hideItem = previousIsSeparator || !cocoaItem->isVisible();
+ item.hidden = hideItem;
}
if (!item.hidden) {
- previousItem = item;
- previousIsSeparator = previousItem.separatorItem;
+ lastVisibleItem = item;
+ previousIsSeparator = lastVisibleItem.separatorItem;
}
}
// We now need to check the final item since we don't want any separators at the end of the list.
- if (previousItem && previousIsSeparator) {
- if (auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(previousItem).platformMenuItem)
- cocoaItem->setVisible(false);
- previousItem.hidden = YES;
- }
+ if (lastVisibleItem && lastVisibleItem.separatorItem)
+ lastVisibleItem.hidden = YES;
} else {
for (auto *item : qAsConst(m_menuItems)) {
if (!item->isSeparator())
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index ba37b40f5e..50072b4e51 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -320,13 +320,8 @@
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
{
if (menuItem.action == @selector(hideOtherApplications:)
- || menuItem.action == @selector(unhideAllApplications:))
- return [NSApp validateMenuItem:menuItem];
-
- if (menuItem.action == @selector(hide:)) {
- auto *w = QCocoaIntegration::instance()->activePopupWindow();
- if (w && (w->window()->type() != Qt::ToolTip))
- return NO;
+ || menuItem.action == @selector(unhideAllApplications:)
+ || menuItem.action == @selector(hide:)) {
return [NSApp validateMenuItem:menuItem];
}
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h
index b109c24f63..91c1e3c63c 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.h
+++ b/src/plugins/platforms/cocoa/qcocoascreen.h
@@ -43,6 +43,7 @@
#include "qcocoacursor.h"
#include <qpa/qplatformintegration.h>
+#include <QtCore/private/qcore_mac_p.h>
#include <CoreGraphics/CoreGraphics.h>
#include <CoreVideo/CoreVideo.h>
@@ -102,8 +103,8 @@ private:
static void updateScreens();
static void cleanupScreens();
- static bool updateScreensIfNeeded();
- static NSArray *s_screenConfigurationBeforeUpdate;
+ static QMacNotificationObserver s_screenParameterObserver;
+ static CGDisplayReconfigurationCallBack s_displayReconfigurationCallBack;
static void add(CGDirectDisplayID displayId);
QCocoaScreen(CGDirectDisplayID displayId);
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index 61f7476159..e419492202 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -74,91 +74,33 @@ namespace CoreGraphics {
Q_ENUM_NS(DisplayChange)
}
-NSArray *QCocoaScreen::s_screenConfigurationBeforeUpdate = nil;
+QMacNotificationObserver QCocoaScreen::s_screenParameterObserver;
+CGDisplayReconfigurationCallBack QCocoaScreen::s_displayReconfigurationCallBack = nullptr;
void QCocoaScreen::initializeScreens()
{
updateScreens();
- CGDisplayRegisterReconfigurationCallback([](CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo) {
+ s_displayReconfigurationCallBack = [](CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo) {
Q_UNUSED(userInfo);
- // Displays are reconfigured in batches, and we want to update our screens
- // once a batch ends, so that all the states of the displays are up to date.
- static int displayReconfigurationsInProgress = 0;
-
const bool beforeReconfigure = flags & kCGDisplayBeginConfigurationFlag;
- qCDebug(lcQpaScreen).verbosity(0).nospace() << "Display " << displayId
- << (beforeReconfigure ? " about to reconfigure" : " was ")
- << QFlags<CoreGraphics::DisplayChange>(flags)
- << " with " << displayReconfigurationsInProgress
- << " display configuration(s) in progress";
-
- if (!flags) {
- // CGDisplayRegisterReconfigurationCallback has been observed to be called
- // with flags unset. This seems like a bug. The callback is not paired with
- // a matching "completion" callback either, so we don't know whether to treat
- // it as a begin or end of reconfigure.
- return;
- }
-
- if (beforeReconfigure) {
- if (!displayReconfigurationsInProgress++) {
- // There might have been a screen reconfigure before this that
- // we didn't process yet, so do that now if that's the case.
- updateScreensIfNeeded();
-
- Q_ASSERT(!s_screenConfigurationBeforeUpdate);
- s_screenConfigurationBeforeUpdate = NSScreen.screens;
- qCDebug(lcQpaScreen, "Display reconfigure transaction started"
- " with screen configuration %p", s_screenConfigurationBeforeUpdate);
-
- static void (^tryScreenUpdate)();
- tryScreenUpdate = ^void () {
- qCDebug(lcQpaScreen) << "Attempting screen update from runloop block";
- if (!updateScreensIfNeeded())
- CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, tryScreenUpdate);
- };
- CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, tryScreenUpdate);
- }
- } else {
- Q_ASSERT_X(displayReconfigurationsInProgress, "QCococaScreen",
- "Display configuration transactions are expected to be balanced");
+ qCDebug(lcQpaScreen).verbosity(0) << "Display" << displayId
+ << (beforeReconfigure ? "beginning" : "finished") << "reconfigure"
+ << QFlags<CoreGraphics::DisplayChange>(flags);
- if (!--displayReconfigurationsInProgress) {
- qCDebug(lcQpaScreen) << "Display reconfigure transaction completed";
- // We optimistically update now, in case the NSScreens have changed
- updateScreensIfNeeded();
- }
- }
- }, nullptr);
+ if (!beforeReconfigure)
+ updateScreens();
+ };
+ CGDisplayRegisterReconfigurationCallback(s_displayReconfigurationCallBack, nullptr);
- static QMacNotificationObserver screenParameterObserver(NSApplication.sharedApplication,
+ s_screenParameterObserver = QMacNotificationObserver(NSApplication.sharedApplication,
NSApplicationDidChangeScreenParametersNotification, [&]() {
qCDebug(lcQpaScreen) << "Received screen parameter change notification";
- updateScreensIfNeeded(); // As a last resort we update screens here
+ updateScreens();
});
}
-bool QCocoaScreen::updateScreensIfNeeded()
-{
- if (!s_screenConfigurationBeforeUpdate) {
- qCDebug(lcQpaScreen) << "QScreens have already been updated, all good";
- return true;
- }
-
- if (s_screenConfigurationBeforeUpdate == NSScreen.screens) {
- qCDebug(lcQpaScreen) << "Still waiting for NSScreen configuration change";
- return false;
- }
-
- qCDebug(lcQpaScreen, "NSScreen configuration changed to %p", NSScreen.screens);
- updateScreens();
-
- s_screenConfigurationBeforeUpdate = nil;
- return true;
-}
-
/*
Update the list of available QScreens, and the properties of existing screens.
@@ -241,6 +183,12 @@ void QCocoaScreen::cleanupScreens()
// Remove screens in reverse order to avoid crash in case of multiple screens
for (QScreen *screen : backwards(QGuiApplication::screens()))
static_cast<QCocoaScreen*>(screen->handle())->remove();
+
+ Q_ASSERT(s_displayReconfigurationCallBack);
+ CGDisplayRemoveReconfigurationCallback(s_displayReconfigurationCallBack, nullptr);
+ s_displayReconfigurationCallBack = nullptr;
+
+ s_screenParameterObserver.remove();
}
void QCocoaScreen::remove()
@@ -312,15 +260,18 @@ void QCocoaScreen::update(CGDirectDisplayID displayId)
Q_ASSERT(isOnline());
+ // Some properties are only available via NSScreen
+ NSScreen *nsScreen = nativeScreen();
+ if (!nsScreen) {
+ qCDebug(lcQpaScreen) << "Corresponding NSScreen not yet available. Deferring update";
+ return;
+ }
+
const QRect previousGeometry = m_geometry;
const QRect previousAvailableGeometry = m_availableGeometry;
const QDpi previousLogicalDpi = m_logicalDpi;
const qreal previousRefreshRate = m_refreshRate;
- // Some properties are only available via NSScreen
- NSScreen *nsScreen = nativeScreen();
- Q_ASSERT(nsScreen);
-
// The reference screen for the geometry is always the primary screen
QRectF primaryScreenGeometry = QRectF::fromCGRect(CGDisplayBounds(CGMainDisplayID()));
m_geometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.frame), primaryScreenGeometry).toRect();
@@ -750,13 +701,17 @@ QList<QPlatformScreen*> QCocoaScreen::virtualSiblings() const
QCocoaScreen *QCocoaScreen::get(NSScreen *nsScreen)
{
- if (s_screenConfigurationBeforeUpdate) {
- qCWarning(lcQpaScreen) << "Trying to resolve screen while waiting for screen reconfigure!";
- if (!updateScreensIfNeeded())
- qCWarning(lcQpaScreen) << "Failed to do last minute screen update. Expect crashes.";
+ auto displayId = nsScreen.qt_displayId;
+ auto *cocoaScreen = get(displayId);
+ if (!cocoaScreen) {
+ qCWarning(lcQpaScreen) << "Failed to map" << nsScreen
+ << "to QCocoaScreen. Doing last minute update.";
+ updateScreens();
+ cocoaScreen = get(displayId);
+ if (!cocoaScreen)
+ qCWarning(lcQpaScreen) << "Last minute update failed!";
}
-
- return get(nsScreen.qt_displayId);
+ return cocoaScreen;
}
QCocoaScreen *QCocoaScreen::get(CGDirectDisplayID displayId)
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index f6276e3d1a..436ed94351 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -73,6 +73,7 @@ public:
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions options = {}) const override;
QVariant themeHint(ThemeHint hint) const override;
+ Appearance appearance() const override;
QString standardButtonText(int button) const override;
QKeySequence standardButtonShortcut(int button) const override;
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index 21f127103f..8f0f6b90d8 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -99,7 +99,6 @@ static QPalette *qt_mac_createSystemPalette()
palette->setBrush(QPalette::Disabled, QPalette::WindowText, dark);
palette->setBrush(QPalette::Disabled, QPalette::Text, dark);
- palette->setBrush(QPalette::Disabled, QPalette::ButtonText, dark);
palette->setBrush(QPalette::Disabled, QPalette::Base, backgroundBrush);
QBrush textBackgroundBrush = qt_mac_toQBrush([NSColor textBackgroundColor]);
palette->setBrush(QPalette::Active, QPalette::Base, textBackgroundBrush);
@@ -124,6 +123,7 @@ static QPalette *qt_mac_createSystemPalette()
qc = qt_mac_toQColor([NSColor controlTextColor]);
palette->setColor(QPalette::Active, QPalette::Text, qc);
+ palette->setColor(QPalette::Active, QPalette::ButtonText, qc);
palette->setColor(QPalette::Active, QPalette::WindowText, qc);
palette->setColor(QPalette::Active, QPalette::HighlightedText, qc);
palette->setColor(QPalette::Inactive, QPalette::Text, qc);
@@ -132,6 +132,7 @@ static QPalette *qt_mac_createSystemPalette()
qc = qt_mac_toQColor([NSColor disabledControlTextColor]);
palette->setColor(QPalette::Disabled, QPalette::Text, qc);
+ palette->setColor(QPalette::Disabled, QPalette::ButtonText, qc);
palette->setColor(QPalette::Disabled, QPalette::WindowText, qc);
palette->setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
@@ -532,6 +533,11 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
return QPlatformTheme::themeHint(hint);
}
+QPlatformTheme::Appearance QCocoaTheme::appearance() const
+{
+ return qt_mac_applicationIsInDarkMode() ? Appearance::Dark : Appearance::Light;
+}
+
QString QCocoaTheme::standardButtonText(int button) const
{
return button == QPlatformDialogHelper::Discard ?
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 9a2fa5f025..fbfe20fe07 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -153,13 +153,11 @@ public:
Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame();
Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame();
- Q_NOTIFICATION_HANDLER(NSWindowWillMoveNotification) void windowWillMove();
Q_NOTIFICATION_HANDLER(NSWindowDidMoveNotification) void windowDidMove();
Q_NOTIFICATION_HANDLER(NSWindowDidResizeNotification) void windowDidResize();
Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize();
Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey();
Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey();
- Q_NOTIFICATION_HANDLER(NSWindowWillMiniaturizeNotification) void windowWillMiniaturize();
Q_NOTIFICATION_HANDLER(NSWindowDidMiniaturizeNotification) void windowDidMiniaturize();
Q_NOTIFICATION_HANDLER(NSWindowDidDeminiaturizeNotification) void windowDidDeminiaturize();
Q_NOTIFICATION_HANDLER(NSWindowWillEnterFullScreenNotification) void windowWillEnterFullScreen();
@@ -170,7 +168,6 @@ public:
Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen();
Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState();
Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen();
- Q_NOTIFICATION_HANDLER(NSWindowWillCloseNotification) void windowWillClose();
bool windowShouldClose();
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
@@ -236,7 +233,6 @@ public: // for QNSView
bool isContentView() const;
bool alwaysShowToolWindow() const;
- void removeMonitor();
enum HandleFlags {
NoHandleFlags = 0,
@@ -268,7 +264,6 @@ public: // for QNSView
static const int NoAlertRequest;
NSInteger m_alertRequest;
- NSObject *m_monitor;
bool m_drawContentBorderGradient;
int m_topContentBorderThickness;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 0190e34b47..6e9166a05a 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -149,7 +149,6 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
, m_registerTouchCount(0)
, m_resizableTransientParent(false)
, m_alertRequest(NoAlertRequest)
- , m_monitor(nil)
, m_drawContentBorderGradient(false)
, m_topContentBorderThickness(0)
, m_bottomContentBorderThickness(0)
@@ -197,24 +196,18 @@ QCocoaWindow::~QCocoaWindow()
if ([m_view superview])
[m_view removeFromSuperview];
- removeMonitor();
-
// Make sure to disconnect observer in all case if view is valid
// to avoid notifications received when deleting when using Qt::AA_NativeWindows attribute
if (!isForeignWindow())
[[NSNotificationCenter defaultCenter] removeObserver:m_view];
- if (QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance()) {
- // While it is unlikely that this window will be in the popup stack
- // during deletetion we clear any pointers here to make sure.
- cocoaIntegration->popupWindowStack()->removeAll(this);
-
#if QT_CONFIG(vulkan)
+ if (QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance()) {
auto vulcanInstance = cocoaIntegration->getCocoaVulkanInstance();
if (vulcanInstance)
vulcanInstance->destroySurface(m_vulkanSurface);
-#endif
}
+#endif
[m_view release];
[m_nsWindow close];
@@ -336,11 +329,6 @@ void QCocoaWindow::setVisible(bool visible)
// so we can send the geometry change. FIXME: Get rid of this workaround.
handleGeometryChange();
- // Register popup windows. The Cocoa platform plugin will forward mouse events
- // to them and close them when needed.
- if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
- QCocoaIntegration::instance()->pushPopupWindow(this);
-
if (parentCocoaWindow) {
// The parent window might have moved while this window was hidden,
// update the window geometry if there is a parent.
@@ -368,7 +356,11 @@ void QCocoaWindow::setVisible(bool visible)
if (window()->windowState() != Qt::WindowMinimized) {
if (parentCocoaWindow && (window()->modality() == Qt::WindowModal || window()->type() == Qt::Sheet)) {
// Show the window as a sheet
- [parentCocoaWindow->nativeWindow() beginSheet:m_view.window completionHandler:nil];
+ NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
+ if (!nativeParentWindow.attachedSheet)
+ [nativeParentWindow beginSheet:m_view.window completionHandler:nil];
+ else
+ [nativeParentWindow beginCriticalSheet:m_view.window completionHandler:nil];
} else if (window()->modality() == Qt::ApplicationModal) {
// Show the window as application modal
eventDispatcher()->beginModalSession(window());
@@ -387,21 +379,6 @@ void QCocoaWindow::setVisible(bool visible)
} else {
[m_view.window orderFront:nil];
}
-
- // Close popup when clicking outside it
- if (window()->type() == Qt::Popup && !(parentCocoaWindow && window()->transientParent()->isActive())) {
- removeMonitor();
- NSEventMask eventMask = NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown
- | NSEventMaskOtherMouseDown | NSEventMaskMouseMoved;
- m_monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:eventMask handler:^(NSEvent *e) {
- const auto button = cocoaButton2QtButton(e);
- const auto buttons = currentlyPressedMouseButtons();
- const auto eventType = cocoaEvent2QtMouseEvent(e);
- const auto globalPoint = QCocoaScreen::mapFromNative(NSEvent.mouseLocation);
- const auto localPoint = window()->mapFromGlobal(globalPoint.toPoint());
- QWindowSystemInterface::handleMouseEvent(window(), localPoint, globalPoint, buttons, button, eventType);
- }];
- }
}
}
@@ -443,11 +420,6 @@ void QCocoaWindow::setVisible(bool visible)
[m_view setHidden:YES];
}
- removeMonitor();
-
- if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
- QCocoaIntegration::instance()->popupWindowStack()->removeAll(this);
-
if (parentCocoaWindow && window()->type() == Qt::Popup) {
NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
if (m_resizableTransientParent
@@ -525,7 +497,7 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
if (frameless) {
// Frameless windows do not display the traffic lights buttons for
// e.g. minimize, however StyleMaskMiniaturizable is required to allow
- // programatic minimize.
+ // programmatic minimize.
styleMask |= NSWindowStyleMaskMiniaturizable;
} else if (flags & Qt::CustomizeWindowHint) {
if (flags & Qt::WindowTitleHint)
@@ -549,9 +521,11 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
if (m_drawContentBorderGradient)
styleMask |= NSWindowStyleMaskTexturedBackground;
- // Don't wipe fullscreen state
+ // Don't wipe existing states
if (m_view.window.styleMask & NSWindowStyleMaskFullScreen)
styleMask |= NSWindowStyleMaskFullScreen;
+ if (m_view.window.styleMask & NSWindowStyleMaskFullSizeContentView)
+ styleMask |= NSWindowStyleMaskFullSizeContentView;
return styleMask;
}
@@ -828,11 +802,6 @@ void QCocoaWindow::windowDidExitFullScreen()
}
}
-void QCocoaWindow::windowWillMiniaturize()
-{
- QCocoaIntegration::instance()->closePopups(window());
-}
-
void QCocoaWindow::windowDidMiniaturize()
{
if (!isContentView())
@@ -1153,12 +1122,6 @@ void QCocoaWindow::viewDidChangeGlobalFrame()
// callback should make sure to filter out notifications if they do not
// apply to that QCocoaWindow, e.g. if the window is not a content view.
-void QCocoaWindow::windowWillMove()
-{
- // Close any open popups on window move
- QCocoaIntegration::instance()->closePopups();
-}
-
void QCocoaWindow::windowDidMove()
{
if (!isContentView())
@@ -1266,11 +1229,15 @@ void QCocoaWindow::windowDidChangeScreen()
return;
// Note: When a window is resized to 0x0 Cocoa will report the window's screen as nil
- auto *currentScreen = QCocoaScreen::get(m_view.window.screen);
+ NSScreen *nsScreen = m_view.window.screen;
+
+ qCDebug(lcQpaWindow) << window() << "did change" << nsScreen;
+ QCocoaScreen::updateScreens();
+
auto *previousScreen = static_cast<QCocoaScreen*>(screen());
+ auto *currentScreen = QCocoaScreen::get(nsScreen);
- Q_ASSERT_X(!m_view.window.screen || currentScreen,
- "QCocoaWindow", "Failed to get QCocoaScreen for NSScreen");
+ qCDebug(lcQpaWindow) << "Screen changed for" << window() << "from" << previousScreen << "to" << currentScreen;
// Note: The previous screen may be the same as the current screen, either because
// a) the screen was just reconfigured, which still results in AppKit sending an
@@ -1283,7 +1250,6 @@ void QCocoaWindow::windowDidChangeScreen()
// device-pixel ratio may have changed, and needs to be delivered to all
// windows, both top level and child windows.
- qCDebug(lcQpaWindow) << "Screen changed for" << window() << "from" << previousScreen << "to" << currentScreen;
QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(
window(), currentScreen ? currentScreen->screen() : nullptr);
@@ -1296,13 +1262,6 @@ void QCocoaWindow::windowDidChangeScreen()
}
}
-void QCocoaWindow::windowWillClose()
-{
- // Close any open popups on window closing.
- if (window() && !windowIsPopupType(window()->type()))
- QCocoaIntegration::instance()->closePopups();
-}
-
// ----------------------- NSWindowDelegate callbacks -----------------------
bool QCocoaWindow::windowShouldClose()
@@ -1666,8 +1625,11 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
applyContentBorderThickness(nsWindow);
- if (format().colorSpace() == QColorSpace::SRgb)
- nsWindow.colorSpace = NSColorSpace.sRGBColorSpace;
+ if (QColorSpace colorSpace = format().colorSpace(); colorSpace.isValid()) {
+ NSData *iccData = colorSpace.iccProfile().toNSData();
+ nsWindow.colorSpace = [[[NSColorSpace alloc] initWithICCProfileData:iccData] autorelease];
+ qCDebug(lcQpaDrawing) << "Set" << this << "color space to" << nsWindow.colorSpace;
+ }
return nsWindow;
}
@@ -1677,14 +1639,6 @@ bool QCocoaWindow::alwaysShowToolWindow() const
return qt_mac_resolveOption(false, window(), "_q_macAlwaysShowToolWindow", "");
}
-void QCocoaWindow::removeMonitor()
-{
- if (!m_monitor)
- return;
- [NSEvent removeMonitor:m_monitor];
- m_monitor = nil;
-}
-
bool QCocoaWindow::setWindowModified(bool modified)
{
if (!isContentView())
@@ -1717,6 +1671,20 @@ void QCocoaWindow::setWindowCursor(NSCursor *cursor)
view.cursor = cursor;
[m_view.window invalidateCursorRectsForView:m_view];
+
+ // There's a bug in AppKit where calling invalidateCursorRectsForView when
+ // there's an override cursor active (for example when hovering over the
+ // window frame), will not result in a cursorUpdate: callback. To work around
+ // this we synthesize a cursor update event and call the callback ourselves,
+ // if we detect that the mouse is currently over the view.
+ auto locationInWindow = m_view.window.mouseLocationOutsideOfEventStream;
+ auto locationInSuperview = [m_view.superview convertPoint:locationInWindow fromView:nil];
+ if ([m_view hitTest:locationInSuperview] == m_view) {
+ [m_view cursorUpdate:[NSEvent enterExitEventWithType:NSEventTypeCursorUpdate
+ location:locationInWindow modifierFlags:0 timestamp:0
+ windowNumber:m_view.window.windowNumber context:nil
+ eventNumber:0 trackingNumber:0 userData:0]];
+ }
}
void QCocoaWindow::registerTouch(bool enable)
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac.mm b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
index 28d641b598..5521b7525c 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac.mm
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
@@ -46,8 +46,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcInputDevices, "qt.qpa.input.devices")
-
QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
QHash<quint64, QPointingDevice*> QCocoaTouch::_touchDevices;
QPointF QCocoaTouch::_screenReferencePos;
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index a9a547c891..526e4c0be2 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -56,6 +56,7 @@ QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSView, NSView
#if defined(__OBJC__)
@interface QNSView (MouseAPI)
+- (void)handleMouseEvent:(NSEvent *)theEvent;
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent;
- (void)resetMouseButtons;
@end
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 8e4efc6fb6..453ef9a0cd 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -62,6 +62,8 @@
#include <private/qguiapplication_p.h>
#include <private/qcoregraphics_p.h>
#include <private/qwindow_p.h>
+#include <private/qpointingdevice_p.h>
+#include <private/qhighdpiscaling_p.h>
#include "qcocoabackingstore.h"
#ifndef QT_NO_OPENGL
#include "qcocoaglcontext.h"
@@ -115,40 +117,37 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
@end
@interface QNSView (ComplexText) <NSTextInputClient>
-- (void)textInputContextKeyboardSelectionDidChangeNotification:(NSNotification *)textInputContextKeyboardSelectionDidChangeNotification;
@end
@implementation QNSView {
QPointer<QCocoaWindow> m_platformWindow;
+
+ // Mouse
+ QNSViewMouseMoveHelper *m_mouseMoveHelper;
Qt::MouseButtons m_buttons;
Qt::MouseButtons m_acceptedMouseDowns;
Qt::MouseButtons m_frameStrutButtons;
- QString m_composingText;
- QPointer<QObject> m_composingFocusObject;
- bool m_lastKeyDead;
- bool m_sendKeyEvent;
+ Qt::KeyboardModifiers m_currentWheelModifiers;
bool m_dontOverrideCtrlLMB;
bool m_sendUpAsRightButton;
- Qt::KeyboardModifiers m_currentWheelModifiers;
- NSString *m_inputSource;
- QNSViewMouseMoveHelper *m_mouseMoveHelper;
- bool m_resendKeyEvent;
bool m_scrolling;
bool m_updatingDrag;
+
+ // Keys
+ bool m_lastKeyDead;
+ bool m_sendKeyEvent;
NSEvent *m_currentlyInterpretedKeyEvent;
QSet<quint32> m_acceptedKeyDowns;
+
+ // Text
+ QString m_composingText;
+ QPointer<QObject> m_composingFocusObject;
}
- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow
{
if ((self = [super initWithFrame:NSZeroRect])) {
m_platformWindow = platformWindow;
- m_lastKeyDead = false;
- m_sendKeyEvent = false;
- m_inputSource = nil;
- m_resendKeyEvent = false;
- m_updatingDrag = false;
- m_currentlyInterpretedKeyEvent = nil;
self.focusRingType = NSFocusRingTypeNone;
@@ -159,10 +158,11 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
[self initMouse];
[self registerDragTypes];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(textInputContextKeyboardSelectionDidChangeNotification:)
- name:NSTextInputContextKeyboardSelectionDidChangeNotification
- object:nil];
+ m_updatingDrag = false;
+
+ m_lastKeyDead = false;
+ m_sendKeyEvent = false;
+ m_currentlyInterpretedKeyEvent = nil;
}
return self;
}
@@ -171,7 +171,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
{
qCDebug(lcQpaWindow) << "Deallocating" << self;
- [m_inputSource release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[m_mouseMoveHelper release];
@@ -330,7 +329,8 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
// QWindow activation from QCocoaWindow::windowDidBecomeKey instead. The only
// exception is if the window can never become key, in which case we naturally
// cannot wait for that to happen.
- QWindowSystemInterface::handleWindowActivated([self topLevelWindow], Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(
+ [self topLevelWindow], Qt::ActiveWindowFocusReason);
}
return YES;
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm
index 48cea12a14..39739d9725 100644
--- a/src/plugins/platforms/cocoa/qnsview_complextext.mm
+++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -39,277 +39,543 @@
// This file is included from qnsview.mm, and only used to organize the code
-@implementation QNSView (ComplexTextAPI)
+@implementation QNSView (ComplexText)
-- (void)cancelComposingText
-{
- if (m_composingText.isEmpty())
- return;
+// ------------- Text insertion -------------
- if (m_composingFocusObject) {
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (QCoreApplication::sendEvent(m_composingFocusObject, &queryEvent)) {
- if (queryEvent.value(Qt::ImEnabled).toBool()) {
- QInputMethodEvent e;
- QCoreApplication::sendEvent(m_composingFocusObject, &e);
- }
+/*
+ Inserts the given text, potentially replacing existing text.
+
+ The text input management system calls this as a result of:
+
+ - A normal key press, via [NSView interpretKeyEvents:] or
+ [NSInputContext handleEvent:]
+
+ - An input method finishing (confirming) composition
+
+ - Pressing a key in the Keyboard Viewer panel
+
+ - Confirming an inline input area (accent popup e.g.)
+
+ \a replacementRange refers to the existing text to replace.
+ Under normal circumstances this is {NSNotFound, 0}, and the
+ implementation should replace either the existing marked text,
+ the current selection, or just insert the text at the current
+ cursor location.
+*/
+- (void)insertText:(id)text replacementRange:(NSRange)replacementRange
+{
+ qCDebug(lcQpaKeys).nospace() << "Inserting \"" << text << "\""
+ << ", replacing range " << replacementRange;
+
+ if (m_composingText.isEmpty()) {
+ // The input method may have transformed the incoming key event
+ // to text that doesn't match what the original key event would
+ // have produced, for example when 'Pinyin - Simplified' does smart
+ // replacement of quotes. If that's the case we can't rely on
+ // handleKeyEvent for sending the text.
+ auto *currentEvent = NSApp.currentEvent;
+ NSString *eventText = currentEvent.type == NSEventTypeKeyDown
+ || currentEvent.type == NSEventTypeKeyUp
+ ? currentEvent.characters : nil;
+
+ if ([text isEqualToString:eventText]) {
+ // We do not send input method events for simple text input,
+ // and instead let handleKeyEvent send the key event.
+ qCDebug(lcQpaKeys) << "Ignoring text insertion for simple text";
+ m_sendKeyEvent = true;
+ return;
}
}
- m_composingText.clear();
- m_composingFocusObject = nullptr;
-}
+ QObject *focusObject = m_platformWindow->window()->focusObject();
+ if (queryInputMethod(focusObject)) {
+ QInputMethodEvent inputMethodEvent;
-- (void)unmarkText
-{
- if (!m_composingText.isEmpty()) {
- if (QObject *fo = m_platformWindow->window()->focusObject()) {
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (QCoreApplication::sendEvent(fo, &queryEvent)) {
- if (queryEvent.value(Qt::ImEnabled).toBool()) {
- QInputMethodEvent e;
- e.setCommitString(m_composingText);
- QCoreApplication::sendEvent(fo, &e);
- }
- }
+ const bool isAttributedString = [text isKindOfClass:NSAttributedString.class];
+ QString commitString = QString::fromNSString(isAttributedString ? [text string] : text);
+
+ // Ensure we have a valid replacement range
+ replacementRange = [self sanitizeReplacementRange:replacementRange];
+
+ // Qt's QInputMethodEvent has different semantics for the replacement
+ // range than AppKit does, so we need to sanitize the range first.
+ auto [replaceFrom, replaceLength] = [self inputMethodRangeForRange:replacementRange];
+
+ if (replaceFrom == NSNotFound) {
+ qCWarning(lcQpaKeys) << "Failed to compute valid replacement range for text insertion";
+ inputMethodEvent.setCommitString(commitString);
+ } else {
+ qCDebug(lcQpaKeys) << "Replacing from" << replaceFrom << "with length" << replaceLength
+ << "based on replacement range" << replacementRange;
+ inputMethodEvent.setCommitString(commitString, replaceFrom, replaceLength);
}
+
+ QCoreApplication::sendEvent(focusObject, &inputMethodEvent);
}
+
m_composingText.clear();
m_composingFocusObject = nullptr;
}
-@end
-
-@implementation QNSView (ComplexText)
-
- (void)insertNewline:(id)sender
{
Q_UNUSED(sender);
- m_resendKeyEvent = true;
-}
-- (void)doCommandBySelector:(SEL)aSelector
-{
- [self tryToPerform:aSelector with:self];
+ // Depending on the input method, pressing enter may
+ // result in simply dismissing the input method editor,
+ // without confirming the composition. In other cases
+ // it may confirm the composition as well. And in some
+ // cases the IME will produce an explicit new line, which
+ // brings us here.
+
+ // Semantically, the input method has asked us to insert
+ // a newline, and we should do so via an QInputMethodEvent,
+ // either directly or via [self insertText:@"\r"]. This is
+ // also how NSTextView handles the command. But, if we did,
+ // we would bypass all the code in Qt (and clients) that
+ // assume that pressing the return key results in a key
+ // event, for example the QLineEdit::returnPressed logic.
+ // To ensure that clients will still see the Qt::Key_Return
+ // key event, we send it as a normal key event.
+
+ // But, we can not fall back to handleKeyEvent for this,
+ // as the original key event may have text that reflects
+ // the combination of the inserted text and the newline,
+ // e.g. "~\r". We have already inserted the composition,
+ // so we need to follow up with a single newline event.
+
+ KeyEvent newlineEvent(NSApp.currentEvent);
+ newlineEvent.key = Qt::Key_Return;
+ newlineEvent.text = QLatin1Char(kReturnCharCode);
+ newlineEvent.nativeVirtualKey = kVK_Return;
+ qCDebug(lcQpaKeys) << "Inserting newline via" << newlineEvent;
+ newlineEvent.sendWindowSystemEvent(m_platformWindow->window());
}
-- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
+// ------------- Text composition -------------
+
+/*
+ Updates the composed text, potentially replacing existing text.
+
+ The NSTextInputClient protocol refers to composed text as "marked",
+ since it is "marked differently from the selection, using temporary
+ attributes that affect only display, not layout or storage.""
+
+ The concept maps to the preeditString of our QInputMethodEvent.
+
+ \a selectedRange refers to the part of the marked text that
+ is considered selected, for example when composing text with
+ multiple clause segments (Hiragana - Kana e.g.).
+
+ \a replacementRange refers to the existing text to replace.
+ Under normal circumstances this is {NSNotFound, 0}, and the
+ implementation should replace either the existing marked text,
+ the current selection, or just insert the text at the current
+ cursor location. But when initiating composition of existing
+ committed text (Hiragana - Kana e.g.), the range will be valid.
+*/
+- (void)setMarkedText:(id)text selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{
- Q_UNUSED(replacementRange);
+ qCDebug(lcQpaKeys).nospace() << "Marking \"" << text << "\""
+ << " with selected range " << selectedRange
+ << ", replacing range " << replacementRange;
+
+ const bool isAttributedString = [text isKindOfClass:NSAttributedString.class];
+ QString preeditString = QString::fromNSString(isAttributedString ? [text string] : text);
+
+ QList<QInputMethodEvent::Attribute> preeditAttributes;
+
+ // The QInputMethodEvent::Cursor specifies that the length
+ // determines whether the cursor is visible or not, but uses
+ // logic opposite of that of native AppKit application, where
+ // the cursor is visible if there's no selection, and hidden
+ // if there's a selection. Instead of passing on the length
+ // directly we need to inverse the logic.
+ const bool showCursor = !selectedRange.length;
+ preeditAttributes << QInputMethodEvent::Attribute(
+ QInputMethodEvent::Cursor, selectedRange.location, showCursor);
+
+ // QInputMethodEvent::Selection unfortunately doesn't apply to the
+ // preedit text, and QInputMethodEvent::Cursor which does, doesn't
+ // support setting a selection. Until we've introduced attributes
+ // that allow us to propagate the preedit selection semantically
+ // we resort to styling the selection via the TextFormat attribute,
+ // so that the preedit selection is visible to the user.
+ QTextCharFormat selectionFormat;
+ auto *platformTheme = QGuiApplicationPrivate::platformTheme();
+ auto *systemPalette = platformTheme->palette();
+ selectionFormat.setBackground(systemPalette->color(QPalette::Highlight));
+ preeditAttributes << QInputMethodEvent::Attribute(
+ QInputMethodEvent::TextFormat,
+ selectedRange.location, selectedRange.length,
+ selectionFormat);
+
+ int index = 0;
+ int composingLength = preeditString.length();
+ while (index < composingLength) {
+ NSRange range = NSMakeRange(index, composingLength - index);
+
+ static NSDictionary *defaultMarkedTextAttributes = []{
+ NSTextView *textView = [[NSTextView new] autorelease];
+ return [textView.markedTextAttributes retain];
+ }();
+
+ NSDictionary *attributes = isAttributedString
+ ? [text attributesAtIndex:index longestEffectiveRange:&range inRange:range]
+ : defaultMarkedTextAttributes;
+
+ qCDebug(lcQpaKeys) << "Decorating range" << range << "based on" << attributes;
+ QTextCharFormat format;
- if (m_sendKeyEvent && m_composingText.isEmpty() && [aString isEqualToString:m_inputSource]) {
- // don't send input method events for simple text input (let handleKeyEvent send key events instead)
- return;
- }
+ if (NSNumber *underlineStyle = attributes[NSUnderlineStyleAttributeName]) {
+ format.setFontUnderline(true);
+ NSUnderlineStyle style = underlineStyle.integerValue;
+ if (style & NSUnderlineStylePatternDot)
+ format.setUnderlineStyle(QTextCharFormat::DotLine);
+ else if (style & NSUnderlineStylePatternDash)
+ format.setUnderlineStyle(QTextCharFormat::DashUnderline);
+ else if (style & NSUnderlineStylePatternDashDot)
+ format.setUnderlineStyle(QTextCharFormat::DashDotLine);
+ if (style & NSUnderlineStylePatternDashDotDot)
+ format.setUnderlineStyle(QTextCharFormat::DashDotDotLine);
+ else
+ format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+
+ // Unfortunately QTextCharFormat::UnderlineStyle does not distinguish
+ // between NSUnderlineStyle{Single,Thick,Double}, which is used by CJK
+ // input methods to highlight the selected clause segments.
+ }
+ if (NSColor *underlineColor = attributes[NSUnderlineColorAttributeName])
+ format.setUnderlineColor(qt_mac_toQColor(underlineColor));
+ if (NSColor *foregroundColor = attributes[NSForegroundColorAttributeName])
+ format.setForeground(qt_mac_toQColor(foregroundColor));
+ if (NSColor *backgroundColor = attributes[NSBackgroundColorAttributeName])
+ format.setBackground(qt_mac_toQColor(backgroundColor));
+
+ if (format != QTextCharFormat()) {
+ preeditAttributes << QInputMethodEvent::Attribute(
+ QInputMethodEvent::TextFormat, range.location, range.length, format);
+ }
- QString commitString;
- if ([aString length]) {
- if ([aString isKindOfClass:[NSAttributedString class]]) {
- commitString = QString::fromCFString(reinterpret_cast<CFStringRef>([aString string]));
- } else {
- commitString = QString::fromCFString(reinterpret_cast<CFStringRef>(aString));
- };
+ index = range.location + range.length;
}
- if (QObject *fo = m_platformWindow->window()->focusObject()) {
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (QCoreApplication::sendEvent(fo, &queryEvent)) {
- if (queryEvent.value(Qt::ImEnabled).toBool()) {
- QInputMethodEvent e;
- e.setCommitString(commitString);
- QCoreApplication::sendEvent(fo, &e);
- // prevent handleKeyEvent from sending a key event
- m_sendKeyEvent = false;
+
+ // Ensure we have a valid replacement range
+ replacementRange = [self sanitizeReplacementRange:replacementRange];
+
+ // Qt's QInputMethodEvent has different semantics for the replacement
+ // range than AppKit does, so we need to sanitize the range first.
+ auto [replaceFrom, replaceLength] = [self inputMethodRangeForRange:replacementRange];
+
+ // Update the composition, now that we've computed the replacement range
+ m_composingText = preeditString;
+
+ if (QObject *focusObject = m_platformWindow->window()->focusObject()) {
+ m_composingFocusObject = focusObject;
+ if (queryInputMethod(focusObject)) {
+ QInputMethodEvent event(preeditString, preeditAttributes);
+ if (replaceLength > 0) {
+ // The input method may extend the preedit into already
+ // committed text. If so, we need to replace existing text
+ // by committing an empty string.
+ qCDebug(lcQpaKeys) << "Replacing from" << replaceFrom << "with length"
+ << replaceLength << "based on replacement range" << replacementRange;
+ event.setCommitString(QString(), replaceFrom, replaceLength);
}
+ QCoreApplication::sendEvent(focusObject, &event);
}
}
+}
- m_composingText.clear();
- m_composingFocusObject = nullptr;
+- (NSArray<NSString *> *)validAttributesForMarkedText
+{
+ return @[
+ NSUnderlineColorAttributeName,
+ NSUnderlineStyleAttributeName,
+ NSForegroundColorAttributeName,
+ NSBackgroundColorAttributeName
+ ];
}
-- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+- (BOOL)hasMarkedText
{
- Q_UNUSED(replacementRange);
- QString preeditString;
-
- QList<QInputMethodEvent::Attribute> attrs;
- attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, selectedRange.location + selectedRange.length, 1, QVariant());
-
- if ([aString isKindOfClass:[NSAttributedString class]]) {
- // Preedit string has attribution
- preeditString = QString::fromCFString(reinterpret_cast<CFStringRef>([aString string]));
- int composingLength = preeditString.length();
- int index = 0;
- // Create attributes for individual sections of preedit text
- while (index < composingLength) {
- NSRange effectiveRange;
- NSRange range = NSMakeRange(index, composingLength-index);
- NSDictionary *attributes = [aString attributesAtIndex:index
- longestEffectiveRange:&effectiveRange
- inRange:range];
- NSNumber *underlineStyle = [attributes objectForKey:NSUnderlineStyleAttributeName];
- if (underlineStyle) {
- QColor clr (Qt::black);
- NSColor *color = [attributes objectForKey:NSUnderlineColorAttributeName];
- if (color) {
- clr = qt_mac_toQColor(color);
- }
- QTextCharFormat format;
- format.setFontUnderline(true);
- format.setUnderlineColor(clr);
- attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
- effectiveRange.location,
- effectiveRange.length,
- format);
- }
- index = effectiveRange.location + effectiveRange.length;
- }
+ return !m_composingText.isEmpty();
+}
+
+/*
+ Returns the range of marked text or {cursorPosition, 0} if there's none.
+
+ This maps to the location and length of the current preedit (composited) string.
+
+ The returned range measures from the start of the receiver’s text storage,
+ that is, from 0 to the document length.
+*/
+- (NSRange)markedRange
+{
+ QObject *focusObject = m_platformWindow->window()->focusObject();
+ if (auto queryResult = queryInputMethod(focusObject, Qt::ImAbsolutePosition)) {
+ int absoluteCursorPosition = queryResult.value(Qt::ImAbsolutePosition).toInt();
+
+ // The cursor position as reflected by Qt::ImAbsolutePosition is not
+ // affected by the offset of the cursor in the preedit area. That means
+ // that when composing text, the cursor position stays the same, at the
+ // preedit insertion point, regardless of where the cursor is positioned within
+ // the preedit string by the QInputMethodEvent::Cursor attribute. This means
+ // we can use the cursor position to determine the range of the marked text.
+
+ // The NSTextInputClient documentation says {NSNotFound, 0} should be returned if there
+ // is no marked text, but in practice NSTextView seems to report {cursorPosition, 0},
+ // so we do the same.
+ return NSMakeRange(absoluteCursorPosition, m_composingText.length());
} else {
- // No attributes specified, take only the preedit text.
- preeditString = QString::fromCFString(reinterpret_cast<CFStringRef>(aString));
+ return {NSNotFound, 0};
}
+}
- if (attrs.isEmpty()) {
- QTextCharFormat format;
- format.setFontUnderline(true);
- attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
- 0, preeditString.length(), format);
- }
+/*
+ Confirms the marked (composed) text.
- m_composingText = preeditString;
+ The marked text is accepted as if it had been inserted normally,
+ and the preedit string is cleared.
- if (QObject *fo = m_platformWindow->window()->focusObject()) {
- m_composingFocusObject = fo;
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (QCoreApplication::sendEvent(fo, &queryEvent)) {
- if (queryEvent.value(Qt::ImEnabled).toBool()) {
- QInputMethodEvent e(preeditString, attrs);
- QCoreApplication::sendEvent(fo, &e);
- // prevent handleKeyEvent from sending a key event
- m_sendKeyEvent = false;
- }
+ If there is no marked text this method has no effect.
+*/
+- (void)unmarkText
+{
+ // FIXME: Match cancelComposingText in early exit and focus object handling
+
+ qCDebug(lcQpaKeys) << "Unmarking" << m_composingText
+ << "for focus object" << m_composingFocusObject;
+
+ if (!m_composingText.isEmpty()) {
+ QObject *focusObject = m_platformWindow->window()->focusObject();
+ if (queryInputMethod(focusObject)) {
+ QInputMethodEvent e;
+ e.setCommitString(m_composingText);
+ QCoreApplication::sendEvent(focusObject, &e);
}
}
+
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
}
-- (BOOL)hasMarkedText
+/*
+ Cancels composition.
+
+ The marked text is discarded, and the preedit string is cleared.
+
+ If there is no marked text this method has no effect.
+*/
+- (void)cancelComposingText
{
- return (m_composingText.isEmpty() ? NO: YES);
+ if (m_composingText.isEmpty())
+ return;
+
+ qCDebug(lcQpaKeys) << "Canceling composition" << m_composingText
+ << "for focus object" << m_composingFocusObject;
+
+ if (queryInputMethod(m_composingFocusObject)) {
+ QInputMethodEvent e;
+ QCoreApplication::sendEvent(m_composingFocusObject, &e);
+ }
+
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
}
-- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+// ------------- Key binding command handling -------------
+
+- (void)doCommandBySelector:(SEL)selector
{
- Q_UNUSED(actualRange);
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return nil;
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImCurrentSelection);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return nil;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return nil;
+ // Note: if the selector cannot be invoked, then doCommandBySelector:
+ // should not pass this message up the responder chain (nor should it
+ // call super, as the NSResponder base class would in that case pass
+ // the message up the responder chain, which we don't want). We will
+ // pass the originating key event up the responder chain if applicable.
+
+ qCDebug(lcQpaKeys) << "Trying to perform command" << selector;
+ if (![self tryToPerform:selector with:self])
+ m_sendKeyEvent = true;
+}
- QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
- if (selectedText.isEmpty())
- return nil;
+// ------------- Various text properties -------------
- QCFString string(selectedText.mid(aRange.location, aRange.length));
- const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
- return [[[NSAttributedString alloc] initWithString:const_cast<NSString *>(tmpString)] autorelease];
-}
+/*
+ Returns the range of selected text, or {cursorPosition, 0} if there's none.
-- (NSRange)markedRange
+ The returned range measures from the start of the receiver’s text storage,
+ that is, from 0 to the document length.
+*/
+- (NSRange)selectedRange
{
- NSRange range;
- if (!m_composingText.isEmpty()) {
- range.location = 0;
- range.length = m_composingText.length();
+ QObject *focusObject = m_platformWindow->window()->focusObject();
+ if (auto queryResult = queryInputMethod(focusObject,
+ Qt::ImCursorPosition | Qt::ImAbsolutePosition | Qt::ImAnchorPosition)) {
+
+ // Unfortunately the Qt::InputMethodQuery values are all relative
+ // to the start of the current editing block (paragraph), but we
+ // need them in absolute values relative to the entire text.
+ // Luckily we have one property, Qt::ImAbsolutePosition, that
+ // we can use to compute the offset.
+ int cursorPosition = queryResult.value(Qt::ImCursorPosition).toInt();
+ int absoluteCursorPosition = queryResult.value(Qt::ImAbsolutePosition).toInt();
+ int absoluteOffset = absoluteCursorPosition - cursorPosition;
+
+ int anchorPosition = absoluteOffset + queryResult.value(Qt::ImAnchorPosition).toInt();
+ int selectionStart = anchorPosition >= absoluteCursorPosition ? absoluteCursorPosition : anchorPosition;
+ int selectionEnd = selectionStart == anchorPosition ? absoluteCursorPosition : anchorPosition;
+ int selectionLength = selectionEnd - selectionStart;
+
+ // Note: The cursor position as reflected by these properties are not
+ // affected by the offset of the cursor in the preedit area. That means
+ // that when composing text, the cursor position stays the same, at the
+ // preedit insertion point, regardless of where the cursor is positioned within
+ // the preedit string by the QInputMethodEvent::Cursor attribute.
+
+ // The NSTextInputClient documentation says {NSNotFound, 0} should be returned if there is no
+ // selection, but in practice NSTextView seems to report {cursorPosition, 0}, so we do the same.
+ return NSMakeRange(selectionStart, selectionLength);
} else {
- range.location = NSNotFound;
- range.length = 0;
+ return {NSNotFound, 0};
}
- return range;
}
-- (NSRange)selectedRange
+/*
+ Returns an attributed string derived from the given range
+ in the underlying focus object's text storage.
+
+ Input methods may call this with a proposed range that is
+ out of bounds. For example, the InkWell text input service
+ may ask for the contents of the text input client that extends
+ beyond the document's range. To remedy this we always compute
+ the intersection between the proposed range and the available
+ text.
+
+ If the intersection is completely outside of the available text
+ this method returns nil.
+*/
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{
- NSRange selectedRange = {0, 0};
-
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return selectedRange;
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImCurrentSelection);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return selectedRange;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return selectedRange;
-
- QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
-
- if (!selectedText.isEmpty()) {
- selectedRange.location = 0;
- selectedRange.length = selectedText.length();
+ QObject *focusObject = m_platformWindow->window()->focusObject();
+ if (auto queryResult = queryInputMethod(focusObject,
+ Qt::ImAbsolutePosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor)) {
+ const int absoluteCursorPosition = queryResult.value(Qt::ImAbsolutePosition).toInt();
+ const QString textBeforeCursor = queryResult.value(Qt::ImTextBeforeCursor).toString();
+ const QString textAfterCursor = queryResult.value(Qt::ImTextAfterCursor).toString();
+
+ // The documentation doesn't say whether the marked text should be included
+ // in the available text, but observing NSTextView shows that this is the
+ // case, so we follow suit.
+ const QString availableText = textBeforeCursor + m_composingText + textAfterCursor;
+ const NSRange availableRange = NSMakeRange(absoluteCursorPosition - textBeforeCursor.length(),
+ availableText.length());
+
+ const NSRange intersectedRange = NSIntersectionRange(range, availableRange);
+ if (actualRange)
+ *actualRange = intersectedRange;
+
+ if (!intersectedRange.length)
+ return nil;
+
+ NSString *substring = QStringView(availableText).mid(
+ intersectedRange.location - availableRange.location,
+ intersectedRange.length).toNSString();
+
+ return [[[NSAttributedString alloc] initWithString:substring] autorelease];
+
+ } else {
+ return nil;
}
- return selectedRange;
}
-- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{
- Q_UNUSED(aRange);
+ Q_UNUSED(range);
Q_UNUSED(actualRange);
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return NSZeroRect;
-
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return NSZeroRect;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
+ QWindow *window = m_platformWindow->window();
+ if (queryInputMethod(window->focusObject())) {
+ QRect cursorRect = qApp->inputMethod()->cursorRectangle().toRect();
+ cursorRect.moveBottomLeft(window->mapToGlobal(cursorRect.bottomLeft()));
+ return QCocoaScreen::mapToNative(cursorRect);
+ } else {
return NSZeroRect;
-
- // The returned rect is always based on the internal cursor.
- QRect mr = qApp->inputMethod()->cursorRectangle().toRect();
- mr.moveBottomLeft(m_platformWindow->window()->mapToGlobal(mr.bottomLeft()));
- return QCocoaScreen::mapToNative(mr);
+ }
}
-- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+- (NSUInteger)characterIndexForPoint:(NSPoint)point
{
// We don't support cursor movements using mouse while composing.
- Q_UNUSED(aPoint);
+ Q_UNUSED(point);
return NSNotFound;
}
-- (NSArray<NSString *> *)validAttributesForMarkedText
-{
- if (!m_platformWindow)
- return nil;
+// ------------- Helper functions -------------
- if (m_platformWindow->window() != QGuiApplication::focusWindow())
- return nil;
+/*
+ Sanitizes the replacement range, ensuring it's valid.
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return nil;
+ If \a range is not valid the range of the current
+ marked text will be used.
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return nil;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return nil;
+ If there's no marked text the range of the current
+ selection will be used.
+
+ If there's no selection the range will be {cursorPosition, 0}.
+*/
+- (NSRange)sanitizeReplacementRange:(NSRange)range
+{
+ if (range.location != NSNotFound)
+ return range; // Use as is
- // Support only underline color/style.
- return @[NSUnderlineColorAttributeName, NSUnderlineStyleAttributeName];
+ // If the replacement range is not specified we are expected to compute
+ // the range ourselves, based on the current state of the input context.
+
+ const auto markedRange = [self markedRange];
+ if (markedRange.location != NSNotFound)
+ return markedRange;
+ else
+ return [self selectedRange];
}
-- (void)textInputContextKeyboardSelectionDidChangeNotification:(NSNotification *)textInputContextKeyboardSelectionDidChangeNotification
+/*
+ Computes the QInputMethodEvent commit string range,
+ based on the NSTextInputClient replacement range.
+
+ The two APIs have different semantics.
+*/
+- (std::pair<long long, long long>)inputMethodRangeForRange:(NSRange)range
{
- Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification);
- if (([NSApp keyWindow] == self.window) && self.window.firstResponder == self) {
- if (QCocoaInputContext *ic = qobject_cast<QCocoaInputContext *>(QCocoaIntegration::instance()->inputContext()))
- ic->updateLocale();
- }
+ long long replaceFrom = range.location;
+ long long replaceLength = range.length;
+
+ const auto markedRange = [self markedRange];
+ const auto selectedRange = [self selectedRange];
+
+ // The QInputMethodEvent replacement start is relative to the start
+ // of the marked text (the location of the preedit string).
+ if (markedRange.location != NSNotFound)
+ replaceFrom -= markedRange.location;
+ else
+ replaceFrom = 0;
+
+ // The replacement length of QInputMethodEvent already includes
+ // the selection, as the documentation says that "If the widget
+ // has selected text, the selected text should get removed."
+ replaceLength -= selectedRange.length;
+
+ // The replacement length of QInputMethodEvent already includes
+ // the preedit string, as the documentation says that "When doing
+ // replacement, the area of the preedit string is ignored".
+ replaceLength -= markedRange.length;
+
+ // What we're left with is any _additional_ replacement.
+ // Make sure it's valid before passing it on.
+ replaceLength = qMax(0ll, replaceLength);
+
+ return {replaceFrom, replaceLength};
}
@end
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm
index 57f7fe1fdd..5e99d0a9c3 100644
--- a/src/plugins/platforms/cocoa/qnsview_keys.mm
+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm
@@ -41,105 +41,89 @@
@implementation QNSView (Keys)
-- (bool)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType
+- (bool)handleKeyEvent:(NSEvent *)nsevent
{
- ulong timestamp = [nsevent timestamp] * 1000;
- ulong nativeModifiers = [nsevent modifierFlags];
- Qt::KeyboardModifiers modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers);
- NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers];
- NSString *characters = [nsevent characters];
- if (m_inputSource != characters) {
- [m_inputSource release];
- m_inputSource = [characters retain];
- }
-
- // Scan codes are hardware dependent codes for each key. There is no way to get these
- // from Carbon or Cocoa, so leave it 0, as documented in QKeyEvent::nativeScanCode().
- const quint32 nativeScanCode = 0;
-
- // Virtual keys on the other hand are mapped to be the same keys on any system
- const quint32 nativeVirtualKey = nsevent.keyCode;
-
- QChar ch = QChar::ReplacementCharacter;
- int keyCode = Qt::Key_unknown;
-
- // If a dead key occurs as a result of pressing a key combination then
- // characters will have 0 length, but charactersIgnoringModifiers will
- // have a valid character in it. This enables key combinations such as
- // ALT+E to be used as a shortcut with an English keyboard even though
- // pressing ALT+E will give a dead key while doing normal text input.
- if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) {
- if (nativeModifiers & (NSEventModifierFlagControl | NSEventModifierFlagOption)
- && [charactersIgnoringModifiers length] != 0)
- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
- else if ([characters length] != 0)
- ch = QChar([characters characterAtIndex:0]);
- keyCode = QAppleKeyMapper::fromCocoaKey(ch);
- }
-
- // we will send a key event unless the input method sets m_sendKeyEvent to false
- m_sendKeyEvent = true;
- QString text;
- // ignore text for the U+F700-U+F8FF range. This is used by Cocoa when
- // delivering function keys (e.g. arrow keys, backspace, F1-F35, etc.)
- if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier)) && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff))
- text = QString::fromNSString(characters);
+ qCDebug(lcQpaKeys) << "Handling" << nsevent;
+ KeyEvent keyEvent(nsevent);
+ // FIXME: Why is this the top level window and not m_platformWindow?
QWindow *window = [self topLevelWindow];
- // Popups implicitly grab key events; forward to the active popup if there is one.
- // This allows popups to e.g. intercept shortcuts and close the popup in response.
- if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
- if (!popup->window()->flags().testFlag(Qt::ToolTip))
- window = popup->window();
- }
+ // We will send a key event unless the input method handles it
+ QBoolBlocker sendKeyEventGuard(m_sendKeyEvent, true);
- if (eventType == QEvent::KeyPress) {
+ if (keyEvent.type == QEvent::KeyPress) {
if (m_composingText.isEmpty()) {
- m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode,
- modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
+ KeyEvent shortcutEvent = keyEvent;
+ shortcutEvent.type = QEvent::Shortcut;
+ qCDebug(lcQpaKeys) << "Trying potential shortcuts in" << window
+ << "for" << shortcutEvent;
- // Handling a shortcut may result in closing the window
- if (!m_platformWindow)
+ if (shortcutEvent.sendWindowSystemEvent(window)) {
+ qCDebug(lcQpaKeys) << "Found matching shortcut; will not send as key event";
return true;
+ } else {
+ qCDebug(lcQpaKeys) << "No matching shortcuts; continuing with key event delivery";
+ }
}
- QObject *fo = m_platformWindow->window()->focusObject();
- if (m_sendKeyEvent && fo) {
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints);
- if (QCoreApplication::sendEvent(fo, &queryEvent)) {
- bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool();
- Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt());
- // make sure we send dead keys and the next key to the input method for composition
- const bool ignoreHidden = (hints & Qt::ImhHiddenText) && !text.isEmpty() && !m_lastKeyDead;
- if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || ignoreHidden)) {
- // pass the key event to the input method. note that m_sendKeyEvent may be set to false during this call
+ QObject *focusObject = m_platformWindow->window()->focusObject();
+ if (m_sendKeyEvent && focusObject) {
+ if (auto queryResult = queryInputMethod(focusObject, Qt::ImHints)) {
+ auto hints = static_cast<Qt::InputMethodHints>(queryResult.value(Qt::ImHints).toUInt());
+
+ // Make sure we send dead keys and the next key to the input method for composition
+ const bool isDeadKey = !nsevent.characters.length;
+ const bool ignoreHidden = (hints & Qt::ImhHiddenText) && !isDeadKey && !m_lastKeyDead;
+
+ if (!(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || ignoreHidden)) {
+ // Pass the key event to the input method, and assume it handles the event,
+ // unless we explicit set m_sendKeyEvent to deliver as a normal key event.
+ m_sendKeyEvent = false;
+
+ // Match NSTextView's keyDown behavior of hiding the cursor before
+ // interpreting key events. Shortcuts should not trigger this though.
+ // Unfortunately many of our controls handle shortcuts by accepting
+ // the ShortcutOverride event and then handling the shortcut in the
+ // following key event, and QWSI::handleShortcutEvent doesn't reveal
+ // whether this will be the case. For NSTextView this is not an issue
+ // as shortcuts are handled via performKeyEquivalent, which happens
+ // prior to keyDown. To work around this until we can get the info
+ // we need from handleShortcutEvent we match AppKit and assume that
+ // any key press with a command or control modifier is a shortcut.
+ if (!(nsevent.modifierFlags & (NSEventModifierFlagCommand | NSEventModifierFlagControl)))
+ [NSCursor setHiddenUntilMouseMoves:YES];
+
+ qCDebug(lcQpaKeys) << "Interpreting key event for focus object" << focusObject;
m_currentlyInterpretedKeyEvent = nsevent;
[self interpretKeyEvents:@[nsevent]];
+
// If the receiver opens an editor in response to a key press, then the focus will change, the input
// method will be reset, and the first key press will be gone. If the focus object changes, then we
// need to pass the key event to the input method once more.
- if (qApp->focusObject() != fo)
+ if (qApp->focusObject() != focusObject) {
+ qCDebug(lcQpaKeys) << "Interpreting key event again for new focus object" << qApp->focusObject();
[self interpretKeyEvents:@[nsevent]];
+ }
+
m_currentlyInterpretedKeyEvent = 0;
- // if the last key we sent was dead, then pass the next key to the IM as well to complete composition
- m_lastKeyDead = text.isEmpty();
+
+ // If the last key we sent was dead, then pass the next
+ // key to the IM as well to complete composition.
+ m_lastKeyDead = isDeadKey;
}
+
}
}
- if (m_resendKeyEvent)
- m_sendKeyEvent = true;
}
bool accepted = true;
if (m_sendKeyEvent && m_composingText.isEmpty()) {
- QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, QEvent::Type(eventType), keyCode, modifiers,
- nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false);
- accepted = QWindowSystemInterface::flushWindowSystemEvents();
+ KeyEvent keyEvent(nsevent);
+ qCDebug(lcQpaKeys) << "Sending as" << keyEvent;
+ accepted = keyEvent.sendWindowSystemEvent(window);
}
- m_sendKeyEvent = false;
- m_resendKeyEvent = false;
return accepted;
}
@@ -148,7 +132,7 @@
if ([self isTransparentForUserInput])
return [super keyDown:nsevent];
- const bool accepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
+ const bool accepted = [self handleKeyEvent:nsevent];
// When Qt is used to implement a plugin for a native application we
// want to propagate unhandled events to other native views. However,
@@ -159,7 +143,7 @@
// Track keyDown acceptance/forward state for later acceptance of the keyUp.
if (!shouldPropagate)
- m_acceptedKeyDowns.insert([nsevent keyCode]);
+ m_acceptedKeyDowns.insert(nsevent.keyCode);
if (shouldPropagate)
[super keyDown:nsevent];
@@ -170,12 +154,12 @@
if ([self isTransparentForUserInput])
return [super keyUp:nsevent];
- const bool keyUpAccepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
+ const bool keyUpAccepted = [self handleKeyEvent:nsevent];
// Propagate the keyUp if neither Qt accepted it nor the corresponding KeyDown was
// accepted. Qt text controls wil often not use and ignore keyUp events, but we
// want to avoid propagating unmatched keyUps.
- const bool keyDownAccepted = m_acceptedKeyDowns.remove([nsevent keyCode]);
+ const bool keyDownAccepted = m_acceptedKeyDowns.remove(nsevent.keyCode);
if (!keyUpAccepted && !keyDownAccepted)
[super keyUp:nsevent];
}
@@ -184,7 +168,7 @@
{
Q_UNUSED(sender);
- NSEvent *currentEvent = [NSApp currentEvent];
+ NSEvent *currentEvent = NSApp.currentEvent;
if (!currentEvent || currentEvent.type != NSEventTypeKeyDown)
return;
@@ -196,61 +180,142 @@
// Send Command+Key_Period and Escape as normal keypresses so that
// the key sequence is delivered through Qt. That way clients can
// intercept the shortcut and override its effect.
- [self handleKeyEvent:currentEvent eventType:int(QEvent::KeyPress)];
+ [self handleKeyEvent:currentEvent];
}
- (void)flagsChanged:(NSEvent *)nsevent
{
- ulong timestamp = [nsevent timestamp] * 1000;
- ulong nativeModifiers = [nsevent modifierFlags];
- Qt::KeyboardModifiers modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers);
-
- // Scan codes are hardware dependent codes for each key. There is no way to get these
- // from Carbon or Cocoa, so leave it 0, as documented in QKeyEvent::nativeScanCode().
- const quint32 nativeScanCode = 0;
-
- // Virtual keys on the other hand are mapped to be the same keys on any system
- const quint32 nativeVirtualKey = nsevent.keyCode;
-
- // calculate the delta and remember the current modifiers for next time
- static ulong m_lastKnownModifiers;
- ulong lastKnownModifiers = m_lastKnownModifiers;
- ulong delta = lastKnownModifiers ^ nativeModifiers;
- m_lastKnownModifiers = nativeModifiers;
-
- struct qt_mac_enum_mapper
- {
- ulong mac_mask;
- Qt::Key qt_code;
- };
- static qt_mac_enum_mapper modifier_key_symbols[] = {
+ // FIXME: Why are we not checking isTransparentForUserInput here?
+
+ KeyEvent keyEvent(nsevent);
+ qCDebug(lcQpaKeys) << "Flags changed resulting in" << keyEvent.modifiers;
+
+ // Calculate the delta and remember the current modifiers for next time
+ static NSEventModifierFlags m_lastKnownModifiers;
+ NSEventModifierFlags lastKnownModifiers = m_lastKnownModifiers;
+ NSEventModifierFlags newModifiers = lastKnownModifiers ^ keyEvent.nativeModifiers;
+ m_lastKnownModifiers = keyEvent.nativeModifiers;
+
+ static constexpr std::tuple<NSEventModifierFlags, Qt::Key> modifierMap[] = {
{ NSEventModifierFlagShift, Qt::Key_Shift },
{ NSEventModifierFlagControl, Qt::Key_Meta },
{ NSEventModifierFlagCommand, Qt::Key_Control },
{ NSEventModifierFlagOption, Qt::Key_Alt },
- { NSEventModifierFlagCapsLock, Qt::Key_CapsLock },
- { 0ul, Qt::Key_unknown } };
- for (int i = 0; modifier_key_symbols[i].mac_mask != 0u; ++i) {
- uint mac_mask = modifier_key_symbols[i].mac_mask;
- if ((delta & mac_mask) == 0u)
+ { NSEventModifierFlagCapsLock, Qt::Key_CapsLock }
+ };
+
+ for (auto [macModifier, qtKey] : modifierMap) {
+ if (!(newModifiers & macModifier))
continue;
- Qt::Key qtCode = modifier_key_symbols[i].qt_code;
+ // FIXME: Use QAppleKeyMapper helper
if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
- if (qtCode == Qt::Key_Meta)
- qtCode = Qt::Key_Control;
- else if (qtCode == Qt::Key_Control)
- qtCode = Qt::Key_Meta;
+ if (qtKey == Qt::Key_Meta)
+ qtKey = Qt::Key_Control;
+ else if (qtKey == Qt::Key_Control)
+ qtKey = Qt::Key_Meta;
}
- QWindowSystemInterface::handleExtendedKeyEvent(m_platformWindow->window(),
- timestamp,
- (lastKnownModifiers & mac_mask) ? QEvent::KeyRelease
- : QEvent::KeyPress,
- qtCode,
- modifiers ^ QAppleKeyMapper::fromCocoaModifiers(mac_mask),
- nativeScanCode, nativeVirtualKey,
- nativeModifiers ^ mac_mask);
+
+ KeyEvent modifierEvent = keyEvent;
+ modifierEvent.type = lastKnownModifiers & macModifier
+ ? QEvent::KeyRelease : QEvent::KeyPress;
+
+ modifierEvent.key = qtKey;
+
+ // FIXME: Shouldn't this be based on lastKnownModifiers?
+ modifierEvent.modifiers ^= QAppleKeyMapper::fromCocoaModifiers(macModifier);
+ modifierEvent.nativeModifiers ^= macModifier;
+
+ // FIXME: Why are we sending to m_platformWindow here, but not for key events?
+ QWindow *window = m_platformWindow->window();
+
+ qCDebug(lcQpaKeys) << "Sending" << modifierEvent;
+ modifierEvent.sendWindowSystemEvent(window);
}
}
@end
+
+// -------------------------------------------------------------------------
+
+KeyEvent::KeyEvent(NSEvent *nsevent)
+{
+ timestamp = nsevent.timestamp * 1000;
+
+ switch (nsevent.type) {
+ case NSEventTypeKeyDown: type = QEvent::KeyPress; break;
+ case NSEventTypeKeyUp: type = QEvent::KeyRelease; break;
+ default: break; // Must be manually set
+ }
+
+ if (nsevent.type == NSEventTypeKeyDown || nsevent.type == NSEventTypeKeyUp) {
+ NSString *charactersIgnoringModifiers = nsevent.charactersIgnoringModifiers;
+ NSString *characters = nsevent.characters;
+
+ QChar character = QChar::ReplacementCharacter;
+
+ // If a dead key occurs as a result of pressing a key combination then
+ // characters will have 0 length, but charactersIgnoringModifiers will
+ // have a valid character in it. This enables key combinations such as
+ // ALT+E to be used as a shortcut with an English keyboard even though
+ // pressing ALT+E will give a dead key while doing normal text input.
+ if (characters.length || charactersIgnoringModifiers.length) {
+ if (nativeModifiers & (NSEventModifierFlagControl | NSEventModifierFlagOption)
+ && charactersIgnoringModifiers.length)
+ character = QChar([charactersIgnoringModifiers characterAtIndex:0]);
+ else if (characters.length)
+ character = QChar([characters characterAtIndex:0]);
+ key = QAppleKeyMapper::fromCocoaKey(character);
+ }
+
+ // Ignore text for the U+F700-U+F8FF range. This is used by Cocoa when
+ // delivering function keys (e.g. arrow keys, backspace, F1-F35, etc.)
+ if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier))
+ && (character.unicode() < 0xf700 || character.unicode() > 0xf8ff))
+ text = QString::fromNSString(characters);
+
+ isRepeat = nsevent.ARepeat;
+ }
+
+ nativeVirtualKey = nsevent.keyCode;
+
+ nativeModifiers = nsevent.modifierFlags;
+ modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers);
+}
+
+bool KeyEvent::sendWindowSystemEvent(QWindow *window) const
+{
+ switch (type) {
+ case QEvent::Shortcut: {
+ return QWindowSystemInterface::handleShortcutEvent(window, timestamp,
+ key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
+ text, isRepeat);
+ }
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease: {
+ static const int count = 1;
+ static const bool tryShortcutOverride = false;
+ QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp,
+ type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
+ text, isRepeat, count, tryShortcutOverride);
+ // FIXME: Make handleExtendedKeyEvent synchronous
+ return QWindowSystemInterface::flushWindowSystemEvents();
+ }
+ default:
+ qCritical() << "KeyEvent can not send event type" << type;
+ return false;
+ }
+}
+
+QDebug operator<<(QDebug debug, const KeyEvent &e)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace().verbosity(0) << "KeyEvent("
+ << e.type << ", timestamp=" << e.timestamp
+ << ", key=" << e.key << ", modifiers=" << e.modifiers
+ << ", text="<< e.text << ", isRepeat=" << e.isRepeat
+ << ", nativeVirtualKey=" << e.nativeVirtualKey
+ << ", nativeModifiers=" << e.nativeModifiers
+ << ")";
+ return debug;
+}
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
index 54a1f06df6..d70d87e40d 100644
--- a/src/plugins/platforms/cocoa/qnsview_mouse.mm
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -39,6 +39,36 @@
// This file is included from qnsview.mm, and only used to organize the code
+static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
+{
+ // macOS will in many cases not report a deviceID (0 value).
+ // We can't pass this on directly, as the QInputDevicePrivate
+ // constructor will treat this as a request to assign a new Id.
+ // Instead we use the default Id of the primary pointing device.
+ static const int kDefaultPrimaryPointingDeviceId = 1;
+ if (!deviceID)
+ deviceID = kDefaultPrimaryPointingDeviceId;
+
+ if (const auto *device = QPointingDevicePrivate::pointingDeviceById(deviceID))
+ return device; // All good, already have the device registered
+
+ const auto *primaryDevice = QPointingDevice::primaryPointingDevice();
+ if (primaryDevice->systemId() == kDefaultPrimaryPointingDeviceId) {
+ // Adopt existing primary device instead of creating a new one
+ QPointingDevicePrivate::get(const_cast<QPointingDevice *>(primaryDevice))->systemId = deviceID;
+ qCDebug(lcInputDevices) << "primaryPointingDevice is now" << primaryDevice;
+ return primaryDevice;
+ } else {
+ // Register a new device. Name and capabilities may need updating later.
+ const auto *device = new QPointingDevice(QLatin1String("mouse"), deviceID,
+ QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
+ QInputDevice::Capability::Scroll | QInputDevice::Capability::Position,
+ 1, 3, QString(), QPointingDeviceUniqueId(), QCocoaIntegration::instance());
+ QWindowSystemInterface::registerInputDevice(device);
+ return device;
+ }
+}
+
/*
The reason for using this helper is to ensure that QNSView doesn't implement
the NSResponder callbacks for mouseEntered, mouseExited, and mouseMoved.
@@ -98,6 +128,50 @@
m_frameStrutButtons = Qt::NoButton;
}
+- (void)handleMouseEvent:(NSEvent *)theEvent
+{
+ if (!m_platformWindow)
+ return;
+
+#ifndef QT_NO_TABLETEVENT
+ // Tablet events may come in via the mouse event handlers,
+ // check if this is a valid tablet event first.
+ if ([self handleTabletEvent: theEvent])
+ return;
+#endif
+
+ QPointF qtWindowPoint;
+ QPointF qtScreenPoint;
+ QNSView *targetView = self;
+ if (!targetView.platformWindow)
+ return;
+
+
+ [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ ulong timestamp = [theEvent timestamp] * 1000;
+
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->setLastMouseEvent(theEvent, self);
+
+ const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(theEvent.modifierFlags);
+ auto button = cocoaButton2QtButton(theEvent);
+ if (button == Qt::LeftButton && m_sendUpAsRightButton)
+ button = Qt::RightButton;
+ const auto eventType = cocoaEvent2QtMouseEvent(theEvent);
+
+ const QPointingDevice *device = pointingDeviceFor(theEvent.deviceID);
+ Q_ASSERT(device);
+
+ if (eventType == QEvent::MouseMove)
+ qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_buttons;
+ else
+ qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << m_buttons;
+
+ QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(),
+ timestamp, qtWindowPoint, qtScreenPoint,
+ m_buttons, button, eventType, modifiers);
+}
+
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
{
if (!m_platformWindow)
@@ -254,56 +328,6 @@
return screenPoint;
}
-- (void)handleMouseEvent:(NSEvent *)theEvent
-{
- if (!m_platformWindow)
- return;
-
-#ifndef QT_NO_TABLETEVENT
- // Tablet events may come in via the mouse event handlers,
- // check if this is a valid tablet event first.
- if ([self handleTabletEvent: theEvent])
- return;
-#endif
-
- QPointF qtWindowPoint;
- QPointF qtScreenPoint;
- QNSView *targetView = self;
- if (!targetView.platformWindow)
- return;
-
- // Popups implicitly grap mouse events; forward to the active popup if there is one
- if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
- // Tooltips must be transparent for mouse events
- // The bug reference is QTBUG-46379
- if (!popup->window()->flags().testFlag(Qt::ToolTip)) {
- if (QNSView *popupView = qnsview_cast(popup->view()))
- targetView = popupView;
- }
- }
-
- [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
- ulong timestamp = [theEvent timestamp] * 1000;
-
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- nativeDrag->setLastMouseEvent(theEvent, self);
-
- const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(theEvent.modifierFlags);
- auto button = cocoaButton2QtButton(theEvent);
- if (button == Qt::LeftButton && m_sendUpAsRightButton)
- button = Qt::RightButton;
- const auto eventType = cocoaEvent2QtMouseEvent(theEvent);
-
- if (eventType == QEvent::MouseMove)
- qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_buttons;
- else
- qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << m_buttons;
-
- QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(),
- timestamp, qtWindowPoint, qtScreenPoint,
- m_buttons, button, eventType, modifiers);
-}
-
- (bool)handleMouseDownEvent:(NSEvent *)theEvent
{
if ([self isTransparentForUserInput])
@@ -317,7 +341,7 @@
Q_UNUSED(qtScreenPoint);
// Maintain masked state for the button for use by MouseDragged and MouseUp.
- QRegion mask = m_platformWindow->window()->mask();
+ QRegion mask = QHighDpi::toNativeLocalPosition(m_platformWindow->window()->mask(), m_platformWindow->window());
const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
if (masked)
m_acceptedMouseDowns &= ~button;
@@ -381,47 +405,12 @@
return [super mouseDown:theEvent];
m_sendUpAsRightButton = false;
- // Handle any active poup windows; clicking outisde them should close them
- // all. Don't do anything or clicks inside one of the menus, let Cocoa
- // handle that case. Note that in practice many windows of the Qt::Popup type
- // will actually close themselves in this case using logic implemented in
- // that particular poup type (for example context menus). However, Qt expects
- // that plain popup QWindows will also be closed, so we implement the logic
- // here as well.
- QList<QCocoaWindow *> *popups = QCocoaIntegration::instance()->popupWindowStack();
- if (!popups->isEmpty()) {
- // Check if the click is outside all popups.
- bool inside = false;
- QPointF qtScreenPoint = QCocoaScreen::mapFromNative([self screenMousePoint:theEvent]);
- for (QList<QCocoaWindow *>::const_iterator it = popups->begin(); it != popups->end(); ++it) {
- if ((*it)->geometry().contains(qtScreenPoint.toPoint())) {
- inside = true;
- break;
- }
- }
- // Close the popups if the click was outside.
- if (!inside) {
- bool selfClosed = false;
- Qt::WindowType type = QCocoaIntegration::instance()->activePopupWindow()->window()->type();
- while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) {
- selfClosed = self == popup->view();
- QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(popup->window());
- if (!m_platformWindow)
- return; // Bail out if window was destroyed
- }
- // Consume the mouse event when closing the popup, except for tool tips
- // were it's expected that the event is processed normally.
- if (type != Qt::ToolTip || selfClosed)
- return;
- }
- }
-
QPointF qtWindowPoint;
QPointF qtScreenPoint;
[self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
Q_UNUSED(qtScreenPoint);
- QRegion mask = m_platformWindow->window()->mask();
+ QRegion mask = QHighDpi::toNativeLocalPosition(m_platformWindow->window()->mask(), m_platformWindow->window());
const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
// Maintain masked state for the button for use by MouseDragged and Up.
if (masked)
@@ -696,8 +685,22 @@
<< " pixelDelta=" << pixelDelta << " angleDelta=" << angleDelta
<< (isInverted ? " inverted=true" : "");
- QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint,
- qt_screenPoint, pixelDelta, angleDelta, m_currentWheelModifiers, phase, source, isInverted);
+ const QPointingDevice *device = pointingDeviceFor(theEvent.deviceID);
+ Q_ASSERT(device);
+
+ if (theEvent.hasPreciseScrollingDeltas) {
+ auto *devicePriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(device));
+ if (!devicePriv->capabilities.testFlag(QInputDevice::Capability::PixelScroll)) {
+ devicePriv->name = QLatin1String("trackpad or magic mouse");
+ devicePriv->deviceType = QInputDevice::DeviceType::TouchPad;
+ devicePriv->capabilities |= QInputDevice::Capability::PixelScroll;
+ qCDebug(lcInputDevices) << "mouse scrolling: updated capabilities" << device;
+ }
+ }
+
+ QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp,
+ device, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta,
+ m_currentWheelModifiers, phase, source, isInverted);
}
#endif // QT_CONFIG(wheelevent)
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index d9158bbcae..bdd2c07f02 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -45,6 +45,7 @@
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
+#include "qcocoaintegration.h"
#include <qpa/qwindowsysteminterface.h>
#include <qoperatingsystemversion.h>
@@ -106,7 +107,7 @@ static bool isMouseEvent(NSEvent *ev)
// Unfortunately there's no NSWindowListOrderedBackToFront,
// so we have to manually reverse the order using an array.
- NSMutableArray<NSWindow *> *windows = [NSMutableArray<NSWindow *> new];
+ NSMutableArray<NSWindow *> *windows = [[NSMutableArray<NSWindow *> new] autorelease];
[application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
usingBlock:^(NSWindow *window, BOOL *) {
// For some reason AppKit will give us nil-windows, skip those
@@ -323,8 +324,18 @@ OSStatus CGSClearWindowTags(const CGSConnectionID, const CGSWindowID, int *, int
- (NSColor *)backgroundColor
{
- return self.styleMask == NSWindowStyleMaskBorderless ?
- [NSColor clearColor] : [super backgroundColor];
+ // FIXME: Plumb to a WA_NoSystemBackground-like window flag,
+ // or a QWindow::backgroundColor() property. In the meantime
+ // we assume that if you have translucent content, without a
+ // frame then you intend to do all background drawing yourself.
+ const QWindow *window = m_platformWindow ? m_platformWindow->window() : nullptr;
+ if (!self.opaque && window && window->flags().testFlag(Qt::FramelessWindowHint))
+ return [NSColor clearColor];
+
+ // This still allows you to have translucent content with a frame,
+ // where the system background (or color set via NSWindow) will
+ // shine through.
+ return [super backgroundColor];
}
- (void)sendEvent:(NSEvent*)theEvent
@@ -349,18 +360,39 @@ OSStatus CGSClearWindowTags(const CGSConnectionID, const CGSWindowID, int *, int
return;
}
+ const bool mouseEventInFrameStrut = [theEvent, self]{
+ if (isMouseEvent(theEvent)) {
+ const NSPoint loc = theEvent.locationInWindow;
+ const NSRect windowFrame = [self convertRectFromScreen:self.frame];
+ const NSRect contentFrame = self.contentView.frame;
+ if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO))
+ return true;
+ }
+ return false;
+ }();
+ // Any mouse-press in the frame of the window, including the title bar buttons, should
+ // close open popups. Presses within the window's content are handled to do that in the
+ // NSView::mouseDown implementation.
+ if (theEvent.type == NSEventTypeLeftMouseDown && mouseEventInFrameStrut)
+ QGuiApplicationPrivate::instance()->closeAllPopups();
+
[super sendEvent:theEvent];
if (!m_platformWindow)
return; // Platform window went away while processing event
- if (m_platformWindow->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
- NSPoint loc = [theEvent locationInWindow];
- NSRect windowFrame = [self convertRectFromScreen:self.frame];
- NSRect contentFrame = self.contentView.frame;
- if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO))
- [qnsview_cast(m_platformWindow->view()) handleFrameStrutMouseEvent:theEvent];
+ // Cocoa will not deliver mouse events to a window that is modally blocked (by Cocoa,
+ // not Qt). However, an active popup is expected to grab any mouse event within the
+ // application, so we need to handle those explicitly and trust Qt's isWindowBlocked
+ // implementation to eat events that shouldn't be delivered anyway.
+ if (isMouseEvent(theEvent) && QGuiApplicationPrivate::instance()->popupActive()
+ && QGuiApplicationPrivate::instance()->isWindowBlocked(m_platformWindow->window(), nullptr)) {
+ qCDebug(lcQpaWindow) << "Mouse event over modally blocked window" << m_platformWindow->window()
+ << "while popup is open - redirecting";
+ [qnsview_cast(m_platformWindow->view()) handleMouseEvent:theEvent];
}
+ if (m_platformWindow->frameStrutEventsEnabled() && mouseEventInFrameStrut)
+ [qnsview_cast(m_platformWindow->view()) handleFrameStrutMouseEvent:theEvent];
}
- (void)closeAndRelease
diff --git a/src/plugins/platforms/direct2d/CMakeLists.txt b/src/plugins/platforms/direct2d/CMakeLists.txt
index 04d317880f..e87d2886d8 100644
--- a/src/plugins/platforms/direct2d/CMakeLists.txt
+++ b/src/plugins/platforms/direct2d/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QWindowsDirect2DIntegrationPlugin
OUTPUT_NAME qdirect2d
- TYPE platforms
+ PLUGIN_TYPE platforms
SOURCES
../windows/qtwindowsglobal.h
../windows/qwin10helpers.cpp ../windows/qwin10helpers.h
@@ -138,7 +138,7 @@ qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE
SOURCES
../windows/qwindowstabletsupport.cpp ../windows/qwindowstabletsupport.h
INCLUDE_DIRECTORIES
- ${QT_SOURCE_TREE}/src/3rdparty/wintab
+ ${QtBase_SOURCE_DIR}/src/3rdparty/wintab
)
qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
diff --git a/src/plugins/platforms/directfb/CMakeLists.txt b/src/plugins/platforms/directfb/CMakeLists.txt
index e54c6a0b79..c634afb4f8 100644
--- a/src/plugins/platforms/directfb/CMakeLists.txt
+++ b/src/plugins/platforms/directfb/CMakeLists.txt
@@ -11,7 +11,7 @@ qt_find_package(EGL)
qt_internal_add_plugin(QDirectFbIntegrationPlugin
OUTPUT_NAME qdirectfb
- TYPE platforms
+ PLUGIN_TYPE platforms
SOURCES
main.cpp
qdirectfbbackingstore.cpp qdirectfbbackingstore.h
diff --git a/src/plugins/platforms/eglfs/CMakeLists.txt b/src/plugins/platforms/eglfs/CMakeLists.txt
index 4b11c85bad..61adb94778 100644
--- a/src/plugins/platforms/eglfs/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/CMakeLists.txt
@@ -98,7 +98,7 @@ endif()
qt_internal_add_plugin(QEglFSIntegrationPlugin
OUTPUT_NAME qeglfs
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES eglfs # special case
SOURCES
qeglfsmain.cpp
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
index 2ee237ec28..b1fdba5a46 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -111,11 +111,11 @@ void QEglFSWindow::create()
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
if (screen->primarySurface() != EGL_NO_SURFACE) {
if (Q_UNLIKELY(!isRaster() || !compositor->targetWindow())) {
-#if !defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_EMBEDDED)
+# ifndef Q_OS_ANDROID
// We can have either a single OpenGL window or multiple raster windows.
// Other combinations cannot work.
qFatal("EGLFS: OpenGL windows cannot be mixed with others.");
-#endif
+# endif
return;
}
m_format = compositor->targetWindow()->format();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt
index 1f75e1717a..e1de63ea42 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEglFSEmulatorIntegrationPlugin
OUTPUT_NAME qeglfs-emu-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfsemulatorintegration.cpp qeglfsemulatorintegration.h
qeglfsemulatorscreen.cpp qeglfsemulatorscreen.h
@@ -15,7 +15,7 @@ qt_internal_add_plugin(QEglFSEmulatorIntegrationPlugin
QT_EGL_NO_X11
INCLUDE_DIRECTORIES
../../api
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
index 99bad1b485..a20a4a084d 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
@@ -30,12 +30,12 @@ qt_internal_add_module(EglFsKmsGbmSupportPrivate
qt_internal_add_plugin(QEglFSKmsGbmIntegrationPlugin
OUTPUT_NAME qeglfs-kms-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfskmsgbmmain.cpp
DEFINES
QT_EGL_NO_X11
- PUBLIC_LIBRARIES
+ LIBRARIES
Libdrm::Libdrm
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/CMakeLists.txt
index ceeddb159e..7cac8ea5dc 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEglFSKmsEglDeviceIntegrationPlugin
OUTPUT_NAME qeglfs-kms-egldevice-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfskmsegldevice.cpp qeglfskmsegldevice.h
qeglfskmsegldeviceintegration.cpp qeglfskmsegldeviceintegration.h
@@ -14,7 +14,7 @@ qt_internal_add_plugin(QEglFSKmsEglDeviceIntegrationPlugin
qeglfskmsegldevicescreen.cpp qeglfskmsegldevicescreen.h
DEFINES
QT_EGL_NO_X11
- PUBLIC_LIBRARIES
+ LIBRARIES
Libdrm::Libdrm
Qt::Core
Qt::CorePrivate
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt
index 84165abafd..7550529f79 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEglFSMaliIntegrationPlugin
OUTPUT_NAME qeglfs-mali-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfsmaliintegration.cpp qeglfsmaliintegration.h
qeglfsmalimain.cpp
@@ -14,7 +14,7 @@ qt_internal_add_plugin(QEglFSMaliIntegrationPlugin
QT_EGL_NO_X11
INCLUDE_DIRECTORIES
../../api
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt
index 1a5f079a19..fb8b79454d 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/CMakeLists.txt
@@ -6,13 +6,13 @@
qt_internal_add_plugin(QEglFSOpenWFDIntegrationPlugin
OUTPUT_NAME qeglfs-openwfd-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfsopenwfdintegration.cpp qeglfsopenwfdintegration.h
qeglfsopenwfdmain.cpp
INCLUDE_DIRECTORIES
../../api
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt
index 72952c6c5d..988ab76d79 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEglFSVivIntegrationPlugin
OUTPUT_NAME qeglfs-viv-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfsvivintegration.cpp qeglfsvivintegration.h
qeglfsvivmain.cpp
@@ -15,7 +15,7 @@ qt_internal_add_plugin(QEglFSVivIntegrationPlugin
LINUX=1
INCLUDE_DIRECTORIES
../../api
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt
index 269bdde02c..cb07c9aecc 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEglFSVivWaylandIntegrationPlugin
OUTPUT_NAME qeglfs-viv-wl-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfsvivwlintegration.cpp qeglfsvivwlintegration.h
qeglfsvivwlmain.cpp
@@ -17,7 +17,6 @@ qt_internal_add_plugin(QEglFSVivWaylandIntegrationPlugin
../../api
LIBRARIES
Wayland::Server
- PUBLIC_LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt
index 8f94ad1fa0..18bb02efe0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QEglFSX11IntegrationPlugin
OUTPUT_NAME qeglfs-x11-integration
- TYPE egldeviceintegrations
+ PLUGIN_TYPE egldeviceintegrations
SOURCES
qeglfsx11integration.cpp qeglfsx11integration.h
qeglfsx11main.cpp
@@ -14,7 +14,7 @@ qt_internal_add_plugin(QEglFSX11IntegrationPlugin
QT_EGL_NO_X11
INCLUDE_DIRECTORIES
../../api
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::EglFSDeviceIntegrationPrivate
diff --git a/src/plugins/platforms/ios/CMakeLists.txt b/src/plugins/platforms/ios/CMakeLists.txt
index cebecadc3c..204add279c 100644
--- a/src/plugins/platforms/ios/CMakeLists.txt
+++ b/src/plugins/platforms/ios/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QIOSIntegrationPlugin
OUTPUT_NAME qios
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES ios # special case
- TYPE platforms
+ PLUGIN_TYPE platforms
SOURCES
plugin.mm
qiosapplicationdelegate.h qiosapplicationdelegate.mm
@@ -27,6 +27,7 @@ qt_internal_add_plugin(QIOSIntegrationPlugin
qioswindow.h qioswindow.mm
quiaccessibilityelement.h quiaccessibilityelement.mm
quiview.h quiview.mm
+ uistrings_p.h uistrings.cpp
LIBRARIES
${FWAudioToolbox}
${FWFoundation}
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt
index 76253adb47..2fceac77ab 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/CMakeLists.txt
@@ -4,9 +4,10 @@
## QIosOptionalPlugin_NSPhotoLibrary Plugin:
#####################################################################
-qt_internal_add_plugin(QIosOptionalPlugin_NSPhotoLibrary
+qt_internal_add_plugin(QIosOptionalPlugin_NSPhotoLibraryPlugin
OUTPUT_NAME qiosnsphotolibrarysupport
- TYPE platforms/darwin
+ PLUGIN_TYPE platforms/darwin
+ CLASS_NAME QIosOptionalPlugin_NSPhotoLibrary
DEFAULT_IF FALSE
SOURCES
plugin.mm
@@ -23,7 +24,7 @@ qt_internal_add_plugin(QIosOptionalPlugin_NSPhotoLibrary
)
# special case begin
-set_target_properties(QIosOptionalPlugin_NSPhotoLibrary
+set_target_properties(QIosOptionalPlugin_NSPhotoLibraryPlugin
PROPERTIES
DISABLE_PRECOMPILE_HEADERS ON
)
diff --git a/src/plugins/platforms/ios/qiosservices.mm b/src/plugins/platforms/ios/qiosservices.mm
index 7222bf6793..41c75dcac8 100644
--- a/src/plugins/platforms/ios/qiosservices.mm
+++ b/src/plugins/platforms/ios/qiosservices.mm
@@ -42,6 +42,7 @@
#include <QtCore/qurl.h>
#include <QtCore/qdebug.h>
#include <QtCore/private/qcore_mac_p.h>
+#include <QtCore/qscopedvaluerollback.h>
#include <QtGui/qdesktopservices.h>
@@ -56,6 +57,7 @@ bool QIOSServices::openUrl(const QUrl &url)
return false;
}
+ // avoid recursing back into self
if (url == m_handlingUrl)
return false;
@@ -94,16 +96,12 @@ bool QIOSServices::openDocument(const QUrl &url)
/* Callback from iOS that the application should handle a URL */
bool QIOSServices::handleUrl(const QUrl &url)
{
- QUrl previouslyHandling = m_handlingUrl;
- m_handlingUrl = url;
+ QScopedValueRollback<QUrl> rollback(m_handlingUrl, url);
// FIXME: Add platform services callback from QDesktopServices::setUrlHandler
// so that we can warn the user if calling setUrlHandler without also setting
// up the matching keys in the Info.plist file (CFBundleURLTypes and friends).
- bool couldHandle = QDesktopServices::openUrl(url);
-
- m_handlingUrl = previouslyHandling;
- return couldHandle;
+ return QDesktopServices::openUrl(url);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm
index 4dd1f9f035..b6c8ca0620 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.mm
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm
@@ -43,6 +43,7 @@
#include "private/qaccessiblecache_p.h"
#include "private/qcore_mac_p.h"
+#include "uistrings_p.h"
QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
@@ -117,7 +118,9 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
QAccessible::State state = iface->state();
if (state.checkable)
- return state.checked ? @"checked" : @"unchecked"; // FIXME: translation
+ return state.checked
+ ? QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_CHECKED).toNSString()
+ : QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_UNCHECKED).toNSString();
QAccessibleValueInterface *val = iface->valueInterface();
if (val) {
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index c7f94cc707..ef6c9f49ad 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -50,6 +50,7 @@
#include "qiosmenu.h"
#endif
+#include <QtCore/qmath.h>
#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qwindow_p.h>
@@ -388,10 +389,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// azimuth unit vector: +x to the right, +y going downwards
CGVector azimuth = [cTouch azimuthUnitVectorInView: self];
// azimuthAngle given in radians, zero when the stylus points towards +x axis; converted to degrees with 0 pointing straight up
- qreal azimuthAngle = [cTouch azimuthAngleInView: self] * 180 / M_PI + 90;
+ qreal azimuthAngle = qRadiansToDegrees([cTouch azimuthAngleInView: self]) + 90;
// altitudeAngle given in radians, pi / 2 is with the stylus perpendicular to the iPad, smaller values mean more tilted, but never negative.
// Convert to degrees with zero being perpendicular.
- qreal altitudeAngle = 90 - cTouch.altitudeAngle * 180 / M_PI;
+ qreal altitudeAngle = 90 - qRadiansToDegrees(cTouch.altitudeAngle);
qCDebug(lcQpaTablet) << i << ":" << timeStamp << localViewPosition << pressure << state << "azimuth" << azimuth.dx << azimuth.dy
<< "angle" << azimuthAngle << "altitude" << cTouch.altitudeAngle
<< "xTilt" << qBound(-60.0, altitudeAngle * azimuth.dx, 60.0) << "yTilt" << qBound(-60.0, altitudeAngle * azimuth.dy, 60.0);
diff --git a/src/plugins/platforms/ios/uistrings.cpp b/src/plugins/platforms/ios/uistrings.cpp
new file mode 100644
index 0000000000..2772d28bc8
--- /dev/null
+++ b/src/plugins/platforms/ios/uistrings.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "uistrings_p.h"
+
+// Translatable messages should go into this .cpp file for them to
+// be picked up by lupdate.
+
+QT_BEGIN_NAMESPACE
+
+const char ACCESSIBILITY_ELEMENT[] = "quiaccessibilityelement";
+const char AE_CHECKED[] = QT_TRANSLATE_NOOP("quiaccessibilityelement", "checked");
+const char AE_UNCHECKED[] = QT_TRANSLATE_NOOP("quiaccessibilityelement", "unchecked");
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/uistrings_p.h b/src/plugins/platforms/ios/uistrings_p.h
new file mode 100644
index 0000000000..e77afb2740
--- /dev/null
+++ b/src/plugins/platforms/ios/uistrings_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef UISTRINGS_P_H
+#define UISTRINGS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+
+// quiaccessibilityelement related strings
+extern const char ACCESSIBILITY_ELEMENT[];
+extern const char AE_CHECKED[];
+extern const char AE_UNCHECKED[];
+
+QT_END_NAMESPACE
+
+#endif // UISTRINGS_P_H
diff --git a/src/plugins/platforms/linuxfb/CMakeLists.txt b/src/plugins/platforms/linuxfb/CMakeLists.txt
index 1a241463a7..a671dcfc1e 100644
--- a/src/plugins/platforms/linuxfb/CMakeLists.txt
+++ b/src/plugins/platforms/linuxfb/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QLinuxFbIntegrationPlugin
OUTPUT_NAME qlinuxfb
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES linuxfb # special case
SOURCES
main.cpp
diff --git a/src/plugins/platforms/minimal/CMakeLists.txt b/src/plugins/platforms/minimal/CMakeLists.txt
index 3abecdcb4a..a763dbac9a 100644
--- a/src/plugins/platforms/minimal/CMakeLists.txt
+++ b/src/plugins/platforms/minimal/CMakeLists.txt
@@ -8,7 +8,7 @@ qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype) # spec
qt_internal_add_plugin(QMinimalIntegrationPlugin
OUTPUT_NAME qminimal
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimal # special case
SOURCES
main.cpp
diff --git a/src/plugins/platforms/minimalegl/CMakeLists.txt b/src/plugins/platforms/minimalegl/CMakeLists.txt
index 5a5b57f963..f285d8ece6 100644
--- a/src/plugins/platforms/minimalegl/CMakeLists.txt
+++ b/src/plugins/platforms/minimalegl/CMakeLists.txt
@@ -7,7 +7,7 @@ qt_find_package(EGL) # special case
qt_internal_add_plugin(QMinimalEglIntegrationPlugin
OUTPUT_NAME qminimalegl
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimalegl # special case
SOURCES
main.cpp
diff --git a/src/plugins/platforms/offscreen/CMakeLists.txt b/src/plugins/platforms/offscreen/CMakeLists.txt
index bb73ce38aa..424da0a980 100644
--- a/src/plugins/platforms/offscreen/CMakeLists.txt
+++ b/src/plugins/platforms/offscreen/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QOffscreenIntegrationPlugin
OUTPUT_NAME qoffscreen
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES offscreen # special case
SOURCES
main.cpp
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.cpp b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
index 33b98cfa1b..f485b4eed8 100644
--- a/src/plugins/platforms/offscreen/qoffscreencommon.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
@@ -55,7 +55,11 @@ QPlatformWindow *QOffscreenScreen::windowContainingCursor = nullptr;
QList<QPlatformScreen *> QOffscreenScreen::virtualSiblings() const
{
- return m_integration->screens();
+ QList<QPlatformScreen *> platformScreens;
+ for (auto screen : m_integration->screens()) {
+ platformScreens.append(screen);
+ }
+ return platformScreens;
}
class QOffscreenCursor : public QPlatformCursor
@@ -232,6 +236,38 @@ void QOffscreenBackingStore::clearHash()
QHash<WId, QOffscreenBackingStore *> QOffscreenBackingStore::m_backingStoreForWinIdHash;
+QOffscreenPlatformNativeInterface::QOffscreenPlatformNativeInterface(QOffscreenIntegration *integration)
+ : m_integration(integration)
+{
+
+}
+
QOffscreenPlatformNativeInterface::~QOffscreenPlatformNativeInterface() = default;
+/*
+ Set platform configuration, e.g. screen configuration
+*/
+void QOffscreenPlatformNativeInterface::setConfiguration(const QJsonObject &configuration, QOffscreenPlatformNativeInterface *iface)
+{
+ iface->m_integration->setConfiguration(configuration);
+}
+
+/*
+ Get the current platform configuration
+*/
+QJsonObject QOffscreenPlatformNativeInterface::configuration(QOffscreenPlatformNativeInterface *iface)
+{
+ return iface->m_integration->configuration();
+}
+
+void *QOffscreenPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
+{
+ if (resource == "setConfiguration")
+ return reinterpret_cast<void*>(&QOffscreenPlatformNativeInterface::setConfiguration);
+ else if (resource == "configuration")
+ return reinterpret_cast<void*>(&QOffscreenPlatformNativeInterface::configuration);
+ else
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.h b/src/plugins/platforms/offscreen/qoffscreencommon.h
index 7f92c5b4d9..d0edfcc48b 100644
--- a/src/plugins/platforms/offscreen/qoffscreencommon.h
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.h
@@ -51,6 +51,7 @@
#include <qscopedpointer.h>
#include <qimage.h>
+#include <qjsonobject.h>
#include <qhash.h>
QT_BEGIN_NAMESPACE
@@ -120,7 +121,15 @@ private:
class QOffscreenPlatformNativeInterface : public QPlatformNativeInterface
{
public:
+ QOffscreenPlatformNativeInterface(QOffscreenIntegration *integration);
~QOffscreenPlatformNativeInterface();
+
+ static void setConfiguration(const QJsonObject &configuration, QOffscreenPlatformNativeInterface *iface);
+ static QJsonObject configuration(QOffscreenPlatformNativeInterface *iface);
+
+ void *nativeResourceForIntegration(const QByteArray &resource) override;
+private:
+ QOffscreenIntegration *m_integration;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
index 14218bb537..2613a42755 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -93,7 +93,7 @@ public:
}
};
-QOffscreenIntegration::QOffscreenIntegration()
+QOffscreenIntegration::QOffscreenIntegration(const QStringList& paramList)
{
#if defined(Q_OS_UNIX)
#if defined(Q_OS_MAC)
@@ -109,15 +109,24 @@ QOffscreenIntegration::QOffscreenIntegration()
m_drag.reset(new QOffscreenDrag);
#endif
m_services.reset(new QPlatformServices);
+
+ QJsonObject config = resolveConfigFileConfiguration(paramList).value_or(defaultConfiguration());
+ setConfiguration(config);
}
QOffscreenIntegration::~QOffscreenIntegration()
{
+ for (auto screen : std::as_const(m_screens))
+ QWindowSystemInterface::handleScreenRemoved(screen);
}
/*
- The offscren platform plugin is configurable with a JSON configuration
- file. Write the config to disk and pass the file path as a platform argument:
+ The offscren platform plugin is configurable with a JSON configuration.
+ The confiuration can be provided either from a file on disk on startup,
+ or at by calling setConfiguration().
+
+ To provide a configuration on startuip, write the config to disk and pass
+ the file path as a platform argument:
./myapp -platform offscreen:configfile=/path/to/config.json
@@ -128,9 +137,9 @@ QOffscreenIntegration::~QOffscreenIntegration()
"screens": [<screens>],
}
- Screen:
+ "screens" is an array of:
{
- "name" : string,
+ "name": string,
"x": int,
"y": int,
"width": int,
@@ -140,9 +149,29 @@ QOffscreenIntegration::~QOffscreenIntegration()
"dpr": double,
}
*/
-void QOffscreenIntegration::configure(const QStringList& paramList)
+
+QJsonObject QOffscreenIntegration::defaultConfiguration() const
+{
+ const auto defaultScreen = QJsonObject {
+ {"name", ""},
+ {"x", 0},
+ {"y", 0},
+ {"width", 800},
+ {"height", 800},
+ {"logicalDpi", 96},
+ {"logicalBaseDpi", 96},
+ {"dpr", 1.0},
+ };
+ const auto defaultConfiguration = QJsonObject {
+ {"synchronousWindowSystemEvents", false},
+ {"windowFrameMargins", true},
+ {"screens", QJsonArray { defaultScreen } },
+ };
+ return defaultConfiguration;
+}
+
+std::optional<QJsonObject> QOffscreenIntegration::resolveConfigFileConfiguration(const QStringList& paramList) const
{
- // Use config file configuring platform plugin, if one was specified
bool hasConfigFile = false;
QString configFilePath;
for (const QString &param : paramList) {
@@ -150,17 +179,11 @@ void QOffscreenIntegration::configure(const QStringList& paramList)
QString configPrefix(QLatin1String("configfile="));
if (param.startsWith(configPrefix)) {
hasConfigFile = true;
- configFilePath= param.mid(configPrefix.length());
+ configFilePath = param.mid(configPrefix.length());
}
}
-
- // Create the default screen if there was no config file
- if (!hasConfigFile) {
- QOffscreenScreen *offscreenScreen = new QOffscreenScreen(this);
- m_screens.append(offscreenScreen);
- QWindowSystemInterface::handleScreenAdded(offscreenScreen);
- return;
- }
+ if (!hasConfigFile)
+ return std::nullopt;
// Read config file
if (configFilePath.isEmpty())
@@ -177,28 +200,145 @@ void QOffscreenIntegration::configure(const QStringList& paramList)
if (config.isNull())
qFatal("Platform config file parse error: %s", qPrintable(error.errorString()));
- // Apply configuration (create screens)
- bool synchronousWindowSystemEvents = config["synchronousWindowSystemEvents"].toBool(false);
+ return config.object();
+}
+
+
+void QOffscreenIntegration::setConfiguration(const QJsonObject &configuration)
+{
+ // Apply the new configuration, diffing against the current m_configuration
+
+ const bool synchronousWindowSystemEvents = configuration["synchronousWindowSystemEvents"].toBool(
+ m_configuration["synchronousWindowSystemEvents"].toBool(false));
QWindowSystemInterface::setSynchronousWindowSystemEvents(synchronousWindowSystemEvents);
- m_windowFrameMarginsEnabled = config["windowFrameMargins"].toBool(true);
- QJsonArray screens = config["screens"].toArray();
- for (QJsonValue screenValue : screens) {
- QJsonObject screen = screenValue.toObject();
- if (screen.isEmpty()) {
- qWarning("QOffscreenIntegration::initializeWithPlatformArguments: empty screen object");
+
+ m_windowFrameMarginsEnabled = configuration["windowFrameMargins"].toBool(
+ m_configuration["windowFrameMargins"].toBool(true));
+
+ // Diff screens array, using the screen name as the screen identity.
+ QJsonArray currentScreens = m_configuration["screens"].toArray();
+ QJsonArray newScreens = configuration["screens"].toArray();
+
+ auto getScreenNames = [](const QJsonArray &screens) -> QList<QString> {
+ QList<QString> names;
+ for (QJsonValue screen : screens) {
+ names.append(screen["name"].toString());
+ };
+ std::sort(names.begin(), names.end());
+ return names;
+ };
+
+ auto currentNames = getScreenNames(currentScreens);
+ auto newNames = getScreenNames(newScreens);
+
+ QList<QString> present;
+ std::set_intersection(currentNames.begin(), currentNames.end(), newNames.begin(), newNames.end(),
+ std::inserter(present, present.begin()));
+ QList<QString> added;
+ std::set_difference(newNames.begin(), newNames.end(), currentNames.begin(), currentNames.end(),
+ std::inserter(added, added.begin()));
+ QList<QString> removed;
+ std::set_difference(currentNames.begin(), currentNames.end(), newNames.begin(), newNames.end(),
+ std::inserter(removed, removed.begin()));
+
+ auto platformScreenByName = [](const QString &name, QList<QOffscreenScreen *> screens) -> QOffscreenScreen * {
+ for (QOffscreenScreen *screen : screens) {
+ if (screen->m_name == name)
+ return screen;
+ }
+ Q_UNREACHABLE();
+ };
+
+ auto screenConfigByName = [](const QString &name, QJsonArray screenConfigs) -> QJsonValue {
+ for (QJsonValue screenConfig : screenConfigs) {
+ if (screenConfig["name"].toString() == name)
+ return screenConfig;
+ }
+ Q_UNREACHABLE();
+ };
+
+ auto geometryFromConfig = [](const QJsonObject &config) -> QRect {
+ return QRect(config["x"].toInt(0), config["y"].toInt(0), config["width"].toInt(640), config["height"].toInt(480));
+ };
+
+ // Remove removed screens
+ for (const QString &remove : removed) {
+ QOffscreenScreen *screen = platformScreenByName(remove, m_screens);
+ m_screens.removeAll(screen);
+ QWindowSystemInterface::handleScreenRemoved(screen);
+ }
+
+ // Add new screens
+ for (const QString &add : added) {
+ QJsonValue configValue = screenConfigByName(add, newScreens);
+ QJsonObject config = configValue.toObject();
+ if (config.isEmpty()) {
+ qWarning("empty screen object");
continue;
}
QOffscreenScreen *offscreenScreen = new QOffscreenScreen(this);
- offscreenScreen->m_name = screen["name"].toString();
- offscreenScreen->m_geometry = QRect(screen["x"].toInt(0), screen["y"].toInt(0),
- screen["width"].toInt(640), screen["height"].toInt(480));
- offscreenScreen->m_logicalDpi = screen["logicalDpi"].toInt(96);
- offscreenScreen->m_logicalBaseDpi = screen["logicalBaseDpi"].toInt(96);
- offscreenScreen->m_dpr = screen["dpr"].toDouble(1.0);
-
+ offscreenScreen->m_name = config["name"].toString();
+ offscreenScreen->m_geometry = geometryFromConfig(config);
+ offscreenScreen->m_logicalDpi = config["logicalDpi"].toInt(96);
+ offscreenScreen->m_logicalBaseDpi = config["logicalBaseDpi"].toInt(96);
+ offscreenScreen->m_dpr = config["dpr"].toDouble(1.0);
m_screens.append(offscreenScreen);
QWindowSystemInterface::handleScreenAdded(offscreenScreen);
}
+
+ // Update present screens
+ for (const QString &pres : present) {
+ QOffscreenScreen *screen = platformScreenByName(pres, m_screens);
+ Q_ASSERT(screen);
+ QJsonObject currentConfig = screenConfigByName(pres, currentScreens).toObject();
+ QJsonObject newConfig = screenConfigByName(pres, newScreens).toObject();
+
+ // Name can't change, because it'd be a different screen
+ Q_ASSERT(currentConfig["name"] == newConfig["name"]);
+
+ // Geometry
+ QRect currentGeomtry = geometryFromConfig(currentConfig);
+ QRect newGeomtry = geometryFromConfig(newConfig);
+ if (currentGeomtry != newGeomtry) {
+ screen->m_geometry = newGeomtry;
+ QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), newGeomtry, newGeomtry);
+ }
+
+ // logical DPI
+ int currentLogicalDpi = currentConfig["logicalDpi"].toInt(96);
+ int newLogicalDpi = newConfig["logicalDpi"].toInt(96);
+ if (currentLogicalDpi != newLogicalDpi) {
+ screen->m_logicalDpi = newLogicalDpi;
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->screen(), newLogicalDpi, newLogicalDpi);
+ }
+
+ // The base DPI is more of a platform constant, and should not change, and
+ // there is no handleChange function for it. Print a warning.
+ int currentLogicalBaseDpi = currentConfig["logicalBaseDpi"].toInt(96);
+ int newLogicalBaseDpi = newConfig["logicalBaseDpi"].toInt(96);
+ if (currentLogicalBaseDpi != newLogicalBaseDpi) {
+ screen->m_logicalBaseDpi = newLogicalBaseDpi;
+ qWarning("You ain't supposed to change logicalBaseDpi - its a platform constant. Qt may not react to the change");
+ }
+
+ // DPR. There is also no handleChange function in Qt at this point, instead
+ // the new DPR value will be used during the next repaint. We could repaint
+ // all windows here, but don't. Print a warning.
+ double currentDpr = currentConfig["dpr"].toDouble(1);
+ double newDpr = newConfig["dpr"].toDouble(1);
+ if (currentDpr != newDpr) {
+ screen->m_dpr = newDpr;
+ qWarning("DPR change notifications is not implemented - Qt may not react to the change");
+ }
+ }
+
+ // Now the new configuration is the current configuration
+ m_configuration = configuration;
+}
+
+QJsonObject QOffscreenIntegration::configuration() const
+{
+ return m_configuration;
}
void QOffscreenIntegration::initialize()
@@ -248,7 +388,7 @@ QAbstractEventDispatcher *QOffscreenIntegration::createEventDispatcher() const
QPlatformNativeInterface *QOffscreenIntegration::nativeInterface() const
{
if (!m_nativeInterface)
- m_nativeInterface.reset(new QOffscreenPlatformNativeInterface);
+ m_nativeInterface.reset(new QOffscreenPlatformNativeInterface(const_cast<QOffscreenIntegration*>(this)));
return m_nativeInterface.get();
}
@@ -321,17 +461,15 @@ QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration(const Q
#if QT_CONFIG(xlib) && QT_CONFIG(opengl) && !QT_CONFIG(opengles2)
QByteArray glx = qgetenv("QT_QPA_OFFSCREEN_NO_GLX");
if (glx.isEmpty())
- offscreenIntegration = new QOffscreenX11Integration;
+ offscreenIntegration = new QOffscreenX11Integration(paramList);
#endif
if (!offscreenIntegration)
- offscreenIntegration = new QOffscreenIntegration;
-
- offscreenIntegration->configure(paramList);
+ offscreenIntegration = new QOffscreenIntegration(paramList);
return offscreenIntegration;
}
-QList<QPlatformScreen *> QOffscreenIntegration::screens() const
+QList<QOffscreenScreen *> QOffscreenIntegration::screens() const
{
return m_screens;
}
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h
index 38d145eee3..a490cf5bed 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.h
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h
@@ -44,18 +44,24 @@
#include <qpa/qplatformnativeinterface.h>
#include <qscopedpointer.h>
+#include <qjsonobject.h>
QT_BEGIN_NAMESPACE
class QOffscreenBackendData;
+class QOffscreenScreen;
class QOffscreenIntegration : public QPlatformIntegration
{
public:
- QOffscreenIntegration();
+ QOffscreenIntegration(const QStringList& paramList);
~QOffscreenIntegration();
- void configure(const QStringList& paramList);
+ QJsonObject defaultConfiguration() const;
+ std::optional<QJsonObject> resolveConfigFileConfiguration(const QStringList& paramList) const;
+ void setConfiguration(const QJsonObject &configuration);
+ QJsonObject configuration() const;
+
void initialize() override;
bool hasCapability(QPlatformIntegration::Capability cap) const override;
@@ -78,7 +84,7 @@ public:
static QOffscreenIntegration *createOffscreenIntegration(const QStringList& paramList);
- QList<QPlatformScreen *> screens() const;
+ QList<QOffscreenScreen *> screens() const;
protected:
QScopedPointer<QPlatformFontDatabase> m_fontDatabase;
#if QT_CONFIG(draganddrop)
@@ -87,8 +93,9 @@ protected:
QScopedPointer<QPlatformInputContext> m_inputContext;
QScopedPointer<QPlatformServices> m_services;
mutable QScopedPointer<QPlatformNativeInterface> m_nativeInterface;
- QList<QPlatformScreen *> m_screens;
+ QList<QOffscreenScreen *> m_screens;
bool m_windowFrameMarginsEnabled = true;
+ QJsonObject m_configuration;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
index 1e533f87dc..3c2fdb1f0f 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
@@ -76,6 +76,12 @@ private:
QOffscreenX11Connection *m_connection;
};
+QOffscreenX11Integration::QOffscreenX11Integration(const QStringList& paramList)
+: QOffscreenIntegration(paramList)
+{
+
+}
+
QOffscreenX11Integration::~QOffscreenX11Integration() = default;
bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -106,10 +112,16 @@ QPlatformOpenGLContext *QOffscreenX11Integration::createPlatformOpenGLContext(QO
QOffscreenX11PlatformNativeInterface *QOffscreenX11Integration::nativeInterface() const
{
if (!m_nativeInterface)
- m_nativeInterface.reset(new QOffscreenX11PlatformNativeInterface);
+ m_nativeInterface.reset(new QOffscreenX11PlatformNativeInterface(const_cast<QOffscreenX11Integration *>(this)));
return static_cast<QOffscreenX11PlatformNativeInterface *>(m_nativeInterface.data());
}
+QOffscreenX11PlatformNativeInterface::QOffscreenX11PlatformNativeInterface(QOffscreenIntegration *integration)
+:QOffscreenPlatformNativeInterface(integration)
+{
+
+}
+
QOffscreenX11PlatformNativeInterface::~QOffscreenX11PlatformNativeInterface() = default;
void *QOffscreenX11PlatformNativeInterface::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
index 7e26b76759..afd30d7b4b 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
@@ -56,6 +56,7 @@ class QOffscreenX11Info;
class QOffscreenX11PlatformNativeInterface : public QOffscreenPlatformNativeInterface
{
public:
+ QOffscreenX11PlatformNativeInterface(QOffscreenIntegration *integration);
~QOffscreenX11PlatformNativeInterface();
void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override;
@@ -69,6 +70,7 @@ public:
class QOffscreenX11Integration : public QOffscreenIntegration
{
public:
+ QOffscreenX11Integration(const QStringList& paramList);
~QOffscreenX11Integration();
bool hasCapability(QPlatformIntegration::Capability cap) const override;
diff --git a/src/plugins/platforms/qnx/CMakeLists.txt b/src/plugins/platforms/qnx/CMakeLists.txt
index b49c5be162..3e952e6ddf 100644
--- a/src/plugins/platforms/qnx/CMakeLists.txt
+++ b/src/plugins/platforms/qnx/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QQnxIntegrationPlugin
OUTPUT_NAME qqnx
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES qnx # special case
SOURCES
main.cpp main.h
@@ -48,7 +48,7 @@ qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_egl
SOURCES
qqnxeglwindow.cpp qqnxeglwindow.h
qqnxglcontext.cpp qqnxglcontext.h
- PUBLIC_LIBRARIES
+ LIBRARIES
EGL::EGL
)
@@ -58,14 +58,14 @@ qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_qqnx_pps
qqnxnavigatoreventnotifier.cpp qqnxnavigatoreventnotifier.h
qqnxnavigatorpps.cpp qqnxnavigatorpps.h
qqnxvirtualkeyboardpps.cpp qqnxvirtualkeyboardpps.h
- PUBLIC_LIBRARIES
+ LIBRARIES
PPS::PPS
)
qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_clipboard AND QT_FEATURE_qqnx_pps
SOURCES
qqnxclipboard.cpp qqnxclipboard.h
- PUBLIC_LIBRARIES
+ LIBRARIES
clipboard
)
@@ -84,7 +84,7 @@ qt_internal_extend_target(QQnxIntegrationPlugin CONDITION lgmon
qqnxlgmon.cpp
DEFINES
QQNX_LGMON
- PUBLIC_LIBRARIES
+ LIBRARIES
lgmon
)
diff --git a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
index de604bc491..98fb6d39b7 100644
--- a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
+++ b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
@@ -2,7 +2,7 @@ qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype)
qt_internal_add_plugin(QVkKhrDisplayIntegrationPlugin
OUTPUT_NAME qvkkhrdisplay
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vkkhrdisplay
SOURCES
main.cpp
@@ -10,7 +10,7 @@ qt_internal_add_plugin(QVkKhrDisplayIntegrationPlugin
qvkkhrdisplayvulkaninstance.cpp qvkkhrdisplayvulkaninstance.h
DEFINES
QT_NO_FOREACH
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::FbSupportPrivate
@@ -24,6 +24,6 @@ qt_internal_extend_target(QVkKhrDisplayIntegrationPlugin CONDITION QT_FEATURE_fr
)
qt_internal_extend_target(QVkKhrDisplayIntegrationPlugin CONDITION TARGET Qt::InputSupportPrivate
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::InputSupportPrivate
)
diff --git a/src/plugins/platforms/vnc/CMakeLists.txt b/src/plugins/platforms/vnc/CMakeLists.txt
index 7c28e26d9b..ca9445207b 100644
--- a/src/plugins/platforms/vnc/CMakeLists.txt
+++ b/src/plugins/platforms/vnc/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QVncIntegrationPlugin
OUTPUT_NAME qvnc
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vnc # special case
SOURCES
main.cpp
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
index 10e247b7dd..00f86b837c 100644
--- a/src/plugins/platforms/wasm/CMakeLists.txt
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QWasmIntegrationPlugin
OUTPUT_NAME qwasm
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES wasm # special case
- TYPE platforms
+ PLUGIN_TYPE platforms
STATIC
SOURCES
main.cpp
@@ -29,7 +29,7 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
DEFINES
QT_EGL_NO_X11
QT_NO_FOREACH
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
@@ -37,26 +37,24 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
)
# Resources:
-set_source_files_properties("${QT_SOURCE_TREE}/src/3rdparty/wasm/Vera.ttf" PROPERTIES QT_RESOURCE_ALIAS "Vera.ttf")
-set_source_files_properties("${QT_SOURCE_TREE}/src/3rdparty/wasm/DejaVuSans.ttf" PROPERTIES QT_RESOURCE_ALIAS "DejaVuSans.ttf")
-set_source_files_properties("${QT_SOURCE_TREE}/src/3rdparty/wasm/DejaVuSansMono.ttf" PROPERTIES QT_RESOURCE_ALIAS "DejaVuSansMono.ttf")
-
set(wasmfonts_resource_files
- "${QT_SOURCE_TREE}/src/3rdparty/wasm/Vera.ttf"
- "${QT_SOURCE_TREE}/src/3rdparty/wasm/DejaVuSans.ttf"
- "${QT_SOURCE_TREE}/src/3rdparty/wasm/DejaVuSansMono.ttf"
+ "${QtBase_SOURCE_DIR}/src/3rdparty/wasm/Vera.ttf"
+ "${QtBase_SOURCE_DIR}/src/3rdparty/wasm/DejaVuSans.ttf"
+ "${QtBase_SOURCE_DIR}/src/3rdparty/wasm/DejaVuSansMono.ttf"
)
qt_internal_add_resource(QWasmIntegrationPlugin "wasmfonts"
PREFIX
"/fonts"
+ BASE
+ "${QtBase_SOURCE_DIR}/src/3rdparty/wasm"
FILES
${wasmfonts_resource_files}
)
qt_internal_extend_target(QWasmIntegrationPlugin CONDITION QT_FEATURE_opengl
SOURCES
qwasmbackingstore.cpp qwasmbackingstore.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::OpenGL
Qt::OpenGLPrivate
)
@@ -64,15 +62,20 @@ qt_internal_extend_target(QWasmIntegrationPlugin CONDITION QT_FEATURE_opengl
#### Keys ignored in scope 4:.:.:wasm.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
# PLUGIN_EXTENDS = "-"
-qt_copy_or_install(FILES
+set(wasm_support_files
wasm_shell.html
- DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins/platforms/"
-)
-qt_copy_or_install(FILES
qtloader.js
- DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins/platforms/"
+ qtlogo.svg
)
+
qt_copy_or_install(FILES
- qtlogo.svg
- DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins/platforms/"
+ ${wasm_support_files}
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins/platforms"
)
+# Need to copy the support files to the build dir in a top-level prefix build
+# So _qt_internal_wasm_add_target_helpers finds them.
+if(QT_WILL_INSTALL)
+ foreach(wasm_support_file ${wasm_support_files})
+ file(COPY "${wasm_support_file}" DESTINATION "${QT_BUILD_DIR}/plugins/platforms")
+ endforeach()
+endif()
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
index b159cd63ab..d73fe3e23a 100644
--- a/src/plugins/platforms/wasm/qtloader.js
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -126,12 +126,25 @@
// Signals to the application that a canvas has been resized.
// setFontDpi
// Sets the logical font dpi for the application.
+// module
+// Returns the Emscripten module object, or undefined if the module
+// has not been created yet. Note that the module object becomes available
+// at the very end of the loading sequence, _after_ the transition from
+// Loading to Running occurs.
-var Module = {}
-
function QtLoader(config)
{
+ // The Emscripten module and module configuration object. The module
+ // object is created in completeLoadEmscriptenModule().
+ self.module = undefined;
+ self.moduleConfig = {};
+
+ // Qt properties. These are propagated to the Emscripten module after
+ // it has been created.
+ self.qtCanvasElements = undefined;
+ self.qtFontDpi = 96;
+
function webAssemblySupported() {
return typeof WebAssembly !== "undefined"
}
@@ -241,6 +254,7 @@ function QtLoader(config)
publicAPI.resizeCanvasElement = resizeCanvasElement;
publicAPI.setFontDpi = setFontDpi;
publicAPI.fontDpi = fontDpi;
+ publicAPI.module = module;
self.restartCount = 0;
@@ -341,7 +355,7 @@ function QtLoader(config)
// The wasm binary has been compiled into a module during resource download,
// and is ready to be instantiated. Define the instantiateWasm callback which
// emscripten will call to create the instance.
- Module.instantiateWasm = function(imports, successCallback) {
+ self.moduleConfig.instantiateWasm = function(imports, successCallback) {
WebAssembly.instantiate(wasmModule, imports).then(function(instance) {
successCallback(instance, wasmModule);
}, function(error) {
@@ -351,27 +365,27 @@ function QtLoader(config)
return {};
};
- Module.locateFile = Module.locateFile || function(filename) {
+ self.moduleConfig.locateFile = self.moduleConfig.locateFile || function(filename) {
return config.path + filename;
};
// Attach status callbacks
- Module.setStatus = Module.setStatus || function(text) {
+ self.moduleConfig.setStatus = self.moduleConfig.setStatus || function(text) {
// Currently the only usable status update from this function
// is "Running..."
if (text.startsWith("Running"))
setStatus("Running");
};
- Module.monitorRunDependencies = Module.monitorRunDependencies || function(left) {
+ self.moduleConfig.monitorRunDependencies = self.moduleConfig.monitorRunDependencies || function(left) {
// console.log("monitorRunDependencies " + left)
};
// Attach standard out/err callbacks.
- Module.print = Module.print || function(text) {
+ self.moduleConfig.print = self.moduleConfig.print || function(text) {
if (config.stdoutEnabled)
console.log(text)
};
- Module.printErr = Module.printErr || function(text) {
+ self.moduleConfig.printErr = self.moduleConfig.printErr || function(text) {
// Filter out OpenGL getProcAddress warnings. Qt tries to resolve
// all possible function/extension names at startup which causes
// emscripten to spam the console log with warnings.
@@ -387,12 +401,12 @@ function QtLoader(config)
// Emscripten will typically call printErr with the error text
// as well. Note that emscripten may also throw exceptions from
// async callbacks. These should be handled in window.onerror by user code.
- Module.onAbort = Module.onAbort || function(text) {
+ self.moduleConfig.onAbort = self.moduleConfig.onAbort || function(text) {
publicAPI.crashed = true;
publicAPI.exitText = text;
setStatus("Exited");
};
- Module.quit = Module.quit || function(code, exception) {
+ self.moduleConfig.quit = self.moduleConfig.quit || function(code, exception) {
if (exception.name == "ExitStatus") {
// Clean exit with code
publicAPI.exitText = undefined
@@ -404,17 +418,20 @@ function QtLoader(config)
setStatus("Exited");
};
- // Set environment variables
- Module.preRun = Module.preRun || []
- Module.preRun.push(function() {
+ self.moduleConfig.preRun = self.moduleConfig.preRun || []
+ self.moduleConfig.preRun.push(function(module) {
+ // Set environment variables
for (var [key, value] of Object.entries(config.environment)) {
- ENV[key.toUpperCase()] = value;
+ module.ENV[key.toUpperCase()] = value;
}
+ // Propagate Qt module properties
+ module.qtCanvasElements = self.qtCanvasElements;
+ module.qtFontDpi = self.qtFontDpi;
});
- Module.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'});
+ self.moduleConfig.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'});
- Module.qtCanvasElements = config.canvasElements;
+ self.qtCanvasElements = config.canvasElements;
config.restart = function() {
@@ -438,9 +455,13 @@ function QtLoader(config)
publicAPI.exitText = undefined;
publicAPI.crashed = false;
- // Finally evaluate the emscripten application script, which will
- // reference the global Module object created above.
- self.eval(emscriptenModuleSource); // ES5 indirect global scope eval
+ // Load the Emscripten application module. This is done by eval()'ing the
+ // javascript runtime generated by Emscripten, and then calling
+ // createQtAppInstance(), which was added to the global scope.
+ eval(emscriptenModuleSource);
+ createQtAppInstance(self.moduleConfig).then(function(module) {
+ self.module = module;
+ });
}
function setErrorContent() {
@@ -544,31 +565,35 @@ function QtLoader(config)
function addCanvasElement(element) {
if (publicAPI.status == "Running")
- Module.qtAddCanvasElement(element);
+ self.module.qtAddCanvasElement(element);
else
console.log("Error: addCanvasElement can only be called in the Running state");
}
function removeCanvasElement(element) {
if (publicAPI.status == "Running")
- Module.qtRemoveCanvasElement(element);
+ self.module.qtRemoveCanvasElement(element);
else
console.log("Error: removeCanvasElement can only be called in the Running state");
}
function resizeCanvasElement(element) {
if (publicAPI.status == "Running")
- Module.qtResizeCanvasElement(element);
+ self.module.qtResizeCanvasElement(element);
}
function setFontDpi(dpi) {
- Module.qtFontDpi = dpi;
+ self.qtFontDpi = dpi;
if (publicAPI.status == "Running")
- Module.qtSetFontDpi(dpi);
+ self.qtSetFontDpi(dpi);
}
function fontDpi() {
- return Module.qtFontDpi;
+ return self.qtFontDpi;
+ }
+
+ function module() {
+ return self.module;
}
setStatus("Created");
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp
index 713adee8f9..222dcff7fa 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.cpp
+++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp
@@ -75,11 +75,7 @@ static void qClipboardCutTo(val event)
QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
0, QEvent::KeyPress, Qt::Key_X, Qt::ControlModifier, "X");
}
-
- val module = val::global("Module");
- val clipdata = module.call<val>("qtGetClipboardData");
- val clipFormat = module.call<val>("qtGetClipboardFormat");
- event["clipboardData"].call<void>("setData", clipFormat, clipdata);
+ event["clipboardData"].call<void>("setData", getClipboardFormat(), getClipboardData());
event.call<void>("preventDefault");
}
@@ -90,19 +86,14 @@ static void qClipboardCopyTo(val event)
QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
0, QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier, "C");
}
-
- val module = val::global("Module");
- val clipdata = module.call<val>("qtGetClipboardData");
- val clipFormat = module.call<val>("qtGetClipboardFormat");
- event["clipboardData"].call<void>("setData", clipFormat, clipdata);
+ event["clipboardData"].call<void>("setData", getClipboardFormat(), getClipboardData());
event.call<void>("preventDefault");
}
static void qClipboardPasteTo(val event)
{
bool hasClipboardApi = QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi;
- val clipdata = hasClipboardApi ?
- val::global("Module").call<val>("qtGetClipboardData") :
+ val clipdata = hasClipboardApi ? getClipboardData() :
event["clipboardData"].call<val>("getData", val("text"));
const QString qstr = QWasmString::toQString(clipdata);
@@ -114,9 +105,6 @@ static void qClipboardPasteTo(val event)
}
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
- function("qtGetClipboardData", &getClipboardData);
- function("qtGetClipboardFormat", &getClipboardFormat);
- function("qtPasteClipboardData", &pasteClipboardData);
function("qtClipboardPromiseResolve", &qClipboardPromiseResolve);
function("qtClipboardCutTo", &qClipboardCutTo);
function("qtClipboardCopyTo", &qClipboardCopyTo);
@@ -212,7 +200,7 @@ void QWasmClipboard::readTextFromClipboard()
if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
val navigator = val::global("navigator");
val textPromise = navigator["clipboard"].call<val>("readText");
- val readTextResolve = val::global("Module")["qtClipboardPromiseResolve"];
+ val readTextResolve = val::module_property("qtClipboardPromiseResolve");
textPromise.call<val>("then", readTextResolve);
}
}
@@ -220,10 +208,7 @@ void QWasmClipboard::readTextFromClipboard()
void QWasmClipboard::writeTextToClipboard()
{
if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
- val module = val::global("Module");
- val txt = module.call<val>("qtGetClipboardData");
- val format = module.call<val>("qtGetClipboardFormat");
val navigator = val::global("navigator");
- navigator["clipboard"].call<void>("writeText", txt);
+ navigator["clipboard"].call<void>("writeText", getClipboardData());
}
}
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
index 29dbf96883..69a38ecd68 100644
--- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
@@ -91,6 +91,16 @@ bool QWasmEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
if (!(flags & QEventLoop::EventLoopExec))
return QUnixEventDispatcherQPA::processEvents(flags);
+ if (flags & QEventLoop::DialogExec) {
+ qWarning() << "Warning: dialog exec() is not supported on Qt for WebAssembly, please use"
+ << "show() instead. When using exec() the dialog will show, the user can interact"
+ << "with it and the appropriate signals will be emitted on close. However, the"
+ << "exec() call never returns, stack content at the time of the exec() call"
+ << "is leaked, and the exec() call may interfere with input event processing";
+
+ emscripten_sleep(1); // This call never returns
+ }
+
// Handle processEvents from QEventLoop::exec():
//
// At this point the application has created its root objects on
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
index 5b1201b5e5..a3e02d9d4a 100644
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
@@ -370,9 +370,9 @@ Qt::MouseButton QWasmEventTranslator::translateMouseButton(unsigned short button
int QWasmEventTranslator::mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
{
QWasmEventTranslator *translator = (QWasmEventTranslator*)userData;
- translator->processMouse(eventType,mouseEvent);
+ bool accepted = translator->processMouse(eventType,mouseEvent);
QWasmEventDispatcher::maintainTimers();
- return 0;
+ return accepted;
}
void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode,
@@ -431,7 +431,7 @@ void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode,
window->setGeometry(x1, y1, w, h);
}
-void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent)
+bool QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent)
{
QPoint targetPoint(mouseEvent->targetX, mouseEvent->targetY);
QPoint globalPoint = screen()->geometry().topLeft() + targetPoint;
@@ -533,10 +533,12 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven
lastWindow = nullptr;
interior = true;
}
+ bool accepted = true;
if (window2 && interior) {
- QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
+ accepted = QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
window2, getTimestamp(), localPoint, globalPoint, pressedButtons, button, buttonEventType, modifiers);
}
+ return accepted;
}
int QWasmEventTranslator::focus_cb(int /*eventType*/, const EmscriptenFocusEvent */*focusEvent*/, void */*userData*/)
@@ -582,11 +584,10 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor);
if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor);
- QWindowSystemInterface::handleWheelEvent(window2, getTimestamp(), localPoint,
+ bool accepted = QWindowSystemInterface::handleWheelEvent(window2, getTimestamp(), localPoint,
globalPoint, QPoint(), pixelDelta, modifiers);
QWasmEventDispatcher::maintainTimers();
-
- return 1;
+ return static_cast<int>(accepted);
}
int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
@@ -663,14 +664,15 @@ int QWasmEventTranslator::handleTouch(int eventType, const EmscriptenTouchEvent
QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(touchEvent);
- QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ bool accepted = QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
window2, getTimestamp(), touchDevice, touchPointList, keyModifier);
if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL)
- QWindowSystemInterface::handleTouchCancelEvent(window2, getTimestamp(), touchDevice, keyModifier);
+ accepted = QWindowSystemInterface::handleTouchCancelEvent(window2, getTimestamp(), touchDevice, keyModifier);
QWasmEventDispatcher::maintainTimers();
- return 1;
+
+ return static_cast<int>(accepted);
}
quint64 QWasmEventTranslator::getTimestamp()
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h
index ab06bb8cf0..3e772583af 100644
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.h
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h
@@ -74,7 +74,7 @@ private:
QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent);
Qt::MouseButton translateMouseButton(unsigned short button);
- void processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent);
+ bool processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent);
bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
Qt::Key translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey);
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index 15d396f479..470deb6d70 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -62,11 +62,6 @@
using namespace emscripten;
QT_BEGIN_NAMESPACE
-static void browserBeforeUnload(emscripten::val)
-{
- QWasmIntegration::QWasmBrowserExit();
-}
-
static void addCanvasElement(emscripten::val canvas)
{
QWasmIntegration::get()->addScreen(canvas);
@@ -95,7 +90,6 @@ static void resizeAllScreens(emscripten::val event)
EMSCRIPTEN_BINDINGS(qtQWasmIntegraton)
{
- function("qtBrowserBeforeUnload", &browserBeforeUnload);
function("qtAddCanvasElement", &addCanvasElement);
function("qtRemoveCanvasElement", &removeCanvasElement);
function("qtResizeCanvasElement", &resizeCanvasElement);
@@ -127,8 +121,6 @@ QWasmIntegration::QWasmIntegration()
addScreen(canvas);
}
- emscripten::val::global("window").set("onbeforeunload", val::module_property("qtBrowserBeforeUnload"));
-
// install browser window resize handler
auto onWindowResize = [](int eventType, const EmscriptenUiEvent *e, void *userData) -> int {
Q_UNUSED(eventType);
@@ -142,7 +134,7 @@ QWasmIntegration::QWasmIntegration()
integration->resizeAllScreens();
return 0;
};
- emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, 1, onWindowResize);
+ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE, onWindowResize);
// install visualViewport resize handler which picks up size and scale change on mobile.
emscripten::val visualViewport = emscripten::val::global("window")["visualViewport"];
@@ -154,6 +146,14 @@ QWasmIntegration::QWasmIntegration()
QWasmIntegration::~QWasmIntegration()
{
+ // Remove event listenes
+ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE, nullptr);
+ emscripten::val visualViewport = emscripten::val::global("window")["visualViewport"];
+ if (!visualViewport.isUndefined()) {
+ visualViewport.call<void>("removeEventListener", val("resize"),
+ val::module_property("qtResizeAllScreens"));
+ }
+
delete m_fontDb;
delete m_desktopServices;
@@ -164,12 +164,6 @@ QWasmIntegration::~QWasmIntegration()
s_instance = nullptr;
}
-void QWasmIntegration::QWasmBrowserExit()
-{
- QCoreApplication *app = QCoreApplication::instance();
- app->quit();
-}
-
bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
index f527053489..16c48e1ea1 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.h
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -82,7 +82,6 @@ public:
QWasmClipboard *getWasmClipboard() { return m_clipboard; }
static QWasmIntegration *get() { return s_instance; }
- static void QWasmBrowserExit();
void addScreen(const emscripten::val &canvas);
void removeScreen(const emscripten::val &canvas);
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
index 7a8bb4f686..0b11415fd3 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.cpp
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -54,9 +54,9 @@ const char * QWasmScreen::m_canvasResizeObserverCallbackContextPropertyName = "d
QWasmScreen::QWasmScreen(const emscripten::val &canvas)
: m_canvas(canvas)
+ , m_compositor(new QWasmCompositor(this))
+ , m_eventTranslator(new QWasmEventTranslator(this))
{
- m_compositor = new QWasmCompositor(this);
- m_eventTranslator = new QWasmEventTranslator(this);
updateQScreenAndCanvasRenderSize();
m_canvas.call<void>("focus");
}
@@ -84,12 +84,12 @@ QWasmScreen *QWasmScreen::get(QScreen *screen)
QWasmCompositor *QWasmScreen::compositor()
{
- return m_compositor;
+ return m_compositor.get();
}
QWasmEventTranslator *QWasmScreen::eventTranslator()
{
- return m_eventTranslator;
+ return m_eventTranslator.get();
}
emscripten::val QWasmScreen::canvas() const
diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h
index 14d5a2f7d1..4acf90d515 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.h
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -86,8 +86,8 @@ public slots:
private:
emscripten::val m_canvas;
- QWasmCompositor *m_compositor = nullptr;
- QWasmEventTranslator *m_eventTranslator = nullptr;
+ std::unique_ptr<QWasmCompositor> m_compositor;
+ std::unique_ptr<QWasmEventTranslator> m_eventTranslator;
QRect m_geometry = QRect(0, 0, 100, 100);
int m_depth = 32;
QImage::Format m_format = QImage::Format_RGB32;
diff --git a/src/plugins/platforms/wasm/qwasmstring.cpp b/src/plugins/platforms/wasm/qwasmstring.cpp
index b1be405eeb..1f2668af05 100644
--- a/src/plugins/platforms/wasm/qwasmstring.cpp
+++ b/src/plugins/platforms/wasm/qwasmstring.cpp
@@ -36,7 +36,7 @@ using namespace emscripten;
val QWasmString::fromQString(const QString &str)
{
static const val UTF16ToString(
- val::global("Module")["UTF16ToString"]);
+ val::module_property("UTF16ToString"));
auto ptr = quintptr(str.utf16());
return UTF16ToString(val(ptr));
@@ -49,7 +49,7 @@ QString QWasmString::toQString(const val &v)
return result;
static const val stringToUTF16(
- val::global("Module")["stringToUTF16"]);
+ val::module_property("stringToUTF16"));
static const val length("length");
int len = v[length].as<int>();
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
index a4fb8524c5..1bcc407bc1 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -416,8 +416,9 @@ bool QWasmWindow::windowIsPopupType(Qt::WindowType type) const
{
if (type == Qt::Widget)
type = window()->type();
- if (type == Qt::Tool)
- return false;
+ if (type != Qt::Tool)
+ return true;
+ return false;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt
index 43f08a6a86..880fa79ef5 100644
--- a/src/plugins/platforms/windows/CMakeLists.txt
+++ b/src/plugins/platforms/windows/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QWindowsIntegrationPlugin
OUTPUT_NAME qwindows
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES windows # special case
SOURCES
main.cpp
@@ -128,7 +128,7 @@ qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_tablete
SOURCES
qwindowstabletsupport.cpp qwindowstabletsupport.h
INCLUDE_DIRECTORIES
- ${QT_SOURCE_TREE}/src/3rdparty/wintab
+ ${QtBase_SOURCE_DIR}/src/3rdparty/wintab
)
qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 79db0b74e6..433e58a97a 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -200,18 +200,16 @@ void QWindowsUser32DLL::init()
getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences");
setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences");
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8) {
- enableMouseInPointer = (EnableMouseInPointer)library.resolve("EnableMouseInPointer");
- getPointerType = (GetPointerType)library.resolve("GetPointerType");
- getPointerInfo = (GetPointerInfo)library.resolve("GetPointerInfo");
- getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects");
- getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo");
- getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo");
- getPointerFrameTouchInfoHistory = (GetPointerFrameTouchInfoHistory)library.resolve("GetPointerFrameTouchInfoHistory");
- getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo");
- getPointerPenInfoHistory = (GetPointerPenInfoHistory)library.resolve("GetPointerPenInfoHistory");
- skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages");
- }
+ enableMouseInPointer = (EnableMouseInPointer)library.resolve("EnableMouseInPointer");
+ getPointerType = (GetPointerType)library.resolve("GetPointerType");
+ getPointerInfo = (GetPointerInfo)library.resolve("GetPointerInfo");
+ getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects");
+ getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo");
+ getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo");
+ getPointerFrameTouchInfoHistory = (GetPointerFrameTouchInfoHistory)library.resolve("GetPointerFrameTouchInfoHistory");
+ getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo");
+ getPointerPenInfoHistory = (GetPointerPenInfoHistory)library.resolve("GetPointerPenInfoHistory");
+ skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages");
if (QOperatingSystemVersion::current()
>= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) {
@@ -220,6 +218,7 @@ void QWindowsUser32DLL::init()
getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext");
getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext");
systemParametersInfoForDpi = (SystemParametersInfoForDpi)library.resolve("SystemParametersInfoForDpi");
+ getDpiForWindow = (GetDpiForWindow)library.resolve("GetDpiForWindow");
}
}
@@ -232,8 +231,6 @@ bool QWindowsUser32DLL::supportsPointerApi()
void QWindowsShcoreDLL::init()
{
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1)
- return;
QSystemLibrary library(QStringLiteral("SHCore"));
getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness");
setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness");
@@ -405,9 +402,6 @@ bool QWindowsContext::initPointer(unsigned integrationOptions)
if (integrationOptions & QWindowsIntegration::DontUseWMPointer)
return false;
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8)
- return false;
-
if (!QWindowsContext::user32dll.supportsPointerApi())
return false;
@@ -516,9 +510,9 @@ void QWindowsContext::setProcessDpiV2Awareness()
QWindowsContextPrivate::m_v2DpiAware = true;
} else {
const HRESULT errorCode = GetLastError();
- // E_ACCESSDENIED means set externally (MSVC manifest or external app loading Qt plugin).
+ // ERROR_ACCESS_DENIED means set externally (MSVC manifest or external app loading Qt plugin).
// Silence warning in that case unless debug is enabled.
- if (errorCode != E_ACCESSDENIED || lcQpaWindows().isDebugEnabled()) {
+ if (errorCode != ERROR_ACCESS_DENIED || lcQpaWindows().isDebugEnabled()) {
qWarning().noquote().nospace() << "setProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) failed: "
<< QWindowsContext::comErrorString(errorCode);
}
@@ -1094,31 +1088,13 @@ static inline QWindowsInputContext *windowsInputContext()
return qobject_cast<QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext());
}
-
-// Child windows, fixed-size windows or pop-ups and similar should not be resized
-static inline bool resizeOnDpiChanged(const QWindow *w)
-{
- bool result = false;
- if (w->isTopLevel()) {
- switch (w->type()) {
- case Qt::Window:
- case Qt::Dialog:
- case Qt::Sheet:
- case Qt::Drawer:
- case Qt::Tool:
- result = !w->flags().testFlag(Qt::MSWindowsFixedSizeDialogHint);
- break;
- default:
- break;
- }
- }
- return result;
-}
-
bool QWindowsContext::shouldHaveNonClientDpiScaling(const QWindow *window)
{
+ // DPI aware V2 processes always have NonClientDpiScaling enabled.
+ if (QWindowsContextPrivate::m_v2DpiAware)
+ return true;
+
return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10
- && !QWindowsContextPrivate::m_v2DpiAware // V2 implies NonClientDpiScaling; no need to enable
&& window->isTopLevel()
&& !window->property(QWindowsWindow::embeddedNativeParentHandleProperty).isValid()
#if QT_CONFIG(opengl) // /QTBUG-62901, EnableNonClientDpiScaling has problems with GL
@@ -1295,8 +1271,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
d->m_creationContext->obtainedPos = QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return true;
case QtWindows::NonClientCreate:
- if (shouldHaveNonClientDpiScaling(d->m_creationContext->window))
- enableNonClientDpiScaling(msg.hwnd);
+ if (shouldHaveNonClientDpiScaling(d->m_creationContext->window) &&
+ // DPI aware V2 processes always have NonClientDpiScaling enabled
+ // and there is no need to make an API call to manually enable.
+ !QWindowsContextPrivate::m_v2DpiAware) {
+ enableNonClientDpiScaling(msg.hwnd);
+ }
return false;
case QtWindows::CalculateSize:
return QWindowsGeometryHint::handleCalculateSize(d->m_creationContext->customMargins, msg, result);
@@ -1474,24 +1454,32 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
#endif
} break;
case QtWindows::DpiChangedEvent: {
- // Try to apply the suggested size first and then notify ScreenChanged
- // so that the resize event sent from QGuiApplication incorporates it
- // WM_DPICHANGED is sent with a size that avoids resize loops (by
- // snapping back to the previous screen, see QTBUG-65580).
- const bool doResize = resizeOnDpiChanged(platformWindow->window());
- if (doResize) {
- platformWindow->setFlag(QWindowsWindow::WithinDpiChanged);
- platformWindow->updateFullFrameMargins();
- const auto prcNewWindow = reinterpret_cast<RECT *>(lParam);
- qCDebug(lcQpaWindows) << __FUNCTION__ << "WM_DPICHANGED"
- << platformWindow->window() << *prcNewWindow;
- SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top,
- prcNewWindow->right - prcNewWindow->left,
- prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE);
- platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged);
- }
+
+ const UINT dpi = HIWORD(wParam);
+ const qreal scale = qreal(dpi) / qreal(platformWindow->savedDpi());
+ platformWindow->setSavedDpi(dpi);
+
+ // Send screen change first, so that the new sceen is set during any following resize
platformWindow->checkForScreenChanged(QWindowsWindow::FromDpiChange);
- return doResize;
+
+ // Apply the suggested window geometry to the native window. This will make
+ // sure the window tracks the mouse cursor during screen change, and also
+ // that the window size is scaled according to the DPI change.
+ platformWindow->updateFullFrameMargins();
+ const auto prcNewWindow = reinterpret_cast<RECT *>(lParam);
+ SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top,
+ prcNewWindow->right - prcNewWindow->left,
+ prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE);
+
+ // Scale child QPlatformWindow size. Windows sends WM_DPICHANGE to top-level windows only.
+ for (QWindow *childWindow : platformWindow->window()->findChildren<QWindow *>()) {
+ QWindowsWindow *platformChildWindow = static_cast<QWindowsWindow *>(childWindow->handle());
+ QRect currentGeometry = platformChildWindow->geometry();
+ QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale);
+ platformChildWindow->setGeometry(scaledGeometry);
+ }
+
+ return true;
}
#if QT_CONFIG(sessionmanager)
case QtWindows::QueryEndSessionApplicationEvent: {
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 99b4bb6c77..04328a0369 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -108,6 +108,7 @@ struct QWindowsUser32DLL
typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND);
typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int);
typedef BOOL (WINAPI *SystemParametersInfoForDpi)(UINT, UINT, PVOID, UINT, UINT);
+ typedef int (WINAPI *GetDpiForWindow)(HWND);
// Windows pointer functions (Windows 8 or later).
EnableMouseInPointer enableMouseInPointer = nullptr;
@@ -124,6 +125,9 @@ struct QWindowsUser32DLL
// Windows Vista onwards
SetProcessDPIAware setProcessDPIAware = nullptr;
+ // Windows 10 version 1607 onwards
+ GetDpiForWindow getDpiForWindow = nullptr;
+
// Windows 10 version 1703 onwards
SetProcessDpiAwarenessContext setProcessDpiAwarenessContext = nullptr;
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 61a885953a..6fbf4183da 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -529,6 +529,11 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
return QPlatformTheme::themeHint(hint);
}
+QPlatformTheme::Appearance QWindowsTheme::appearance() const
+{
+ return QWindowsContext::isDarkMode() ? Appearance::Dark : Appearance::Light;
+}
+
void QWindowsTheme::clearPalettes()
{
qDeleteAll(m_palettes, m_palettes + NPalettes);
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index af28f2878c..9d5fcc92fe 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -64,6 +64,9 @@ public:
QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override;
#endif
QVariant themeHint(ThemeHint) const override;
+
+ Appearance appearance() const override;
+
const QPalette *palette(Palette type = SystemPalette) const override
{ return m_palettes[type]; }
const QFont *font(Font type = SystemFont) const override
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index a282f7c238..38e42a6282 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -360,20 +360,11 @@ static inline bool windowIsAccelerated(const QWindow *w)
static bool applyBlurBehindWindow(HWND hwnd)
{
- BOOL compositionEnabled;
- if (DwmIsCompositionEnabled(&compositionEnabled) != S_OK)
- return false;
-
DWM_BLURBEHIND blurBehind = {0, 0, nullptr, 0};
- if (compositionEnabled) {
- blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
- blurBehind.fEnable = TRUE;
- blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
- } else {
- blurBehind.dwFlags = DWM_BB_ENABLE;
- blurBehind.fEnable = FALSE;
- }
+ blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ blurBehind.fEnable = TRUE;
+ blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
const bool result = DwmEnableBlurBehindWindow(hwnd, &blurBehind) == S_OK;
@@ -1428,6 +1419,8 @@ void QWindowsWindow::initialize()
if (obtainedScreen && screen() != obtainedScreen)
QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, obtainedScreen->screen());
}
+ QWindowsWindow::setSavedDpi(QWindowsContext::user32dll.getDpiForWindow ?
+ QWindowsContext::user32dll.getDpiForWindow(handle()) : 96);
}
QSurfaceFormat QWindowsWindow::format() const
@@ -2006,10 +1999,6 @@ void QWindowsWindow::handleGeometryChange()
{
const QRect previousGeometry = m_data.geometry;
m_data.geometry = geometry_sys();
- if (testFlag(WithinDpiChanged)
- && QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd) != screen()) {
- return; // QGuiApplication will send resize when screen actually changes
- }
QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
// QTBUG-32121: OpenGL/normal windows (with exception of ANGLE
// which we no longer support in Qt 6) do not receive expose
@@ -2104,12 +2093,6 @@ void QWindowsWindow::releaseDC()
}
}
-static inline bool dwmIsCompositionEnabled()
-{
- BOOL dWmCompositionEnabled = FALSE;
- return SUCCEEDED(DwmIsCompositionEnabled(&dWmCompositionEnabled)) && dWmCompositionEnabled == TRUE;
-}
-
static inline bool isSoftwareGl()
{
#if QT_CONFIG(dynamicgl)
@@ -2133,22 +2116,13 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
return false;
PAINTSTRUCT ps;
- // GL software rendering (QTBUG-58178) and Windows 7/Aero off with some AMD cards
+ // GL software rendering (QTBUG-58178) with some AMD cards
// (QTBUG-60527) need InvalidateRect() to suppress artifacts while resizing.
- if (testFlag(OpenGLSurface) && (isSoftwareGl() || !dwmIsCompositionEnabled()))
+ if (testFlag(OpenGLSurface) && isSoftwareGl())
InvalidateRect(hwnd, nullptr, false);
BeginPaint(hwnd, &ps);
- // Observed painting problems with Aero style disabled (QTBUG-7865).
- if (Q_UNLIKELY(!dwmIsCompositionEnabled())
- && ((testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered))
- || testFlag(VulkanSurface)
- || testFlag(Direct3DSurface)))
- {
- SelectClipRgn(ps.hdc, nullptr);
- }
-
// If the a window is obscured by another window (such as a child window)
// we still need to send isExposed=true, for compatibility.
// Our tests depend on it.
@@ -2721,11 +2695,6 @@ static int getBorderWidth(const QPlatformScreen *screen)
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
{
- // We don't apply the min/max size hint as we change the dpi, because we did not adjust the
- // QScreen of the window yet so we don't have the min/max with the right ratio
- if (!testFlag(QWindowsWindow::WithinDpiChanged))
- QWindowsGeometryHint::applyToMinMaxInfo(window(), fullFrameMargins(), mmi);
-
// This block fixes QTBUG-8361, QTBUG-4362: Frameless/title-less windows shouldn't cover the
// taskbar when maximized
if ((testFlag(WithinMaximize) || window()->windowStates().testFlag(Qt::WindowMinimized))
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index b0f58b09a9..ea170aeee1 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -235,11 +235,10 @@ public:
MaximizeToFullScreen = 0x80000,
Compositing = 0x100000,
HasBorderInFullScreen = 0x200000,
- WithinDpiChanged = 0x400000,
- VulkanSurface = 0x800000,
- ResizeMoveActive = 0x1000000,
- DisableNonClientScaling = 0x2000000,
- Direct3DSurface = 0x4000000
+ VulkanSurface = 0x400000,
+ ResizeMoveActive = 0x800000,
+ DisableNonClientScaling = 0x1000000,
+ Direct3DSurface = 0x2000000
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
@@ -372,6 +371,9 @@ public:
static const char *embeddedNativeParentHandleProperty;
static const char *hasBorderInFullScreenProperty;
+ void setSavedDpi(int dpi) { m_savedDpi = dpi; }
+ int savedDpi() const { return m_savedDpi; }
+
private:
inline void show_sys() const;
inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const;
@@ -405,6 +407,7 @@ private:
HICON m_iconSmall = nullptr;
HICON m_iconBig = nullptr;
void *m_surface = nullptr;
+ int m_savedDpi = 96;
static bool m_screenForGLInitialized;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
index 682b8c19c0..12bdc9e6b7 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
@@ -132,22 +132,19 @@ void setVariantString(const QString &value, VARIANT *variant)
void rectToNativeUiaRect(const QRect &rect, const QWindow *w, UiaRect *uiaRect)
{
if (w && uiaRect) {
- const qreal factor = QHighDpiScaling::factor(w);
- uiaRect->left = qreal(rect.x()) * factor;
- uiaRect->top = qreal(rect.y()) * factor;
- uiaRect->width = qreal(rect.width()) * factor;
- uiaRect->height = qreal(rect.height()) * factor;
+ QRectF r = QHighDpi::toNativePixels(QRectF(rect), w);
+ uiaRect->left =r.x();
+ uiaRect->top = r.y();
+ uiaRect->width = r.width();
+ uiaRect->height = r.height();
}
}
// Scales a point from native coordinates, according to high dpi settings.
void nativeUiaPointToPoint(const UiaPoint &uiaPoint, const QWindow *w, QPoint *point)
{
- if (w && point) {
- const qreal factor = QHighDpiScaling::factor(w);
- point->setX(int(std::lround(uiaPoint.x / factor)));
- point->setY(int(std::lround(uiaPoint.y / factor)));
- }
+ if (w && point)
+ *point = QHighDpi::fromNativePixels(QPoint(uiaPoint.x, uiaPoint.y), w);
}
// Maps an accessibility role ID to an UI Automation control type ID.
diff --git a/src/plugins/platforms/xcb/CMakeLists.txt b/src/plugins/platforms/xcb/CMakeLists.txt
index 83f4d5b209..48c44a92ab 100644
--- a/src/plugins/platforms/xcb/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/CMakeLists.txt
@@ -162,7 +162,7 @@ endif()
qt_internal_add_plugin(QXcbIntegrationPlugin
OUTPUT_NAME qxcb
- TYPE platforms
+ PLUGIN_TYPE platforms
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES xcb # special case
SOURCES
qxcbmain.cpp
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt
index d24050edf3..4a62c8ad46 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/CMakeLists.txt
@@ -8,7 +8,7 @@ qt_find_package(EGL) # special case
qt_internal_add_plugin(QXcbEglIntegrationPlugin
OUTPUT_NAME qxcb-egl-integration
- TYPE xcbglintegrations
+ PLUGIN_TYPE xcbglintegrations
SOURCES
qxcbeglcontext.h
qxcbeglintegration.cpp qxcbeglintegration.h
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/CMakeLists.txt b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/CMakeLists.txt
index 80f785a2f0..ae81eba545 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QXcbGlxIntegrationPlugin
OUTPUT_NAME qxcb-glx-integration
- TYPE xcbglintegrations
+ PLUGIN_TYPE xcbglintegrations
SOURCES
qglxintegration.cpp qglxintegration.h
qxcbglxintegration.cpp qxcbglxintegration.h
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index 736b56ef60..21bc710987 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -835,6 +835,8 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
alloc_error = buf.size() != nbytes+1;
}
+ QElapsedTimer timer;
+ timer.start();
for (;;) {
connection()->flush();
xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY);
@@ -870,9 +872,11 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
tmp_buf.resize(0);
offset += length;
}
- } else {
- break;
}
+
+ const auto elapsed = timer.elapsed();
+ if (elapsed > clipboard_timeout)
+ break;
}
// timed out ... create a new requestor window, otherwise the requestor
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index e1c9bf80fc..b5b9b72ca8 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -99,7 +99,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
if (hasXRandr())
xrandrSelectEvents();
- initializeScreens();
+ initializeScreens(false);
if (hasXInput2()) {
xi2SetupDevices();
@@ -579,6 +579,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
case XCB_BUTTON_PRESS: {
auto ev = reinterpret_cast<xcb_button_press_event_t *>(event);
+ setTime(ev->time);
m_keyboard->updateXKBStateFromCore(ev->state);
// the event explicitly contains the state of the three first buttons,
// the rest we need to manage ourselves
@@ -591,6 +592,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
}
case XCB_BUTTON_RELEASE: {
auto ev = reinterpret_cast<xcb_button_release_event_t *>(event);
+ setTime(ev->time);
if (m_duringSystemMoveResize && ev->root != XCB_NONE)
abortSystemMoveResize(ev->root);
m_keyboard->updateXKBStateFromCore(ev->state);
@@ -603,6 +605,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
}
case XCB_MOTION_NOTIFY: {
auto ev = reinterpret_cast<xcb_motion_notify_event_t *>(event);
+ setTime(ev->time);
m_keyboard->updateXKBStateFromCore(ev->state);
m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
@@ -610,8 +613,14 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
ev->event_x, ev->event_y, ev->detail, static_cast<unsigned int>(m_buttonState));
HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
}
- case XCB_CONFIGURE_NOTIFY:
+ case XCB_CONFIGURE_NOTIFY: {
+ if (isAtLeastXRandR15()) {
+ auto ev = reinterpret_cast<xcb_configure_notify_event_t *>(event);
+ if (ev->event == rootWindow())
+ initializeScreens(true);
+ }
HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
+ }
case XCB_MAP_NOTIFY:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent);
case XCB_UNMAP_NOTIFY:
@@ -637,14 +646,19 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
// Prefer XI2 enter (XCB_INPUT_ENTER) events over core events.
break;
}
+ setTime(reinterpret_cast<xcb_enter_notify_event_t *>(event)->time);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
case XCB_LEAVE_NOTIFY:
+ {
if (hasXInput2()) {
// Prefer XI2 leave (XCB_INPUT_LEAVE) events over core events.
break;
}
- m_keyboard->updateXKBStateFromCore(reinterpret_cast<xcb_leave_notify_event_t *>(event)->state);
+ auto ev = reinterpret_cast<xcb_leave_notify_event_t *>(event);
+ setTime(ev->time);
+ m_keyboard->updateXKBStateFromCore(ev->state);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
+ }
case XCB_FOCUS_IN:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
case XCB_FOCUS_OUT:
@@ -652,13 +666,18 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
case XCB_KEY_PRESS:
{
auto keyPress = reinterpret_cast<xcb_key_press_event_t *>(event);
+ setTime(keyPress->time);
m_keyboard->updateXKBStateFromCore(keyPress->state);
setTime(keyPress->time);
HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
}
case XCB_KEY_RELEASE:
- m_keyboard->updateXKBStateFromCore(reinterpret_cast<xcb_key_release_event_t *>(event)->state);
+ {
+ auto keyRelease = reinterpret_cast<xcb_key_release_event_t *>(event);
+ setTime(keyRelease->time);
+ m_keyboard->updateXKBStateFromCore(keyRelease->state);
HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
+ }
case XCB_MAPPING_NOTIFY:
m_keyboard->updateKeymap(reinterpret_cast<xcb_mapping_notify_event_t *>(event));
break;
@@ -666,6 +685,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
{
#if QT_CONFIG(draganddrop) || QT_CONFIG(clipboard)
auto selectionRequest = reinterpret_cast<xcb_selection_request_event_t *>(event);
+ setTime(selectionRequest->time);
#endif
#if QT_CONFIG(draganddrop)
if (selectionRequest->selection == atom(QXcbAtom::XdndSelection))
@@ -690,11 +710,12 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
break;
case XCB_PROPERTY_NOTIFY:
{
+ auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event);
+ setTime(propertyNotify->time);
#ifndef QT_NO_CLIPBOARD
if (m_clipboard->handlePropertyNotify(event))
break;
#endif
- auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event);
if (propertyNotify->atom == atom(QXcbAtom::_NET_WORKAREA)) {
QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window);
if (virtualDesktop)
@@ -729,11 +750,14 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops))
virtualDesktop->handleXFixesSelectionNotify(notify_event);
} else if (isXRandrType(response_type, XCB_RANDR_NOTIFY)) {
- updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event));
+ if (!isAtLeastXRandR15())
+ updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event));
} else if (isXRandrType(response_type, XCB_RANDR_SCREEN_CHANGE_NOTIFY)) {
- auto change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event);
- if (auto virtualDesktop = virtualDesktopForRootWindow(change_event->root))
- virtualDesktop->handleScreenChange(change_event);
+ if (!isAtLeastXRandR15()) {
+ auto change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event);
+ if (auto virtualDesktop = virtualDesktopForRootWindow(change_event->root))
+ virtualDesktop->handleScreenChange(change_event);
+ }
} else if (isXkbType(response_type)) {
auto xkb_event = reinterpret_cast<_xkb_event *>(event);
if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) {
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index a7db3eda89..b0b26085d7 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -261,7 +261,16 @@ private:
const xcb_randr_output_change_t &outputChange,
xcb_randr_get_output_info_reply_t *outputInfo);
void destroyScreen(QXcbScreen *screen);
- void initializeScreens();
+ void initializeScreens(bool initialized);
+ void initializeScreensFromOutput(xcb_screen_iterator_t *it, int screenNumber, QXcbScreen *primaryScreen);
+
+ void updateScreen_monitor(QXcbScreen *screen, xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp = XCB_NONE);
+ QXcbScreen *createScreen_monitor(QXcbVirtualDesktop *virtualDesktop,
+ xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp = XCB_NONE);
+ QXcbVirtualDesktop* virtualDesktopForNumber(int n) const;
+ QXcbScreen* findScreenForMonitorInfo(const QList<QPlatformScreen *> &screens, xcb_randr_monitor_info_t *monitorInfo);
+ void initializeScreensFromMonitor(xcb_screen_iterator_t *it, int screenNumber, QXcbScreen *primaryScreen, bool initialized);
+
bool compressEvent(xcb_generic_event_t *event) const;
inline bool timeGreaterThan(xcb_timestamp_t a, xcb_timestamp_t b) const
{ return static_cast<int32_t>(a - b) > 0 || b == XCB_CURRENT_TIME; }
diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
index 020412fc87..6482395f86 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_basic.cpp
@@ -333,11 +333,14 @@ void QXcbBasicConnection::initializeXRandr()
XCB_RANDR_MINOR_VERSION);
if (!xrandrQuery || (xrandrQuery->major_version < 1 ||
(xrandrQuery->major_version == 1 && xrandrQuery->minor_version < 2))) {
- qCWarning(lcQpaXcb, "failed to initialize XRandr");
+ qCWarning(lcQpaXcb, "failed to initialize XRandr 1.2");
return;
}
m_hasXRandr = true;
+
+ m_xrandr1Minor = xrandrQuery->minor_version;
+
m_xrandrFirstEvent = reply->first_event;
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection_basic.h b/src/plugins/platforms/xcb/qxcbconnection_basic.h
index bda02ce9c2..d6eb962f56 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_basic.h
+++ b/src/plugins/platforms/xcb/qxcbconnection_basic.h
@@ -98,6 +98,9 @@ public:
bool hasXSync() const { return m_hasXSync; }
bool hasBigRequest() const;
+ bool isAtLeastXRandR12() const { return m_hasXRandr && m_xrandr1Minor >= 2; }
+ bool isAtLeastXRandR15() const { return m_hasXRandr && m_xrandr1Minor >= 5; }
+
bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; }
bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
bool isXIEvent(xcb_generic_event_t *event) const;
@@ -144,6 +147,8 @@ private:
int m_xiOpCode = -1;
uint32_t m_xinputFirstEvent = 0;
+ int m_xrandr1Minor = -1;
+
uint32_t m_xfixesFirstEvent = 0;
uint32_t m_xrandrFirstEvent = 0;
uint32_t m_xkbFirstEvent = 0;
diff --git a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
index 867bbef020..22285b836d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_screens.cpp
@@ -63,8 +63,15 @@ void QXcbConnection::xrandrSelectEvents()
QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const
{
for (QXcbScreen *screen : m_screens) {
- if (screen->root() == rootWindow && screen->crtc() == crtc)
- return screen;
+ if (screen->root() == rootWindow) {
+ if (screen->m_monitor) {
+ if (screen->crtcs().contains(crtc))
+ return screen;
+ } else {
+ if (screen->crtc() == crtc)
+ return screen;
+ }
+ }
}
return nullptr;
@@ -73,8 +80,15 @@ QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr
QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const
{
for (QXcbScreen *screen : m_screens) {
- if (screen->root() == rootWindow && screen->output() == output)
- return screen;
+ if (screen->root() == rootWindow) {
+ if (screen->m_monitor) {
+ if (screen->outputs().contains(output))
+ return screen;
+ } else {
+ if (screen->output() == output)
+ return screen;
+ }
+ }
}
return nullptr;
@@ -263,117 +277,84 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen)
QWindowSystemInterface::handlePrimaryScreenChanged(newPrimary);
}
+ qCDebug(lcQpaScreen) << "destroyScreen: destroy" << screen;
QWindowSystemInterface::handleScreenRemoved(screen);
}
}
-void QXcbConnection::initializeScreens()
+void QXcbConnection::updateScreen_monitor(QXcbScreen *screen, xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
+{
+ screen->setMonitor(monitorInfo, timestamp);
+
+ if (screen->isPrimary()) {
+ const int idx = m_screens.indexOf(screen);
+ if (idx > 0) {
+ qAsConst(m_screens).first()->setPrimary(false);
+ m_screens.swapItemsAt(0, idx);
+ }
+ screen->virtualDesktop()->setPrimaryScreen(screen);
+ QWindowSystemInterface::handlePrimaryScreenChanged(screen);
+ }
+ qCDebug(lcQpaScreen) << "updateScreen_monitor: update" << screen << "(Primary:" << screen->isPrimary() << ")";
+}
+
+QXcbScreen *QXcbConnection::createScreen_monitor(QXcbVirtualDesktop *virtualDesktop, xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
+{
+ QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, monitorInfo, timestamp);
+
+ if (screen->isPrimary()) {
+ if (!m_screens.isEmpty())
+ qAsConst(m_screens).first()->setPrimary(false);
+
+ m_screens.prepend(screen);
+ } else {
+ m_screens.append(screen);
+ }
+ qCDebug(lcQpaScreen) << "createScreen_monitor: adding" << screen << "(Primary:" << screen->isPrimary() << ")";
+ virtualDesktop->addScreen(screen);
+ QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
+ return screen;
+}
+
+QXcbVirtualDesktop *QXcbConnection::virtualDesktopForNumber(int n) const
+{
+ for (QXcbVirtualDesktop *virtualDesktop : m_virtualDesktops) {
+ if (virtualDesktop->number() == n)
+ return virtualDesktop;
+ }
+
+ return nullptr;
+}
+
+QXcbScreen *QXcbConnection::findScreenForMonitorInfo(const QList<QPlatformScreen *> &screens, xcb_randr_monitor_info_t *monitorInfo)
+{
+ for (int i = 0; i < screens.size(); ++i) {
+ auto s = static_cast<QXcbScreen*>(screens[i]);
+ if (s->m_monitor && monitorInfo) {
+ QByteArray ba1 = atomName(s->m_monitor->name);
+ QByteArray ba2 = atomName(monitorInfo->name);
+ if (ba1 == ba2)
+ return s;
+ }
+ }
+
+ return nullptr;
+}
+
+void QXcbConnection::initializeScreens(bool initialized)
{
xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup());
int xcbScreenNumber = 0; // screen number in the xcb sense
QXcbScreen *primaryScreen = nullptr;
while (it.rem) {
- // Each "screen" in xcb terminology is a virtual desktop,
- // potentially a collection of separate juxtaposed monitors.
- // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
- // which will become virtual siblings.
- xcb_screen_t *xcbScreen = it.data;
- QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
- m_virtualDesktops.append(virtualDesktop);
- QList<QPlatformScreen *> siblings;
- if (hasXRandr()) {
- // RRGetScreenResourcesCurrent is fast but it may return nothing if the
- // configuration is not initialized wrt to the hardware. We should call
- // RRGetScreenResources in this case.
- auto resources_current = Q_XCB_REPLY(xcb_randr_get_screen_resources_current,
- xcb_connection(), xcbScreen->root);
- decltype(Q_XCB_REPLY(xcb_randr_get_screen_resources,
- xcb_connection(), xcbScreen->root)) resources;
- if (!resources_current) {
- qWarning("failed to get the current screen resources");
- } else {
- xcb_timestamp_t timestamp = 0;
- xcb_randr_output_t *outputs = nullptr;
- int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.get());
- if (outputCount) {
- timestamp = resources_current->config_timestamp;
- outputs = xcb_randr_get_screen_resources_current_outputs(resources_current.get());
- } else {
- resources = Q_XCB_REPLY(xcb_randr_get_screen_resources,
- xcb_connection(), xcbScreen->root);
- if (!resources) {
- qWarning("failed to get the screen resources");
- } else {
- timestamp = resources->config_timestamp;
- outputCount = xcb_randr_get_screen_resources_outputs_length(resources.get());
- outputs = xcb_randr_get_screen_resources_outputs(resources.get());
- }
- }
-
- if (outputCount) {
- auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, xcb_connection(), xcbScreen->root);
- if (!primary) {
- qWarning("failed to get the primary output of the screen");
- } else {
- for (int i = 0; i < outputCount; i++) {
- auto output = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_output_info,
- xcb_connection(), outputs[i], timestamp);
- // Invalid, disconnected or disabled output
- if (!output)
- continue;
-
- if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
- qCDebug(lcQpaScreen, "Output %s is not connected", qPrintable(
- QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
- xcb_randr_get_output_info_name_length(output.get()))));
- continue;
- }
-
- if (output->crtc == XCB_NONE) {
- qCDebug(lcQpaScreen, "Output %s is not enabled", qPrintable(
- QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
- xcb_randr_get_output_info_name_length(output.get()))));
- continue;
- }
+ if (isAtLeastXRandR15())
+ initializeScreensFromMonitor(&it, xcbScreenNumber, primaryScreen, initialized);
+ else if (isAtLeastXRandR12())
+ initializeScreensFromOutput(&it, xcbScreenNumber, primaryScreen);
- QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputs[i], output.get());
- siblings << screen;
- m_screens << screen;
-
- // There can be multiple outputs per screen, use either
- // the first or an exact match. An exact match isn't
- // always available if primary->output is XCB_NONE
- // or currently disconnected output.
- if (primaryScreenNumber() == xcbScreenNumber) {
- if (!primaryScreen || (primary && outputs[i] == primary->output)) {
- if (primaryScreen)
- primaryScreen->setPrimary(false);
- primaryScreen = screen;
- primaryScreen->setPrimary(true);
- siblings.prepend(siblings.takeLast());
- }
- }
- }
- }
- }
- }
- }
- if (siblings.isEmpty()) {
- // If there are no XRandR outputs or XRandR extension is missing,
- // then create a fake/legacy screen.
- QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, nullptr);
- qCDebug(lcQpaScreen) << "created fake screen" << screen;
- m_screens << screen;
- if (primaryScreenNumber() == xcbScreenNumber) {
- primaryScreen = screen;
- primaryScreen->setPrimary(true);
- }
- siblings << screen;
- }
- virtualDesktop->setScreens(std::move(siblings));
xcb_screen_next(&it);
++xcbScreenNumber;
- } // for each xcb screen
+ }
for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops))
virtualDesktop->subscribeToXFixesSelectionNotify();
@@ -390,11 +371,208 @@ void QXcbConnection::initializeScreens()
}
// Push the screens to QGuiApplication
- for (QXcbScreen *screen : qAsConst(m_screens)) {
- qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
- QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
+ if (!initialized) {
+ for (QXcbScreen *screen : qAsConst(m_screens)) {
+ qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
+ QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
+ }
}
- qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
+ if (!m_screens.isEmpty())
+ qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
+ }
+}
+
+void QXcbConnection::initializeScreensFromOutput(xcb_screen_iterator_t *it, int xcbScreenNumber, QXcbScreen *primaryScreen)
+{
+ // Each "screen" in xcb terminology is a virtual desktop,
+ // potentially a collection of separate juxtaposed monitors.
+ // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
+ // which will become virtual siblings.
+ xcb_screen_t *xcbScreen = it->data;
+ QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
+ m_virtualDesktops.append(virtualDesktop);
+ QList<QPlatformScreen *> siblings;
+ if (isAtLeastXRandR12()) {
+ // RRGetScreenResourcesCurrent is fast but it may return nothing if the
+ // configuration is not initialized wrt to the hardware. We should call
+ // RRGetScreenResources in this case.
+ auto resources_current = Q_XCB_REPLY(xcb_randr_get_screen_resources_current,
+ xcb_connection(), xcbScreen->root);
+ decltype(Q_XCB_REPLY(xcb_randr_get_screen_resources,
+ xcb_connection(), xcbScreen->root)) resources;
+ if (!resources_current) {
+ qWarning("failed to get the current screen resources");
+ } else {
+ xcb_timestamp_t timestamp = 0;
+ xcb_randr_output_t *outputs = nullptr;
+ int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.get());
+ if (outputCount) {
+ timestamp = resources_current->config_timestamp;
+ outputs = xcb_randr_get_screen_resources_current_outputs(resources_current.get());
+ } else {
+ resources = Q_XCB_REPLY(xcb_randr_get_screen_resources,
+ xcb_connection(), xcbScreen->root);
+ if (!resources) {
+ qWarning("failed to get the screen resources");
+ } else {
+ timestamp = resources->config_timestamp;
+ outputCount = xcb_randr_get_screen_resources_outputs_length(resources.get());
+ outputs = xcb_randr_get_screen_resources_outputs(resources.get());
+ }
+ }
+
+ if (outputCount) {
+ auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, xcb_connection(), xcbScreen->root);
+ if (!primary) {
+ qWarning("failed to get the primary output of the screen");
+ } else {
+ for (int i = 0; i < outputCount; i++) {
+ auto output = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_output_info,
+ xcb_connection(), outputs[i], timestamp);
+ // Invalid, disconnected or disabled output
+ if (!output)
+ continue;
+
+ if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
+ qCDebug(lcQpaScreen, "Output %s is not connected", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
+ xcb_randr_get_output_info_name_length(output.get()))));
+ continue;
+ }
+
+ if (output->crtc == XCB_NONE) {
+ qCDebug(lcQpaScreen, "Output %s is not enabled", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
+ xcb_randr_get_output_info_name_length(output.get()))));
+ continue;
+ }
+
+ QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputs[i], output.get());
+ siblings << screen;
+ m_screens << screen;
+
+ // There can be multiple outputs per screen, use either
+ // the first or an exact match. An exact match isn't
+ // always available if primary->output is XCB_NONE
+ // or currently disconnected output.
+ if (primaryScreenNumber() == xcbScreenNumber) {
+ if (!primaryScreen || (primary && outputs[i] == primary->output)) {
+ if (primaryScreen)
+ primaryScreen->setPrimary(false);
+ primaryScreen = screen;
+ primaryScreen->setPrimary(true);
+ siblings.prepend(siblings.takeLast());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (siblings.isEmpty()) {
+ // If there are no XRandR outputs or XRandR extension is missing,
+ // then create a fake/legacy screen.
+ QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, nullptr);
+ qCDebug(lcQpaScreen) << "created fake screen" << screen;
+ m_screens << screen;
+ if (primaryScreenNumber() == xcbScreenNumber) {
+ primaryScreen = screen;
+ primaryScreen->setPrimary(true);
+ }
+ siblings << screen;
}
+ virtualDesktop->setScreens(std::move(siblings));
+}
+
+void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int xcbScreenNumber, QXcbScreen *primaryScreen, bool initialized)
+{
+ // Each "screen" in xcb terminology is a virtual desktop,
+ // potentially a collection of separate juxtaposed monitors.
+ // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
+ // which will become virtual siblings.
+ xcb_screen_t *xcbScreen = it->data;
+ QXcbVirtualDesktop *virtualDesktop = nullptr;
+ if (initialized)
+ virtualDesktop = virtualDesktopForNumber(xcbScreenNumber);
+ if (!virtualDesktop) {
+ virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
+ m_virtualDesktops.append(virtualDesktop);
+ }
+ QList<QPlatformScreen*> old = virtualDesktop->m_screens;
+ if (initialized)
+ m_screens.clear();
+
+ QList<QPlatformScreen *> siblings;
+
+ xcb_randr_get_monitors_cookie_t monitors_c = xcb_randr_get_monitors(xcb_connection(), xcbScreen->root, 1);
+ xcb_randr_get_monitors_reply_t *monitors_r = xcb_randr_get_monitors_reply(xcb_connection(), monitors_c, nullptr);
+
+ if (!monitors_r) {
+ qWarning("RANDR GetMonitors failed; this should not be possible");
+ return;
+ }
+
+ xcb_randr_monitor_info_iterator_t monitor_iter = xcb_randr_get_monitors_monitors_iterator(monitors_r);
+ while (monitor_iter.rem) {
+ xcb_randr_monitor_info_t *monitor_info = monitor_iter.data;
+ QXcbScreen *screen = nullptr;
+ if (!initialized) {
+ screen = new QXcbScreen(this, virtualDesktop, monitor_info, monitors_r->timestamp);
+ m_screens << screen;
+ } else {
+ screen = findScreenForMonitorInfo(virtualDesktop->m_screens, monitor_info);
+ if (!screen) {
+ screen = createScreen_monitor(virtualDesktop, monitor_info, monitors_r->timestamp);
+ QHighDpiScaling::updateHighDpiScaling();
+ } else {
+ m_screens << screen;
+ updateScreen_monitor(screen, monitor_info, monitors_r->timestamp);
+ old.removeAll(screen);
+ }
+ }
+
+ siblings << screen;
+
+ if (primaryScreenNumber() == xcbScreenNumber) {
+ primaryScreen = screen;
+ primaryScreen->setPrimary(true);
+ }
+
+ xcb_randr_monitor_info_next(&monitor_iter);
+ }
+
+ if (siblings.isEmpty()) {
+ QXcbScreen *screen = nullptr;
+ if (initialized && !old.isEmpty()) {
+ // If there are no other screens on the same virtual desktop,
+ // then transform the physical screen into a fake screen.
+ screen = static_cast<QXcbScreen *>(old.takeFirst());
+ const QString nameWas = screen->name();
+ screen->setMonitor(nullptr, XCB_NONE);
+ qCDebug(lcQpaScreen) << "transformed" << nameWas << "to fake" << screen;
+ } else {
+ // If there are no XRandR outputs or XRandR extension is missing,
+ // then create a fake/legacy screen.
+ screen = new QXcbScreen(this, virtualDesktop, nullptr);
+ qCDebug(lcQpaScreen) << "create a fake screen: " << screen;
+ }
+
+ if (primaryScreenNumber() == xcbScreenNumber) {
+ primaryScreen = screen;
+ primaryScreen->setPrimary(true);
+ }
+ siblings << screen;
+ m_screens << screen;
+ }
+
+ if (initialized) {
+ for (QPlatformScreen *ps : old) {
+ virtualDesktop->removeScreen(ps);
+ qCDebug(lcQpaScreen) << "destroy screen: " << ps;
+ QWindowSystemInterface::handleScreenRemoved(ps);
+ }
+ }
+
+ virtualDesktop->setScreens(std::move(siblings));
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 4657c2ac89..c0bd2c6165 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -639,6 +639,7 @@ static inline qreal fixed1616ToReal(xcb_input_fp1616_t val)
void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
{
auto *xiEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
+ setTime(xiEvent->time);
if (m_xiSlavePointerIds.contains(xiEvent->deviceid)) {
if (!m_duringSystemMoveResize)
return;
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index a032085f0b..4210bf428e 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -534,6 +534,8 @@ bool updateCursorTheme(void *dpy, const QByteArray &theme) {
Q_UNUSED(screen);
Q_UNUSED(name);
QXcbCursor *self = static_cast<QXcbCursor *>(handle);
+ self->m_cursorHash.clear();
+
updateCursorTheme(self->connection()->xlib_display(),property.toByteArray());
}
@@ -559,14 +561,16 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
int cursorId = cursorIdForShape(cshape);
xcb_cursor_t cursor = XCB_NONE;
- // Try Xcursor first
#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
+ if (m_screen->xSettings()->initialized())
+ m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName",cursorThemePropertyChanged,this);
+
+ // Try Xcursor first
if (cshape >= 0 && cshape <= Qt::LastCursor) {
void *dpy = connection()->xlib_display();
cursor = loadCursor(dpy, cshape);
if (!cursor && !m_gtkCursorThemeInitialized && m_screen->xSettings()->initialized()) {
QByteArray gtkCursorTheme = m_screen->xSettings()->setting("Gtk/CursorThemeName").toByteArray();
- m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName",cursorThemePropertyChanged,this);
if (updateCursorTheme(dpy,gtkCursorTheme)) {
cursor = loadCursor(dpy, cshape);
}
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 7495d0fdc3..9ab804ca1b 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -60,11 +60,11 @@ Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const
ret |= Qt::ShiftModifier;
if (s & XCB_MOD_MASK_CONTROL)
ret |= Qt::ControlModifier;
- if ((s & rmod_masks.alt) == rmod_masks.alt)
+ if (s & rmod_masks.alt)
ret |= Qt::AltModifier;
- if ((s & rmod_masks.meta) == rmod_masks.meta)
+ if (s & rmod_masks.meta)
ret |= Qt::MetaModifier;
- if ((s & rmod_masks.altgr) == rmod_masks.altgr)
+ if (s & rmod_masks.altgr)
ret |= Qt::GroupSwitchModifier;
return ret;
}
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 95c552a468..55633aade7 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -118,7 +118,7 @@ void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resour
case RootWindow:
result = rootWindow();
break;
- case Display:
+ case XDisplay:
result = display();
break;
case AtspiBus:
@@ -155,7 +155,7 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceStr
const QXcbScreen *xcbScreen = static_cast<QXcbScreen *>(screen->handle());
switch (resourceType(lowerCaseResource)) {
- case Display:
+ case XDisplay:
#if QT_CONFIG(xcb_xlib)
result = xcbScreen->connection()->xlib_display();
#endif
@@ -203,7 +203,7 @@ void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceStr
return result;
switch (resourceType(lowerCaseResource)) {
- case Display:
+ case XDisplay:
result = displayForWindow(window);
break;
case Connection:
@@ -365,18 +365,17 @@ void *QXcbNativeInterface::rootWindow()
return nullptr;
}
-void *QXcbNativeInterface::display()
+Display *QXcbNativeInterface::display() const
{
#if QT_CONFIG(xcb_xlib)
QXcbIntegration *integration = QXcbIntegration::instance();
- QXcbConnection *connection = integration->connection();
- if (connection)
- return connection->xlib_display();
+ if (QXcbConnection *connection = integration->connection())
+ return reinterpret_cast<Display *>(connection->xlib_display());
#endif
return nullptr;
}
-void *QXcbNativeInterface::connection()
+xcb_connection_t *QXcbNativeInterface::connection() const
{
QXcbIntegration *integration = QXcbIntegration::instance();
return integration->connection()->xcb_connection();
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index 4656f46be5..5508d57679 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -45,6 +45,8 @@
#include <QtCore/QRect>
+#include <QtGui/qguiapplication.h>
+
#include "qxcbexport.h"
#include "qxcbconnection.h"
@@ -54,11 +56,12 @@ class QXcbScreen;
class QXcbNativeInterfaceHandler;
class Q_XCB_EXPORT QXcbNativeInterface : public QPlatformNativeInterface
+ , public QNativeInterface::QX11Application
{
Q_OBJECT
public:
enum ResourceType {
- Display,
+ XDisplay,
Connection,
Screen,
AppTime,
@@ -109,9 +112,11 @@ public:
void *startupId();
void *x11Screen();
void *rootWindow();
- void *display();
+
+ Display *display() const override;
+ xcb_connection_t *connection() const override;
+
void *atspiBus();
- void *connection();
static void setStartupId(const char *);
static void setAppTime(QScreen *screen, xcb_timestamp_t time);
static void setAppUserTime(QScreen *screen, xcb_timestamp_t time);
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index c084b17782..1ecf995f7c 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -530,12 +530,13 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output)
: QXcbObject(connection)
, m_virtualDesktop(virtualDesktop)
+ , m_monitor(nullptr)
, m_output(outputId)
, m_crtc(output ? output->crtc : XCB_NONE)
, m_outputName(getOutputName(output))
, m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize())
{
- if (connection->hasXRandr()) {
+ if (connection->isAtLeastXRandR12()) {
xcb_randr_select_input(xcb_connection(), screen()->root, true);
auto crtc = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_crtc_info, xcb_connection(),
m_crtc, output ? output->timestamp : 0);
@@ -567,7 +568,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
m_colorSpace = QColorSpace::fromIccProfile(data);
}
}
- if (connection->hasXRandr()) { // Parse EDID
+ if (connection->isAtLeastXRandR12()) { // Parse EDID
QByteArray edid = getEdid();
if (m_edid.parse(edid)) {
qCDebug(lcQpaScreen, "EDID data for output \"%s\": identifier '%s', manufacturer '%s',"
@@ -610,6 +611,119 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
m_colorSpace = QColorSpace::SRgb;
}
+QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
+ xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
+ : QXcbObject(connection)
+ , m_virtualDesktop(virtualDesktop)
+ , m_monitor(monitorInfo)
+{
+ setMonitor(monitorInfo, timestamp);
+}
+
+void QXcbScreen::setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
+{
+ if (!connection()->isAtLeastXRandR15())
+ return;
+
+ m_outputs.clear();
+ m_crtcs.clear();
+
+ if (!monitorInfo) {
+ m_monitor = nullptr;
+ m_output = XCB_NONE;
+ m_crtc = XCB_NONE;
+ m_mode = XCB_NONE;
+ m_outputName = defaultName();
+ // TODO: Send an event to the QScreen instance that the screen changed its name
+ return;
+ }
+
+ xcb_randr_select_input(xcb_connection(), screen()->root, true);
+
+ m_monitor = monitorInfo;
+ QRect monitorGeometry = QRect(m_monitor->x, m_monitor->y,
+ m_monitor->width, m_monitor->height);
+
+ int outputCount = xcb_randr_monitor_info_outputs_length(m_monitor);
+ xcb_randr_output_t *outputs = nullptr;
+ if (outputCount) {
+ outputs = xcb_randr_monitor_info_outputs(m_monitor);
+ for (int i = 0; i < outputCount; i++) {
+ auto output = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_output_info,
+ xcb_connection(), outputs[i], timestamp);
+ // Invalid, disconnected or disabled output
+ if (!output)
+ continue;
+
+ if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
+ qCDebug(lcQpaScreen, "Output %s is not connected", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
+ xcb_randr_get_output_info_name_length(output.get()))));
+ continue;
+ }
+
+ if (output->crtc == XCB_NONE) {
+ qCDebug(lcQpaScreen, "Output %s is not enabled", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
+ xcb_randr_get_output_info_name_length(output.get()))));
+ continue;
+ }
+
+ m_outputs << outputs[i];
+ m_crtcs << output->crtc;
+ }
+ }
+
+ if (m_crtcs.size() == 1) {
+ auto crtc = Q_XCB_REPLY(xcb_randr_get_crtc_info,
+ xcb_connection(), m_crtcs[0], timestamp);
+ m_singlescreen = (monitorGeometry == (QRect(crtc->x, crtc->y, crtc->width, crtc->height)));
+ if (m_singlescreen) {
+ if (crtc->mode) {
+ if (crtc->rotation == XCB_RANDR_ROTATION_ROTATE_90 ||
+ crtc->rotation == XCB_RANDR_ROTATION_ROTATE_270)
+ std::swap(crtc->width, crtc->height);
+ updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
+ if (mode() != crtc->mode)
+ updateRefreshRate(crtc->mode);
+ }
+ }
+ }
+
+ if (!m_singlescreen)
+ m_geometry = monitorGeometry;
+ m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
+ if (m_geometry.isEmpty())
+ m_geometry = QRect(QPoint(), virtualDesktop()->size());
+ if (m_availableGeometry.isEmpty())
+ m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
+
+ m_sizeMillimeters = sizeInMillimeters(m_geometry.size(), m_virtualDesktop->dpi());
+
+ if (m_sizeMillimeters.isEmpty())
+ m_sizeMillimeters = virtualDesktop()->physicalSize();
+
+ QByteArray ba = connection()->atomName(monitorInfo->name);
+ m_outputName = getName(monitorInfo);
+
+ if (monitorInfo->primary)
+ m_primary = true;
+
+ m_cursor = new QXcbCursor(connection(), this);
+}
+
+QString QXcbScreen::defaultName()
+{
+ QString name;
+ QByteArray displayName = connection()->displayName();
+ int dotPos = displayName.lastIndexOf('.');
+ if (dotPos != -1)
+ displayName.truncate(dotPos);
+ name = QString::fromLocal8Bit(displayName) + QLatin1Char('.')
+ + QString::number(m_virtualDesktop->number());
+ return name;
+}
+
QXcbScreen::~QXcbScreen()
{
delete m_cursor;
@@ -622,6 +736,18 @@ QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo)
name = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(outputInfo),
xcb_randr_get_output_info_name_length(outputInfo));
} else {
+ name = defaultName();
+ }
+ return name;
+}
+
+QString QXcbScreen::getName(xcb_randr_monitor_info_t *monitorInfo)
+{
+ QString name;
+ QByteArray ba = connection()->atomName(monitorInfo->name);
+ if (!ba.isEmpty()) {
+ name = QString::fromLatin1(ba.constData());
+ } else {
QByteArray displayName = connection()->displayName();
int dotPos = displayName.lastIndexOf('.');
if (dotPos != -1)
@@ -773,6 +899,7 @@ QPlatformCursor *QXcbScreen::cursor() const
void QXcbScreen::setOutput(xcb_randr_output_t outputId,
xcb_randr_get_output_info_reply_t *outputInfo)
{
+ m_monitor = nullptr;
m_output = outputId;
m_crtc = outputInfo ? outputInfo->crtc : XCB_NONE;
m_mode = XCB_NONE;
@@ -782,7 +909,7 @@ void QXcbScreen::setOutput(xcb_randr_output_t outputId,
void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
{
- if (!connection()->hasXRandr())
+ if (!connection()->isAtLeastXRandR12())
return;
auto crtc = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_crtc_info, xcb_connection(),
@@ -838,7 +965,7 @@ void QXcbScreen::updateAvailableGeometry()
void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
{
- if (!connection()->hasXRandr())
+ if (!connection()->isAtLeastXRandR12())
return;
if (m_mode == mode)
@@ -974,7 +1101,7 @@ QByteArray QXcbScreen::getOutputProperty(xcb_atom_t atom) const
QByteArray QXcbScreen::getEdid() const
{
QByteArray result;
- if (!connection()->hasXRandr())
+ if (!connection()->isAtLeastXRandR12())
return result;
// Try a bunch of atoms
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index ff30f599d6..04d90e0c68 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -138,6 +138,8 @@ private:
QMap<xcb_visualid_t, quint8> m_visualDepths;
mutable QMap<xcb_visualid_t, xcb_colormap_t> m_visualColormaps;
uint16_t m_rotation = 0;
+
+ friend class QXcbConnection;
};
class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen
@@ -146,9 +148,12 @@ class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen
public:
QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *outputInfo);
+ QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
+ xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp = XCB_NONE);
~QXcbScreen();
QString getOutputName(xcb_randr_get_output_info_reply_t *outputInfo);
+ QString getName(xcb_randr_monitor_info_t *monitorInfo);
QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
@@ -184,9 +189,14 @@ public:
xcb_randr_crtc_t crtc() const { return m_crtc; }
xcb_randr_mode_t mode() const { return m_mode; }
+ QList<xcb_randr_output_t> outputs() const { return m_outputs; }
+ QList<xcb_randr_crtc_t> crtcs() const { return m_crtcs; }
+
void setOutput(xcb_randr_output_t outputId,
xcb_randr_get_output_info_reply_t *outputInfo);
void setCrtc(xcb_randr_crtc_t crtc) { m_crtc = crtc; }
+ void setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp = XCB_NONE);
+ QString defaultName();
void windowShown(QXcbWindow *window);
QString windowManagerName() const { return m_virtualDesktop->windowManagerName(); }
@@ -219,11 +229,17 @@ private:
QByteArray getEdid() const;
QXcbVirtualDesktop *m_virtualDesktop;
+ xcb_randr_monitor_info_t *m_monitor;
xcb_randr_output_t m_output;
xcb_randr_crtc_t m_crtc;
xcb_randr_mode_t m_mode = XCB_NONE;
bool m_primary = false;
+ bool m_singlescreen = false;
+
+ QList<xcb_randr_output_t> m_outputs;
+ QList<xcb_randr_crtc_t> m_crtcs;
+
QString m_outputName;
QSizeF m_outputSizeMillimeters;
QSizeF m_sizeMillimeters;
@@ -234,6 +250,9 @@ private:
QXcbCursor *m_cursor;
qreal m_refreshRate = 60.0;
QEdidParser m_edid;
+
+ friend class QXcbConnection;
+ friend class QXcbVirtualDesktop;
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index ea8e1f479d..fd1a1970f7 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -548,6 +548,11 @@ void QXcbWindow::setGeometry(const QRect &rect)
{
QPlatformWindow::setGeometry(rect);
+ if (shouldDeferTask(Task::SetGeometry)) {
+ m_deferredGeometry = rect;
+ return;
+ }
+
propagateSizeHints();
QXcbScreen *currentScreen = xcbScreen();
@@ -672,6 +677,9 @@ void QXcbWindow::setVisible(bool visible)
void QXcbWindow::show()
{
+ if (shouldDeferTask(Task::Map))
+ return;
+
if (window()->isTopLevel()) {
// update WM_NORMAL_HINTS
@@ -722,6 +730,10 @@ void QXcbWindow::show()
void QXcbWindow::hide()
{
+ if (shouldDeferTask(Task::Unmap))
+ return;
+
+ m_wmStateValid = false;
xcb_unmap_window(xcb_connection(), m_window);
// send synthetic UnmapNotify event according to icccm 4.1.4
@@ -881,6 +893,9 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates()
void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
{
+ if (shouldDeferTask(Task::SetWindowFlags))
+ return;
+
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
if (type == Qt::ToolTip)
@@ -910,6 +925,8 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput);
updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus);
+
+ m_isWmManagedWindow = !(flags & Qt::X11BypassWindowManagerHint);
}
void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags)
@@ -1109,6 +1126,9 @@ void QXcbWindow::setWindowState(Qt::WindowStates state)
if (state == m_windowState)
return;
+ if (shouldDeferTask(Task::SetWindowState))
+ return;
+
// unset old state
if (m_windowState & Qt::WindowMinimized)
xcb_map_window(xcb_connection(), m_window);
@@ -1826,6 +1846,10 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
if (event->window == m_window) {
m_mapped = false;
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
+ if (!m_isWmManagedWindow) {
+ m_wmStateValid = true;
+ handleDeferredTasks();
+ }
}
}
@@ -2140,30 +2164,98 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event)
handleLeaveNotifyEvent(event->root_x, event->root_y, event->mode, event->detail, event->time);
}
+bool QXcbWindow::shouldDeferTask(Task task)
+{
+ if (m_wmStateValid)
+ return false;
+
+ m_deferredTasks.append(task);
+ return true;
+}
+
+void QXcbWindow::handleDeferredTasks()
+{
+ Q_ASSERT(m_wmStateValid == true);
+ if (m_deferredTasks.isEmpty())
+ return;
+
+ bool map = false;
+ bool unmap = false;
+
+ QVector<Task> tasks;
+ for (auto taskIt = m_deferredTasks.rbegin(); taskIt != m_deferredTasks.rend(); ++taskIt) {
+ if (!tasks.contains(*taskIt))
+ tasks.prepend(*taskIt);
+ }
+
+ for (Task task : tasks) {
+ switch (task) {
+ case Task::Map:
+ map = true;
+ unmap = false;
+ break;
+ case Task::Unmap:
+ unmap = true;
+ map = false;
+ break;
+ case Task::SetGeometry:
+ setGeometry(m_deferredGeometry);
+ break;
+ case Task::SetWindowFlags:
+ setWindowFlags(window()->flags());
+ break;
+ case Task::SetWindowState:
+ setWindowState(window()->windowState());
+ break;
+ }
+ }
+ m_deferredTasks.clear();
+
+ if (map) {
+ Q_ASSERT(unmap == false);
+ show();
+ }
+ if (unmap) {
+ Q_ASSERT(map == false);
+ hide();
+ }
+}
+
void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
{
connection()->setTime(event->time);
- const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
-
- if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) {
- if (propertyDeleted)
+ const bool wmStateChanged = event->atom == atom(QXcbAtom::WM_STATE);
+ const bool netWmStateChanged = event->atom == atom(QXcbAtom::_NET_WM_STATE);
+ if (netWmStateChanged || wmStateChanged) {
+ if (wmStateChanged && !m_wmStateValid && m_isWmManagedWindow) {
+ // ICCCM 4.1.4
+ // Clients that want to re-use a client window (e.g. by mapping it again)
+ // after withdrawing it must wait for the withdrawal to be complete before
+ // proceeding. The preferred method for doing this is for clients to wait for
+ // a window manager to update or remove the WM_STATE property.
+ m_wmStateValid = true;
+ handleDeferredTasks();
+ }
+ if (event->state == XCB_PROPERTY_DELETE)
return;
- Qt::WindowStates newState = Qt::WindowNoState;
-
- if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'.
+ if (wmStateChanged) {
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(),
0, m_window, atom(QXcbAtom::WM_STATE),
XCB_ATOM_ANY, 0, 1024);
if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) {
- const quint32 *data = (const quint32 *)xcb_get_property_value(reply.get());
- if (reply->length != 0)
- m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC
- || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized));
+ auto data = static_cast<const quint32 *>(xcb_get_property_value(reply.get()));
+ if (reply->length != 0) {
+ const bool changedToWithdrawn = data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN;
+ const bool changedToIconic = data[0] == XCB_ICCCM_WM_STATE_ICONIC;
+ m_minimized = changedToIconic || (changedToWithdrawn && m_minimized);
+ }
}
}
+ // _NET_WM_STATE handling
+ Qt::WindowStates newState = Qt::WindowNoState;
const NetWmStates states = netWmStates();
// _NET_WM_STATE_HIDDEN should be set by the Window Manager to indicate that a window would
// not be visible on the screen if its desktop/viewport were active and its coordinates were
@@ -2185,7 +2277,6 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() == this)
connection()->setMouseGrabber(nullptr);
}
- return;
} else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
m_dirtyFrameMargins = true;
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 5e5aa96629..f7bed7f67b 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -74,6 +74,14 @@ public:
Q_DECLARE_FLAGS(NetWmStates, NetWmState)
+ enum Task {
+ Map,
+ Unmap,
+ SetGeometry,
+ SetWindowFlags,
+ SetWindowState
+ };
+
QXcbWindow(QWindow *window);
~QXcbWindow();
@@ -143,6 +151,9 @@ public:
QXcbWindow *toWindow() override;
+ bool shouldDeferTask(Task task);
+ void handleDeferredTasks();
+
void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global,
Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source);
@@ -276,6 +287,11 @@ protected:
int m_swapInterval = -1;
qreal m_sizeHintsScaleFactor = 1.0;
+
+ bool m_wmStateValid = true;
+ QVector<Task> m_deferredTasks;
+ bool m_isWmManagedWindow = true;
+ QRect m_deferredGeometry;
};
class QXcbForeignWindow : public QXcbWindow
diff --git a/src/plugins/platformthemes/gtk3/CMakeLists.txt b/src/plugins/platformthemes/gtk3/CMakeLists.txt
index da61354237..62e752bd92 100644
--- a/src/plugins/platformthemes/gtk3/CMakeLists.txt
+++ b/src/plugins/platformthemes/gtk3/CMakeLists.txt
@@ -9,7 +9,7 @@ qt_find_package(X11) # special case
qt_internal_add_plugin(QGtk3ThemePlugin
OUTPUT_NAME qgtk3
- TYPE platformthemes
+ PLUGIN_TYPE platformthemes
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt b/src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt
index 980ef4a44a..82fb94e31d 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt
+++ b/src/plugins/platformthemes/xdgdesktopportal/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QXdgDesktopPortalThemePlugin
OUTPUT_NAME qxdgdesktopportal
- TYPE platformthemes
+ PLUGIN_TYPE platformthemes
DEFAULT_IF FALSE
SOURCES
main.cpp
diff --git a/src/plugins/printsupport/cups/CMakeLists.txt b/src/plugins/printsupport/cups/CMakeLists.txt
index 0a8b2253af..1132ff0845 100644
--- a/src/plugins/printsupport/cups/CMakeLists.txt
+++ b/src/plugins/printsupport/cups/CMakeLists.txt
@@ -8,7 +8,7 @@ qt_find_package(Cups PROVIDED_TARGETS Cups::Cups) # special case
qt_internal_add_plugin(QCupsPrinterSupportPlugin
OUTPUT_NAME cupsprintersupport
- TYPE printsupport
+ PLUGIN_TYPE printsupport
SOURCES
main.cpp
qcupsprintengine.cpp qcupsprintengine_p.h
diff --git a/src/plugins/sqldrivers/.cmake.conf b/src/plugins/sqldrivers/.cmake.conf
index 213991f589..aae2a6822b 100644
--- a/src/plugins/sqldrivers/.cmake.conf
+++ b/src/plugins/sqldrivers/.cmake.conf
@@ -1 +1 @@
-set(QT_REPO_MODULE_VERSION "6.1.0")
+set(QT_REPO_MODULE_VERSION "6.3.0")
diff --git a/src/plugins/sqldrivers/db2/CMakeLists.txt b/src/plugins/sqldrivers/db2/CMakeLists.txt
index de90d92581..1c693faa3b 100644
--- a/src/plugins/sqldrivers/db2/CMakeLists.txt
+++ b/src/plugins/sqldrivers/db2/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QDB2DriverPlugin
OUTPUT_NAME qsqldb2
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_db2.cpp qsql_db2_p.h
diff --git a/src/plugins/sqldrivers/ibase/CMakeLists.txt b/src/plugins/sqldrivers/ibase/CMakeLists.txt
index 4b914401ed..8cd5c24dfc 100644
--- a/src/plugins/sqldrivers/ibase/CMakeLists.txt
+++ b/src/plugins/sqldrivers/ibase/CMakeLists.txt
@@ -1,6 +1,6 @@
qt_internal_add_plugin(QIBaseDriverPlugin
OUTPUT_NAME qsqlibase
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_ibase.cpp qsql_ibase_p.h
diff --git a/src/plugins/sqldrivers/mysql/CMakeLists.txt b/src/plugins/sqldrivers/mysql/CMakeLists.txt
index 0679bcb698..a05fc513f1 100644
--- a/src/plugins/sqldrivers/mysql/CMakeLists.txt
+++ b/src/plugins/sqldrivers/mysql/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QMYSQLDriverPlugin
OUTPUT_NAME qsqlmysql
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_mysql.cpp qsql_mysql_p.h
diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
index 12e15bfc47..96bba79da1 100644
--- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
+++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
@@ -121,6 +121,20 @@ static inline QVariant qDateTimeFromString(QString &val)
#endif
}
+// check if this client and server version of MySQL/MariaDB support prepared statements
+static inline bool checkPreparedQueries(MYSQL *mysql)
+{
+ std::unique_ptr<MYSQL_STMT, decltype(&mysql_stmt_close)> stmt(mysql_stmt_init(mysql), &mysql_stmt_close);
+ if (!stmt)
+ return false;
+
+ static const char dummyQuery[] = "SELECT ? + ?";
+ if (mysql_stmt_prepare(stmt.get(), dummyQuery, sizeof(dummyQuery) - 1))
+ return false;
+
+ return mysql_stmt_param_count(stmt.get()) == 2;
+}
+
class QMYSQLResultPrivate;
class QMYSQLResult : public QSqlResult
@@ -172,7 +186,7 @@ public:
struct QMyField
{
char *outField = nullptr;
- MYSQL_FIELD *myField = nullptr;
+ const MYSQL_FIELD *myField = nullptr;
QMetaType type = QMetaType();
my_bool nullIndicator = false;
ulong bufLength = 0ul;
@@ -289,6 +303,13 @@ static bool qIsBlob(int t)
|| t == MYSQL_TYPE_LONG_BLOB;
}
+static bool qIsTimeOrDate(int t)
+{
+ // *not* MYSQL_TYPE_TIME because its range is bigger than QTime
+ // (see above)
+ return t == MYSQL_TYPE_DATE || t == MYSQL_TYPE_DATETIME || t == MYSQL_TYPE_TIMESTAMP;
+}
+
static bool qIsInteger(int t)
{
return t == QMetaType::Char || t == QMetaType::UChar
@@ -300,7 +321,7 @@ static bool qIsInteger(int t)
void QMYSQLResultPrivate::bindBlobs()
{
for (int i = 0; i < fields.count(); ++i) {
- MYSQL_FIELD *fieldInfo = fields.at(i).myField;
+ const MYSQL_FIELD *fieldInfo = fields.at(i).myField;
if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) {
MYSQL_BIND *bind = &inBinds[i];
bind->buffer_length = fieldInfo->max_length;
@@ -323,36 +344,39 @@ bool QMYSQLResultPrivate::bindInValues()
inBinds = new MYSQL_BIND[fields.size()];
memset(inBinds, 0, fields.size() * sizeof(MYSQL_BIND));
- MYSQL_FIELD *fieldInfo;
+ const MYSQL_FIELD *fieldInfo;
int i = 0;
while((fieldInfo = mysql_fetch_field(meta))) {
+ MYSQL_BIND *bind = &inBinds[i];
+
QMyField &f = fields[i];
f.myField = fieldInfo;
-
+ bind->buffer_length = f.bufLength = fieldInfo->length + 1;
+ bind->buffer_type = fieldInfo->type;
f.type = qDecodeMYSQLType(fieldInfo->type, fieldInfo->flags);
if (qIsBlob(fieldInfo->type)) {
// the size of a blob-field is available as soon as we call
// mysql_stmt_store_result()
// after mysql_stmt_exec() in QMYSQLResult::exec()
- fieldInfo->length = 0;
+ bind->buffer_length = f.bufLength = 0;
hasBlobs = true;
+ } else if (qIsTimeOrDate(fieldInfo->type)) {
+ bind->buffer_length = f.bufLength = sizeof(MYSQL_TIME);
} else if (qIsInteger(f.type.id())) {
- fieldInfo->length = 8;
+ bind->buffer_length = f.bufLength = 8;
} else {
- fieldInfo->type = MYSQL_TYPE_STRING;
+ bind->buffer_type = MYSQL_TYPE_STRING;
}
- MYSQL_BIND *bind = &inBinds[i];
- char *field = new char[fieldInfo->length + 1];
- memset(field, 0, fieldInfo->length + 1);
- bind->buffer_type = fieldInfo->type;
- bind->buffer = field;
- bind->buffer_length = f.bufLength = fieldInfo->length + 1;
bind->is_null = &f.nullIndicator;
bind->length = &f.bufLength;
bind->is_unsigned = fieldInfo->flags & UNSIGNED_FLAG ? 1 : 0;
- f.outField=field;
+
+ char *field = bind->buffer_length ? new char[bind->buffer_length + 1]{} : nullptr;
+ bind->buffer = f.outField = field;
+ if (qIsTimeOrDate(fieldInfo->type))
+ new (field) MYSQL_TIME;
++i;
}
@@ -403,9 +427,11 @@ void QMYSQLResult::cleanup()
d->meta = 0;
}
- int i;
- for (i = 0; i < d->fields.count(); ++i)
- delete[] d->fields[i].outField;
+ for (const auto &field : qAsConst(d->fields)) {
+ if (qIsTimeOrDate(field.myField->type))
+ reinterpret_cast<MYSQL_TIME *>(field.outField)->~MYSQL_TIME();
+ delete[] field.outField;
+ }
if (d->outBinds) {
delete[] d->outBinds;
@@ -544,6 +570,20 @@ QVariant QMYSQLResult::data(int field)
else if (f.type.id() == QMetaType::Char)
return variant.toInt();
return variant;
+ } else if (qIsTimeOrDate(f.myField->type) && f.bufLength == sizeof(MYSQL_TIME)) {
+ auto t = reinterpret_cast<const MYSQL_TIME *>(f.outField);
+ QDate date;
+ QTime time;
+ if (f.type.id() != QMetaType::QTime)
+ date = QDate(t->year, t->month, t->day);
+ if (f.type.id() != QMetaType::QDate)
+ time = QTime(t->hour, t->minute, t->second, t->second_part / 1000);
+ if (f.type.id() == QMetaType::QDateTime)
+ return QDateTime(date, time);
+ else if (f.type.id() == QMetaType::QDate)
+ return date;
+ else
+ return time;
}
if (f.type.id() != QMetaType::QByteArray)
@@ -1221,9 +1261,22 @@ bool QMYSQLDriver::open(const QString& db,
}
// try utf8 with non BMP first, utf8 (BMP only) if that fails
- if (mysql_set_character_set(d->mysql, "utf8mb4"))
- if (mysql_set_character_set(d->mysql, "utf8"))
- qWarning() << "MySQL: Unable to set the client character set to utf8.";
+ static const char wanted_charsets[][8] = { "utf8mb4", "utf8" };
+#ifdef MARIADB_VERSION_ID
+ MARIADB_CHARSET_INFO *cs = nullptr;
+ for (const char *p : wanted_charsets) {
+ cs = mariadb_get_charset_by_name(p);
+ if (cs) {
+ d->mysql->charset = cs;
+ break;
+ }
+ }
+#else
+ // dummy
+ struct {
+ const char *csname;
+ } *cs = nullptr;
+#endif
if (!sslKey.isNull() || !sslCert.isNull() || !sslCA.isNull() ||
!sslCAPath.isNull() || !sslCipher.isNull()) {
@@ -1251,6 +1304,21 @@ bool QMYSQLDriver::open(const QString& db,
unixSocket.isNull() ? nullptr : unixSocket.toUtf8().constData(),
optionFlags);
+ // now ask the server to match the charset we selected
+ if (!cs || mysql_set_character_set(d->mysql, cs->csname)) {
+ bool ok = false;
+ for (const char *p : wanted_charsets) {
+ if (mysql_set_character_set(d->mysql, p)) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok)
+ qWarning("MySQL: Unable to set the client character set to utf8 (\"%s\"). Using '%s' instead.",
+ mysql_error(d->mysql),
+ mysql_character_set_name(d->mysql));
+ }
+
if (mysql == d->mysql) {
if (!db.isEmpty() && mysql_select_db(d->mysql, db.toUtf8().constData())) {
setLastError(qMakeError(tr("Unable to open database '%1'").arg(db), QSqlError::ConnectionError, d));
@@ -1269,15 +1337,7 @@ bool QMYSQLDriver::open(const QString& db,
return false;
}
- // force the communication to be utf8mb4 (only utf8mb4 supports 4-byte characters)
- if (mysql_set_character_set(d->mysql, "utf8mb4")) {
- // this failed, try forcing it to utf (BMP only)
- if (mysql_set_character_set(d->mysql, "utf8"))
- qWarning() << "MySQL: Unable to set the client character set to utf8.";
- }
-
- d->preparedQuerysEnabled = mysql_get_client_version() >= 40108
- && mysql_get_server_version(d->mysql) >= 40100;
+ d->preparedQuerysEnabled = checkPreparedQueries(d->mysql);
#if QT_CONFIG(thread)
mysql_thread_init();
@@ -1452,6 +1512,20 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
qWarning("QMYSQLDriver::formatValue: Database not open");
}
Q_FALLTHROUGH();
+ case QMetaType::QDateTime:
+ if (QDateTime dt = field.value().toDateTime(); dt.isValid()) {
+ // MySQL format doesn't like the "Z" at the end, but does allow
+ // "+00:00" starting in version 8.0.19. However, if we got here,
+ // it's because the MySQL server is too old for prepared queries
+ // in the first place, so it won't understand timezones either.
+ // Besides, MYSQL_TIME does not support timezones, so match it.
+ r = QLatin1Char('\'') +
+ dt.date().toString(Qt::ISODate) +
+ QLatin1Char('T') +
+ dt.time().toString(Qt::ISODate) +
+ QLatin1Char('\'');
+ }
+ break;
default:
r = QSqlDriver::formatValue(field, trimStrings);
}
diff --git a/src/plugins/sqldrivers/oci/CMakeLists.txt b/src/plugins/sqldrivers/oci/CMakeLists.txt
index 4830586064..15ab7f7f87 100644
--- a/src/plugins/sqldrivers/oci/CMakeLists.txt
+++ b/src/plugins/sqldrivers/oci/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QOCIDriverPlugin
OUTPUT_NAME qsqloci
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_oci.cpp qsql_oci_p.h
diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp
index 1566428f26..638b01b022 100644
--- a/src/plugins/sqldrivers/oci/qsql_oci.cpp
+++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtSql module of the Qt Toolkit.
@@ -222,15 +222,16 @@ class QOCIDriverPrivate : public QSqlDriverPrivate
public:
QOCIDriverPrivate();
- OCIEnv *env;
- OCISvcCtx *svc;
- OCIServer *srvhp;
- OCISession *authp;
- OCIError *err;
- bool transaction;
- int serverVersion;
- int prefetchRows;
- int prefetchMem;
+ OCIEnv *env = nullptr;
+ OCISvcCtx *svc = nullptr;
+ OCIServer *srvhp = nullptr;
+ OCISession *authp = nullptr;
+ OCITrans *trans = nullptr;
+ OCIError *err = nullptr;
+ bool transaction = false;
+ int serverVersion = -1;
+ int prefetchRows = -1;
+ int prefetchMem = QOCI_PREFETCH_MEM;
QString user;
void allocErrorHandle();
@@ -271,11 +272,11 @@ public:
QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv);
~QOCIResultPrivate();
- QOCICols *cols;
+ QOCICols *cols = nullptr;
OCIEnv *env;
- OCIError *err;
+ OCIError *err = nullptr;
OCISvcCtx *&svc;
- OCIStmt *sql;
+ OCIStmt *sql = nullptr;
bool transaction;
int serverVersion;
int prefetchRows, prefetchMem;
@@ -572,20 +573,19 @@ void QOCIResultPrivate::outValues(QVariantList &values, IndicatorArray &indicato
QOCIDriverPrivate::QOCIDriverPrivate()
- : QSqlDriverPrivate(), env(0), svc(0), srvhp(0), authp(0), err(0), transaction(false),
- serverVersion(-1), prefetchRows(-1), prefetchMem(QOCI_PREFETCH_MEM)
+ : QSqlDriverPrivate()
{
dbmsType = QSqlDriver::Oracle;
}
void QOCIDriverPrivate::allocErrorHandle()
{
+ Q_ASSERT(!err);
int r = OCIHandleAlloc(env,
reinterpret_cast<void **>(&err),
OCI_HTYPE_ERROR,
- 0,
- 0);
- if (r != 0)
+ 0, nullptr);
+ if (r != OCI_SUCCESS)
qWarning("QOCIDriver: unable to allocate error handle");
}
@@ -1838,22 +1838,19 @@ void QOCICols::getValues(QVariantList &v, int index)
QOCIResultPrivate::QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv)
: QSqlCachedResultPrivate(q, drv),
- cols(0),
env(drv_d_func()->env),
- err(0),
svc(const_cast<OCISvcCtx*&>(drv_d_func()->svc)),
- sql(0),
transaction(drv_d_func()->transaction),
serverVersion(drv_d_func()->serverVersion),
prefetchRows(drv_d_func()->prefetchRows),
prefetchMem(drv_d_func()->prefetchMem)
{
+ Q_ASSERT(!err);
int r = OCIHandleAlloc(env,
reinterpret_cast<void **>(&err),
OCI_HTYPE_ERROR,
- 0,
- 0);
- if (r != 0)
+ 0, nullptr);
+ if (r != OCI_SUCCESS)
qWarning("QOCIResult: unable to alloc error handle");
}
@@ -1861,9 +1858,11 @@ QOCIResultPrivate::~QOCIResultPrivate()
{
delete cols;
- int r = OCIHandleFree(err, OCI_HTYPE_ERROR);
- if (r != 0)
+ if (sql && OCIHandleFree(sql, OCI_HTYPE_STMT) != OCI_SUCCESS)
qWarning("~QOCIResult: unable to free statement handle");
+
+ if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS)
+ qWarning("~QOCIResult: unable to free error report handle");
}
@@ -1876,12 +1875,6 @@ QOCIResult::QOCIResult(const QOCIDriver *db)
QOCIResult::~QOCIResult()
{
- Q_D(QOCIResult);
- if (d->sql) {
- int r = OCIHandleFree(d->sql, OCI_HTYPE_STMT);
- if (r != 0)
- qWarning("~QOCIResult: unable to free statement handle");
- }
}
QVariant QOCIResult::handle() const
@@ -1977,12 +1970,14 @@ bool QOCIResult::prepare(const QString& query)
QSqlResult::prepare(query);
delete d->cols;
- d->cols = 0;
+ d->cols = nullptr;
QSqlCachedResult::cleanup();
if (d->sql) {
r = OCIHandleFree(d->sql, OCI_HTYPE_STMT);
- if (r != OCI_SUCCESS)
+ if (r == OCI_SUCCESS)
+ d->sql = nullptr;
+ else
qOraWarning("QOCIResult::prepare: unable to free statement handle:", d->err);
}
if (query.isEmpty())
@@ -1990,8 +1985,7 @@ bool QOCIResult::prepare(const QString& query)
r = OCIHandleAlloc(d->env,
reinterpret_cast<void **>(&d->sql),
OCI_HTYPE_STMT,
- 0,
- 0);
+ 0, nullptr);
if (r != OCI_SUCCESS) {
qOraWarning("QOCIResult::prepare: unable to alloc statement:", d->err);
setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
@@ -2279,28 +2273,40 @@ bool QOCIDriver::open(const QString & db,
QString::fromLatin1("(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=%1)(Port=%2))"
"(CONNECT_DATA=(SID=%3)))").arg(hostname).arg((port > -1 ? port : 1521)).arg(db);
- r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->srvhp), OCI_HTYPE_SERVER, 0, 0);
- if (r == OCI_SUCCESS)
- r = OCIServerAttach(d->srvhp, d->err, reinterpret_cast<const OraText *>(connectionString.utf16()),
+ Q_ASSERT(!d->srvhp);
+ r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->srvhp), OCI_HTYPE_SERVER, 0, nullptr);
+ if (r == OCI_SUCCESS) {
+ r = OCIServerAttach(d->srvhp, d->err,
+ reinterpret_cast<const OraText *>(connectionString.utf16()),
connectionString.length() * sizeof(QChar), OCI_DEFAULT);
- if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO)
- r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->svc), OCI_HTYPE_SVCCTX, 0, 0);
+ }
+ Q_ASSERT(!d->svc);
+ if (r == OCI_SUCCESS || r == OCI_SUCCESS_WITH_INFO) {
+ r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->svc), OCI_HTYPE_SVCCTX,
+ 0, nullptr);
+ }
if (r == OCI_SUCCESS)
r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->srvhp, 0, OCI_ATTR_SERVER, d->err);
- if (r == OCI_SUCCESS)
- r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->authp), OCI_HTYPE_SESSION, 0, 0);
- if (r == OCI_SUCCESS)
+ Q_ASSERT(!d->authp);
+ if (r == OCI_SUCCESS) {
+ r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->authp), OCI_HTYPE_SESSION,
+ 0, nullptr);
+ }
+ if (r == OCI_SUCCESS) {
r = OCIAttrSet(d->authp, OCI_HTYPE_SESSION, const_cast<ushort *>(user.utf16()),
user.length() * sizeof(QChar), OCI_ATTR_USERNAME, d->err);
- if (r == OCI_SUCCESS)
+ }
+ if (r == OCI_SUCCESS) {
r = OCIAttrSet(d->authp, OCI_HTYPE_SESSION, const_cast<ushort *>(password.utf16()),
password.length() * sizeof(QChar), OCI_ATTR_PASSWORD, d->err);
-
- OCITrans* trans;
- if (r == OCI_SUCCESS)
- r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&trans), OCI_HTYPE_TRANS, 0, 0);
+ }
+ Q_ASSERT(!d->trans);
+ if (r == OCI_SUCCESS) {
+ r = OCIHandleAlloc(d->env, reinterpret_cast<void **>(&d->trans), OCI_HTYPE_TRANS,
+ 0, nullptr);
+ }
if (r == OCI_SUCCESS)
- r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, trans, 0, OCI_ATTR_TRANS, d->err);
+ r = OCIAttrSet(d->svc, OCI_HTYPE_SVCCTX, d->trans, 0, OCI_ATTR_TRANS, d->err);
if (r == OCI_SUCCESS) {
if (user.isEmpty() && password.isEmpty())
@@ -2314,12 +2320,18 @@ bool QOCIDriver::open(const QString & db,
if (r != OCI_SUCCESS) {
setLastError(qMakeError(tr("Unable to logon"), QSqlError::ConnectionError, d->err));
setOpenError(true);
+ if (d->trans)
+ OCIHandleFree(d->trans, OCI_HTYPE_TRANS);
+ d->trans = nullptr;
if (d->authp)
OCIHandleFree(d->authp, OCI_HTYPE_SESSION);
- d->authp = 0;
+ d->authp = nullptr;
+ if (d->svc)
+ OCIHandleFree(d->svc, OCI_HTYPE_SVCCTX);
+ d->svc = nullptr;
if (d->srvhp)
OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
- d->srvhp = 0;
+ d->srvhp = nullptr;
return false;
}
@@ -2359,12 +2371,14 @@ void QOCIDriver::close()
OCISessionEnd(d->svc, d->err, d->authp, OCI_DEFAULT);
OCIServerDetach(d->srvhp, d->err, OCI_DEFAULT);
+ OCIHandleFree(d->trans, OCI_HTYPE_TRANS);
+ d->trans = nullptr;
OCIHandleFree(d->authp, OCI_HTYPE_SESSION);
- d->authp = 0;
- OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
- d->srvhp = 0;
+ d->authp = nullptr;
OCIHandleFree(d->svc, OCI_HTYPE_SVCCTX);
- d->svc = 0;
+ d->svc = nullptr;
+ OCIHandleFree(d->srvhp, OCI_HTYPE_SERVER);
+ d->srvhp = nullptr;
setOpen(false);
setOpenError(false);
}
diff --git a/src/plugins/sqldrivers/odbc/CMakeLists.txt b/src/plugins/sqldrivers/odbc/CMakeLists.txt
index 032d89a244..1bbae1b3ec 100644
--- a/src/plugins/sqldrivers/odbc/CMakeLists.txt
+++ b/src/plugins/sqldrivers/odbc/CMakeLists.txt
@@ -8,7 +8,7 @@ qt_find_package(ODBC) # special case
qt_internal_add_plugin(QODBCDriverPlugin
OUTPUT_NAME qsqlodbc
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_odbc.cpp qsql_odbc_p.h
diff --git a/src/plugins/sqldrivers/psql/CMakeLists.txt b/src/plugins/sqldrivers/psql/CMakeLists.txt
index 648d29f582..8ed84c9028 100644
--- a/src/plugins/sqldrivers/psql/CMakeLists.txt
+++ b/src/plugins/sqldrivers/psql/CMakeLists.txt
@@ -8,7 +8,7 @@ qt_find_package(PostgreSQL) # special case
qt_internal_add_plugin(QPSQLDriverPlugin
OUTPUT_NAME qsqlpsql
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
main.cpp
qsql_psql.cpp qsql_psql_p.h
diff --git a/src/plugins/sqldrivers/sqlite/CMakeLists.txt b/src/plugins/sqldrivers/sqlite/CMakeLists.txt
index bbd03e451f..1fba18290b 100644
--- a/src/plugins/sqldrivers/sqlite/CMakeLists.txt
+++ b/src/plugins/sqldrivers/sqlite/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QSQLiteDriverPlugin
OUTPUT_NAME qsqlite
- TYPE sqldrivers
+ PLUGIN_TYPE sqldrivers
SOURCES
qsql_sqlite.cpp qsql_sqlite_p.h
smain.cpp
@@ -82,6 +82,10 @@ qt_internal_extend_target(QSQLiteDriverPlugin CONDITION UNIX AND NOT QT_FEATURE_
HAVE_USLEEP=1
)
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION INTEGRITY
+ COMPILE_OPTIONS -include qplatformdefs.h
+)
+
qt_internal_extend_target(QSQLiteDriverPlugin CONDITION QT_FEATURE_dlopen AND NOT QT_FEATURE_system_sqlite
LIBRARIES
${CMAKE_DL_LIBS}
@@ -91,6 +95,3 @@ qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_dlopen AN
DEFINES
SQLITE_OMIT_LOAD_EXTENSION
)
-
-#### Keys ignored in scope 12:.:../../../3rdparty:../../../3rdparty/sqlite.pri:INTEGRITY:
-# QMAKE_CFLAGS = "-include" "qplatformdefs.h"
diff --git a/src/plugins/styles/android/CMakeLists.txt b/src/plugins/styles/android/CMakeLists.txt
index 312f8ecfff..3dc0ed1e2e 100644
--- a/src/plugins/styles/android/CMakeLists.txt
+++ b/src/plugins/styles/android/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QAndroidStylePlugin
OUTPUT_NAME qandroidstyle
- TYPE styles
+ PLUGIN_TYPE styles
SOURCES
main.cpp
qandroidstyle.cpp qandroidstyle_p.h
diff --git a/src/plugins/styles/mac/CMakeLists.txt b/src/plugins/styles/mac/CMakeLists.txt
index f95579b474..98d6791d82 100644
--- a/src/plugins/styles/mac/CMakeLists.txt
+++ b/src/plugins/styles/mac/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QMacStylePlugin
OUTPUT_NAME qmacstyle
- TYPE styles
+ PLUGIN_TYPE styles
SOURCES
main.mm
qmacstyle_mac.mm qmacstyle_mac_p.h
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index 2030b47923..076a729170 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -196,6 +196,8 @@ const int pushButtonBevelRectOffsets[3] = {
QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
+bool isDarkMode() { return QGuiApplicationPrivate::platformTheme()->appearance() == QPlatformTheme::Appearance::Dark; }
+
// Title bar gradient colors for Lion were determined by inspecting PSDs exported
// using CoreUI's CoreThemeDocument; there is no public API to retrieve them
@@ -216,7 +218,7 @@ static QLinearGradient titlebarGradientActive()
gradient.setColorAt(1, QColor(180, 180, 180));
return gradient;
}();
- return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient;
+ return isDarkMode() ? darkGradient : lightGradient;
}
static QLinearGradient titlebarGradientInactive()
@@ -232,7 +234,7 @@ static QLinearGradient titlebarGradientInactive()
gradient.setColorAt(1, QColor(225, 225, 225));
return gradient;
}();
- return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient;
+ return isDarkMode() ? darkGradient : lightGradient;
}
#if QT_CONFIG(tabwidget)
@@ -254,7 +256,7 @@ static void clipTabBarFrame(const QStyleOption *option, const QMacStyle *style,
Q_ASSERT(style);
Q_ASSERT(ctx);
- if (qt_mac_applicationIsInDarkMode()) {
+ if (isDarkMode()) {
QTabWidget *tabWidget = qobject_cast<QTabWidget *>(option->styleObject);
Q_ASSERT(tabWidget);
@@ -302,7 +304,6 @@ static const qreal titleBarButtonSpacing = 8;
// active: window is active
// selected: tab is selected
// hovered: tab is hovered
-bool isDarkMode() { return qt_mac_applicationIsInDarkMode(); }
#if QT_CONFIG(tabbar)
static const QColor lightTabBarTabBackgroundActive(190, 190, 190);
@@ -388,16 +389,15 @@ static const QMarginsF pushButtonShadowMargins[3] = {
{ 1.5, 0.5, 1.5, 2.5 }
};
-// These are frame heights as reported by Xcode 9's Interface Builder.
-// Alignemnet rectangle's heights match for push and popup buttons
-// with respective values 21, 18 and 15.
+// These are frame heights as reported by Xcode 9's Interface Builder
+// and determined experimentally.
static const qreal comboBoxDefaultHeight[3] = {
26, 22, 19
};
static const qreal pushButtonDefaultHeight[3] = {
- 32, 28, 16
+ 32, 28, 24
};
static const qreal popupButtonDefaultHeight[3] = {
@@ -423,7 +423,7 @@ public:
{
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
- && !qt_mac_applicationIsInDarkMode()) {
+ && !isDarkMode()) {
auto requiredAppearanceName = NSApplication.sharedApplication.effectiveAppearance.name;
if (![NSAppearance.currentAppearance.name isEqualToString:requiredAppearanceName]) {
previous = NSAppearance.currentAppearance;
@@ -1207,8 +1207,9 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int
focusRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]);
if (cw.type == QMacStylePrivate::Button_PushButton) {
focusRect -= pushButtonShadowMargins[cw.size];
- }
- else if (cw.type == QMacStylePrivate::Button_PullDown) {
+ if (cw.size == QStyleHelper::SizeMini)
+ focusRect.adjust(0, 3, 0, -3);
+ } else if (cw.type == QMacStylePrivate::Button_PullDown) {
focusRect -= pullDownButtonShadowMargins[cw.size];
//fix focus ring drawn slightly off for pull downs
if (cw.size == QStyleHelper::SizeLarge)
@@ -1233,6 +1234,8 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int
QRectF focusRect = targetRect;
if (isBigSurOrAbove)
focusRect.translate(0, -1.5);
+ else if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSCatalina)
+ focusRect.adjust(0, 0, 0, -1);
const qreal innerRadius = cw.type == Button_PushButton ? 3 : 4;
const qreal outerRadius = innerRadius + focusRingWidth;
hOffset = focusRect.left();
@@ -1286,7 +1289,7 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int
}
auto focusRingColor = qt_mac_toQColor(NSColor.keyboardFocusIndicatorColor.CGColor);
- if (!qt_mac_applicationIsInDarkMode()) {
+ if (!isDarkMode()) {
// This color already has alpha ~ 0.25, this value is too small - the ring is
// very pale and nothing like the native one. 0.39 makes it better (not ideal
// anyway). The color seems to be correct in dark more without any modification.
@@ -1596,9 +1599,9 @@ QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect)
frameRect = QRectF(rect.topLeft(),
QSizeF(rect.width(), frameSize.height()));
if (size == QStyleHelper::SizeSmall)
- frameRect = frameRect.translated(0, 1.5);
+ frameRect.translate(0, 0.5);
else if (size == QStyleHelper::SizeMini)
- frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, 4);
+ frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, -0.5);
frameRect = frameRect.adjusted(-pushButtonBevelRectOffsets[size], 0,
pushButtonBevelRectOffsets[size], 0);
} else {
@@ -1684,13 +1687,15 @@ QMacStylePrivate::CocoaControlType cocoaControlType(const QStyleOption *opt, con
{
if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
- // When the contents won't fit in a large sized button,
- // and WA_MacNormalSize is not set, make the button square.
+ // Buttons that don't fit (or don't get filled by) the default bevel
+ // will be made of square type, unless WA_MacNormalSize is not set.
// Threshold used to be at 34, not 32.
- const auto maxNonSquareHeight = pushButtonDefaultHeight[QStyleHelper::SizeLarge];
+ // Needs to be in sync with similar logic in CE_FocusFrame handling
+ QStyleHelper::WidgetSizePolicy sizePolicy = QStyleHelper::widgetSizePolicy(w, opt);
+ if (sizePolicy == QStyleHelper::SizeDefault)
+ sizePolicy = QStyleHelper::SizeLarge;
const bool isSquare = (btn->features & QStyleOptionButton::Flat)
- || (btn->rect.height() > maxNonSquareHeight
- && !(w && w->testAttribute(Qt::WA_MacNormalSize)));
+ || (btn->rect.height() != pushButtonDefaultHeight[sizePolicy]);
return (isSquare? QMacStylePrivate::Button_SquareButton :
hasMenu ? QMacStylePrivate::Button_PullDown :
QMacStylePrivate::Button_PushButton);
@@ -1832,7 +1837,7 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
if (widget.type == Box) {
if (__builtin_available(macOS 10.14, *)) {
- if (qt_mac_applicationIsInDarkMode()) {
+ if (isDarkMode()) {
// See render code in drawPrimitive(PE_FrameTabWidget)
widget.type = Box_Dark;
}
@@ -3098,7 +3103,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
auto adjustedRect = opt->rect;
bool needTranslation = false;
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
- && !qt_mac_applicationIsInDarkMode()) {
+ && !isDarkMode()) {
// In Aqua theme we have to use the 'default' NSBox (as opposite
// to the 'custom' QDarkNSBox we use in dark theme). Since -drawRect:
// does nothing in default NSBox, we call -displayRectIgnoringOpaticty:.
@@ -3146,14 +3151,14 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
theStroker.setCapStyle(Qt::FlatCap);
theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
path = theStroker.createStroke(path);
- const auto dark = qt_mac_applicationIsInDarkMode() ? opt->palette.dark().color().darker()
+ const auto dark = isDarkMode() ? opt->palette.dark().color().darker()
: QColor(0, 0, 0, 119);
p->fillPath(path, dark);
}
break;
case PE_FrameWindow:
if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
- if (w && w->inherits("QMdiSubWindow")) {
+ if (qobject_cast<const QMdiSubWindow*>(w)) {
p->save();
p->setPen(QPen(frame->palette.dark().color(), frame->lineWidth));
p->setBrush(frame->palette.window());
@@ -3340,7 +3345,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
tf.frame = opt->rect.toCGRect();
d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
- if (!qt_mac_applicationIsInDarkMode()) {
+ if (!isDarkMode()) {
// In 'Dark' mode controls are transparent, so we do not
// over-paint the (potentially custom) color in the background.
// In 'Light' mode we have to care about the correct
@@ -3373,7 +3378,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
case PE_PanelLineEdit:
{
const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt);
- if (qt_mac_applicationIsInDarkMode() || (panel && panel->lineWidth <= 0)) {
+ if (isDarkMode() || (panel && panel->lineWidth <= 0)) {
// QCommonStyle::drawPrimitive(PE_PanelLineEdit) fill the background with
// a proper color, defined in opt->palette and then, if lineWidth > 0, it
// calls QMacStyle::drawPrimitive(PE_FrameLineEdit). We use NSTextFieldCell
@@ -3564,9 +3569,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
QPixmap pixmap = header->icon.pixmap(QSize(iconExtent, iconExtent), p->device()->devicePixelRatio(), mode);
QRect pixr = header->rect;
- pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
+ QSizeF size = pixmap.deviceIndependentSize();
+ pixr.setY(header->rect.center().y() - (size.height() - 1) / 2);
proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
- textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
+ textr.translate(size.width() + 2, 0);
}
QString text = header->text;
if (const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(header)) {
@@ -3623,12 +3629,13 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
// Draw the text if it's needed.
if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
needText = true;
+ QSizeF size = pixmap.deviceIndependentSize();
if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
- pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6);
+ pr.setHeight(size.height() + 6);
cr.adjust(0, pr.bottom(), 0, -3);
alignment |= Qt::AlignCenter;
} else {
- pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8);
+ pr.setWidth(size.width() + 8);
cr.adjust(pr.right(), 0, 0, 0);
alignment |= Qt::AlignLeft | Qt::AlignVCenter;
}
@@ -3765,7 +3772,13 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const bool isActive = btn.state & State_Active;
const bool isPressed = btn.state & State_Sunken;
+ // cocoaControlType evaluates the type based on the control's geometry, not on the
+ // label's geometry
+ const QRect oldRect = btn.rect;
+ if (w)
+ btn.rect = w->rect();
const auto ct = cocoaControlType(&btn, w);
+ btn.rect = oldRect;
if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
if (isPressed
@@ -3802,12 +3815,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
if (btn.state & State_On)
state = QIcon::On;
QPixmap pixmap = btn.icon.pixmap(btn.iconSize, p->device()->devicePixelRatio(), mode, state);
- int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
- int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
- contentW += pixmapWidth + QMacStylePrivate::PushButtonContentPadding;
+ QSizeF pixmapSize = pixmap.deviceIndependentSize();
+ contentW += pixmapSize.width() + QMacStylePrivate::PushButtonContentPadding;
int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
- int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2;
- QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight);
+ int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapSize.height()) / 2;
+ QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapSize.width(), pixmapSize.height());
QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
int newOffset = iconDestRect.x() + iconDestRect.width()
@@ -4171,17 +4183,21 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const auto *ffw = ff ? ff->widget() : nullptr;
const auto ct = [=] {
if (ffw) {
- if (ffw->inherits("QCheckBox"))
+ if (qobject_cast<const QCheckBox*>(ffw))
return QMacStylePrivate::Button_CheckBox;
- if (ffw->inherits("QRadioButton"))
+ if (qobject_cast<const QRadioButton*>(ffw))
return QMacStylePrivate::Button_RadioButton;
- if (ffw->inherits("QLineEdit") || ffw->inherits("QTextEdit"))
+ if (qobject_cast<const QLineEdit*>(ffw) || qobject_cast<const QTextEdit*>(ffw))
return QMacStylePrivate::TextField;
if (const auto *pb = qobject_cast<const QPushButton *>(ffw)) {
- if (pb->isFlat() || (pb->rect().height()
- > pushButtonDefaultHeight[QStyleHelper::SizeLarge]
- && !(pb->testAttribute(Qt::WA_MacNormalSize))))
- return QMacStylePrivate::Button_SquareButton;
+ // keep in sync with cocoaControlType
+ auto sizePolicy = QStyleHelper::widgetSizePolicy(ffw, opt);
+ if (sizePolicy == QStyleHelper::SizeDefault)
+ sizePolicy = QStyleHelper::SizeLarge;
+ if (pb->isFlat()
+ || (pb->rect().height() != pushButtonDefaultHeight[sizePolicy])) {
+ return QMacStylePrivate::Button_SquareButton;
+ }
if (pb->menu() != nullptr)
return QMacStylePrivate::Button_PullDown;
return QMacStylePrivate::Button_PushButton;
@@ -4190,10 +4206,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
return QMacStylePrivate::Box; // Not really, just make it the default
} ();
- const auto cs = ffw ? (ffw->testAttribute(Qt::WA_MacMiniSize) ? QStyleHelper::SizeMini :
- ffw->testAttribute(Qt::WA_MacSmallSize) ? QStyleHelper::SizeSmall :
- QStyleHelper::SizeLarge) :
- QStyleHelper::SizeLarge;
+ auto cs = QStyleHelper::widgetSizePolicy(ffw, opt);
+ if (cs == QStyleHelper::SizeDefault)
+ cs = QStyleHelper::SizeLarge;
const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt, w);
const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt, w);
d->drawFocusRing(p, opt->rect, hMargin, vMargin, QMacStylePrivate::CocoaControl(ct, cs));
@@ -4301,13 +4316,12 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
}
#endif
QPixmap pixmap = mi->icon.pixmap(iconSize, p->device()->devicePixelRatio(), mode);
- int pixw = pixmap.width() / pixmap.devicePixelRatio();
- int pixh = pixmap.height() / pixmap.devicePixelRatio();
QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
- QRect pmr(0, 0, pixw, pixh);
+ QSize size = pixmap.deviceIndependentSize().toSize();
+ QRect pmr(QPoint(0, 0), size);
pmr.moveCenter(cr.center());
p->drawPixmap(pmr.topLeft(), pixmap);
- xpos += pixw + 6;
+ xpos += size.width() + 6;
}
QString s = mi->text;
@@ -4581,7 +4595,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
#ifndef QT_NO_TOOLBAR
case CE_ToolBar: {
const QStyleOptionToolBar *toolBar = qstyleoption_cast<const QStyleOptionToolBar *>(opt);
- const bool isDarkMode = qt_mac_applicationIsInDarkMode();
+ const bool darkMode = isDarkMode();
// Unified title and toolbar drawing. In this mode the cocoa platform plugin will
// fill the top toolbar area part with a background gradient that "unifies" with
@@ -4606,7 +4620,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
if (isEndOfUnifiedArea) {
const int margin = qt_mac_aqua_get_metric(SeparatorSize);
const auto separatorRect = QRect(opt->rect.left(), opt->rect.bottom(), opt->rect.width(), margin);
- p->fillRect(separatorRect, isDarkMode ? darkModeSeparatorLine : opt->palette.dark().color());
+ p->fillRect(separatorRect, darkMode ? darkModeSeparatorLine : opt->palette.dark().color());
}
break;
}
@@ -4621,24 +4635,24 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
else
linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
- QColor mainWindowGradientBegin = isDarkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
- QColor mainWindowGradientEnd = isDarkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
+ QColor mainWindowGradientBegin = darkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
+ QColor mainWindowGradientEnd = darkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
linearGrad.setColorAt(0, mainWindowGradientBegin);
linearGrad.setColorAt(1, mainWindowGradientEnd);
p->fillRect(opt->rect, linearGrad);
p->save();
- QRect toolbarRect = isDarkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
+ QRect toolbarRect = darkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
if (opt->state & State_Horizontal) {
- p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
+ p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
- p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
+ p->setPen(darkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
} else {
- p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
+ p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
- p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
+ p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
}
p->restore();
diff --git a/src/plugins/styles/windowsvista/CMakeLists.txt b/src/plugins/styles/windowsvista/CMakeLists.txt
index f668b21632..efd552ab08 100644
--- a/src/plugins/styles/windowsvista/CMakeLists.txt
+++ b/src/plugins/styles/windowsvista/CMakeLists.txt
@@ -6,7 +6,7 @@
qt_internal_add_plugin(QWindowsVistaStylePlugin
OUTPUT_NAME qwindowsvistastyle
- TYPE styles
+ PLUGIN_TYPE styles
SOURCES
main.cpp
qwindowsvistastyle.cpp qwindowsvistastyle_p.h
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
index f7496b62ca..73be33b278 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
+++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
@@ -1273,9 +1273,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On);
else
pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode);
- const int pixw = pixmap.width() / pixmap.devicePixelRatio();
- const int pixh = pixmap.height() / pixmap.devicePixelRatio();
- QRect pmr(0, 0, pixw, pixh);
+ QRect pmr(QPoint(0, 0), pixmap.deviceIndependentSize().toSize());
pmr.moveCenter(vCheckRect.center());
painter->setPen(menuitem->palette.text().color());
painter->drawPixmap(pmr.topLeft(), pixmap);
@@ -1773,21 +1771,6 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle
theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
theme.stateId = stateId;
d->drawBackground(theme);
-
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) {
- const QRect gripperBounds = QWindowsXPStylePrivate::scrollBarGripperBounds(flags, widget, &theme);
- // Draw gripper if there is enough space
- if (!gripperBounds.isEmpty() && flags & State_Enabled) {
- painter->save();
- XPThemeData grippBackground = theme;
- grippBackground.partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
- theme.rect = gripperBounds;
- painter->setClipRegion(d->region(theme));// Only change inside the region of the gripper
- d->drawBackground(grippBackground);// The gutter is the grippers background
- d->drawBackground(theme); // Transparent gripper ontop of background
- painter->restore();
- }
- }
}
}
}
diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
index e9df7a1e8c..d91da5a04c 100644
--- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
+++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
@@ -997,7 +997,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa
#endif
img = QImage(bufferPixels, bufferW, bufferH, format);
if (hasCorrectionFactor)
- img = img.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ img = img.scaled(img.size() * correctionFactor, Qt::KeepAspectRatio, Qt::SmoothTransformation);
img.setDevicePixelRatio(additionalDevicePixelRatio);
}
@@ -1974,9 +1974,7 @@ void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *op
QPixmap pixmap = checked ?
menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On) :
menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode);
- const int pixw = pixmap.width() / pixmap.devicePixelRatio();
- const int pixh = pixmap.height() / pixmap.devicePixelRatio();
- QRect iconRect(0, 0, pixw, pixh);
+ QRect iconRect(QPoint(0, 0), pixmap.deviceIndependentSize().toSize());
iconRect.moveCenter(QRect(xpos, y, checkcol, h).center());
QRect vIconRect = visualRect(option->direction, option->rect, iconRect);
p->setPen(menuitem->palette.text().color());
@@ -2293,7 +2291,7 @@ static void populateMdiButtonTheme(const QStyle *proxy, const QWidget *widget,
// Calculate an small (max 2), empirical correction factor for scaling up
// WP_MDICLOSEBUTTON, WP_MDIRESTOREBUTTON, WP_MDIMINBUTTON, which are too
// small on High DPI screens (QTBUG-75927).
-qreal mdiButtonCorrectionFactor(XPThemeData &theme, const QPaintDevice *pd = nullptr)
+static qreal mdiButtonCorrectionFactor(XPThemeData &theme, const QPaintDevice *pd = nullptr)
{
const auto dpr = pd ? pd->devicePixelRatio() : qApp->devicePixelRatio();
const QSizeF nativeSize = QSizeF(theme.size()) / dpr;
diff --git a/src/plugins/tls/certonly/CMakeLists.txt b/src/plugins/tls/certonly/CMakeLists.txt
index 275045dc49..14b769cbba 100644
--- a/src/plugins/tls/certonly/CMakeLists.txt
+++ b/src/plugins/tls/certonly/CMakeLists.txt
@@ -1,7 +1,7 @@
qt_internal_add_plugin(QTlsBackendCertOnlyPlugin
- OUTPUT_NAME certonlybackend
+ OUTPUT_NAME qcertonlybackend
CLASS_NAME QTlsBackendCertOnly
- TYPE tls
+ PLUGIN_TYPE tls
DEFAULT_IF NOT QT_FEATURE_securetransport AND NOT (QT_FEATURE_openssl OR QT_FEATURE_openssl_linked) AND NOT QT_FEATURE_schannel
SOURCES
../shared/qx509_base_p.h
@@ -12,6 +12,6 @@ qt_internal_add_plugin(QTlsBackendCertOnlyPlugin
../shared/qasn1element.cpp
qtlsbackend_cert.cpp
qtlsbackend_cert_p.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::NetworkPrivate
)
diff --git a/src/plugins/tls/certonly/qtlsbackend_cert.cpp b/src/plugins/tls/certonly/qtlsbackend_cert.cpp
index c81eb0252e..e7e5f0f760 100644
--- a/src/plugins/tls/certonly/qtlsbackend_cert.cpp
+++ b/src/plugins/tls/certonly/qtlsbackend_cert.cpp
@@ -47,8 +47,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.cert-only");
-
QString QTlsBackendCertOnly::backendName() const
{
return builtinBackendNames[nameIndexCertOnly];
diff --git a/src/plugins/tls/openssl/CMakeLists.txt b/src/plugins/tls/openssl/CMakeLists.txt
index 266292c62a..0a35d5888b 100644
--- a/src/plugins/tls/openssl/CMakeLists.txt
+++ b/src/plugins/tls/openssl/CMakeLists.txt
@@ -1,7 +1,7 @@
qt_internal_add_plugin(QTlsBackendOpenSSLPlugin
- OUTPUT_NAME opensslbackend
+ OUTPUT_NAME qopensslbackend
CLASS_NAME QTlsBackendOpenSSL
- TYPE tls
+ PLUGIN_TYPE tls
SOURCES
../shared/qx509_base.cpp ../shared/qx509_base_p.h
../shared/qtlskey_base.cpp ../shared/qtlskey_base_p.h
@@ -14,7 +14,7 @@ qt_internal_add_plugin(QTlsBackendOpenSSLPlugin
qsslcontext_openssl.cpp qsslcontext_openssl_p.h
qsslsocket_openssl_symbols.cpp qsslsocket_openssl_symbols_p.h
qopenssl_p.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::NetworkPrivate
Qt::CorePrivate
DEFINES
@@ -35,7 +35,7 @@ qt_internal_extend_target(QTlsBackendOpenSSLPlugin CONDITION APPLE
${FWSecurity}
)
-qt_internal_extend_target(QTlsBackendOpenSSLPlugin CONDITION ANDROID AND NOT ANDROID_EMBEDDED
+qt_internal_extend_target(QTlsBackendOpenSSLPlugin CONDITION ANDROID
SOURCES
qsslsocket_openssl_android.cpp
)
@@ -48,4 +48,3 @@ qt_internal_extend_target(QTlsBackendOpenSSLPlugin CONDITION QT_FEATURE_openssl
LIBRARIES
crypt32
)
-
diff --git a/src/plugins/tls/openssl/qdtls_openssl.cpp b/src/plugins/tls/openssl/qdtls_openssl.cpp
index 55a82f7fd4..a1f2c707f9 100644
--- a/src/plugins/tls/openssl/qdtls_openssl.cpp
+++ b/src/plugins/tls/openssl/qdtls_openssl.cpp
@@ -605,7 +605,7 @@ bool DtlsState::init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
Q_ASSERT(dtlsBase);
Q_ASSERT(socket);
- if (!tlsContext.data() && !initTls(dtlsBase))
+ if (!tlsContext && !initTls(dtlsBase))
return false;
udpSocket = socket;
@@ -632,7 +632,7 @@ void DtlsState::reset()
bool DtlsState::initTls(QDtlsBasePrivate *dtlsBase)
{
- if (tlsContext.data())
+ if (tlsContext)
return true;
if (!QSslSocket::supportsSsl())
@@ -716,7 +716,7 @@ bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
bool DtlsState::initBIO(QDtlsBasePrivate *dtlsBase)
{
Q_ASSERT(dtlsBase);
- Q_ASSERT(tlsContext.data() && tlsConnection.data());
+ Q_ASSERT(tlsContext && tlsConnection);
BioMethod customMethod(q_BIO_meth_new(BIO_TYPE_DGRAM, dtlsbio::qdtlsMethodName),
dtlsutil::delete_bio_method);
@@ -1421,9 +1421,12 @@ void QDtlsPrivateOpenSSL::fetchNegotiatedParameters()
// TLS 1.2, that's how it's set by OpenSSL (and that's what they are?).
switch (q_SSL_version(dtls.tlsConnection.data())) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case DTLS1_VERSION:
sessionProtocol = QSsl::DtlsV1_0;
break;
+QT_WARNING_POP
case DTLS1_2_VERSION:
sessionProtocol = QSsl::DtlsV1_2;
break;
diff --git a/src/plugins/tls/openssl/qdtls_openssl_p.h b/src/plugins/tls/openssl/qdtls_openssl_p.h
index d10d4ce584..8f2b59c8b0 100644
--- a/src/plugins/tls/openssl/qdtls_openssl_p.h
+++ b/src/plugins/tls/openssl/qdtls_openssl_p.h
@@ -92,7 +92,7 @@ public:
using BioMethod = QSharedPointer<BIO_METHOD>;
BioMethod bioMethod;
- using TlsContext = QSharedPointer<QSslContext>;
+ using TlsContext = std::shared_ptr<QSslContext>;
TlsContext tlsContext;
using TlsConnection = QSharedPointer<SSL>;
diff --git a/src/plugins/tls/openssl/qsslcontext_openssl.cpp b/src/plugins/tls/openssl/qsslcontext_openssl.cpp
index c0afc32e47..54d749b147 100644
--- a/src/plugins/tls/openssl/qsslcontext_openssl.cpp
+++ b/src/plugins/tls/openssl/qsslcontext_openssl.cpp
@@ -46,6 +46,7 @@
#include "qsslsocket_openssl_symbols_p.h"
#include "qsslcontext_openssl_p.h"
#include "qtlsbackend_openssl_p.h"
+#include "qtlskey_openssl_p.h"
#include "qopenssl_p.h"
#include <QtNetwork/private/qssl_p.h>
@@ -102,13 +103,16 @@ long QSslContext::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptio
{
long options;
switch (protocol) {
- case QSsl::SecureProtocols:
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::TlsV1_0OrLater:
options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
break;
case QSsl::TlsV1_1OrLater:
options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
break;
+QT_WARNING_POP
+ case QSsl::SecureProtocols:
case QSsl::TlsV1_2OrLater:
options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
break;
@@ -169,21 +173,15 @@ QSslContext::~QSslContext()
q_SSL_SESSION_free(session);
}
-QSslContext* QSslContext::fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
-{
- QSslContext *sslContext = new QSslContext();
- initSslContext(sslContext, mode, configuration, allowRootCertOnDemandLoading);
- return sslContext;
-}
-
-QSharedPointer<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
+std::shared_ptr<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
{
- QSharedPointer<QSslContext> sslContext = QSharedPointer<QSslContext>::create();
- initSslContext(sslContext.data(), mode, configuration, allowRootCertOnDemandLoading);
+ struct AccessToPrivateCtor : QSslContext {};
+ std::shared_ptr<QSslContext> sslContext = std::make_shared<AccessToPrivateCtor>();
+ initSslContext(sslContext.get(), mode, configuration, allowRootCertOnDemandLoading);
return sslContext;
}
-QSharedPointer<QSslContext> QSslContext::sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
+std::shared_ptr<QSslContext> QSslContext::sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
bool allowRootCertOnDemandLoading)
{
return sharedFromConfiguration(mode, privConfiguration, allowRootCertOnDemandLoading);
@@ -363,8 +361,11 @@ void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mo
bool isDtls = false;
init_context:
switch (sslContext->sslConfiguration.protocol()) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::DtlsV1_0:
case QSsl::DtlsV1_0OrLater:
+QT_WARNING_POP
case QSsl::DtlsV1_2:
case QSsl::DtlsV1_2OrLater:
#if QT_CONFIG(dtls)
@@ -419,6 +420,8 @@ init_context:
long maxVersion = anyVersion;
switch (sslContext->sslConfiguration.protocol()) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::TlsV1_0:
minVersion = TLS1_VERSION;
maxVersion = TLS1_VERSION;
@@ -427,6 +430,7 @@ init_context:
minVersion = TLS1_1_VERSION;
maxVersion = TLS1_1_VERSION;
break;
+QT_WARNING_POP
case QSsl::TlsV1_2:
minVersion = TLS1_2_VERSION;
maxVersion = TLS1_2_VERSION;
@@ -443,7 +447,8 @@ init_context:
break;
// Ranges:
case QSsl::AnyProtocol:
- case QSsl::SecureProtocols:
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::TlsV1_0OrLater:
minVersion = TLS1_VERSION;
maxVersion = 0;
@@ -452,25 +457,30 @@ init_context:
minVersion = TLS1_1_VERSION;
maxVersion = 0;
break;
+QT_WARNING_POP
+ case QSsl::SecureProtocols:
case QSsl::TlsV1_2OrLater:
minVersion = TLS1_2_VERSION;
maxVersion = 0;
break;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::DtlsV1_0:
minVersion = DTLS1_VERSION;
maxVersion = DTLS1_VERSION;
break;
case QSsl::DtlsV1_0OrLater:
minVersion = DTLS1_VERSION;
- maxVersion = DTLS_MAX_VERSION;
+ maxVersion = 0;
break;
+QT_WARNING_POP
case QSsl::DtlsV1_2:
minVersion = DTLS1_2_VERSION;
maxVersion = DTLS1_2_VERSION;
break;
case QSsl::DtlsV1_2OrLater:
minVersion = DTLS1_2_VERSION;
- maxVersion = DTLS_MAX_VERSION;
+ maxVersion = 0;
break;
case QSsl::TlsV1_3OrLater:
#ifdef TLS1_3_VERSION
@@ -617,6 +627,13 @@ init_context:
if (configuration.d->privateKey.algorithm() == QSsl::Opaque) {
sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
} else {
+#ifdef OPENSSL_NO_DEPRECATED_3_0
+ auto qtKey = QTlsBackend::backend<QTlsPrivate::TlsKeyOpenSSL>(configuration.d->privateKey);
+ Q_ASSERT(qtKey);
+ sslContext->pkey = qtKey->genericKey;
+ Q_ASSERT(sslContext->pkey);
+ q_EVP_PKEY_up_ref(sslContext->pkey);
+#else
// Load private key
sslContext->pkey = q_EVP_PKEY_new();
// before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
@@ -629,7 +646,8 @@ init_context:
#ifndef OPENSSL_NO_EC
else if (configuration.d->privateKey.algorithm() == QSsl::Ec)
q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
-#endif
+#endif // OPENSSL_NO_EC
+#endif // OPENSSL_NO_DEPRECATED_3_0
}
auto pkey = sslContext->pkey;
if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
diff --git a/src/plugins/tls/openssl/qsslcontext_openssl_p.h b/src/plugins/tls/openssl/qsslcontext_openssl_p.h
index c350a93f5e..f031386ee1 100644
--- a/src/plugins/tls/openssl/qsslcontext_openssl_p.h
+++ b/src/plugins/tls/openssl/qsslcontext_openssl_p.h
@@ -69,11 +69,9 @@ public:
~QSslContext();
- static QSslContext* fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading);
- static QSharedPointer<QSslContext> sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
+ static std::shared_ptr<QSslContext> sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
bool allowRootCertOnDemandLoading);
- static QSharedPointer<QSslContext> sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
+ static std::shared_ptr<QSslContext> sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
bool allowRootCertOnDemandLoading);
static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
@@ -105,7 +103,6 @@ public:
protected:
QSslContext();
- friend class QSharedPointer<QSslContext>;
private:
static void initSslContext(QSslContext* sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration,
diff --git a/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp b/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
index a917a20744..8a268eeebe 100644
--- a/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
+++ b/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
@@ -55,57 +55,6 @@ QT_BEGIN_NAMESPACE
namespace {
-#ifdef OPENSSL_NO_DEPRECATED_3_0
-
-int q_DH_check(DH *dh, int *status)
-{
- // DH_check was first deprecated in OpenSSL 3.0.0, as low-level
- // API; the EVP_PKEY family of functions was advised as an alternative.
- // As of now EVP_PKEY_params_check ends up calling ... DH_check,
- // which is good enough.
-
- Q_ASSERT(dh);
- Q_ASSERT(status);
-
- EVP_PKEY *key = q_EVP_PKEY_new();
- if (!key) {
- qCWarning(lcSsl, "EVP_PKEY_new failed");
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- return 0;
- }
- const auto keyDeleter = qScopeGuard([key](){
- q_EVP_PKEY_free(key);
- });
- if (!q_EVP_PKEY_set1_DH(key, dh)) {
- qCWarning(lcTlsBackend, "EVP_PKEY_set1_DH failed");
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- return 0;
- }
-
- EVP_PKEY_CTX *keyCtx = q_EVP_PKEY_CTX_new(key, nullptr);
- if (!keyCtx) {
- qCWarning(lcTlsBackend, "EVP_PKEY_CTX_new failed");
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- return 0;
- }
- const auto ctxDeleter = qScopeGuard([keyCtx]{
- q_EVP_PKEY_CTX_free(keyCtx);
- });
-
- const int result = q_EVP_PKEY_param_check(keyCtx);
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- // Note: unlike DH_check, we cannot obtain the 'status',
- // if the 'result' is 0 (actually the result is 1 only
- // if this 'status' was 0). We could probably check the
- // errors from the error queue, but it's not needed anyway
- // - see the 'isSafeDH' below, how it returns immediately
- // on 0.
- Q_UNUSED(status);
-
- return result;
-}
-#endif // OPENSSL_NO_DEPRECATED_3_0
-
bool isSafeDH(DH *dh)
{
int status = 0;
diff --git a/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp b/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp
index 6b4601163b..a30348b20e 100644
--- a/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp
+++ b/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp
@@ -55,6 +55,7 @@
****************************************************************************/
#include "qsslsocket_openssl_symbols_p.h"
+#include "qtlsbackend_openssl_p.h"
#include <QtNetwork/private/qssl_p.h>
@@ -149,9 +150,6 @@ DEFINEFUNC(int, EVP_PKEY_up_ref, EVP_PKEY *a, a, return 0, return)
DEFINEFUNC2(EVP_PKEY_CTX *, EVP_PKEY_CTX_new, EVP_PKEY *pkey, pkey, ENGINE *e, e, return nullptr, return)
DEFINEFUNC(int, EVP_PKEY_param_check, EVP_PKEY_CTX *ctx, ctx, return 0, return)
DEFINEFUNC(void, EVP_PKEY_CTX_free, EVP_PKEY_CTX *ctx, ctx, return, return)
-DEFINEFUNC(int, EVP_PKEY_base_id, EVP_PKEY *a, a, return NID_undef, return)
-DEFINEFUNC(int, RSA_bits, RSA *a, a, return 0, return)
-DEFINEFUNC(int, DSA_bits, DSA *a, a, return 0, return)
DEFINEFUNC(int, OPENSSL_sk_num, OPENSSL_STACK *a, a, return -1, return)
DEFINEFUNC2(void, OPENSSL_sk_pop_free, OPENSSL_STACK *a, a, void (*b)(void*), b, return, DUMMYARG)
DEFINEFUNC(OPENSSL_STACK *, OPENSSL_sk_new_null, DUMMYARG, DUMMYARG, return nullptr, return)
@@ -183,6 +181,8 @@ DEFINEFUNC(const SSL_METHOD *, TLS_server_method, DUMMYARG, DUMMYARG, return nul
DEFINEFUNC(void, X509_up_ref, X509 *a, a, return, DUMMYARG)
DEFINEFUNC(ASN1_TIME *, X509_getm_notBefore, X509 *a, a, return nullptr, return)
DEFINEFUNC(ASN1_TIME *, X509_getm_notAfter, X509 *a, a, return nullptr, return)
+DEFINEFUNC2(void, ASN1_item_free, ASN1_VALUE *val, val, const ASN1_ITEM *it, it, return, return)
+DEFINEFUNC(void, X509V3_conf_free, CONF_VALUE *val, val, return, return)
DEFINEFUNC(long, X509_get_version, X509 *a, a, return -1, return)
DEFINEFUNC(EVP_PKEY *, X509_get_pubkey, X509 *a, a, return nullptr, return)
DEFINEFUNC2(void, X509_STORE_set_verify_cb, X509_STORE *a, a, X509_STORE_CTX_verify_cb verify_cb, verify_cb, return, DUMMYARG)
@@ -194,7 +194,6 @@ DEFINEFUNC(long, OpenSSL_version_num, void, DUMMYARG, return 0, return)
DEFINEFUNC(const char *, OpenSSL_version, int a, a, return nullptr, return)
DEFINEFUNC(unsigned long, SSL_SESSION_get_ticket_lifetime_hint, const SSL_SESSION *session, session, return 0, return)
DEFINEFUNC4(void, DH_get0_pqg, const DH *dh, dh, const BIGNUM **p, p, const BIGNUM **q, q, const BIGNUM **g, g, return, DUMMYARG)
-DEFINEFUNC(int, DH_bits, DH *dh, dh, return 0, return)
#if QT_CONFIG(dtls)
DEFINEFUNC2(int, DTLSv1_listen, SSL *s, s, BIO_ADDR *c, c, return -1, return)
@@ -239,6 +238,7 @@ DEFINEFUNC6(int, OCSP_basic_sign, OCSP_BASICRESP *br, br, X509 *signer, signer,
const EVP_MD *dg, dg, STACK_OF(X509) *cs, cs, unsigned long flags, flags, return 0, return)
#endif // ocsp
+DEFINEFUNC(void, AUTHORITY_INFO_ACCESS_free, AUTHORITY_INFO_ACCESS *p, p, return, return)
DEFINEFUNC2(void, BIO_set_data, BIO *a, a, void *ptr, ptr, return, DUMMYARG)
DEFINEFUNC(void *, BIO_get_data, BIO *a, a, return nullptr, return)
DEFINEFUNC2(void, BIO_set_init, BIO *a, a, int init, init, return, DUMMYARG)
@@ -258,10 +258,6 @@ DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return)
DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return)
DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return)
DEFINEFUNC2(BN_ULONG, BN_mod_word, const BIGNUM *a, a, BN_ULONG w, w, return static_cast<BN_ULONG>(-1), return)
-#ifndef OPENSSL_NO_EC
-DEFINEFUNC(const EC_GROUP*, EC_KEY_get0_group, const EC_KEY* k, k, return nullptr, return)
-DEFINEFUNC(int, EC_GROUP_get_degree, const EC_GROUP* g, g, return 0, return)
-#endif
DEFINEFUNC(DSA *, DSA_new, DUMMYARG, DUMMYARG, return nullptr, return)
DEFINEFUNC(void, DSA_free, DSA *a, a, return, DUMMYARG)
DEFINEFUNC3(X509 *, d2i_X509, X509 **a, a, const unsigned char **b, b, long c, c, return nullptr, return)
@@ -290,21 +286,7 @@ DEFINEFUNC(const EVP_CIPHER *, EVP_aes_192_cbc, DUMMYARG, DUMMYARG, return nullp
DEFINEFUNC(const EVP_CIPHER *, EVP_aes_256_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
#endif
DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, void *r, r, return -1, return)
-DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
-DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return)
-DEFINEFUNC2(int, EVP_PKEY_set1_DH, EVP_PKEY *a, a, DH *b, b, return -1, return)
-#ifndef OPENSSL_NO_EC
-DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return)
-#endif
-DEFINEFUNC2(int, EVP_PKEY_cmp, const EVP_PKEY *a, a, const EVP_PKEY *b, b, return -1, return)
DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
-DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return nullptr, return)
-DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return nullptr, return)
-DEFINEFUNC(DH *, EVP_PKEY_get1_DH, EVP_PKEY *a, a, return nullptr, return)
-#ifndef OPENSSL_NO_EC
-DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return nullptr, return)
-#endif
DEFINEFUNC(EVP_PKEY *, EVP_PKEY_new, DUMMYARG, DUMMYARG, return nullptr, return)
DEFINEFUNC(int, EVP_PKEY_type, int a, a, return NID_undef, return)
DEFINEFUNC2(int, i2d_X509, X509 *a, a, unsigned char **b, b, return -1, return)
@@ -316,25 +298,11 @@ DEFINEFUNC3(int, i2t_ASN1_OBJECT, char *a, a, int b, b, ASN1_OBJECT *c, c, retur
DEFINEFUNC4(int, OBJ_obj2txt, char *a, a, int b, b, ASN1_OBJECT *c, c, int d, d, return -1, return)
DEFINEFUNC(int, OBJ_obj2nid, const ASN1_OBJECT *a, a, return NID_undef, return)
DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PrivateKey, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC4(DSA *, PEM_read_bio_DSAPrivateKey, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC4(RSA *, PEM_read_bio_RSAPrivateKey, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-
-#ifndef OPENSSL_NO_EC
-DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC7(int, PEM_write_bio_ECPrivateKey, BIO *a, a, EC_KEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
-DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
-#endif // OPENSSL_NO_EC
DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
-DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
DEFINEFUNC7(int, PEM_write_bio_PrivateKey, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_PrivateKey_traditional, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PUBKEY, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC4(DSA *, PEM_read_bio_DSA_PUBKEY, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC4(RSA *, PEM_read_bio_RSA_PUBKEY, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return)
-DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return)
DEFINEFUNC2(int, PEM_write_bio_PUBKEY, BIO *a, a, EVP_PKEY *b, b, return 0, return)
DEFINEFUNC2(void, RAND_seed, const void *a, a, int b, b, return, DUMMYARG)
DEFINEFUNC(int, RAND_status, void, DUMMYARG, return -1, return)
@@ -374,7 +342,16 @@ DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return nullptr
DEFINEFUNC(int, SSL_version, const SSL *a, a, return 0, return)
DEFINEFUNC2(int, SSL_get_error, SSL *a, a, int b, b, return -1, return)
DEFINEFUNC(STACK_OF(X509) *, SSL_get_peer_cert_chain, SSL *a, a, return nullptr, return)
+
+#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
+DEFINEFUNC(X509 *, SSL_get1_peer_certificate, SSL *a, a, return nullptr, return)
+DEFINEFUNC(int, EVP_PKEY_get_bits, const EVP_PKEY *pkey, pkey, return -1, return)
+DEFINEFUNC(int, EVP_PKEY_get_base_id, const EVP_PKEY *pkey, pkey, return -1, return)
+#else
DEFINEFUNC(X509 *, SSL_get_peer_certificate, SSL *a, a, return nullptr, return)
+DEFINEFUNC(int, EVP_PKEY_base_id, EVP_PKEY *a, a, return NID_undef, return)
+#endif // OPENSSL_VERSION_MAJOR >= 3
+
DEFINEFUNC(long, SSL_get_verify_result, const SSL *a, a, return -1, return)
DEFINEFUNC(SSL *, SSL_new, SSL_CTX *a, a, return nullptr, return)
DEFINEFUNC(SSL_CTX *, SSL_get_SSL_CTX, SSL *a, a, return nullptr, return)
@@ -495,9 +472,7 @@ DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return nullptr, return)
DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG)
DEFINEFUNC3(DH *, d2i_DHparams, DH**a, a, const unsigned char **pp, pp, long length, length, return nullptr, return)
DEFINEFUNC2(int, i2d_DHparams, DH *a, a, unsigned char **p, p, return -1, return)
-#ifndef OPENSSL_NO_DEPRECATED_3_0
DEFINEFUNC2(int, DH_check, DH *dh, dh, int *codes, codes, return 0, return)
-#endif // OPENSSL_NO_DEPRECATED_3_0
DEFINEFUNC3(BIGNUM *, BN_bin2bn, const unsigned char *s, s, int len, len, BIGNUM *ret, ret, return nullptr, return)
#ifndef OPENSSL_NO_EC
@@ -513,6 +488,53 @@ DEFINEFUNC5(int, PKCS12_parse, PKCS12 *p12, p12, const char *pass, pass, EVP_PKE
DEFINEFUNC2(PKCS12 *, d2i_PKCS12_bio, BIO *bio, bio, PKCS12 **pkcs12, pkcs12, return nullptr, return);
DEFINEFUNC(void, PKCS12_free, PKCS12 *pkcs12, pkcs12, return, DUMMYARG)
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+DEFINEFUNC4(DSA *, PEM_read_bio_DSA_PUBKEY, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC4(RSA *, PEM_read_bio_RSA_PUBKEY, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC4(DSA *, PEM_read_bio_DSAPrivateKey, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC4(RSA *, PEM_read_bio_RSAPrivateKey, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+
+DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return)
+DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+
+DEFINEFUNC(int, RSA_bits, RSA *a, a, return 0, return)
+DEFINEFUNC(int, DSA_bits, DSA *a, a, return 0, return)
+DEFINEFUNC(int, DH_bits, DH *dh, dh, return 0, return)
+
+DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return nullptr, return)
+DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return nullptr, return)
+DEFINEFUNC(DH *, EVP_PKEY_get1_DH, EVP_PKEY *a, a, return nullptr, return)
+
+DEFINEFUNC2(int, EVP_PKEY_cmp, const EVP_PKEY *a, a, const EVP_PKEY *b, b, return -1, return)
+DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, void *r, r, return -1, return)
+
+DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_DH, EVP_PKEY *a, a, DH *b, b, return -1, return)
+
+#ifndef OPENSSL_NO_EC
+
+DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+
+DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_ECPrivateKey, BIO *a, a, EC_KEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+
+DEFINEFUNC(const EC_GROUP*, EC_KEY_get0_group, const EC_KEY* k, k, return nullptr, return)
+DEFINEFUNC(int, EC_GROUP_get_degree, const EC_GROUP* g, g, return 0, return)
+
+DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return)
+DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return nullptr, return)
+
+#endif // OPENSSL_NO_EC
+
+
+
+#endif
+
#define RESOLVEFUNC(func) \
if (!(_q_##func = _q_PTR_##func(libs.ssl->resolve(#func))) \
&& !(_q_##func = _q_PTR_##func(libs.crypto->resolve(#func)))) \
@@ -797,6 +819,11 @@ static LoadedOpenSsl loadOpenSsl()
const QStringList cryptoList = findAllLibCrypto();
for (const QString &crypto : cryptoList) {
+#ifdef Q_OS_DARWIN
+ // Clients should not load the unversioned libcrypto dylib as it does not have a stable ABI
+ if (crypto.endsWith("libcrypto.dylib"))
+ continue;
+#endif
libcrypto->setFileNameAndVersion(crypto, -1);
if (libcrypto->load()) {
QFileInfo fi(crypto);
@@ -854,12 +881,11 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(OPENSSL_init_crypto)
RESOLVEFUNC(ASN1_STRING_get0_data)
RESOLVEFUNC(EVP_CIPHER_CTX_reset)
+ RESOLVEFUNC(AUTHORITY_INFO_ACCESS_free)
RESOLVEFUNC(EVP_PKEY_up_ref)
RESOLVEFUNC(EVP_PKEY_CTX_new)
RESOLVEFUNC(EVP_PKEY_param_check)
RESOLVEFUNC(EVP_PKEY_CTX_free)
- RESOLVEFUNC(EVP_PKEY_base_id)
- RESOLVEFUNC(RSA_bits)
RESOLVEFUNC(OPENSSL_sk_new_null)
RESOLVEFUNC(OPENSSL_sk_push)
RESOLVEFUNC(OPENSSL_sk_free)
@@ -893,6 +919,8 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(X509_STORE_CTX_get0_chain)
RESOLVEFUNC(X509_getm_notBefore)
RESOLVEFUNC(X509_getm_notAfter)
+ RESOLVEFUNC(ASN1_item_free)
+ RESOLVEFUNC(X509V3_conf_free)
RESOLVEFUNC(X509_get_version)
RESOLVEFUNC(X509_get_pubkey)
RESOLVEFUNC(X509_STORE_set_verify_cb)
@@ -910,8 +938,6 @@ bool q_resolveOpenSslSymbols()
}
RESOLVEFUNC(SSL_SESSION_get_ticket_lifetime_hint)
- RESOLVEFUNC(DH_bits)
- RESOLVEFUNC(DSA_bits)
#if QT_CONFIG(dtls)
RESOLVEFUNC(DTLSv1_listen)
@@ -973,11 +999,6 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(BIO_clear_flags)
RESOLVEFUNC(BIO_set_ex_data)
RESOLVEFUNC(BIO_get_ex_data)
-
-#ifndef OPENSSL_NO_EC
- RESOLVEFUNC(EC_KEY_get0_group)
- RESOLVEFUNC(EC_GROUP_get_degree)
-#endif
RESOLVEFUNC(BN_num_bits)
RESOLVEFUNC(BN_is_word)
RESOLVEFUNC(BN_mod_word)
@@ -1008,25 +1029,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(EVP_aes_256_cbc)
#endif
RESOLVEFUNC(EVP_sha1)
- RESOLVEFUNC(EVP_PKEY_assign)
- RESOLVEFUNC(EVP_PKEY_set1_RSA)
- RESOLVEFUNC(EVP_PKEY_set1_DSA)
- RESOLVEFUNC(EVP_PKEY_set1_DH)
-
-#ifndef OPENSSL_NO_EC
- RESOLVEFUNC(EVP_PKEY_set1_EC_KEY)
- RESOLVEFUNC(EVP_PKEY_get1_EC_KEY)
- RESOLVEFUNC(PEM_read_bio_ECPrivateKey)
- RESOLVEFUNC(PEM_write_bio_ECPrivateKey)
- RESOLVEFUNC(PEM_read_bio_EC_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_EC_PUBKEY)
-#endif // OPENSSL_NO_EC
-
- RESOLVEFUNC(EVP_PKEY_cmp)
RESOLVEFUNC(EVP_PKEY_free)
- RESOLVEFUNC(EVP_PKEY_get1_DSA)
- RESOLVEFUNC(EVP_PKEY_get1_RSA)
- RESOLVEFUNC(EVP_PKEY_get1_DH)
RESOLVEFUNC(EVP_PKEY_new)
RESOLVEFUNC(EVP_PKEY_type)
RESOLVEFUNC(OBJ_nid2sn)
@@ -1037,17 +1040,10 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(OBJ_obj2txt)
RESOLVEFUNC(OBJ_obj2nid)
RESOLVEFUNC(PEM_read_bio_PrivateKey)
- RESOLVEFUNC(PEM_read_bio_DSAPrivateKey)
- RESOLVEFUNC(PEM_read_bio_RSAPrivateKey)
RESOLVEFUNC(PEM_read_bio_DHparams)
- RESOLVEFUNC(PEM_write_bio_DSAPrivateKey)
- RESOLVEFUNC(PEM_write_bio_RSAPrivateKey)
RESOLVEFUNC(PEM_write_bio_PrivateKey)
+ RESOLVEFUNC(PEM_write_bio_PrivateKey_traditional)
RESOLVEFUNC(PEM_read_bio_PUBKEY)
- RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY)
- RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY)
RESOLVEFUNC(PEM_write_bio_PUBKEY)
RESOLVEFUNC(RAND_seed)
RESOLVEFUNC(RAND_status)
@@ -1087,7 +1083,57 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_version)
RESOLVEFUNC(SSL_get_error)
RESOLVEFUNC(SSL_get_peer_cert_chain)
+
+#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
+ RESOLVEFUNC(SSL_get1_peer_certificate)
+ RESOLVEFUNC(EVP_PKEY_get_bits)
+ RESOLVEFUNC(EVP_PKEY_get_base_id)
+#else
RESOLVEFUNC(SSL_get_peer_certificate)
+ RESOLVEFUNC(EVP_PKEY_base_id)
+#endif // OPENSSL_VERSION_MAJOR >= 3
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+ RESOLVEFUNC(EVP_PKEY_assign)
+ RESOLVEFUNC(EVP_PKEY_cmp)
+
+ RESOLVEFUNC(EVP_PKEY_set1_RSA)
+ RESOLVEFUNC(EVP_PKEY_set1_DSA)
+ RESOLVEFUNC(EVP_PKEY_set1_DH)
+
+ RESOLVEFUNC(EVP_PKEY_get1_DSA)
+ RESOLVEFUNC(EVP_PKEY_get1_RSA)
+ RESOLVEFUNC(EVP_PKEY_get1_DH)
+
+ RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY)
+ RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY)
+ RESOLVEFUNC(PEM_read_bio_DSAPrivateKey)
+ RESOLVEFUNC(PEM_read_bio_RSAPrivateKey)
+
+ RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY)
+ RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY)
+ RESOLVEFUNC(PEM_write_bio_DSAPrivateKey)
+ RESOLVEFUNC(PEM_write_bio_RSAPrivateKey)
+
+ RESOLVEFUNC(DH_bits)
+ RESOLVEFUNC(DSA_bits)
+ RESOLVEFUNC(RSA_bits)
+
+#ifndef OPENSSL_NO_EC
+
+ RESOLVEFUNC(EVP_PKEY_set1_EC_KEY)
+ RESOLVEFUNC(EVP_PKEY_get1_EC_KEY)
+ RESOLVEFUNC(PEM_read_bio_EC_PUBKEY)
+ RESOLVEFUNC(PEM_read_bio_ECPrivateKey)
+ RESOLVEFUNC(PEM_write_bio_EC_PUBKEY)
+ RESOLVEFUNC(PEM_write_bio_ECPrivateKey)
+ RESOLVEFUNC(EC_KEY_get0_group)
+ RESOLVEFUNC(EC_GROUP_get_degree)
+
+#endif // OPENSSL_NO_EC
+
+#endif // OPENSSL_NO_DEPRECATED_3_0
+
RESOLVEFUNC(SSL_get_verify_result)
RESOLVEFUNC(SSL_new)
RESOLVEFUNC(SSL_get_SSL_CTX)
@@ -1186,9 +1232,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(DH_free)
RESOLVEFUNC(d2i_DHparams)
RESOLVEFUNC(i2d_DHparams)
-#ifndef OPENSSL_NO_DEPRECATED_3_0
RESOLVEFUNC(DH_check)
-#endif // OPENSSL_NO_DEPRECATED_3_0
RESOLVEFUNC(BN_bin2bn)
#ifndef OPENSSL_NO_EC
diff --git a/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h b/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h
index 1eb6387c23..3426635464 100644
--- a/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h
+++ b/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h
@@ -232,14 +232,12 @@ const unsigned char * q_ASN1_STRING_get0_data(const ASN1_STRING *x);
BIO *q_BIO_new(const BIO_METHOD *a);
const BIO_METHOD *q_BIO_s_mem();
-int q_DSA_bits(DSA *a);
+void q_AUTHORITY_INFO_ACCESS_free(AUTHORITY_INFO_ACCESS *a);
int q_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c);
int q_EVP_PKEY_up_ref(EVP_PKEY *a);
EVP_PKEY_CTX *q_EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
void q_EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
int q_EVP_PKEY_param_check(EVP_PKEY_CTX *ctx);
-int q_EVP_PKEY_base_id(EVP_PKEY *a);
-int q_RSA_bits(RSA *a);
int q_OPENSSL_sk_num(OPENSSL_STACK *a);
void q_OPENSSL_sk_pop_free(OPENSSL_STACK *a, void (*b)(void *));
OPENSSL_STACK *q_OPENSSL_sk_new_null();
@@ -257,6 +255,8 @@ const SSL_METHOD *q_TLS_client_method();
const SSL_METHOD *q_TLS_server_method();
ASN1_TIME *q_X509_getm_notBefore(X509 *a);
ASN1_TIME *q_X509_getm_notAfter(X509 *a);
+void q_ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it);
+void q_X509V3_conf_free(CONF_VALUE *val);
void q_X509_up_ref(X509 *a);
long q_X509_get_version(X509 *a);
@@ -266,7 +266,6 @@ int q_X509_STORE_set_ex_data(X509_STORE *ctx, int idx, void *data);
void *q_X509_STORE_get_ex_data(X509_STORE *r, int idx);
STACK_OF(X509) *q_X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx);
void q_DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
-int q_DH_bits(DH *dh);
# define q_SSL_load_error_strings() q_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)
@@ -281,7 +280,6 @@ int q_DH_bits(DH *dh);
| OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)
int q_OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
-void q_CRYPTO_free(void *str, const char *file, int line);
long q_OpenSSL_version_num();
const char *q_OpenSSL_version(int type);
@@ -380,11 +378,6 @@ int q_BN_num_bits(const BIGNUM *a);
int q_BN_is_word(BIGNUM *a, BN_ULONG w);
BN_ULONG q_BN_mod_word(const BIGNUM *a, BN_ULONG w);
-#ifndef OPENSSL_NO_EC
-const EC_GROUP* q_EC_KEY_get0_group(const EC_KEY* k);
-int q_EC_GROUP_get_degree(const EC_GROUP* g);
-#endif // OPENSSL_NO_EC
-
DSA *q_DSA_new();
void q_DSA_free(DSA *a);
X509 *q_d2i_X509(X509 **a, const unsigned char **b, long c);
@@ -417,23 +410,8 @@ const EVP_CIPHER *q_EVP_aes_256_cbc();
#endif // OPENSSL_NO_AES
const EVP_MD *q_EVP_sha1();
-int q_EVP_PKEY_assign(EVP_PKEY *a, int b, void *r);
-int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
-int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
-int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b);
-#ifndef OPENSSL_NO_EC
-int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b);
-#endif
-
-int q_EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
void q_EVP_PKEY_free(EVP_PKEY *a);
-RSA *q_EVP_PKEY_get1_RSA(EVP_PKEY *a);
-DSA *q_EVP_PKEY_get1_DSA(EVP_PKEY *a);
-DH *q_EVP_PKEY_get1_DH(EVP_PKEY *a);
-#ifndef OPENSSL_NO_EC
-EC_KEY *q_EVP_PKEY_get1_EC_KEY(EVP_PKEY *a);
-#endif
int q_EVP_PKEY_type(int a);
EVP_PKEY *q_EVP_PKEY_new();
int q_i2d_X509(X509 *a, unsigned char **b);
@@ -446,29 +424,13 @@ int q_OBJ_obj2txt(char *buf, int buf_len, ASN1_OBJECT *obj, int no_name);
int q_OBJ_obj2nid(const ASN1_OBJECT *a);
#define q_EVP_get_digestbynid(a) q_EVP_get_digestbyname(q_OBJ_nid2sn(a))
EVP_PKEY *q_PEM_read_bio_PrivateKey(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d);
-DSA *q_PEM_read_bio_DSAPrivateKey(BIO *a, DSA **b, pem_password_cb *c, void *d);
-RSA *q_PEM_read_bio_RSAPrivateKey(BIO *a, RSA **b, pem_password_cb *c, void *d);
-
-#ifndef OPENSSL_NO_EC
-EC_KEY *q_PEM_read_bio_ECPrivateKey(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_ECPrivateKey(BIO *a, EC_KEY *b, const EVP_CIPHER *c, unsigned char *d,
- int e, pem_password_cb *f, void *g);
-EC_KEY *q_PEM_read_bio_EC_PUBKEY(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b);
-#endif // OPENSSL_NO_EC
DH *q_PEM_read_bio_DHparams(BIO *a, DH **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned char *d,
- int e, pem_password_cb *f, void *g);
-int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned char *d,
- int e, pem_password_cb *f, void *g);
int q_PEM_write_bio_PrivateKey(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d,
int e, pem_password_cb *f, void *g);
+int q_PEM_write_bio_PrivateKey_traditional(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
EVP_PKEY *q_PEM_read_bio_PUBKEY(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d);
-DSA *q_PEM_read_bio_DSA_PUBKEY(BIO *a, DSA **b, pem_password_cb *c, void *d);
-RSA *q_PEM_read_bio_RSA_PUBKEY(BIO *a, RSA **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b);
-int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b);
int q_PEM_write_bio_PUBKEY(BIO *a, EVP_PKEY *b);
void q_RAND_seed(const void *a, int b);
@@ -512,7 +474,6 @@ const SSL_CIPHER *q_SSL_get_current_cipher(SSL *a);
int q_SSL_version(const SSL *a);
int q_SSL_get_error(SSL *a, int b);
STACK_OF(X509) *q_SSL_get_peer_cert_chain(SSL *a);
-X509 *q_SSL_get_peer_certificate(SSL *a);
long q_SSL_get_verify_result(const SSL *a);
SSL *q_SSL_new(SSL_CTX *a);
SSL_CTX *q_SSL_get_SSL_CTX(SSL *a);
@@ -584,10 +545,7 @@ DH *q_DH_new();
void q_DH_free(DH *dh);
DH *q_d2i_DHparams(DH **a, const unsigned char **pp, long length);
int q_i2d_DHparams(DH *a, unsigned char **p);
-
-#ifndef OPENSSL_NO_DEPRECATED_3_0
int q_DH_check(DH *dh, int *codes);
-#endif // OPENSSL_NO_DEPRECATED_3_0
BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
#define q_SSL_CTX_set_tmp_dh(ctx, dh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_DH, 0, (char *)dh)
@@ -625,10 +583,6 @@ void q_GENERAL_NAME_free(GENERAL_NAME *a);
#define q_sk_SSL_CIPHER_value(st, i) q_SKM_sk_value(SSL_CIPHER, (st), (i))
#define q_SSL_CTX_add_extra_chain_cert(ctx,x509) \
q_SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
-#define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
- (char *)(rsa))
-#define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
- (char *)(dsa))
#define q_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_conf()
#if OPENSSL_VERSION_MAJOR < 3
@@ -746,6 +700,8 @@ int q_OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
void *q_CRYPTO_malloc(size_t num, const char *file, int line);
#define q_OPENSSL_malloc(num) q_CRYPTO_malloc(num, "", 0)
+void q_CRYPTO_free(void *str, const char *file, int line);
+# define q_OPENSSL_free(addr) q_CRYPTO_free(addr, "", 0)
void q_SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val));
const char *q_SSL_alert_type_string(int value);
@@ -754,6 +710,74 @@ const char *q_SSL_alert_desc_string_long(int value);
int q_SSL_CTX_get_security_level(const SSL_CTX *ctx);
void q_SSL_CTX_set_security_level(SSL_CTX *ctx, int level);
+// Here we have the ones that make difference between OpenSSL pre/post v3:
+#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
+X509 *q_SSL_get1_peer_certificate(SSL *a);
+#define q_SSL_get_peer_certificate q_SSL_get1_peer_certificate
+int q_EVP_PKEY_get_bits(const EVP_PKEY *pkey);
+int q_EVP_PKEY_get_base_id(const EVP_PKEY *pkey);
+#define q_EVP_PKEY_base_id q_EVP_PKEY_get_base_id
+#else
+X509 *q_SSL_get_peer_certificate(SSL *a);
+int q_EVP_PKEY_base_id(EVP_PKEY *a);
+#endif // OPENSSL_VERSION_MAJOR >= 3
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+DSA *q_PEM_read_bio_DSA_PUBKEY(BIO *a, DSA **b, pem_password_cb *c, void *d);
+RSA *q_PEM_read_bio_RSA_PUBKEY(BIO *a, RSA **b, pem_password_cb *c, void *d);
+
+DSA *q_PEM_read_bio_DSAPrivateKey(BIO *a, DSA **b, pem_password_cb *c, void *d);
+RSA *q_PEM_read_bio_RSAPrivateKey(BIO *a, RSA **b, pem_password_cb *c, void *d);
+
+int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b);
+int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b);
+
+int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+
+RSA *q_EVP_PKEY_get1_RSA(EVP_PKEY *a);
+DSA *q_EVP_PKEY_get1_DSA(EVP_PKEY *a);
+DH *q_EVP_PKEY_get1_DH(EVP_PKEY *a);
+
+int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
+int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
+int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b);
+
+int q_DH_bits(DH *dh);
+int q_RSA_bits(RSA *a);
+int q_DSA_bits(DSA *a);
+
+int q_EVP_PKEY_assign(EVP_PKEY *a, int b, void *r);
+int q_EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
+
+#ifndef OPENSSL_NO_EC
+
+EC_KEY *q_PEM_read_bio_EC_PUBKEY(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
+EC_KEY *q_PEM_read_bio_ECPrivateKey(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
+
+int q_PEM_write_bio_ECPrivateKey(BIO *a, EC_KEY *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b);
+
+EC_KEY *q_EVP_PKEY_get1_EC_KEY(EVP_PKEY *a);
+int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b);
+
+const EC_GROUP* q_EC_KEY_get0_group(const EC_KEY* k);
+int q_EC_GROUP_get_degree(const EC_GROUP* g);
+
+#define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
+ (char *)(rsa))
+#define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
+ (char *)(dsa))
+
+
+#endif // OPENSSL_NO_EC
+
+#endif // OPENSSL_NO_DEPRECATED_3_0
+
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/tls/openssl/qtls_openssl.cpp b/src/plugins/tls/openssl/qtls_openssl.cpp
index 9ed9ab7538..5a9a55ebbd 100644
--- a/src/plugins/tls/openssl/qtls_openssl.cpp
+++ b/src/plugins/tls/openssl/qtls_openssl.cpp
@@ -258,15 +258,22 @@ static unsigned q_ssl_psk_restore_client(SSL *ssl, const char *hint, char *ident
Q_ASSERT(tls->d);
Q_ASSERT(tls->d->tlsMode() == QSslSocket::SslClientMode);
#endif
+ unsigned retVal = 0;
+
+ // Let developers opt-in to having the normal PSK callback get called for TLS 1.3
+ // PSK (which works differently in a few ways, and is called at the start of every connection).
+ // When they do opt-in we just call the old callback from here.
+ if (qEnvironmentVariableIsSet("QT_USE_TLS_1_3_PSK"))
+ retVal = q_ssl_psk_client_callback(ssl, hint, identity, max_identity_len, psk, max_psk_len);
+
q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
- return 0;
+ return retVal;
}
static int q_ssl_psk_use_session_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id,
size_t *idlen, SSL_SESSION **sess)
{
- Q_UNUSED(ssl);
Q_UNUSED(md);
Q_UNUSED(id);
Q_UNUSED(idlen);
@@ -504,13 +511,13 @@ void TlsCryptographOpenSSL::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
caToFetch = QSslCertificate{};
}
-void TlsCryptographOpenSSL::checkSettingSslContext(QSharedPointer<QSslContext> tlsContext)
+void TlsCryptographOpenSSL::checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext)
{
- if (sslContextPointer.isNull())
- sslContextPointer = tlsContext;
+ if (!sslContextPointer)
+ sslContextPointer = std::move(tlsContext);
}
-QSharedPointer<QSslContext> TlsCryptographOpenSSL::sslContext() const
+std::shared_ptr<QSslContext> TlsCryptographOpenSSL::sslContext() const
{
return sslContextPointer;
}
@@ -815,7 +822,7 @@ void TlsCryptographOpenSSL::continueHandshake()
// Cache this SSL session inside the QSslContext
if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionSharing))) {
if (!sslContextPointer->cacheSession(ssl)) {
- sslContextPointer.clear(); // we could not cache the session
+ sslContextPointer.reset(); // we could not cache the session
} else {
// Cache the session for permanent usage as well
if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionPersistence))) {
@@ -1127,6 +1134,7 @@ void TlsCryptographOpenSSL::disconnected()
Q_ASSERT(d);
auto *plainSocket = d->plainTcpSocket();
Q_ASSERT(plainSocket);
+ d->setEncrypted(false);
if (plainSocket->bytesAvailable() <= 0) {
destroySslContext();
@@ -1158,10 +1166,13 @@ QSsl::SslProtocol TlsCryptographOpenSSL::sessionProtocol() const
const int ver = q_SSL_version(ssl);
switch (ver) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case 0x301:
return QSsl::TlsV1_0;
case 0x302:
return QSsl::TlsV1_1;
+QT_WARNING_POP
case 0x303:
return QSsl::TlsV1_2;
case 0x304:
@@ -1363,7 +1374,7 @@ bool TlsCryptographOpenSSL::initSslContext()
if (sslContextPointer->error() != QSslError::NoError) {
setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
- sslContextPointer.clear(); // deletes the QSslContext
+ sslContextPointer.reset();
return false;
}
@@ -1491,7 +1502,7 @@ void TlsCryptographOpenSSL::destroySslContext()
q_SSL_free(ssl);
ssl = nullptr;
}
- sslContextPointer.clear();
+ sslContextPointer.reset();
}
void TlsCryptographOpenSSL::storePeerCertificates()
diff --git a/src/plugins/tls/openssl/qtls_openssl_p.h b/src/plugins/tls/openssl/qtls_openssl_p.h
index 48c9223f99..9e7283b15d 100644
--- a/src/plugins/tls/openssl/qtls_openssl_p.h
+++ b/src/plugins/tls/openssl/qtls_openssl_p.h
@@ -80,8 +80,8 @@ public:
~TlsCryptographOpenSSL();
void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override;
- void checkSettingSslContext(QSharedPointer<QSslContext> tlsContext) override;
- QSharedPointer<QSslContext> sslContext() const override;
+ void checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext) override;
+ std::shared_ptr<QSslContext> sslContext() const override;
QList<QSslError> tlsErrors() const override;
@@ -133,7 +133,7 @@ private:
bool initSslContext();
void destroySslContext();
- QSharedPointer<QSslContext> sslContextPointer;
+ std::shared_ptr<QSslContext> sslContextPointer;
SSL *ssl = nullptr; // TLSTODO: RAII.
QList<QSslErrorEntry> errorList;
diff --git a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
index 544ce1bcef..69a85a83ec 100644
--- a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
+++ b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
@@ -223,11 +223,11 @@ void QTlsBackendOpenSSL::ensureCiphersAndCertsLoaded() const
QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
// check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
- QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
+ const QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
QStringList symLinkFilter;
symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
- for (int a = 0; a < dirs.count(); ++a) {
- QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
+ for (const auto &dir : dirs) {
+ QDirIterator iterator(QLatin1String(dir), symLinkFilter, QDir::Files);
if (iterator.hasNext()) {
QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
break;
@@ -291,10 +291,13 @@ QList<QSsl::SslProtocol> QTlsBackendOpenSSL::supportedProtocols() const
protocols << QSsl::AnyProtocol;
protocols << QSsl::SecureProtocols;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
protocols << QSsl::TlsV1_0;
protocols << QSsl::TlsV1_0OrLater;
protocols << QSsl::TlsV1_1;
protocols << QSsl::TlsV1_1OrLater;
+QT_WARNING_POP
protocols << QSsl::TlsV1_2;
protocols << QSsl::TlsV1_2OrLater;
@@ -304,8 +307,11 @@ QList<QSsl::SslProtocol> QTlsBackendOpenSSL::supportedProtocols() const
#endif // TLS1_3_VERSION
#if QT_CONFIG(dtls)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
protocols << QSsl::DtlsV1_0;
protocols << QSsl::DtlsV1_0OrLater;
+QT_WARNING_POP
protocols << QSsl::DtlsV1_2;
protocols << QSsl::DtlsV1_2OrLater;
#endif // dtls
@@ -318,8 +324,12 @@ QList<QSsl::SupportedFeature> QTlsBackendOpenSSL::supportedFeatures() const
QList<QSsl::SupportedFeature> features;
features << QSsl::SupportedFeature::CertificateVerification;
+
+#if !defined(OPENSSL_NO_TLSEXT)
features << QSsl::SupportedFeature::ClientSideAlpn;
features << QSsl::SupportedFeature::ServerSideAlpn;
+#endif // !OPENSSL_NO_TLSEXT
+
features << QSsl::SupportedFeature::Ocsp;
features << QSsl::SupportedFeature::Psk;
features << QSsl::SupportedFeature::SessionTicket;
@@ -358,7 +368,7 @@ QTlsPrivate::X509Certificate *QTlsBackendOpenSSL::createCertificate() const
namespace QTlsPrivate {
// TLSTODO: remove.
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#ifdef Q_OS_ANDROID
QList<QByteArray> fetchSslCertificateData();
#endif
@@ -388,50 +398,29 @@ QList<QSslCertificate> systemCaCertificates()
}
CertCloseStore(hSystemStore, 0);
}
+#elif defined(Q_OS_ANDROID)
+ // TODO: find where it hides its system certs !
#elif defined(Q_OS_UNIX)
- QSet<QString> certFiles;
- QDir currentDir;
- QStringList nameFilters;
- QList<QByteArray> directories;
- QSsl::EncodingFormat platformEncodingFormat;
-# ifndef Q_OS_ANDROID
- directories = QSslSocketPrivate::unixRootCertDirectories();
- nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt");
- platformEncodingFormat = QSsl::Pem;
-# else
- // Q_OS_ANDROID
- QByteArray ministroPath = qgetenv("MINISTRO_SSL_CERTS_PATH"); // Set by Ministro
- directories << ministroPath;
- nameFilters << QLatin1String("*.der");
- platformEncodingFormat = QSsl::Der;
-# ifndef Q_OS_ANDROID_EMBEDDED
- if (ministroPath.isEmpty()) {
- QList<QByteArray> certificateData = fetchSslCertificateData();
- for (int i = 0; i < certificateData.size(); ++i) {
- systemCerts.append(QSslCertificate::fromData(certificateData.at(i), QSsl::Der));
- }
- } else
-# endif //Q_OS_ANDROID_EMBEDDED
-# endif //Q_OS_ANDROID
{
- currentDir.setNameFilters(nameFilters);
- for (int a = 0; a < directories.count(); a++) {
- currentDir.setPath(QLatin1String(directories.at(a)));
+ const QList<QByteArray> directories = QSslSocketPrivate::unixRootCertDirectories();
+ QSet<QString> certFiles = {
+ QStringLiteral("/etc/pki/tls/certs/ca-bundle.crt"), // Fedora, Mandriva
+ QStringLiteral("/usr/local/share/certs/ca-root-nss.crt") // FreeBSD's ca_root_nss
+ };
+ QDir currentDir;
+ currentDir.setNameFilters(QStringList{QStringLiteral("*.pem"), QStringLiteral("*.crt")});
+ for (const auto &directory : directories) {
+ currentDir.setPath(QLatin1String(directory));
QDirIterator it(currentDir);
while (it.hasNext()) {
- it.next();
// use canonical path here to not load the same certificate twice if symlinked
- certFiles.insert(it.fileInfo().canonicalFilePath());
+ certFiles.insert(it.nextFileInfo().canonicalFilePath());
}
}
for (const QString& file : qAsConst(certFiles))
- systemCerts.append(QSslCertificate::fromPath(file, platformEncodingFormat));
-# ifndef Q_OS_ANDROID
- systemCerts.append(QSslCertificate::fromPath(QLatin1String("/etc/pki/tls/certs/ca-bundle.crt"), QSsl::Pem)); // Fedora, Mandriva
- systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/share/certs/ca-root-nss.crt"), QSsl::Pem)); // FreeBSD's ca_root_nss
-# endif
+ systemCerts.append(QSslCertificate::fromPath(file, QSsl::Pem));
}
-#endif
+#endif // platform
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
qCDebug(lcTlsBackend) << "imported " << systemCerts.count() << " certificates";
diff --git a/src/plugins/tls/openssl/qtlsbackend_openssl_p.h b/src/plugins/tls/openssl/qtlsbackend_openssl_p.h
index 93b6442a59..04044f489e 100644
--- a/src/plugins/tls/openssl/qtlsbackend_openssl_p.h
+++ b/src/plugins/tls/openssl/qtlsbackend_openssl_p.h
@@ -134,6 +134,8 @@ private:
void forceAutotestSecurityLevel() override;
};
+Q_DECLARE_LOGGING_CATEGORY(lcTlsBackend)
+
QT_END_NAMESPACE
#endif // QTLSBACKEND_OPENSSL_P_H
diff --git a/src/plugins/tls/openssl/qtlskey_openssl.cpp b/src/plugins/tls/openssl/qtlskey_openssl.cpp
index 5333623d70..08b806a74d 100644
--- a/src/plugins/tls/openssl/qtlskey_openssl.cpp
+++ b/src/plugins/tls/openssl/qtlskey_openssl.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qsslsocket_openssl_symbols_p.h"
+#include "qtlsbackend_openssl_p.h"
#include "qtlskey_openssl_p.h"
#include <QtNetwork/private/qsslkey_p.h>
@@ -84,6 +85,16 @@ void TlsKeyOpenSSL::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteA
void *phrase = const_cast<char *>(passPhrase.data());
+#ifdef OPENSSL_NO_DEPRECATED_3_0
+ if (type == QSsl::PublicKey)
+ genericKey = q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase);
+ else
+ genericKey = q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase);
+ keyIsNull = !genericKey;
+ if (keyIsNull)
+ QTlsBackendOpenSSL::logAndClearErrorQueue();
+#else
+
if (algorithm == QSsl::Rsa) {
RSA *result = (type == QSsl::PublicKey)
? q_PEM_read_bio_RSA_PUBKEY(bio, &rsa, nullptr, phrase)
@@ -112,8 +123,10 @@ void TlsKeyOpenSSL::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteA
: q_PEM_read_bio_ECPrivateKey(bio, &ec, nullptr, phrase);
if (ec && ec == result)
keyIsNull = false;
-#endif
+#endif // OPENSSL_NO_EC
}
+
+#endif // OPENSSL_NO_DEPRECATED_3_0
}
QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
@@ -182,6 +195,7 @@ void TlsKeyOpenSSL::clear(bool deep)
{
keyIsNull = true;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
if (algorithm() == QSsl::Rsa && rsa) {
if (deep)
q_RSA_free(rsa);
@@ -204,18 +218,30 @@ void TlsKeyOpenSSL::clear(bool deep)
ec = nullptr;
}
#endif
+#endif // OPENSSL_NO_DEPRECATED_3_0
+
if (algorithm() == QSsl::Opaque && opaque) {
if (deep)
q_EVP_PKEY_free(opaque);
opaque = nullptr;
}
+
+ if (genericKey) {
+ // None of the above cleared it. genericKey is either
+ // initialised by PEM read operation, or from X509, and
+ // we are the owners and not sharing. So we free it.
+ q_EVP_PKEY_free(genericKey);
+ genericKey = nullptr;
+ }
}
Qt::HANDLE TlsKeyOpenSSL::handle() const
{
- switch (keyAlgorithm) {
- case QSsl::Opaque:
+ if (keyAlgorithm == QSsl::Opaque)
return Qt::HANDLE(opaque);
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+ switch (keyAlgorithm) {
case QSsl::Rsa:
return Qt::HANDLE(rsa);
case QSsl::Dsa:
@@ -229,6 +255,11 @@ Qt::HANDLE TlsKeyOpenSSL::handle() const
default:
return Qt::HANDLE(nullptr);
}
+#else
+ qCWarning(lcTlsBackend,
+ "This version of OpenSSL disabled direct manipulation with RSA/DSA/DH/EC_KEY structures, consider using QSsl::Opaque instead.");
+ return Qt::HANDLE(nullptr);
+#endif
}
int TlsKeyOpenSSL::length() const
@@ -236,6 +267,7 @@ int TlsKeyOpenSSL::length() const
if (isNull() || algorithm() == QSsl::Opaque)
return -1;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
switch (algorithm()) {
case QSsl::Rsa:
return q_RSA_bits(rsa);
@@ -250,6 +282,10 @@ int TlsKeyOpenSSL::length() const
default:
return -1;
}
+#else // OPENSSL_NO_DEPRECATED_3_0
+ Q_ASSERT(genericKey);
+ return q_EVP_PKEY_get_bits(genericKey);
+#endif // OPENSSL_NO_DEPRECATED_3_0
}
QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const
@@ -272,54 +308,61 @@ QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const
const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
- bool fail = false;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+#define write_pubkey(alg, key) q_PEM_write_bio_##alg##_PUBKEY(bio, key)
+#define write_privatekey(alg, key) \
+ q_PEM_write_bio_##alg##PrivateKey(bio, key, cipher, (uchar *)passPhrase.data(), \
+ passPhrase.size(), nullptr, nullptr)
+
+#else
+
+#define write_pubkey(alg, key) q_PEM_write_bio_PUBKEY(bio, genericKey)
+#define write_privatekey(alg, key) \
+ q_PEM_write_bio_PrivateKey_traditional(bio, genericKey, cipher, (uchar *)passPhrase.data(), passPhrase.size(), nullptr, nullptr)
+
+#endif // OPENSSL_NO_DEPRECATED_3_0
+ bool fail = false;
if (algorithm() == QSsl::Rsa) {
if (type() == QSsl::PublicKey) {
- if (!q_PEM_write_bio_RSA_PUBKEY(bio, rsa))
- fail = true;
- } else {
- if (!q_PEM_write_bio_RSAPrivateKey(
- bio, rsa, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
+ if (!write_pubkey(RSA, rsa))
fail = true;
- }
+ } else if (!write_privatekey(RSA, rsa)) {
+ fail = true;
}
} else if (algorithm() == QSsl::Dsa) {
if (type() == QSsl::PublicKey) {
- if (!q_PEM_write_bio_DSA_PUBKEY(bio, dsa))
- fail = true;
- } else {
- if (!q_PEM_write_bio_DSAPrivateKey(
- bio, dsa, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
+ if (!write_pubkey(DSA, dsa))
fail = true;
- }
+ } else if (!write_privatekey(DSA, dsa)) {
+ fail = true;
}
} else if (algorithm() == QSsl::Dh) {
+#ifdef OPENSSL_NO_DEPRECATED_3_0
+ EVP_PKEY *result = genericKey;
+#else
EVP_PKEY *result = q_EVP_PKEY_new();
+ const auto guard = qScopeGuard([result]{if (result) q_EVP_PKEY_free(result);});
if (!result || !q_EVP_PKEY_set1_DH(result, dh)) {
fail = true;
- } else if (type() == QSsl::PublicKey) {
+ } else
+#endif
+ if (type() == QSsl::PublicKey) {
if (!q_PEM_write_bio_PUBKEY(bio, result))
fail = true;
- } else if (!q_PEM_write_bio_PrivateKey(
- bio, result, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
+ } else if (!q_PEM_write_bio_PrivateKey(bio, result, cipher, (uchar *)passPhrase.data(),
+ passPhrase.size(), nullptr, nullptr)) {
fail = true;
}
- q_EVP_PKEY_free(result);
#ifndef OPENSSL_NO_EC
} else if (algorithm() == QSsl::Ec) {
if (type() == QSsl::PublicKey) {
- if (!q_PEM_write_bio_EC_PUBKEY(bio, ec))
+ if (!write_pubkey(EC, ec))
fail = true;
} else {
- if (!q_PEM_write_bio_ECPrivateKey(
- bio, ec, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
+ if (!write_privatekey(EC, ec))
fail = true;
- }
}
#endif
} else {
@@ -332,6 +375,8 @@ QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const
const long size = q_BIO_get_mem_data(bio, &data);
if (size > 0 && data)
pem = QByteArray(data, size);
+ } else {
+ QTlsBackendOpenSSL::logAndClearErrorQueue();
}
return pem;
@@ -356,34 +401,37 @@ bool TlsKeyOpenSSL::fromEVP_PKEY(EVP_PKEY *pkey)
if (!pkey)
return false;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+#define get_key(key, alg) key = q_EVP_PKEY_get1_##alg(pkey)
+#else
+#define get_key(key, alg) q_EVP_PKEY_up_ref(pkey); genericKey = pkey;
+#endif
+
switch (q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey))) {
case EVP_PKEY_RSA:
keyIsNull = false;
keyAlgorithm = QSsl::Rsa;
keyType = QSsl::PrivateKey;
- rsa = q_EVP_PKEY_get1_RSA(pkey);
-
+ get_key(rsa, RSA);
return true;
case EVP_PKEY_DSA:
keyIsNull = false;
keyAlgorithm = QSsl::Dsa;
keyType = QSsl::PrivateKey;
- dsa = q_EVP_PKEY_get1_DSA(pkey);
-
+ get_key(dsa, DSA);
return true;
case EVP_PKEY_DH:
keyIsNull = false;
keyAlgorithm = QSsl::Dh;
keyType = QSsl::PrivateKey;
- dh = q_EVP_PKEY_get1_DH(pkey);
+ get_key(dh, DH);
return true;
#ifndef OPENSSL_NO_EC
case EVP_PKEY_EC:
keyIsNull = false;
keyAlgorithm = QSsl::Ec;
keyType = QSsl::PrivateKey;
- ec = q_EVP_PKEY_get1_EC_KEY(pkey);
-
+ get_key(ec, EC_KEY);
return true;
#endif
default:;
@@ -437,7 +485,12 @@ QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data,
EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new();
q_EVP_CIPHER_CTX_reset(ctx);
- q_EVP_CipherInit(ctx, type, nullptr, nullptr, enc);
+ if (q_EVP_CipherInit(ctx, type, nullptr, nullptr, enc) != 1) {
+ q_EVP_CIPHER_CTX_free(ctx);
+ QTlsBackendOpenSSL::logAndClearErrorQueue();
+ return {};
+ }
+
q_EVP_CIPHER_CTX_set_key_length(ctx, key.size());
if (cipher == Cipher::Rc2Cbc)
q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), nullptr);
@@ -478,21 +531,31 @@ TlsKeyOpenSSL *TlsKeyOpenSSL::publicKeyFromX509(X509 *x)
tlsKey->keyType = QSsl::PublicKey;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+
+#define get_pubkey(keyName, alg) tlsKey->keyName = q_EVP_PKEY_get1_##alg(pkey)
+
+#else
+
+#define get_pubkey(a, b) tlsKey->genericKey = pkey
+
+#endif
+
EVP_PKEY *pkey = q_X509_get_pubkey(x);
Q_ASSERT(pkey);
const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
if (keyType == EVP_PKEY_RSA) {
- tlsKey->rsa = q_EVP_PKEY_get1_RSA(pkey);
+ get_pubkey(rsa, RSA);
tlsKey->keyAlgorithm = QSsl::Rsa;
tlsKey->keyIsNull = false;
} else if (keyType == EVP_PKEY_DSA) {
- tlsKey->dsa = q_EVP_PKEY_get1_DSA(pkey);
+ get_pubkey(dsa, DSA);
tlsKey->keyAlgorithm = QSsl::Dsa;
tlsKey->keyIsNull = false;
#ifndef OPENSSL_NO_EC
} else if (keyType == EVP_PKEY_EC) {
- tlsKey->ec = q_EVP_PKEY_get1_EC_KEY(pkey);
+ get_pubkey(ec, EC_KEY);
tlsKey->keyAlgorithm = QSsl::Ec;
tlsKey->keyIsNull = false;
#endif
@@ -502,7 +565,10 @@ TlsKeyOpenSSL *TlsKeyOpenSSL::publicKeyFromX509(X509 *x)
// error? (key is null)
}
+#ifndef OPENSSL_NO_DEPRECATED_3_0
q_EVP_PKEY_free(pkey);
+#endif
+
return keyRaii.release();
}
diff --git a/src/plugins/tls/openssl/qtlskey_openssl_p.h b/src/plugins/tls/openssl/qtlskey_openssl_p.h
index 815770112f..ac75caec41 100644
--- a/src/plugins/tls/openssl/qtlskey_openssl_p.h
+++ b/src/plugins/tls/openssl/qtlskey_openssl_p.h
@@ -67,6 +67,14 @@
#include <openssl/dsa.h>
#include <openssl/dh.h>
+#ifdef OPENSSL_NO_DEPRECATED_3_0
+typedef struct evp_pkey_st EVP_PKEY;
+typedef struct dsa_st DSA;
+typedef struct rsa_st RSA;
+typedef struct dh_st DH;
+typedef struct ec_key_st EC_KEY;
+#endif // OPENSSL_NO_DEPRECATED_3_0
+
QT_BEGIN_NAMESPACE
QT_REQUIRE_CONFIG(ssl);
@@ -115,6 +123,7 @@ public:
#ifndef OPENSSL_NO_EC
EC_KEY *ec;
#endif
+ EVP_PKEY *genericKey;
};
bool fromEVP_PKEY(EVP_PKEY *pkey);
diff --git a/src/plugins/tls/openssl/qx509_openssl.cpp b/src/plugins/tls/openssl/qx509_openssl.cpp
index bf52c9345c..b7c2e7cff4 100644
--- a/src/plugins/tls/openssl/qx509_openssl.cpp
+++ b/src/plugins/tls/openssl/qx509_openssl.cpp
@@ -197,10 +197,27 @@ QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
}
void *ext_internal = q_X509V3_EXT_d2i(ext);
+ if (!ext_internal)
+ return {};
+
+ const auto extCleaner = qScopeGuard([meth, ext_internal]{
+ Q_ASSERT(ext_internal && meth);
+
+ if (meth->it)
+ q_ASN1_item_free(static_cast<ASN1_VALUE *>(ext_internal), ASN1_ITEM_ptr(meth->it));
+ else if (meth->ext_free)
+ meth->ext_free(ext_internal);
+ else
+ qCWarning(lcTlsBackend, "No method to free an unknown extension, a potential memory leak?");
+ });
// If this extension can be converted
- if (meth->i2v && ext_internal) {
+ if (meth->i2v) {
STACK_OF(CONF_VALUE) *val = meth->i2v(meth, ext_internal, nullptr);
+ const auto stackCleaner = qScopeGuard([val]{
+ if (val)
+ q_OPENSSL_sk_pop_free((OPENSSL_STACK *)val, (void(*)(void*))q_X509V3_conf_free);
+ });
QVariantMap map;
QVariantList list;
@@ -222,10 +239,12 @@ QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
return map;
else
return list;
- } else if (meth->i2s && ext_internal) {
- QVariant result(QString::fromUtf8(meth->i2s(meth, ext_internal)));
+ } else if (meth->i2s) {
+ const char *hexString = meth->i2s(meth, ext_internal);
+ QVariant result(hexString ? QString::fromUtf8(hexString) : QString{});
+ q_OPENSSL_free((void *)hexString);
return result;
- } else if (meth->i2r && ext_internal) {
+ } else if (meth->i2r) {
QByteArray result;
BIO *bio = q_BIO_new(q_BIO_s_mem());
@@ -254,6 +273,31 @@ QVariant x509ExtensionToValue(X509_EXTENSION *ext)
{
ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
int nid = q_OBJ_obj2nid(obj);
+
+ // We cast away the const-ness here because some versions of openssl
+ // don't use const for the parameters in the functions pointers stored
+ // in the object.
+ X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
+
+ void *ext_internal = nullptr; // The value, returned by X509V3_EXT_d2i.
+ const auto extCleaner = qScopeGuard([meth, &ext_internal]() {
+ if (!meth || !ext_internal)
+ return;
+
+ if (meth->it)
+ q_ASN1_item_free(static_cast<ASN1_VALUE *>(ext_internal), ASN1_ITEM_ptr(meth->it));
+ else if (meth->ext_free)
+ meth->ext_free(ext_internal);
+ else
+ qWarning(lcTlsBackend, "Cannot free an extension, a potential memory leak?");
+ });
+
+ const char * hexString = nullptr; // The value returned by meth->i2s.
+ const auto hexStringCleaner = qScopeGuard([&hexString](){
+ if (hexString)
+ q_OPENSSL_free((void*)hexString);
+ });
+
switch (nid) {
case NID_basic_constraints:
{
@@ -295,21 +339,18 @@ QVariant x509ExtensionToValue(X509_EXTENSION *ext)
}
}
- q_OPENSSL_sk_pop_free((OPENSSL_STACK*)info, reinterpret_cast<void(*)(void *)>(q_OPENSSL_sk_free));
+ q_AUTHORITY_INFO_ACCESS_free(info);
return result;
}
break;
case NID_subject_key_identifier:
{
- void *ext_internal = q_X509V3_EXT_d2i(ext);
+ ext_internal = q_X509V3_EXT_d2i(ext);
if (!ext_internal)
return {};
- // we cast away the const-ness here because some versions of openssl
- // don't use const for the parameters in the functions pointers stored
- // in the object.
- X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
- return QVariant(QString::fromUtf8(meth->i2s(meth, ext_internal)));
+ hexString = meth->i2s(meth, ext_internal);
+ return QVariant(QString::fromUtf8(hexString));
}
break;
case NID_authority_key_identifier:
@@ -633,7 +674,7 @@ QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &ca
// certificate will be searched. Make sure to not have expired
// certificates mixed with valid ones.
//
- // See also: QSslContext::fromConfiguration()
+ // See also: QSslContext::sharedFromConfiguration()
if (caCertificate.expiryDate() >= now) {
q_X509_STORE_add_cert(certStore, reinterpret_cast<X509 *>(caCertificate.handle()));
}
diff --git a/src/plugins/tls/schannel/CMakeLists.txt b/src/plugins/tls/schannel/CMakeLists.txt
index 9f347416a4..f03964069a 100644
--- a/src/plugins/tls/schannel/CMakeLists.txt
+++ b/src/plugins/tls/schannel/CMakeLists.txt
@@ -1,8 +1,8 @@
qt_internal_add_plugin(QSchannelBackendPlugin
- OUTPUT_NAME schannelbackend
+ OUTPUT_NAME qschannelbackend
CLASS_NAME QSchannelBackend
- TYPE tls
- DEFAULT_IF WINDOWS
+ PLUGIN_TYPE tls
+ DEFAULT_IF WIN32
SOURCES
../shared/qtlskey_base_p.h
../shared/qtlskey_base.cpp
@@ -21,10 +21,9 @@ qt_internal_add_plugin(QSchannelBackendPlugin
qtlskey_schannel.cpp qtlskey_schannel_p.h
qx509_schannel.cpp qx509_schannel_p.h
LIBRARIES
+ Qt::NetworkPrivate
crypt32
secur32
bcrypt
ncrypt
- PUBLIC_LIBRARIES
- Qt::NetworkPrivate
)
diff --git a/src/plugins/tls/schannel/qtls_schannel.cpp b/src/plugins/tls/schannel/qtls_schannel.cpp
index 2ba0651cba..eb102c2553 100644
--- a/src/plugins/tls/schannel/qtls_schannel.cpp
+++ b/src/plugins/tls/schannel/qtls_schannel.cpp
@@ -161,7 +161,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.schannel");
+Q_LOGGING_CATEGORY(lcTlsBackendSchannel, "qt.tlsbackend.schannel");
// Defined in qsslsocket_qt.cpp.
QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
@@ -176,8 +176,11 @@ QList<QSslCipher> defaultCiphers()
// @temp (I hope), stolen from qsslsocket_winrt.cpp
const QString protocolStrings[] = { QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"),
QStringLiteral("TLSv1.2"), QStringLiteral("TLSv1.3") };
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1,
QSsl::TlsV1_2, QSsl::TlsV1_3 };
+QT_WARNING_POP
const int size = ARRAYSIZE(protocols);
static_assert(size == ARRAYSIZE(protocolStrings));
ciphers.reserve(size);
@@ -264,10 +267,13 @@ QList<QSsl::SslProtocol> QSchannelBackend::supportedProtocols() const
protocols << QSsl::AnyProtocol;
protocols << QSsl::SecureProtocols;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
protocols << QSsl::TlsV1_0;
protocols << QSsl::TlsV1_0OrLater;
protocols << QSsl::TlsV1_1;
protocols << QSsl::TlsV1_1OrLater;
+QT_WARNING_POP
protocols << QSsl::TlsV1_2;
protocols << QSsl::TlsV1_2OrLater;
@@ -283,8 +289,10 @@ QList<QSsl::SupportedFeature> QSchannelBackend::supportedFeatures() const
{
QList<QSsl::SupportedFeature> features;
+#ifdef SUPPORTS_ALPN
features << QSsl::SupportedFeature::ClientSideAlpn;
features << QSsl::SupportedFeature::ServerSideAlpn;
+#endif
return features;
}
@@ -430,9 +438,12 @@ DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
switch (protocol) {
case QSsl::UnknownProtocol:
return DWORD(-1);
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_2:
case QSsl::DtlsV1_0OrLater:
+QT_WARNING_POP
+ case QSsl::DtlsV1_2:
case QSsl::DtlsV1_2OrLater:
return DWORD(-1); // Not supported at the moment (@future)
case QSsl::AnyProtocol:
@@ -440,12 +451,15 @@ DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
if (supportsTls13())
protocols |= SP_PROT_TLS1_3;
break;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::TlsV1_0:
protocols = SP_PROT_TLS1_0;
break;
case QSsl::TlsV1_1:
protocols = SP_PROT_TLS1_1;
break;
+QT_WARNING_POP
case QSsl::TlsV1_2:
protocols = SP_PROT_TLS1_2;
break;
@@ -455,7 +469,8 @@ DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
else
protocols = DWORD(-1);
break;
- case QSsl::SecureProtocols: // TLS v1.0 and later is currently considered secure
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::TlsV1_0OrLater:
// For the "OrLater" protocols we fall through from one to the next, adding all of them
// in ascending order
@@ -464,6 +479,8 @@ DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
case QSsl::TlsV1_1OrLater:
protocols |= SP_PROT_TLS1_1;
Q_FALLTHROUGH();
+QT_WARNING_POP
+ case QSsl::SecureProtocols: // TLS v1.2 and later is currently considered secure
case QSsl::TlsV1_2OrLater:
protocols |= SP_PROT_TLS1_2;
Q_FALLTHROUGH();
@@ -504,8 +521,11 @@ QSsl::SslProtocol toQtSslProtocol(DWORD protocol)
return q_protocol; \
}
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
MAP_PROTOCOL(SP_PROT_TLS1_0, QSsl::TlsV1_0)
MAP_PROTOCOL(SP_PROT_TLS1_1, QSsl::TlsV1_1)
+QT_WARNING_POP
MAP_PROTOCOL(SP_PROT_TLS1_2, QSsl::TlsV1_2)
MAP_PROTOCOL(SP_PROT_TLS1_3, QSsl::TlsV1_3)
#undef MAP_PROTOCOL
@@ -570,7 +590,7 @@ bool matchesContextRequirements(DWORD attributes, DWORD requirements,
bool isClient)
{
#ifdef QSSLSOCKET_DEBUG
-#define DEBUG_WARN(message) qCWarning(lcTlsBackend, message)
+#define DEBUG_WARN(message) qCWarning(lcTlsBackendSchannel, message)
#else
#define DEBUG_WARN(message)
#endif
@@ -614,21 +634,16 @@ Required const_reinterpret_cast(Actual *p)
}
#ifdef SUPPORTS_ALPN
-bool supportsAlpn()
-{
- return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8_1;
-}
-
QByteArray createAlpnString(const QByteArrayList &nextAllowedProtocols)
{
QByteArray alpnString;
- if (!nextAllowedProtocols.isEmpty() && supportsAlpn()) {
+ if (!nextAllowedProtocols.isEmpty()) {
const QByteArray names = [&nextAllowedProtocols]() {
QByteArray protocolString;
for (QByteArray proto : nextAllowedProtocols) {
if (proto.size() > 255) {
- qCWarning(lcTlsBackend) << "TLS ALPN extension" << proto
- << "is too long and will be ignored.";
+ qCWarning(lcTlsBackendSchannel)
+ << "TLS ALPN extension" << proto << "is too long and will be ignored.";
continue;
} else if (proto.isEmpty()) {
continue;
@@ -681,7 +696,8 @@ void retainExtraData(QByteArray &buffer, const SecBuffer &secBuffer)
return;
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "We got SECBUFFER_EXTRA, will retain %lu bytes", secBuffer.cbBuffer);
+ qCDebug(lcTlsBackendSchannel, "We got SECBUFFER_EXTRA, will retain %lu bytes",
+ secBuffer.cbBuffer);
#endif
std::move(buffer.end() - secBuffer.cbBuffer, buffer.end(), buffer.begin());
buffer.resize(secBuffer.cbBuffer);
@@ -691,7 +707,7 @@ qint64 checkIncompleteData(const SecBuffer &secBuffer)
{
if (secBuffer.BufferType == SECBUFFER_MISSING) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "Need %lu more bytes.", secBuffer.cbBuffer);
+ qCDebug(lcTlsBackendSchannel, "Need %lu more bytes.", secBuffer.cbBuffer);
#endif
return secBuffer.cbBuffer;
}
@@ -1141,8 +1157,9 @@ bool TlsCryptographSchannel::performHandshake()
Q_ASSERT(schannelState == SchannelState::PerformHandshake);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "Bytes available from socket: %lld", plainSocket->bytesAvailable());
- qCDebug(lcTlsBackend, "intermediateBuffer size: %d", intermediateBuffer.size());
+ qCDebug(lcTlsBackendSchannel, "Bytes available from socket: %lld",
+ plainSocket->bytesAvailable());
+ qCDebug(lcTlsBackendSchannel, "intermediateBuffer size: %d", intermediateBuffer.size());
#endif
if (missingData > plainSocket->bytesAvailable())
@@ -1305,7 +1322,7 @@ bool TlsCryptographSchannel::verifyHandshake()
#ifdef SUPPORTS_ALPN
const auto allowedProtos = configuration.allowedNextProtocols();
- if (!allowedProtos.isEmpty() && supportsAlpn()) {
+ if (!allowedProtos.isEmpty()) {
SecPkgContext_ApplicationProtocol alpn;
status = QueryContextAttributes(&contextHandle,
SECPKG_ATTR_APPLICATION_PROTOCOL,
@@ -1350,8 +1367,8 @@ bool TlsCryptographSchannel::verifyHandshake()
&& configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::QueryPeer)) {
if (status != SEC_E_OK) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "Couldn't retrieve peer certificate, status:"
- << schannelErrorToString(status);
+ qCDebug(lcTlsBackendSchannel) << "Couldn't retrieve peer certificate, status:"
+ << schannelErrorToString(status);
#endif
const QSslError error{ QSslError::NoPeerCertificate };
sslErrors += error;
@@ -1367,7 +1384,7 @@ bool TlsCryptographSchannel::verifyHandshake()
if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << __func__ << "was unsuccessful. Paused:" << paused;
+ qCDebug(lcTlsBackendSchannel) << __func__ << "was unsuccessful. Paused:" << d->isPaused();
#endif
// If we're paused then checkSslErrors returned false, but it's not an error
return d->isPaused() && q->state() == QAbstractSocket::ConnectedState;
@@ -1550,7 +1567,8 @@ void TlsCryptographSchannel::transmit()
fullMessage.resize(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer + inputBuffers[2].cbBuffer);
const qint64 bytesWritten = plainSocket->write(fullMessage);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "Wrote %lld of total %d bytes", bytesWritten, fullMessage.length());
+ qCDebug(lcTlsBackendSchannel, "Wrote %lld of total %d bytes", bytesWritten,
+ fullMessage.length());
#endif
if (bytesWritten >= 0) {
totalBytesWritten += bytesWritten;
@@ -1580,7 +1598,8 @@ void TlsCryptographSchannel::transmit()
if (missingData > plainSocket->bytesAvailable()
&& (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "We're still missing %lld bytes, will check later.", missingData);
+ qCDebug(lcTlsBackendSchannel, "We're still missing %lld bytes, will check later.",
+ missingData);
#endif
break;
}
@@ -1588,18 +1607,20 @@ void TlsCryptographSchannel::transmit()
missingData = 0;
const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "Read %lld encrypted bytes from the socket", bytesRead);
+ qCDebug(lcTlsBackendSchannel, "Read %lld encrypted bytes from the socket", bytesRead);
#endif
if (intermediateBuffer.length() == 0 || (hadIncompleteData && bytesRead == 0)) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, (hadIncompleteData ? "No new data received, leaving loop!"
- : "Nothing to decrypt, leaving loop!"));
+ qCDebug(lcTlsBackendSchannel,
+ (hadIncompleteData ? "No new data received, leaving loop!"
+ : "Nothing to decrypt, leaving loop!"));
#endif
break;
}
hadIncompleteData = false;
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "Total amount of bytes to decrypt: %d", intermediateBuffer.length());
+ qCDebug(lcTlsBackendSchannel, "Total amount of bytes to decrypt: %d",
+ intermediateBuffer.length());
#endif
SecBuffer dataBuffer[4]{
@@ -1624,7 +1645,7 @@ void TlsCryptographSchannel::transmit()
dataBuffer[1].cbBuffer);
totalRead += dataBuffer[1].cbBuffer;
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "Decrypted %lu bytes. New read buffer size: %d",
+ qCDebug(lcTlsBackendSchannel, "Decrypted %lu bytes. New read buffer size: %d",
dataBuffer[1].cbBuffer, buffer.size());
#endif
}
@@ -1641,16 +1662,17 @@ void TlsCryptographSchannel::transmit()
if (status == SEC_E_INCOMPLETE_MESSAGE) {
missingData = checkIncompleteData(dataBuffer[0]);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "We didn't have enough data to decrypt anything, will try again!");
+ qCDebug(lcTlsBackendSchannel,
+ "We didn't have enough data to decrypt anything, will try again!");
#endif
// We try again, but if we don't get any more data then we leave
hadIncompleteData = true;
} else if (status == SEC_E_INVALID_HANDLE) {
// I don't think this should happen, if it does we're done...
- qCWarning(lcTlsBackend, "The internal SSPI handle is invalid!");
+ qCWarning(lcTlsBackendSchannel, "The internal SSPI handle is invalid!");
Q_UNREACHABLE();
} else if (status == SEC_E_INVALID_TOKEN) {
- qCWarning(lcTlsBackend, "Got SEC_E_INVALID_TOKEN!");
+ qCWarning(lcTlsBackendSchannel, "Got SEC_E_INVALID_TOKEN!");
Q_UNREACHABLE(); // Happened once due to a bug, but shouldn't generally happen(?)
} else if (status == SEC_E_MESSAGE_ALTERED) {
// The message has been altered, disconnect now.
@@ -1677,7 +1699,7 @@ void TlsCryptographSchannel::transmit()
} else if (status == SEC_I_RENEGOTIATE) {
// 'remote' wants to renegotiate
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend, "The peer wants to renegotiate.");
+ qCDebug(lcTlsBackendSchannel, "The peer wants to renegotiate.");
#endif
schannelState = SchannelState::Renegotiate;
renegotiating = true;
@@ -1713,7 +1735,8 @@ void TlsCryptographSchannel::sendShutdown()
if (status != SEC_E_OK) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "Failed to apply shutdown control token:" << schannelErrorToString(status);
+ qCDebug(lcTlsBackendSchannel)
+ << "Failed to apply shutdown control token:" << schannelErrorToString(status);
#endif
return;
}
@@ -1771,7 +1794,8 @@ void TlsCryptographSchannel::sendShutdown()
}
} else {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "Failed to initialize shutdown:" << schannelErrorToString(status);
+ qCDebug(lcTlsBackendSchannel)
+ << "Failed to initialize shutdown:" << schannelErrorToString(status);
#endif
}
}
@@ -1965,7 +1989,7 @@ void TlsCryptographSchannel::initializeCertificateStores()
localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(),
configuration.privateKey());
if (localCertificateStore == nullptr)
- qCWarning(lcTlsBackend, "Failed to load certificate chain!");
+ qCWarning(lcTlsBackendSchannel, "Failed to load certificate chain!");
}
}
@@ -1992,7 +2016,7 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
nullptr));
if (!tempCertCollection) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend, "Failed to create certificate store collection!");
+ qCWarning(lcTlsBackendSchannel, "Failed to create certificate store collection!");
#endif
return false;
}
@@ -2005,12 +2029,14 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
auto rootStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
if (!rootStore) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend, "Failed to open the system root CA certificate store!");
+ qCWarning(lcTlsBackendSchannel, "Failed to open the system root CA certificate store!");
#endif
return false;
} else if (!CertAddStoreToCollection(tempCertCollection.get(), rootStore.get(), 0, 1)) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend, "Failed to add the system root CA certificate store to the certificate store collection!");
+ qCWarning(lcTlsBackendSchannel,
+ "Failed to add the system root CA certificate store to the certificate store "
+ "collection!");
#endif
return false;
}
@@ -2018,7 +2044,9 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
if (caCertificateStore) {
if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend, "Failed to add the user's CA certificate store to the certificate store collection!");
+ qCWarning(lcTlsBackendSchannel,
+ "Failed to add the user's CA certificate store to the certificate store "
+ "collection!");
#endif
return false;
}
@@ -2026,7 +2054,8 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend, "Failed to add certificate's origin store to the certificate store collection!");
+ qCWarning(lcTlsBackendSchannel,
+ "Failed to add certificate's origin store to the certificate store collection!");
#endif
return false;
}
@@ -2118,11 +2147,11 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
const QList<QSslCertificateExtension> extensions = certificate.extensions();
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "issuer:" << certificate.issuerDisplayName()
- << "\nsubject:" << certificate.subjectDisplayName()
- << "\nQSslCertificate info:" << certificate
- << "\nextended error info:" << element->pwszExtendedErrorInfo
- << "\nerror status:" << element->TrustStatus.dwErrorStatus;
+ qCDebug(lcTlsBackendSchannel) << "issuer:" << certificate.issuerDisplayName()
+ << "\nsubject:" << certificate.subjectDisplayName()
+ << "\nQSslCertificate info:" << certificate
+ << "\nextended error info:" << element->pwszExtendedErrorInfo
+ << "\nerror status:" << element->TrustStatus.dwErrorStatus;
#endif
peerCertificateChain.append(certificate);
diff --git a/src/plugins/tls/schannel/qtlsbackend_schannel_p.h b/src/plugins/tls/schannel/qtlsbackend_schannel_p.h
index e53cf17f13..d866e67c9e 100644
--- a/src/plugins/tls/schannel/qtlsbackend_schannel_p.h
+++ b/src/plugins/tls/schannel/qtlsbackend_schannel_p.h
@@ -97,6 +97,8 @@ private:
static bool s_loadedCiphersAndCerts;
};
+Q_DECLARE_LOGGING_CATEGORY(lcTlsBackendSchannel)
+
QT_END_NAMESPACE
#endif // QTLSBACKEND_ST_P_H
diff --git a/src/plugins/tls/schannel/qtlskey_schannel.cpp b/src/plugins/tls/schannel/qtlskey_schannel.cpp
index e407da2ed3..5004cd9c55 100644
--- a/src/plugins/tls/schannel/qtlskey_schannel.cpp
+++ b/src/plugins/tls/schannel/qtlskey_schannel.cpp
@@ -39,6 +39,7 @@
#include <QtNetwork/private/qssl_p.h>
+#include "qtlsbackend_schannel_p.h"
#include "qtlskey_schannel_p.h"
#include "../shared/qwincrypt_p.h"
@@ -81,7 +82,7 @@ BCRYPT_ALG_HANDLE getHandle(QSslKeyPrivate::Cipher cipher)
0 // dwFlags
);
if (status < 0) {
- qCWarning(lcTlsBackend, "Failed to open algorithm handle (%ld)!", status);
+ qCWarning(lcTlsBackendSchannel, "Failed to open algorithm handle (%ld)!", status);
return nullptr;
}
@@ -102,7 +103,7 @@ BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle,
0 // dwFlags
);
if (status < 0) {
- qCWarning(lcTlsBackend, "Failed to generate symmetric key (%ld)!", status);
+ qCWarning(lcTlsBackendSchannel, "Failed to generate symmetric key (%ld)!", status);
return nullptr;
}
@@ -115,7 +116,8 @@ BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle,
);
if (status < 0) {
BCryptDestroyKey(keyHandle);
- qCWarning(lcTlsBackend, "Failed to change the symmetric key's chaining mode (%ld)!", status);
+ qCWarning(lcTlsBackendSchannel, "Failed to change the symmetric key's chaining mode (%ld)!",
+ status);
return nullptr;
}
return keyHandle;
@@ -160,7 +162,8 @@ QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const
BCRYPT_BLOCK_PADDING // dwFlags
);
if (status < 0) {
- qCWarning(lcTlsBackend, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt", status);
+ qCWarning(lcTlsBackendSchannel, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt",
+ status);
return {};
}
}
diff --git a/src/plugins/tls/securetransport/CMakeLists.txt b/src/plugins/tls/securetransport/CMakeLists.txt
index 6d86191879..0355049157 100644
--- a/src/plugins/tls/securetransport/CMakeLists.txt
+++ b/src/plugins/tls/securetransport/CMakeLists.txt
@@ -1,7 +1,7 @@
qt_internal_add_plugin(QSecureTransportBackendPlugin
- OUTPUT_NAME securetransportbackend
+ OUTPUT_NAME qsecuretransportbackend
CLASS_NAME QSecureTransportBackend
- TYPE tls
+ PLUGIN_TYPE tls
DEFAULT_IF APPLE
SOURCES
../shared/qsslsocket_mac_shared.cpp
@@ -24,10 +24,9 @@ qt_internal_add_plugin(QSecureTransportBackendPlugin
qx509_st_p.h
qtls_st.cpp
qtls_st_p.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::NetworkPrivate
Qt::CorePrivate
- LIBRARIES
${FWCoreFoundation}
${FWSecurity}
)
diff --git a/src/plugins/tls/securetransport/qtls_st.cpp b/src/plugins/tls/securetransport/qtls_st.cpp
index 306f184f25..8b391b9f31 100644
--- a/src/plugins/tls/securetransport/qtls_st.cpp
+++ b/src/plugins/tls/securetransport/qtls_st.cpp
@@ -109,7 +109,7 @@ EphemeralSecKeychain::EphemeralSecKeychain()
{
const auto uuid = QUuid::createUuid();
if (uuid.isNull()) {
- qCWarning(lcTlsBackend) << "Failed to create a unique keychain name";
+ qCWarning(lcSecureTransport) << "Failed to create a unique keychain name";
return;
}
@@ -136,14 +136,14 @@ EphemeralSecKeychain::EphemeralSecKeychain()
const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0],
CFIndex(posixPath.size()));
if (!ok) {
- qCWarning(lcTlsBackend) << "Failed to create a unique keychain name from"
- << "QDir::tempPath()";
+ qCWarning(lcSecureTransport) << "Failed to create a unique keychain name from"
+ << "QDir::tempPath()";
return;
}
std::vector<uint8_t> passUtf8(256);
if (SecRandomCopyBytes(kSecRandomDefault, passUtf8.size(), &passUtf8[0])) {
- qCWarning(lcTlsBackend) << "SecRandomCopyBytes: failed to create a key";
+ qCWarning(lcSecureTransport) << "SecRandomCopyBytes: failed to create a key";
return;
}
@@ -151,7 +151,7 @@ EphemeralSecKeychain::EphemeralSecKeychain()
&passUtf8[0], FALSE, nullptr,
&keychain);
if (status != errSecSuccess || !keychain) {
- qCWarning(lcTlsBackend) << "SecKeychainCreate: failed to create a custom keychain";
+ qCWarning(lcSecureTransport) << "SecKeychainCreate: failed to create a custom keychain";
if (keychain) {
SecKeychainDelete(keychain);
CFRelease(keychain);
@@ -166,13 +166,13 @@ EphemeralSecKeychain::EphemeralSecKeychain()
// == false, set interval to INT_MAX to never lock ...
settings.lockInterval = INT_MAX;
if (SecKeychainSetSettings(keychain, &settings) != errSecSuccess)
- qCWarning(lcTlsBackend) << "SecKeychainSettings: failed to disable lock on sleep";
+ qCWarning(lcSecureTransport) << "SecKeychainSettings: failed to disable lock on sleep";
}
#ifdef QSSLSOCKET_DEBUG
if (keychain) {
- qCDebug(lcTlsBackend) << "Custom keychain with name" << keychainName << "was created"
- << "successfully";
+ qCDebug(lcSecureTransport) << "Custom keychain with name" << keychainName << "was created"
+ << "successfully";
}
#endif
}
@@ -204,7 +204,7 @@ SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
// We never use kSSLDatagramType, so it's kSSLStreamType unconditionally.
SSLContextRef context = SSLCreateContext(nullptr, side, kSSLStreamType);
if (!context)
- qCWarning(lcTlsBackend) << "SSLCreateContext failed";
+ qCWarning(lcSecureTransport) << "SSLCreateContext failed";
return context;
}
@@ -280,7 +280,7 @@ OSStatus TlsCryptographSecureTransport::ReadCallback(TlsCryptographSecureTranspo
const qint64 bytes = plainSocket->read(data, *dataLength);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "read" << bytes;
+ qCDebug(lcSecureTransport) << plainSocket << "read" << bytes;
#endif
if (bytes < 0) {
*dataLength = 0;
@@ -306,7 +306,7 @@ OSStatus TlsCryptographSecureTransport::WriteCallback(TlsCryptographSecureTransp
const qint64 bytes = plainSocket->write(data, *dataLength);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "write" << bytes;
+ qCDebug(lcSecureTransport) << plainSocket << "write" << bytes;
#endif
if (bytes < 0) {
*dataLength = 0;
@@ -346,7 +346,7 @@ void TlsCryptographSecureTransport::continueHandshake()
Q_ASSERT(d);
d->setEncrypted(true);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << d->plainTcpSocket() << "connection encrypted";
+ qCDebug(lcSecureTransport) << d->plainTcpSocket() << "connection encrypted";
#endif
#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13_4, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
@@ -398,6 +398,7 @@ void TlsCryptographSecureTransport::continueHandshake()
void TlsCryptographSecureTransport::disconnected()
{
Q_ASSERT(d && d->plainTcpSocket());
+ d->setEncrypted(false);
if (d->plainTcpSocket()->bytesAvailable() <= 0)
destroySslContext();
// If there is still buffered data in the plain socket, don't destroy the ssl context yet.
@@ -433,15 +434,18 @@ QSsl::SslProtocol TlsCryptographSecureTransport::sessionProtocol() const
SSLProtocol protocol = kSSLProtocolUnknown;
const OSStatus err = SSLGetNegotiatedProtocolVersion(context, &protocol);
if (err != errSecSuccess) {
- qCWarning(lcTlsBackend) << "SSLGetNegotiatedProtocolVersion failed:" << err;
+ qCWarning(lcSecureTransport) << "SSLGetNegotiatedProtocolVersion failed:" << err;
return QSsl::UnknownProtocol;
}
switch (protocol) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case kTLSProtocol1:
return QSsl::TlsV1_0;
case kTLSProtocol11:
return QSsl::TlsV1_1;
+QT_WARNING_POP
case kTLSProtocol12:
return QSsl::TlsV1_2;
case kTLSProtocol13:
@@ -499,7 +503,7 @@ void TlsCryptographSecureTransport::transmit()
size_t writtenBytes = 0;
const OSStatus err = SSLWrite(context, writeBuffer.readPointer(), nextDataBlockSize, &writtenBytes);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << d->plainTcpSocket() << "SSLWrite returned" << err;
+ qCDebug(lcSecureTransport) << d->plainTcpSocket() << "SSLWrite returned" << err;
#endif
if (err != errSecSuccess && err != errSSLWouldBlock) {
setErrorAndEmit(d, QAbstractSocket::SslInternalError,
@@ -537,7 +541,7 @@ void TlsCryptographSecureTransport::transmit()
data.resize(4096);
const OSStatus err = SSLRead(context, data.data(), data.size(), &readBytes);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << d->plainTcpSocket() << "SSLRead returned" << err;
+ qCDebug(lcSecureTransport) << d->plainTcpSocket() << "SSLRead returned" << err;
#endif
if (err == errSSLClosedGraceful) {
shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
@@ -702,8 +706,8 @@ bool TlsCryptographSecureTransport::initSslContext()
if (cfNames) {
for (const QByteArray &name : protocolNames) {
if (name.size() > 255) {
- qCWarning(lcTlsBackend) << "TLS ALPN extension" << name
- << "is too long and will be ignored.";
+ qCWarning(lcSecureTransport) << "TLS ALPN extension" << name
+ << "is too long and will be ignored.";
continue;
} else if (name.isEmpty()) {
continue;
@@ -717,10 +721,10 @@ bool TlsCryptographSecureTransport::initSslContext()
// failed, and handle this non-TLS error, we do not handle
// the result of this call as an error:
if (SSLSetALPNProtocols(context, cfNames) != errSecSuccess)
- qCWarning(lcTlsBackend) << "SSLSetALPNProtocols failed - too long protocol names?";
+ qCWarning(lcSecureTransport) << "SSLSetALPNProtocols failed - too long protocol names?";
}
} else {
- qCWarning(lcTlsBackend) << "failed to allocate ALPN names array";
+ qCWarning(lcSecureTransport) << "failed to allocate ALPN names array";
}
}
#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE
@@ -775,12 +779,12 @@ bool TlsCryptographSecureTransport::initSslContext()
cfCiphers << sslCipher;
}
if (cfCiphers.size() == 0) {
- qCWarning(lcTlsBackend) << "failed to add any of the requested ciphers from the configuration";
+ qCWarning(lcSecureTransport) << "failed to add any of the requested ciphers from the configuration";
return false;
}
OSStatus err = SSLSetEnabledCiphers(context, cfCiphers.data(), cfCiphers.size());
if (err != errSecSuccess) {
- qCWarning(lcTlsBackend) << "failed to set the ciphers from the configuration";
+ qCWarning(lcSecureTransport) << "failed to set the ciphers from the configuration";
return false;
}
}
@@ -842,8 +846,8 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
OSStatus err = SecPKCS12Import(pkcs12, options, &items);
if (err != errSecSuccess) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend) << plainSocket
- << QStringLiteral("SecPKCS12Import failed: %1").arg(err);
+ qCWarning(lcSecureTransport) << plainSocket
+ << QStringLiteral("SecPKCS12Import failed: %1").arg(err);
#endif
errorCode = QAbstractSocket::SslInvalidUserDataError;
errorDescription = QStringLiteral("SecPKCS12Import failed: %1").arg(err);
@@ -852,7 +856,7 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
if (!CFArrayGetCount(items)) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend) << plainSocket << "SecPKCS12Import returned no items";
+ qCWarning(lcSecureTransport) << plainSocket << "SecPKCS12Import returned no items";
#endif
errorCode = QAbstractSocket::SslInvalidUserDataError;
errorDescription = QStringLiteral("SecPKCS12Import returned no items");
@@ -863,7 +867,7 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(import, kSecImportItemIdentity);
if (!identity) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend) << plainSocket << "SecPKCS12Import returned no identity";
+ qCWarning(lcSecureTransport) << plainSocket << "SecPKCS12Import returned no identity";
#endif
errorCode = QAbstractSocket::SslInvalidUserDataError;
errorDescription = QStringLiteral("SecPKCS12Import returned no identity");
@@ -888,8 +892,8 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
err = SSLSetCertificate(context, certs);
if (err != errSecSuccess) {
#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend)
- << plainSocket << QStringLiteral("Cannot set certificate and key: %1").arg(err);
+ qCWarning(lcSecureTransport) << plainSocket
+ << QStringLiteral("Cannot set certificate and key: %1").arg(err);
#endif
errorCode = QAbstractSocket::SslInvalidUserDataError;
errorDescription = QStringLiteral("Cannot set certificate and key: %1").arg(err);
@@ -914,62 +918,68 @@ bool TlsCryptographSecureTransport::setSessionProtocol()
switch (configuration.protocol()) {
case QSsl::TlsV1_3:
case QSsl::TlsV1_3OrLater:
- qCWarning(lcTlsBackend) << plainSocket << "SecureTransport does not support TLS 1.3";
+ qCWarning(lcSecureTransport) << plainSocket << "SecureTransport does not support TLS 1.3";
return false;
default:;
}
OSStatus err = errSecSuccess;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
if (configuration.protocol() == QSsl::TlsV1_0) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.0";
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.0";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
if (err == errSecSuccess)
err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
} else if (configuration.protocol() == QSsl::TlsV1_1) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1";
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.1";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
if (err == errSecSuccess)
err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
+QT_WARNING_POP
} else if (configuration.protocol() == QSsl::TlsV1_2) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
if (err == errSecSuccess)
err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
} else if (configuration.protocol() == QSsl::AnyProtocol) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : any";
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : any";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
} else if (configuration.protocol() == QSsl::SecureProtocols) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
#endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
} else if (configuration.protocol() == QSsl::TlsV1_0OrLater) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1 - TLSv1.2";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
} else if (configuration.protocol() == QSsl::TlsV1_1OrLater) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
+QT_WARNING_POP
} else if (configuration.protocol() == QSsl::TlsV1_2OrLater) {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
+ qCDebug(lcSecureTransport) << plainSocket << "requesting : TLSv1.2";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
} else {
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "no protocol version found in the configuration";
+ qCDebug(lcSecureTransport) << plainSocket << "no protocol version found in the configuration";
#endif
return false;
}
@@ -998,11 +1008,14 @@ bool TlsCryptographSecureTransport::verifySessionProtocol() const
if (configuration.protocol() == QSsl::AnyProtocol)
protocolOk = true;
else if (configuration.protocol() == QSsl::SecureProtocols)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
+ protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
else if (configuration.protocol() == QSsl::TlsV1_0OrLater)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
else if (configuration.protocol() == QSsl::TlsV1_1OrLater)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
+QT_WARNING_POP
else if (configuration.protocol() == QSsl::TlsV1_2OrLater)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
else if (configuration.protocol() == QSsl::TlsV1_3OrLater)
@@ -1127,7 +1140,7 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
CFArrayAppendValue(certArray, secRef);
else
- qCWarning(lcTlsBackend, "Failed to create SecCertificate from QSslCertificate");
+ qCWarning(lcSecureTransport, "Failed to create SecCertificate from QSslCertificate");
}
SecTrustSetAnchorCertificates(trust, certArray);
@@ -1236,7 +1249,7 @@ bool TlsCryptographSecureTransport::startHandshake()
OSStatus err = SSLHandshake(context);
#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "SSLHandhake returned" << err;
+ qCDebug(lcSecureTransport) << plainSocket << "SSLHandhake returned" << err;
#endif
if (err == errSSLWouldBlock) {
@@ -1282,7 +1295,7 @@ bool TlsCryptographSecureTransport::startHandshake()
// Connection aborted during handshake phase.
if (q->state() != QAbstractSocket::ConnectedState) {
- qCDebug(lcTlsBackend) << "connection aborted";
+ qCDebug(lcSecureTransport) << "connection aborted";
renegotiating = false;
return false;
}
diff --git a/src/plugins/tls/securetransport/qtlsbackend_st.cpp b/src/plugins/tls/securetransport/qtlsbackend_st.cpp
index 7fc7692350..5b60b69b4f 100644
--- a/src/plugins/tls/securetransport/qtlsbackend_st.cpp
+++ b/src/plugins/tls/securetransport/qtlsbackend_st.cpp
@@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QRecursiveMutex, qt_securetransport_mutex)
-Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.securetransport");
+Q_LOGGING_CATEGORY(lcSecureTransport, "qt.tlsbackend.securetransport");
namespace QTlsPrivate {
@@ -294,10 +294,13 @@ QList<QSsl::SslProtocol> QSecureTransportBackend::supportedProtocols() const
protocols << QSsl::AnyProtocol;
protocols << QSsl::SecureProtocols;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
protocols << QSsl::TlsV1_0;
protocols << QSsl::TlsV1_0OrLater;
protocols << QSsl::TlsV1_1;
protocols << QSsl::TlsV1_1OrLater;
+QT_WARNING_POP
protocols << QSsl::TlsV1_2;
protocols << QSsl::TlsV1_2OrLater;
diff --git a/src/plugins/tls/securetransport/qtlsbackend_st_p.h b/src/plugins/tls/securetransport/qtlsbackend_st_p.h
index ebce859db3..3ccad01a95 100644
--- a/src/plugins/tls/securetransport/qtlsbackend_st_p.h
+++ b/src/plugins/tls/securetransport/qtlsbackend_st_p.h
@@ -91,6 +91,8 @@ private:
static bool s_loadedCiphersAndCerts;
};
+Q_DECLARE_LOGGING_CATEGORY(lcSecureTransport)
+
QT_END_NAMESPACE
#endif // QTLSBACKEND_ST_P_H
diff --git a/src/plugins/tls/shared/qdtls_base.cpp b/src/plugins/tls/shared/qdtls_base.cpp
index 6a5979eb9e..b27cac11d5 100644
--- a/src/plugins/tls/shared/qdtls_base.cpp
+++ b/src/plugins/tls/shared/qdtls_base.cpp
@@ -99,8 +99,11 @@ QDtlsBasePrivate::cookieGeneratorParameters() const
bool QDtlsBasePrivate::isDtlsProtocol(QSsl::SslProtocol protocol)
{
switch (protocol) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::DtlsV1_0:
case QSsl::DtlsV1_0OrLater:
+QT_WARNING_POP
case QSsl::DtlsV1_2:
case QSsl::DtlsV1_2OrLater:
return true;
diff --git a/src/plugins/tls/shared/qsslsocket_mac_shared.cpp b/src/plugins/tls/shared/qsslsocket_mac_shared.cpp
index b808c9e83b..cdecdee9b2 100644
--- a/src/plugins/tls/shared/qsslsocket_mac_shared.cpp
+++ b/src/plugins/tls/shared/qsslsocket_mac_shared.cpp
@@ -57,8 +57,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcTlsBackend)
-
#ifdef Q_OS_MACOS
namespace {
@@ -107,9 +105,8 @@ bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain)
}
}
}
- } else {
- qCWarning(lcTlsBackend, "Error receiving trust for a CA certificate");
}
+
return false;
}
@@ -133,11 +130,8 @@ QList<QSslCertificate> systemCaCertificates()
SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert);
if (isCaCertificateTrusted(cfCert, dom)) {
- if (derData == nullptr) {
- qCWarning(lcTlsBackend, "Error retrieving a CA certificate from the system store");
- } else {
+ if (derData)
systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
- }
}
}
}
diff --git a/src/plugins/tls/shared/qsslsocket_qt.cpp b/src/plugins/tls/shared/qsslsocket_qt.cpp
index 128459ea19..8f8a87138f 100644
--- a/src/plugins/tls/shared/qsslsocket_qt.cpp
+++ b/src/plugins/tls/shared/qsslsocket_qt.cpp
@@ -109,15 +109,11 @@ static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QStrin
QByteArray A;
QByteArray B;
B.resize(v);
- QCryptographicHash hash(QCryptographicHash::Sha1);
for (int i = 0; i < c; ++i) {
// hash r iterations
QByteArray Ai = D + I;
- for (int j = 0; j < r; ++j) {
- hash.reset();
- hash.addData(Ai);
- Ai = hash.result();
- }
+ for (int j = 0; j < r; ++j)
+ Ai = QCryptographicHash::hash(Ai, QCryptographicHash::Sha1);
for (int j = 0; j < v; ++j)
B[j] = Ai[j % u];
diff --git a/src/plugins/tls/shared/qtlskey_generic.cpp b/src/plugins/tls/shared/qtlskey_generic.cpp
index b9eaf3c1f6..495ccec681 100644
--- a/src/plugins/tls/shared/qtlskey_generic.cpp
+++ b/src/plugins/tls/shared/qtlskey_generic.cpp
@@ -424,9 +424,9 @@ QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhr
hash.addData(data);
if (cipher == Cipher::Aes192Cbc)
- return key.append(hash.result().constData(), 8);
+ return key.append(hash.resultView().first(8));
- return key.append(hash.result());
+ return key.append(hash.resultView());
}
QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase,
diff --git a/src/plugins/tls/shared/qx509_generic.cpp b/src/plugins/tls/shared/qx509_generic.cpp
index 9265498c4e..f5fd1b6b30 100644
--- a/src/plugins/tls/shared/qx509_generic.cpp
+++ b/src/plugins/tls/shared/qx509_generic.cpp
@@ -79,8 +79,6 @@ bool X509CertificateGeneric::isSelfSigned() const
if (null)
return false;
- qCWarning(lcTlsBackend, "QSslCertificate::isSelfSigned: This function does not check, whether the certificate "
- "is actually signed. It just checks whether issuer and subject are identical");
return subjectMatchesIssuer;
}